21.2. 双方向一対多

Parent から Child への単純な <one-to-many> 関連から始めるとします。
<set name="children">
    <key column="parent_id"/>
    <one-to-many class="Child"/>
</set>
以下のコードを実行したとすると、
Parent p = .....;
Child c = new Child();
p.getChildren().add(c);
session.save(c);
session.flush();
Hibernate は二つの SQL 文を発行します:
  • c に対するレコードを生成する INSERT
  • p から c へのリンクを作成する UPDATE
これは非効率的なだけではなく、parent_id カラムにおいて NOT NULL 制約に違反します。コレクションのマッピングで not-null="true" と指定することで、null 制約違反を解決することができます:
<set name="children">
    <key column="parent_id" not-null="true"/>
    <one-to-many class="Child"/>
</set>
しかしこの解決策は推奨できません。
この動作の根本的な原因は、 p から c へのリンク(外部キー parent_id) は Child オブジェクトの状態の一部とは考えられず、そのため INSERT によってリンクが生成されないことです。つまり、解決策はリンクを Child マッピングの一部にすることです。
<many-to-one name="parent" column="parent_id" not-null="true"/>
また Child クラスに parent プロパティを追加する必要があります。
それでは Child エンティティがリンクの状態を制御するようになったので、コレクションがリンクを更新しないようにしましょう。それには inverse 属性を使います:
<set name="children" inverse="true">
    <key column="parent_id"/>
    <one-to-many class="Child"/>
</set>
以下のコードを使えば、新しい Child を追加することができます:
Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
c.setParent(p);
p.getChildren().add(c);
session.save(c);
session.flush();
SQL の INSERT 文が一つだけが発行されるようになりました。
ParentaddChild() メソッドを作成することもできます。
public void addChild(Child c) {
    c.setParent(this);
    children.add(c);
}
Child を追加するコードはこのようになります:
Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
p.addChild(c);
session.save(c);
session.flush();