分享

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

 蜗牛手 2011-05-23

传智播客-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条评论

    发表

    请遵守用户 评论公约

    类似文章 更多