2009-08-06 32 views
1

这是我的情况:我将一个包含双向父亲子关系的对象加载到我的数据库中。稍后,该对象会加载到可以进行更改的UI中,其中包括从子集中删除任意数量的子项。然后使用saveOrUpdate方法加载此对象的修改副本。但是,保存此修改后的副本时,任何已删除的子项都保留在数据库中(新添加的子元素可以正常工作)。在整个过程中不会出现任何错误,但我需要将这些删除的子项实际从数据库中删除。我在下面粘贴了我的hibernate和java代码的相关部分。Hibernate无法从数据库中删除子项

父冬眠配置:

<bag name="specimenTypes" table="masterPkSpecimenType" cascade="all-delete-orphan" inverse="true"> 
    <key column="runid"/> 
    <one-to-many class="SpecimenType"/> 
</bag> 

儿童冬眠配置:

<many-to-one name="reportCriteriaBean" class="ReportCriteriaBean" column="runid" not-null="true" /> 

父对象代码:

public List<SpecimenType> getSpecimenTypes() { 
    return specimenTypes; 
} 

public void setSpecimenTypes(List<SpecimenType> specimenTypes) { 
    this.specimenTypes = specimenTypes; 
    if(this.specimenTypes != null){ 
     for(SpecimenType specType : this.specimenTypes){ 
      specType.setReportCriteriaBean(this); 
     } 
    } 
} 

子对象代码:

public ReportCriteriaBean getReportCriteriaBean() { 
    return reportCriteriaBean; 
} 
public void setReportCriteriaBean(ReportCriteriaBean reportCriteriaBean) { 
    this.reportCriteriaBean = reportCriteriaBean; 
} 

编辑:

显然,我的问题是由于显式调用setSpecimenTypes()后,我从数据库中检索父对象,在此之前我保存更新的对象回来。我这样做的原因是,由于一些动态的List绑定,我需要List作为List的具体实现(特别是apache的LazyList),当它呈现给UI时。但是,当对象从数据库中拉出时,它不会以这种方式实现,所以我创建了从数据库中拉出的常规列表的LazyList副本,并调用setSpecimenTypes()将其替换为新填充的LazyList。有没有人知道我的方式做到这一点?

回答

0

您的映射看起来正确。你如何取下孩子?类似getSpecimenTypes().remove(X)的东西,或者你有一个特殊的方法(如果是这样,你可以发布它)?

此外,当你的父对象被转移到UI层并返回 - 是否在同一会话内完成?你确定没有人通过调用setSpecimenTypes()中间的某个地方来重置儿童收藏吗?

更新(基于澄清):

重置specimenTypes肯定是有问题。 Hibernate如何知道你已经删除了一个特定的元素?在Hibernate自己的PersistentList中跟踪删除,当你的父对象被加载时,它包装你的列表。 LazyList(我假设你的意思是Commons Collections中的一个)是一个装饰器,所以你可以在你的父对象中创建另一个getter方法,将你的specimenTypes集合包装到LazyList中并返回(将其缓存在成员中在重复访问尝试期间可变的效率)。

这里的底线是你永远不应该用自己的版本覆盖由Hibernate管理的集合。

+0

我在更新对象之前调用setSpecimenTypes()(因为我在文章的更新中列出的原因),我不明白为什么这很重要。不应该更新子列表以反映当前的子集所包含的任何内容,从而删除任何旧的子数据库条目? – TimmyJ 2009-08-06 20:48:10

+0

感谢您的帮助。我仍然有一个问题,但。当我将getter更改为返回装饰的列表时,当父类从DB中拉出时,出现以下错误: 具有cascade =“all-delete-orphan”的集合不再由拥有的实体实例引用。 我相信,setSpecimenTypes永远不会被调用(我甚至把它设为私有)。你在上面提到我应该创建*另一个* getter,而不是像我那样替换当前的那个。我的方式会不正确吗? – TimmyJ 2009-08-07 16:42:18

+0

从现有getter返回修饰列表的问题是它不再是Hibernate的PersistentList。 Hibernate不知道你已经封装了它(或者如何解开它) - 它只是看到那里的PersistentList现在已经消失 - 因此是例外。你确实需要另一个getter,但是如果你的代码依赖于getSpecimenTypes(),你可以创建一个私有的'getSpecimentTypesDB()'并映射到Hibernate中。我个人比较喜欢装饰UI bean而不是业务对象,但是任何一种方法都有它的位置。 – ChssPly76 2009-08-07 17:01:28