🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 21.2\. 双向的一对多关系(Bidirectional one-to-many) 假设我们要实现一个简单的从Parent到Child的&lt;one-to-many&gt;关联。 ``` <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(); ```