传智播客-jpa与hibernate(3)-继承映射

Hibernate支持三种基本的继承映射策略:每个类分层结构一张表(table per class hierarchy),每个子类一张表(table per subclass),每个具体类一张表(table per concrete class),此外,Hibernate还支持第四种稍有不同的多态映射策略--隐式多态(implicit polymorphism) 。这里只介绍前三种,最后一种请参阅相关文档。代码示例为注解方式,配置方式请参阅文档。

 

每个类分层结构一张表(table per class hierarchy)
也称单表策略,就是一棵继承树映射为一张表,或者说将一棵继承树里所有类的信息不重复地放到一张表里。因为所有的父子类都在一张表里体现,所以还需要一个额外的字段以区分每条记录代表的具体的类别。

 

举例来说,有父类Employee(雇员),子类HE(钟点工),同级子类SE(正式员工);HE和SE的区别在于薪资,HE以时效计,字段为rate,SE以月薪计,字段为salary;还有一个字段etype作为具体类别信息的区分标识。

 

很明显,rate和salary是互斥的。所以这两个字段应当允许为空,而且实际操作的时候必然会有一个字段列的冗余。etype对于每个类别信息自身而言,也可以视为是一个冗余字段。所以这个策略一般在父类的属性字段占总字段的权重大的时候较为适用。
示例代码:
@Entity
@Table(name="jpa_inherit_single_ess")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="etype",discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue(value="ee")
public class Employee {...}

@Entity
@DiscriminatorValue(value="he")
public class HE extends Employee {...}

@Entity
@DiscriminatorValue(value="se")
public class SE extends Employee {...}

 

NOTE: 查询的时候不是用entityManager.find(XXX.class, serialable)。可以用entityManager.createQuery("select he from HE he").getResultList(),打印的sql语句是:select ... from jpa_inherit_single_ess where etype = 'he'。

 

每个子类一张表(table per subclass)
每个类建一个表,子表只存放子类自身属性,但是有都有同名主键,并通过主键关联到父类表,因而关系模型实际上是一对一关联。这样就没有第一种方式那么多冗余字段。子类属性字段的权重大时较为适用。

 

还是上述例子,父类Employee(雇员),子类HE(钟点工),同级子类SE(正式员工)在这个策略里需要三张对应的表,父类表主键字段假定为id,HE和SE表使用同名主键,并与父类表主键id关联。


示例代码:
@Entity(name="EmployeeJoined")
@Table(name="jpa_inherit_joined_ees")
@Inheritance(strategy=InheritanceType.JOINED)
public class Employee {...}

@Entity(name="HEJoined")
@Table(name="jpa_inherit_joined_hes")
@PrimaryKeyJoinColumn(name="eid")
public class HE extends Employee {...}

@Entity(name="SEJoined")
@Table(name="jpa_inherit_joined_ses")
@PrimaryKeyJoinColumn(name="eid")
public class SE extends Employee {...}

 

NOTE:因为hes∈ess,所以select he时打印的sql语句只有一次inner join,而hes∪ses=ees,select ees时印的sql语句有两次lefte outer join。

 

有时候通过一个(技术上或业务上)父类共享一些公共属性是很有用的,同时还不用将该父类作为映射的实体(也就是该实体没有对应的表)。这个时候就需要使用@MappedSuperclass注解来进行映射。(下文略,请参见满江红翻译的官方文档hibernate_annotations.pdf-->2.2.4.4从父类继承的属性)

 

每个具体类一张表(table per concrete class)
还是每个类一张表,不过表与表之间没有关联关系,每个表主键id值都是唯一的,主键生成策略用table,而且每个表都有全部的信息。

示例代码:
@Entity(name="EmployeeUnion")
@Table(name="jpa_inherit_union_ees")
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
@TableGenerator(name="tabgen_inherit_union",
    table="jpa_inherit_union_tabgen",
    pkColumnName="pkname",
    valueColumnName="valuename",
    pkColumnValue="currvalue",
    allocationSize=10)
public class Employee {
 @Id
 @GeneratedValue(strategy=GenerationType.TABLE,generator="tabgen_inherit_union")
 private Integer id ;
 ...
}

@Entity(name="HEUnion")
@Table(name="jpa_inherit_union_hes")
public class HE extends Employee {...}

@Entity(name="SEUnion")
@Table(name="jpa_inherit_union_ses")
public class SE extends Employee {...}

 

下面的内容引自《深入浅出Hibernate》6.5.6类继承树,有助于更好地理解hibernate的继承映射。
hibernate操作的持久化对象是POJO。hibernate并不关心,也不会关心某个java类是否继承自某个基类,甚至是否是某棵继承树上的一个节点。hibernate能做的,就是对这个java类的属性进行操作,把它们与数据库中的内容按照规定的规则进行同步。而hibernate的subclass定义是为了实现不同的持久化子类采取不同的映射策略,这并不需要和你的POJO的继承树完全一一对应。

 

(图片以后再传)

 

假设我们的程序处理是仓库保管部分,只需要在一个表中做一个type字段来分出“枪支”,“火箭筒”,“单兵对空导弹”(作者难道是国防科大出身???)这3种类型,分别放在不同的仓库位置。左边的POJO继承树中,则为了表明保养等级的不同,可能会出现中间的抽象类层,比如说有制导武器需要定期对制导头进行测试检查及保养,而这完全可以不出现在持久化类继承树中。持久化策略的实现是非常灵活自由的。(和上文的@MappedSuperclass有关联么??)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值