Hibernate之jpa实体映射的三种继承关系

时间:2021-10-11 16:00:31

在JPA中,实体继承关系的映射策略共有三种:单表继承策略(table per class)、Joined策略(table per subclass)和Table_PER_Class策略。

1.单表继承策略

单表继承策略,父类实体和子类实体共用一张数据库表,在表中通过一列辨别字段来区别不同类别的实体。具体做法如下:

a.在父类实体的@Entity注解下添加如下的注解:

@Inheritance(Strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name=”辨别字段列名”)
@DiscriminatorValue(父类实体辨别字段列值)

b.在子类实体的@Entity注解下添加如下的注解:

@DiscriminatorValue(子类实体辨别字段列值)

定义了一个父类

  1. @Entity
  2. @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
  3. @Table(name = "WINDOW_FILE")
  4. @DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING, length = 30)
  5. @DiscriminatorValue("WindowFile")
  6. public class WindowFile {
  7. @Id
  8. @GeneratedValue(strategy = GenerationType.AUTO)
  9. private Integer id;
  10. @Basic
  11. @Column(name = "NAME")
  12. private String name;
  13. @Basic
  14. @Column(name = "TYPE")
  15. private String type;
  16. @Basic
  17. @Column(name = "DATE")
  18. private Date date;
  19. //省略get set
  20. }

后定义2个子类

  1. @Entity
  2. @DiscriminatorValue("Folder")
  3. public class Folder extends WindowFile {
  4. @Basic
  5. @Column(name = "FILE_COUNT")
  6. private Integer fileCount;
  7. //省略get set
  8. }
  1. @Entity
  2. @DiscriminatorValue("Document")
  3. public class Document extends WindowFile {
  4. @Basic
  5. @Column(name = "SIZE")
  6. private String size;
  7. //省略get set
  8. }

以上通过列DISCRIMINATOR的不同,区分具体父子实体。

实际表结构如下:

WINDOW_FILE  DISCRIMINATOR,ID,NAME,DATE,TYPE,SIZE,FILE_COUNT

当你使用WindowFile实体时,实际表的字段为DISCRIMINATOR='WindowFile',SIZE与FILE_COUNT永远是空

当使用Folder实体时,DISCRIMINATOR='Folder',SIZE永远是空,FILE_COUNT为实际值。

Document同理,与Folder类似。

2.Joined策略

父类实体和子类实体分别对应数据库中不同的表,子类实体的表中只存在其扩展的特殊属性,父类的公共属性保存在父类实体映射表中。具体做法:

@Inheritance(Strategy=InheritanceType.JOINED)

子类实体不需要特殊说明。

  1. @Entity
  2. @Table(name = "T_ANIMAL")
  3. @Inheritance(strategy = InheritanceType.JOINED)
  4. public class Animal {
  5. @Id
  6. @Column(name = "ID")
  7. @GeneratedValue(strategy = GenerationType.AUTO)
  8. private Integer id;
  9. @Column(name = "NAME")
  10. private String name;
  11. @Column(name = "COLOR")
  12. private String color;
  13. //省略get set
  14. }
  1. @Entity
  2. @Table(name = "T_BIRD")
  3. @PrimaryKeyJoinColumn(name = "BIRD_ID")
  4. public class Bird extends Animal {
  5. @Column(name = "SPEED")
  6. private String speed;
  7. //省略get set
  8. }
  1. @Entity
  2. @Table(name = "T_DOG")
  3. @PrimaryKeyJoinColumn(name = "DOG_ID")
  4. public class Dog extends Animal {
  5. @Column(name = "LEGS")
  6. private Integer legs;
  7. //省略get set
  8. }

实际表结构如下:

T_ANIMAL  ID,COLOR,NAME

T_BIRD  SPEED,BIRD(既是外键,也是主键)

T_DOG  LEGS,DOG_ID(既是外键,也是主键)

3.Table_PER_Class策略:

Table_PER_Class策略,父类实体和子类实体每个类分别对应一张数据库中的表,子类表中保存所有属性,包括从父类实体中继承的属性。具体做法:

只需在父类实体的@Entity注解下添加如下注解:

@Inheritance(Strategy=InheritanceType.TABLE_PER_CLASS)

  1. @Entity
  2. @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
  3. @Table(name = "T_VEHICLE")
  4. public class Vehicle { // 基类
  5. @Id
  6. // @GeneratedValue
  7. @Column(name = "ID")
  8. private Integer id;
  9. @Column(name = "SPEED")
  10. private Integer speed;// 速度
  11. //省略get set
  12. }
  1. @Entity
  2. @Table(name = "T_CAR")
  3. public class Car extends Vehicle {
  4. @Column(name = "ENGINE")
  5. private String engine;// 发动机
  6. //省略get set
  7. }

一旦使用这种策略就意味着你不能使用AUTO generator 和IDENTITY generator,即主键值不能采用数据库自动生成。

实际表结构如下:

T_VEHICLE  ID,SPEED

T_CAR  ID,SPEED,ENGINE