最近在使用Hibernate的时候,发现其中在管理对象间关系时有一个 inverse 属性,原来没太在意,仔细研究下发现这个属性还是比较关键的,详细解释一下
inverse属性一般是用在 1-N 对象关系中,默认值为 false
以 Parent,Child 这2个对象举例,从他们的关系上2者是 1-N 关系,PO对象描述通常为:
Parent 中包含一个属性 Set<Child> children
Child 中包含一个属性 Parent parent
Parent对应的hbm文件通常这样配置
<set property="children" cascade="all"> <key column="parent_id"/> <ont-to-many class="Child"/> </set>
这里,<set>标签中未配置 inverse 属性,其实代表 <set ... inverse="false">
说明 1-N 关系中,关系的建立由当前对象完成(也就是Parent负责)
在保存关联数据时需要将 Parent 作为主要操作目标,最后使用 session.save(parent) 来完成关联保存操作
Parent parent = ....;
Set<Child> children = ....;
parent.setChildren(children);
Transaction tx = session.beginTransaction();
// 注意这里要保存parent(主控对象)
session.save(parent);
tx.commit();
session.close();
如果设置为 <set ... inverse="true">,代表将对象关联关系的维护工作交给 N 端对象完成,那么按照以上方法使用 session 保存 parent 将会发现数据不完整,因为 inverse="true" 以后 parent 在保存和更新动作中不负责对关联关系进行维护(仅可关联查询),关系控制权现在交由 N 段 Child 对象,所以应该用 session 保存 Child;
Parent parent = ...;
Child child = ...;
child.setParent(parent);
Transaction tx = session.beginTransaction();
// 注意这里保存的对象应该是Child,因为关系控制权已经交给Many一端
session.save(child);
tx.commit();
session.close();
总结
简单来说,one-to-many 关系我们默认将 one 作为主控对象,many 作为附属属性,在默认情况下通过保存主控对象随带着完成附属属性的保存,并完成2者关系的建立(默认inverse="false"就是应对这种情况)
但如果根据业务需要,想以附属对象作为操作入口的话,就应该将 inverse 属性设置为 true
举个购物车的例子
用户和订单 是 one-to-many 的关系
订单和订单内的每条购买记录也是 one-to-many 的关系
从业务操作习惯上,用户执行下单时,应用实现习惯是保存“订单”对象,而不是保存“用户”对象
因此 用户-订单 关系的配置上就应该设置 inverse="true"
同样,在保存订单时要保存订单内每一条购买记录,应用实现习惯是保存“订单”对象,附带着把包括的购买记录也保存下来
因此 订单-记录 关系的配置上就应该设置 inverse="false"