我正在使用Hibernate 2.1.8以及以下父子关系:
public class Parent {
private Set<Child> children = new HashSet<Child>();
}
public class Child{
private Parent parent;
}
Hibernate映射看起来像:
<hibernate-mapping>
<class name="Parent" table="parent">
<id name="id" column="parent_id" unsaved-value="0" type="int">
<generator
class="com.mx.releasemgr.db.hibernate.HibernateIdentityGenerator" />
</id>
...
<set name="children" table="child" inverse="false" cascade="all-delete-orphan">
<key column="parent_id" />
<one-to-many class="child"/>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.mx.releasemgr.domain.ImplementationProjectChange" table="implementation_project_change" >
<id name="id" column="implementation_project_change_id" unsaved-value="0" type="int">
<generator class="com.mx.releasemgr.db.hibernate.HibernateIdentityGenerator"/>
</id>
<many-to-one name="parent" column="parent_id" class="Parent" not-null="true"/>
</class>
</hibernate-mapping>
如果执行以下代码,则子(ren)的parent_id
列仅设置为NULL,但不删除记录。我希望儿童记录也被删除,但无法弄明白。
parent.getChildren().clear();
session.update(parent);
如果我使用空集合更新父级,如何删除子项?
答案 0 :(得分:2)
在Hibernate中,如果你有一个ManyToOne,那么它总是一个关系的一流拥有方(除非你的ManyToOne由一个连接表而不是多边的列表示)。换句话说,没有办法在关系的多边设置inverse=true
。
当您创建OneToMany时,如果您指定inverse=false
,那么您将创建该关系的另一个一流拥有方。
你创建的是一个无效的场景,其中Hibernate认为有两个完全独立的关系并且没有将它们链接在一起。
以下方案有效:
inverse=false
inverse=true
我不知道双方是否拥有双向关系的方式。如果您想要双向关系,可能最简单的解决方法是在inverse=true
类上设置Parent
,然后将您的代码调整为:
for(ImplementationProjectChange child : parent.getChildren()) {
child.setParent(null);
}
parent.getChildren().clear();
session.update(parent);
答案 1 :(得分:2)
双向关系&amp;反向财产
当单个外键(FK)被映射为双向关系时,一方的关系应该管理FK(inverse=false
),另一方的关系不应该对FK做任何事情({{1 }})。
在您的情况下,双方都是inverse=true
,因为这是子inverse=false
关系的默认值。父母&amp;孩子互相竞争以修改同一列的数据。他们认为他们每个人都在独立的FK上运作;他们不知道他们写的是同一个FK专栏。如果您没有以编程方式保持关系两侧的数据100%一致(父对象的关系属性v子对象的关系属性),那么您将在数据库中获得数据错误。
谁应该管理FK:父母或子女?
孩子应该。
当子管理关系时,一切顺利,SQL最小,并且始终满足参照完整性。如果创建了子实例并将其链接到父实例,则插入新行,并将FK作为单个操作包含在内。同样的更新&amp;删除。
当父管理关系时,需要额外的SQL语句。如果创建子实例并将其链接到父实例,则首先执行子操作 - 插入子行。接下来,父操作发生 - 一个单独的更新,为它的“远程”FK列设置FK值,该列实际上存在于子表中。同样的更新&amp;删除。 在某些情况下,可能会发生数据库约束违规,因此操作失败。子插入必须始终包含空FK列。如果DB列是NOT NULL或者FK列也是PK的一部分(不是在你的情况下),它会因为违反DB参照完整性而导致DB错误 - insert语句将失败并且不会发生更新。
< / LI>最终答案:
在父实体many-to-one
映射中:set
。
(您已经正确拥有inverse="true"
)。
您已经拥有正确的子实体cascade="all-delete-orphan"
映射(保留many-to-one
,默认值,并离开inverse=false
,这意味着孩子必须始终与其父级有关系,并且不能存在分开)。
答案 2 :(得分:1)
你应该采取另一种提取策略
在您的示例中,您使用的是默认提取策略(select
)
您无法使用此策略删除对象。使用join
或subselect
策略:
<set name="children" table="child" inverse="false"
fetch="join" cascade="all-delete-orphan">
或
<set name="children" table="child" inverse="false"
fetch="subselect" cascade="all-delete-orphan">