假设我们要实现一个简单的从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语句:
一条INSERT
语句,为c
创建一条记录
一条UPDATE
语句,创建从p
到c
的连接
这样做不仅效率低,而且违反了列parent_id
非空的限制。我们可以通过在集合类映射上指定not-null="true"
来解决违反非空约束的问题:
<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
在管理连接的状态,为了使collection不更新连接,我们使用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();
现在,只会有一条INSERT
语句被执行!
为了让事情变得井井有条,可以为Parent
加一个addChild()
方法。
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();