JPA 继承

JAP实现继承有三种类型.假设有A.B.C三个类,A为基类,B,C均为A的子类.那么三种设计方式分别为:

1.A.B.C共用一张表

2.每个类分层结构一张表A.B.C各一张表,各自包含自己的属性.

3.A.B.C各一张表.

首先,我们针对第一种情况,进行分析.

[共用一张表]

   首先我们定义基类(本例以文件为例,子类分别为文件夹和文件)

  

  1. @Entity  
  2. @Inheritance(strategy=InheritanceType.SINGLE_TABLE)  
  3. @Table(name="window_file")  
  4. @DiscriminatorColumn(name="Discriminator",  
  5.                                          discriminatorType = DiscriminatorType.STRING,  
  6.                                          length=30)  
  7. @DiscriminatorValue("WindowFile")  
  8. public class WindowFile {  
  9.       
  10.     @Id  
  11.     @GeneratedValue(strategy = GenerationType.AUTO)  
  12.     private Integer id;  
  13.     @Basic  
  14.     @Column(name="name")  
  15.     private String name;  
  16.       
  17.     @Basic  
  18.     @Column(name="type")  
  19.     private String type;  
  20.       
  21.     @Basic  
  22.     @Column(name="date")  
  23.     private String date;  
  24. //getter setter......  

 分别再定义两个子类:

  1. @Entity  
  2. @DiscriminatorValue("Folder")  
  3. public class Folder extends WindowFile {  
  4.   
  5.     @Basic  
  6.     @Column(name="file_count")  
  7.     private Integer fileCount;  
  8.   
  9.     public Integer getFileCount() {  
  10.         return fileCount;  
  11.     }  
  12.   
  13.     public void setFileCount(Integer fileCount) {  
  14.         this.fileCount = fileCount;  
  15.     }  
  16.       
  17.       
  18.       
  19. }  
  1. @Entity  
  2. @DiscriminatorValue("Document")  
  3. public class Document extends WindowFile {  
  4.   
  5.     @Basic  
  6.     @Column(name="size")  
  7.     private String size;  
  8.   
  9.     public String getSize() {  
  10.         return size;  
  11.     }  
  12.   
  13.     public void setSize(String size) {  
  14.         this.size = size;  
  15.     }  

仔细观查,你会发现,除了基类上指定了@Table属性外,两个子类均没有指定,而且还有几个特殊的地方

1>父类中的@Inheritance(strategy=InheritanceType.SINGLE_TABLE):继承表标,指定实现方式为一张表,即所有的对象一张表.

2>父类中的@DiscriminatorColumn(name="Discriminator",
                                         discriminatorType = DiscriminatorType.STRING,
                                         length=30) 其实这个字段就是一个区分字段,我们平时自己设计数据库的时候,有时候也会在表中加入一个字段用于判断该记录的类型,那么这个字段就是同样功能,name 为自定义的.

3>三个类都有这个注解:@DiscriminatorValue("WindowFile"),很显明,明白了第2>点,这点也很容 易理解,就是上面那个字段的值,当这个字段值为"windowFile"时,他就是基类,为"Document"时,就是Document类....这个 值是自定义的..

配置好项目,启动.查看数据库,发现我们的表已经被创建好.表名为"window_file" 有7个字段:Discriminator id date name type file_cout size插入一条纪录,会发现,Discriminator的值是系统自动我们插入的..

采用这种式有一个不好的地方:当页面需要进行展示的时候,我们需要对记录的类型的进行判断,因为folder的size为nll  Document类型的file_count为null,不进行判断,则会报nullPointException.而我们的 Discrimination不能在页面上进行获取.所以通常做法是:多加一个字段,可以让其值保持与Discriminator的一样,或者重新创建一 个Dto对象(简单的pojo),拥有这七个属性,专门用与在页面上进行显示,个人比较推荐后面的这种试,原因不多说,既然涉及到hibernate就会 跟session有关,如果session关闭,采用后一种方式在页面上进行展示时也不会报NullPointException.

2.每个类分层结构一张表  这种映射方式为每个类创建一个表。在每个类对应的表中只需包含和这个类本身的属性对应的字段,子类对应的表参照父类对应的表,使用每个子类一张表 (table per subclass)策略,需要把@javax.persistence.Inheritance 注释的strategy 属性设置为InheritanceType.JOINED
代码如下:

  1. //三个类我一起贴出来..偷下懒  
  2. @Entity  
  3. @Table(name="animal")  
  4. @Inheritance(strategy = InheritanceType.JOINED )  
  5. public class Animal {  
  6.   
  7.     @Id  
  8.     @GeneratedValue(strategy = GenerationType.AUTO)  
  9.     private Integer id;  
  10.       
  11.     @Column(name="name")  
  12.     private String name;  
  13.       
  14.     @Column(name="color")  
  15.     private String color;  
  16.    //getter...setter  
  17. }  
  18.   
  19. @Entity  
  20. @Table(name="bird")  
  21. @PrimaryKeyJoinColumn(name="BirdId")  
  22. public class Bird extends Animal {  
  23.       
  24.     @Column(name="speed")  
  25.     private String speed;  
  26.   
  27.     public String getSpeed() {  
  28.         return speed;  
  29.     }  
  30.   
  31.     public void setSpeed(String speed) {  
  32.         this.speed = speed;  
  33.     }  
  34.       
  35. }  
  36.   
  37. @Entity  
  38. @Table(name="Dog")  
  39. @PrimaryKeyJoinColumn(name="DogId")  
  40. public class Dog extends Animal {  
  41.   
  42.     @Column(name="legs")  
  43.     private Integer legs;  
  44.   
  45.     public Integer getLegs() {  
  46.         return legs;  
  47.     }  
  48.   
  49.     public void setLegs(Integer legs) {  
  50.         this.legs = legs;  
  51.     }  
  52.       
  53.       
  54. }  

  

  多的不说,看下数据库:生成了三张表,并分别有如下字段

animal : id color name

bird     : speed birdId(既为主键,又为外键)

dog     : legs  dogId(既为主键,又为外键)

现在写一个JSP页面,上面有name legs color输入框(即创造一条狗),当我们save成功以后,查看数据库发现animal表有值,dog有值,但bird没有,dog表中的dogId的 值等于animal中的id. 这种方式也就是我们常用的外键设计方式.一般情况下推荐使用这种方式.

3.每个具体类一张表(table per concrete class)
       这种映射方式为每个类创建一个表。在每个类对应的表中包含和这个类所有属性(包括从超类继承的属性)对应的字段,使用每个具体类一张表(table per concrete class)策略,需要把@javax.persistence.Inheritance 注释的strategy 属性设置为InheritanceType.TABLE_PER_CLASS
此种方式,代码我就不贴了.. 把Animal中的inheritance改过来.去掉Dog和Bird类中的PrimaryKeyJoinColumn标注.还有一点非常重 要,Animal类的主键生成策略不能自动生成了需要使用@Column(columnDefinition="integer")..进入数据库,删除 animal dog brid三张表.重新编译运行项目.再进入数据库,依然是三张表,不过这三张表和以往的已经不同了..各自都包括了自己应有的属性.什么意思列?父类包含 了自己的属性,而子类包括了从父类继续来的属性..

这种方式,不推荐使用,理解有三:

1>如果父类的属性特别多,那么在数据量大的时候,会产生很多见冗涂.

2>  查询所有Animal时,因为他是最继承树中的根,查询结果会得到所有继承于Animal类的记录

     delete from delete from Vehicle  a       执行该操作会删除自身对应记录,还会删除所有继承Vehicle的记录,因为他是最继承树中的根,就相当于清除整个表的数据a       

Employee.java:(基类)

复制代码
 1 @Entity
 2 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)//选择继承策略
 3 @DiscriminatorColumn(name="type")//配置鉴别器
 4 @DiscriminatorValue("0")//设置鉴别器值
 5 public class Employee {
 6     @Id
 7     @GeneratedValue
 8     private Integer id;
 9     private String name;
10     public Integer getId() {
11         return id;
12     }
13     public void setId(Integer id) {
14         this.id = id;
15     }
16     public String getName() {
17         return name;
18     }
19     public void setName(String name) {
20         this.name = name;
21     }
22 }
复制代码

其中@Inheritance(strategy=InheritanceType.SINGLE_TABLE)//选择继承策略 可以选择多种策略,如下图所示:

  • JOINED:继承的子类各自生成一张表
  • SINGLE_TABLE:只生成一张表,用一个字段当鉴别器
  • TABLE_PER_CLASS:每个类都生产一张表,包括基类

Skiller.java(继承自Employee.java)

复制代码
 1 @Entity
 2 @DiscriminatorValue("1")
 3 public class Skiller extends Employee {
 4     private String skill;
 5 
 6     public String getSkill() {
 7         return skill;
 8     }
 9 
10     public void setSkill(String skill) {
11         this.skill = skill;
12     }
13 }
复制代码

Sales.java(继承自Employee.java)

复制代码
 1 @Entity
 2 @DiscriminatorValue("2")
 3 public class Sales extends Employee {
 4     private String sell;
 5     public String getSell() {
 6         return sell;
 7     }
 8     public void setSell(String sell) {
 9         this.sell = sell;
10     }
11 }
复制代码

测试:

复制代码
 1     @Test
 2     public void save(){
 3         EntityManagerFactory factory=Persistence.createEntityManagerFactory("sample");
 4         EntityManager em=factory.createEntityManager();
 5         em.getTransaction().begin();
 6         Employee p1=new Employee();
 7         p1.setName("Jim");
 8         Skiller p2=new Skiller();
 9         p2.setName("Hanson");
10         p2.setSkill("skill");
11         Sales p3=new Sales();
12         p3.setName("Brian");
13         p3.setSell("sale");
14         em.persist(p1);
15         em.persist(p2);
16         em.persist(p3);
17         em.getTransaction().commit();
18         em.close();
19         factory.close();
20     }
复制代码

打开数据库:

猜你喜欢

转载自john521.iteye.com/blog/2073283
JPA
今日推荐