Hibernate继承策略及其原因

时间:2009-10-07 10:06:22

标签: hibernate inheritance

我有3个非抽象的持久化类。 MyClubUser和HisClubUser类继承自User类。对于这些类,我为每个子类策略使用一个表,即@Inheritance(strategy = InheritanceType.JOINED)

我观察到的是当我对User类进行查询时,生成的SQL使用左外连接HisClubUser和MyClubUser。为什么Hibernate会这样做[加入其他表格]我的关注点只是用户?我的观点是,即使检索到数据,我也无法在MyClubUser或HisClubUser中访问这些属性,因为返回了User实例。此外,与仅查询没有左外连接的用户表的查询相比,这是否会导致额外的开销?

谢谢

3 个答案:

答案 0 :(得分:5)

Hibernate 始终会返回实际类型的持久化实体。如果您存储了“MyClubUser”,它将作为“MyClubUser”返回,而不是“User”。原因很明显 - 如果Hibernate将“MyClubUser”作为“用户”返回并且你再次坚持它,你将失去“MyClubUser”中定义的所有其他属性。

为了做到这一点,Hibernate需要知道实际类型是什么。对于InheritanceType.JOINED策略,找到它的唯一方法是检查继承层次结构中的所有表(从技术上讲,它是当前级别或低于当前级别的所有表格以及所有高于当前级别的表格当前树分支)。所以,如果你有一个像:

这样的层次结构
           Root
          /   \
      Node1  Node2
      /   \
   Node11 Node12

并且您尝试从root中进行选择,Hibernate将在所有表上执行外连接。如果您从Node1中选择,Hibernate将在Node1和Root上进行内连接,在Node11和Node12上进行外连接。不会触及Node2,因为它不是Node1的后代。

就外部联接开销而言 - 是的,这绝对是一个开销,但这是你为加入战略付出的代价。你可以使用鉴别器来避免这种情况,但它有自己的副作用。这种开销是否显着取决于层次结构,索引和许多其他内容的深度和范围。听取KLE的建议并对其进行描述。

答案 1 :(得分:4)

  

为什么Hibernate会这样做[加入其他表格]我的顾虑只是用户?

因为所有HisClubUser也是User的有效实例,所以当您要求用户时检索这些实例是合乎逻辑的。

  

我的观点是,即使检索到数据,我也无法在MyClubUser或HisClubUser中访问这些属性,因为返回了用户实例。

你确定吗?检查(例如在调试中)返回的有效类,它应该是子类。因此,可以进行向下转换,并且可以访问属性。

  

此外,与仅查询没有左外连接的User表的查询相比,这是否会导致额外的开销?

是的,额外的加入会产生开销。这可能很重要或不重要:我建议你根据具体情况进行测试。

答案 2 :(得分:2)

您在User上查询,因此Hibernate将执行'多态查询'。由于MyClubUser和HisClubUser本质上是User对象(它们继承自User),因此Hibernate也将检索这些类型的用户。

相关问题