1

我正在使用具有以下父子关系的 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>

如果执行以下代码,parent_id则 child(ren) 的列仅设置为 NULL,但不会删除记录。我希望子记录也被删除,但无法弄清楚。

parent.getChildren().clear();
session.update(parent);

如果我用空集合更新父级,如何删除子级?

4

3 回答 3

2

在 Hibernate 中,如果您有一个 ManyToOne,那么它始终是关系的一流拥有方(除非您的 ManyToOne 由连接表表示,而不是多方的列)。换句话说,没有办法设置inverse=true关系的多方面。

当您创建 OneToMany 时,如果您指定,inverse=false那么您将创建关系的另一个头等拥有方。

您创建的是一个无效的场景,其中 Hibernate 认为有两个完全独立的关系并且没有将它们链接在一起。

以下场景有效:

  • 只有 OneToMany 与inverse=false
  • 只有ManyToOne
  • inverse=true在 OneToMany上同时拥有 OneToMany 和 ManyToOne
  • 使用连接表

我不知道有任何方式可以建立双向关系,其中一方是拥有方。如果您想要双向关系,可能最简单的解决方法是inverse=trueParent类上设置,然后将您的代码调整为:

for(ImplementationProjectChange child : parent.getChildren()) { 
  child.setParent(null);
}
parent.getChildren().clear();
session.update(parent); 
于 2013-06-17T14:02:19.717 回答
2
  1. 双向关系和逆属性

    当单个外键 (FK) 映射为双向关系时,一侧的关系应管理 FK ( inverse=false),而另一侧的关系不应对 FK ( inverse=true) 做任何事情。

    在您的情况下,inverse=false双方都是,因为这是子many-to-one关系的默认设置。父母和孩子相互竞争以修改同一列的数据。他们认为他们每个人都在独立的 FK 上运行;他们不知道他们正在写入同一个 FK 列。如果您不以编程方式保持关系两侧的数据 100% 一致(父对象的关系属性 v 子对象的关系属性),那么您将在数据库中得到数据错误。

  2. 谁应该管理 FK:父母还是孩子?

    孩子应该。

    孩子管理关系时,一切都以最少的 SQL 顺利进行,并且始终满足参照完整性。如果创建了子实例并将其链接到父实例,则会插入新行,并将 FK 作为单个操作包含在内。更新和删除也是如此。

    父级管理关系时,需要额外的 SQL 语句。如果创建子实例并将其链接到父实例,则子实例的操作首先发生 - 插入子行。接下来,父级的操作发生 - 为它的“远程” FK 列设置 FK 值的单独更新,该列实际上位于子表中。更新和删除也是如此。在某些情况下,可能会发生 DB 约束冲突,因此操作会失败。子插入必须始终包含空 FK 列。如果 DB 列不是 NULL 或 FK 列也是 PK 的一部分(在您的情况下不是),则会因违反 DB 引用完整性而给出 DB 错误 - 插入语句将失败并且不会发生更新。

  3. 最终答案

    在父实体set映射中:inverse="true".
    (您已经正确拥有cascade="all-delete-orphan")。

    您已经拥有正确的子实体many-to-one映射(inverse=false默认值 leave 和 leave not-null=true,这意味着子实体必须始终与其父实体有关系,并且不能单独存在)。

于 2013-06-18T06:22:35.643 回答
1

你应该另一种获取策略。
在您的示例中,您使用的是默认获取策略(select)。
您不能使用此策略删除对象。使用joinsubselect策略:

    <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">  
于 2013-06-17T14:02:48.040 回答