【问题标题】:Hibernate cannot remove child from databaseHibernate 无法从数据库中删除子节点
【发布时间】:2009-08-06 15:54:18
【问题描述】:

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

父休眠配置:

<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 绑定,当它呈现给 UI 时,我需要 List 是 List 的特定实现(特别是 apache 的 LazyList)。但是,当从数据库中提取对象时,它并没有以这种方式实现,因此我创建了从数据库中提取的常规 List 的 LazyList 副本,并调用 setSpecimenTypes() 将其替换为我新填充的 LazyList。有谁知道我这样做的方法吗?

【问题讨论】:

    标签: hibernate


    【解决方案1】:

    您的映射看起来正确。你怎么把孩子带走?类似于getSpecimenTypes().remove(X) 的东西,或者你有什么特殊的方法(如果有,你可以发布它)吗?

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

    更新(基于澄清):

    重置specimenTypes 绝对是个问题。 Hibernate 怎么知道你已经删除了一个特定的元素?在 Hibernate 自己的 PersistentList 中跟踪删除,当您的父对象被加载时,它会包装您的列表。

    LazyList(我假设你的意思是来自 Commons Collections 的那个)是一个装饰器,所以你可以在你的父对象中创建另一个 getter 方法,它将你的 specimenTypes 集合包装到 LazyList 中并返回它(将它缓存在在重复访问尝试期间提高效率的成员变量)。

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

    【讨论】:

    • 我在更新对象之前调用了 setSpecimenTypes() (原因我在我的帖子的更新中概述了),但我不明白为什么这很重要。不应该更新子列表以反映当前子集包含的任何内容,从而删除任何旧的子数据库条目吗?
    • 感谢您的帮助。我仍然有一个问题。当我更改 getter 以返回装饰列表时,从数据库中提取父类时出现以下错误:拥有实体实例不再引用具有 cascade="all-delete-orphan" 的集合。我确信 setSpecimenTypes 永远不会被调用(我什至将其设为私有)。您在上面提到我应该创建 another getter,而不是像我一样替换当前的 getter。我的方式不正确有什么原因吗?
    • 从现有 getter 返回修饰列表的问题是它不再是 Hibernate 的 PersistentList。 Hibernate 不知道您已经包装了它(或如何打开它) - 它只是看到那里的 PersistentList 现在已经消失了 - 因此出现了异常。你确实需要另一个吸气剂——但如果你的代码依赖于getSpecimenTypes(),你可以创建一个私有的getSpecimentTypesDB() 并在Hibernate 中映射它。我个人更喜欢装饰 UI bean 而不是业务对象,但任何一种方法都有它的位置。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-30
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    相关资源
    最近更新 更多