Hibernate一对多双向关联

来源:互联网 发布:越秀网络教学平台 编辑:程序博客网 时间:2024/06/11 09:29

如果只是最简单的关联起来,没有级联,没有inverse

<set name="users" table="USER">
<!-- 这个需要填写别的表的外键,而不是本表的主键 -->
<key column="DEPART_ID" />
<one-to-many class="model.User" />
</set>

<many-to-one name="department" column="DEPART_ID" />

那么在保存对象的时候必须进行两步操作

第一步先保存主表数据,即被引用外键的表的数据

第二步再保存从表数据,即引用主表外键的表的数据

如果直接保存从表数据,由于没有设置级联和inverse,Hibernate肯定不知道先给你把主表数据保存起来。

下面看看查询主表对象会出现什么效果。

查询主表对象的时候会直接将所有的从表对象加载出来,貌似没有使用懒加载,下面加个懒加载属性试试。lazy="true"属性加到set标签上即可。

删除主表对象的时候如果没有加上级联cascade删除的话,那么不会删除从表的对象,会将从表对象的外键属性设置为空,这样看来的话如果不设置级联,那么也不能设置外键not-null,否则会报错,如果设置了从表外键非空,有两种方法去删除,一种是先根据主表的主键找到所有从表数据并删除,然后再删除主表数据,一种是设置级联,那么在删除主表数据的时候,Hibernate会自动帮你先删除从表的数据,设不设置级联应该根据业务需要来定,我觉得最好不要设置,而是自己来做删除这个操作,并且外键也不要限制必须非空。如果一开始外键没有设置非空限制,后来加上的话,hibernate不会根据<property name="hbm2ddl.auto">update</property>更新数据库表结构,必须将update改为create。

如果在从表的many-to-one标签上加入cascade="save-update"属性,那么在保存从表对象的时候会自动保存主表对象。但是有个问题就是如果从表数据比较多,因为从表是一对多中多得一方,那么保存起来代码会很多,解决方法就是将cascade="save-update"属性放到主表映射文件的set标签上面。如此做得话保存代码只需像如下:

//创建需要持久化的对象User u1 = new User();u1.setName("user1");User u2 = new User();u2.setName("user2");Department d1 = new Department();d1.setName("depart1");d1.getUsers().add(u1);d1.getUsers().add(u2);//数据库保存数据操作代码session.save(d1);
但是这样有个弊端就是保存主表对象时的sql语句会增加多条update语句,如果数据多得话可能会影响性能的。。解决方法就是在set标签上加一个inverse="true"属性,如果这样做得话,就可以解决上面的问题了,但是代码需要像下面的这样。

//创建需要持久化的对象
User u1 = new User();u1.setName("user1");User u2 = new User();u2.setName("user2");Department d1 = new Department();d1.setName("depart1");d1.getUsers().add(u1);d1.getUsers().add(u2);u1.setDepartment(d1);u2.setDepartment(d1);session.save(d1);

因为在保存主表对象的时候检查映射文件的时候,由于设置了set级联保存和更新,那么会去检查主表对象的集合属性,但是由于设置了inverse="true"的属性,那么控制权其实是交给了集合中的对象,集合对象会去先保存跟自己关联的主表对象,再保存自己,如此就不会多出几条update语句。


但是又有个问题,比如d1中加了两个用户u1和u2,但是u1不设置Department属性,那么最后存到数据库的数据中u1的部门属性就是空的了,如果把u1设置成另外一个新部门,那么保存的时候会报错,因为另外一个新部门没有持久化,如果再把User的cascade属性设为"save-update",那么最后u1就是新部门的,这样的话关联关系就会混乱了,所以最好还是不要这样做。


原创粉丝点击