惊喜,实现hibernate中一对一关联的从方的延迟加载的一种方法

关于hibernate中一对一关联时,从方不能实现延迟加载好对帖子里都讲到了,关键是 外键列是在从方表中的,由从方指向主方,加载主方时必须要查询从方表才能知道对应的从方是否存在。

[quote]关于one-to-one关联的从方不能lazy loading是由one-to-one的机制造成的,比如user和contact是一对一,user是主,contact是从,约束依赖于user,那么在数据库中,contact表中应该有一个外键字段指向user表的主键。

当加载contact对象时,从contact表的记录中就可以得到user记录的id,这和多对一是一样的,就可以知道user对象是否存在,不存在则user为null,存在就生成代理对象,所以可以实现主方的延迟加载。

当加载user对象时,从user表记录中没有办法知道这个contact从方是否存在,它就不能确定是用null还是生成代理对象来代替contact对象,因为代理对象一定 != null,所以必须要查询contact表,查询这个从方是否存在。

基于上面的情况,所以我现在一般不用one-to-one关联,倒不是一定要延迟加载,还有n+1次问题等等,处理起来比较麻烦,宁可用user到contact的多对一关联,contact为一方,虽然意义上好像反了,但是从user对象可以很方便的得到contact对象,实际上也都是从user来获取contact信息的,延迟加载也没问题。[/quote]
上面一段描述时实际是将外键列放在主方user表中来指向contact表,来解决contact不能延迟加载的问题的。
那么按照正常的contact表中外键列指向user表,到底能不能实现加载user时contact的延迟加载呢?


能不能在加载主表user表时同时查询出对应的contact表的Id呢?
一个偶然的机会,我测试了类似以下的配置:
User类的映射文件中:
[code]<many-to-one name="contact" class="com.xxx.Contact" >
<formula>(select c.CONTACT_ID from CONTACT c where c.USER_ID = USER_ID)</formula>
</many-to-one>[/code]
在User类中有一个contact属性对象,但是在user表中并没有一个外键指向contact表,相反是contact表中的外键列USER_ID指向user表的主键,在user类的映射文件中用一句子查询来代替contact对象,返回的是与user表对应的contact的id值。
测试通过,可以实现user.contact的延迟加载!!
加载user时hibernate生成的sql语句类似如下:
[code]select user0_.USER_ID as USER1_0_1_, user0_.ACCOUNT as ACCOUNT0_1_, user0_.NAME as NAME0_1_, ...... , (select c.CONTACT_ID from CONTACT c where c.USER_ID = user0_.USER_ID) as formula0_1_ from USER user0_ where ......[/code]
当那个子查询返回null时,user.contact为null;当那个子查询返回一个值时user.contact为Contact类的代理对象,代理对象的id是该子查询的返回值;当子查询返回值多于一个时报错。再获取user.contact的其他属性时就像普通延迟加载的多对一关联一样没有任何问题。

这种配置方式与普通的多对一配置相比,最大的不同点在于“多方”表中并没有一个外键列指向“一方”的主键,而是用一个子查询的返回值来代替这个外键列值。

后面继续测试了多对一的lazy和fetch的各种配置,可喜的是完全与普通的多对一关联方式一样,可以实现延迟加载、非延迟加载、select方式抓取以及连接方式抓取,并且在get、hql查询、Criteria查询中都没有问题,看来hibernate完全将这个子查询代替了本来的外键列值。

以上测试在hibernate版本3.2.2中通过。

这种方法的最大好处在于可以实现两个方向的多对一对象关联(两个方向都是多对一),而数据库中只需要单向的指向约束,没有相互指向约束引起的问题。相当于双向一对一。也给非主外键关联提供了另一种方法。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值