2009-12-15 119 views
0

假设这些都是我的父母和我的子对象:Hibernate的级联删除不工作

家长:

@Entity 
@Table(name = "import_table") 
public class ImportTable { 
    @Cascade({ CascadeType.ALL, CascadeType.DELETE_ORPHAN }) 
    @OneToMany(
     mappedBy = "table", 
     fetch = FetchType.EAGER 
    ) 
    public List<ImportTableColumn> getColumns() 
    { 
     return columns; 
    } 
    ... setter is defined but I don't think it's important for the example 
} 

儿童:

@Entity 
@Table(name = "import_table_column") 
public class ImportTableColumn { 
    @ManyToOne 
    @JoinColumn(
     name = "import_table_name", 
     nullable = false 
    ) 
    public ImportTable getTable() 
    { 
     return table; 
    } 
} 

以下伪代码将起作用

  • 创建ImportTable实例,添加2列,创建会话,保存它,关闭会话;
  • 在不同的会话中读取保存的实例,删除一列;
  • 将它保存在另一个会话中;
  • 检查列数等于1。

但下面的不会起作用:

  • 创建ImportTable的情况下,增加2列,创建一个会话,保存,关闭会话;
  • 在不同的会话中读取保存的实例;
  • 手动重新创建保存的对象;
  • 删除列;
  • 将它保存在另一个会话中;
  • 检查列数等于1。

原因是我们有一个Java服务器/ Flex客户端应用程序,我们需要加载对象,将它发送到客户端,让客户端做它必须做的任何事情,将对象发回到服务器,然后保存它。

我认为当我重新创建对象时,Hibernate正在迷失。据我所知,当从数据库中检索到对象时,Hibernate确实在对象中注入了一些东西。当我重新创建对象时,我不会复制对象类中不是已声明字段的任何内容。这是重新创建对象的代码(用于我的单元测试):

private ImportTable recreate(ImportTable original) throws IOException 
{ 
    final ImportTable copy = new ImportTable(); 
    copy.setDatabaseTableName(original.getDatabaseTableName()); 
    copy.setDisplayTableName(original.getDisplayTableName()); 
    if(original.getColumns() != null) { 
     copy.setColumns(new ArrayList<ImportTableColumn>(original.getColumns().size())); 
     for(ImportTableColumn originalColumn : original.getColumns()) { 
      final ImportTableColumn copyColumn = new ImportTableColumn(); 
      copyColumn.setTable(copy); 
      copyColumn.setDatabaseColumnName(originalColumn.getDatabaseColumnName()); 
      copyColumn.setDatatype(originalColumn.getDatatype()); 
      copyColumn.setExcelColumnName(originalColumn.getExcelColumnName()); 
      copyColumn.setId(originalColumn.getId()); 
      copyColumn.setLength(originalColumn.getLength()); 
      copyColumn.setPk(originalColumn.isPk()); 
      copyColumn.setRequired(originalColumn.isRequired()); 
      copyColumn.setPrecision(originalColumn.getPrecision()); 
      copy.getColumns().add(copyColumn); 
     } 
    } 
    return copy; 
} 

我相信当我重新创建对象时,hibernate会丢失。我想让hibernate做的是将数据库中的内容与对象中的内容进行比较,并仅保存差异。有没有办法做到这一点?

回答

2

当拥有者实体第一次连接到会话时,Hibernate将收集实例包装到AbstractPersistentCollection的适当子类中。

PersistentCollection然后跟踪删除的收集元素;没有它,Hibernate将只能够对它们执行插入/更新(在大多数情况下;对于某些id生成器类,即使这是不可能的)。

你基本上运气不好;您唯一能做的就是从数据库中加载一个现有实体(ImportTable)并对其进行修改(例如,删除已加载副本中但不在克隆中的集合元素),然后保存它。我不太了解为什么你需要首先克隆你的实体(我不知道Flex ...你是否将实体编组为XML/JSON/etc?)所有PersistentCollection实现是Serializable,因此可以通过电线发送并返回。有一些方法可以将它们组装到XML中,并返回。

+0

flex引擎(flex.messaging)不会序列化对象,我相信引擎使用反射来读取字段,然后它使用自己的与flex客户端兼容的序列化引擎。我只是检查源代码,当列表从客户端返回时,引擎创建一个ArrayList来保存其内容。 我想我必须自己实施解决方案。我可以使用反射(通过commons-bean)读取所有对象获取器,找出是否有任何列表,然后读取数据库并使用其中的hibernate注释比较列表id。 – 2009-12-15 04:19:55

+0

通过阅读@Id注释。我将评估这种情况是否会经常发生,足以证明额外的编码,否则我可能会在对象本身手动执行此操作。 – 2009-12-15 04:22:04