Hibernate继承类的实现


对于继承关系类的映射。比如在论坛中文章(Ariticla)有主题类型(Topic),有回复类型(Reply)。其中Topic都id、title、context、postDate、type(类型:如普通、精华、置顶......),而Replay有id,title,context,postDate,floor(楼层)。针对这样的情况,Topic和Replay都有共同的属性,那么就可以提取出一个抽象类Ariticla,并给Aritcla添加共同属性id,title,context,postDate。然后让Topic和Reply继承Aritcla,然后各自在指定各自的属性。如图:

继承类三种设计方式

第一种:subclass

这种类型的特点,可以使用一张表来存储所有数据。我们需要在数据库表设计的时候增加一列用于判断该条记录的类型

Sql数据表结构

代码实现:

Article.java

1 package com.myproc.domain;
 2 
 3 import java.util.Date;
 4 
 5  public class Article {
 6     private Integer id;  
 7     private String title;    //标题
 8     private String context;  //内容
 9     private Date postDate;   //提交日期
10     public Integer getId() {
11         return id;
12     }
13     public void setId(Integer id) {
14         this.id = id;
15     }
16     public String getTitle() {
17         return title;
18     }
19     public void setTitle(String title) {
20         this.title = title;
21     }
22     public String getContext() {
23         return context;
24     }
25     public void setContext(String context) {
26         this.context = context;
27     }
28     public Date getPostDate() {
29         return postDate;
30     }
31     public void setPostDate(Date postDate) {
32         this.postDate = postDate;
33     }    
34 }

Topic.java

1 package com.myproc.domain;
 2 
 3 public class Topic extends Article {
 4     private int type;  //类型:精华、置顶、推荐......
 5 
 6     public int getType() {
 7         return type;
 8     }
 9 
10     public void setType(int type) {
11         this.type = type;
12     }
13     
14 }

Reply.java

1 package com.myproc.domain;
 2 
 3 public class Reply extends Article {
 4     private int floor;  //楼层
 5 
 6     public int getFloor() {
 7         return floor;
 8     }
 9 
10     public void setFloor(int floor) {
11         this.floor = floor;
12     }
13     
14 }

Article.hbm.xml

1 <?xml version="1.0"?>
 2 
 3 <!DOCTYPE hibernate-mapping PUBLIC
 4         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 5         "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 6 <hibernate-mapping package="com.myproc.domain">
 7     <!--discriminator-value:鉴别器的值,如果不指定则为类的全限名(含包) -->
 8     <class name="Article" table="t_article" discriminator-value="A">
 9         <id name="id" column="Id" type="integer">
10             <generator class="native"></generator>
11         </id>
12         <!-- 设置鉴别器,column:在数据库中的列。根据该列的值判断是什么类型 -->
13         <discriminator column="class_" type="string"></discriminator>
14         <property name="title"  type="string"></property>
15         <property name="context" type="text" length="1000"></property>
16         <property name="postDate" type="timestamp"></property>
17         
18         <!-- 子类 -->
19         <subclass name="Topic" discriminator-value="T">
20             <!-- 子类属性 -->
21             <property name="type" type="int"></property>
22         </subclass>
23         
24         <subclass name="Reply" discriminator-value="R">
25             <property name="floor"></property>
26         </subclass>
27     </class>
28 </hibernate-mapping>

这里主要知识点:

a、subclass:子类的指定

b、discriminator:鉴别器的设置

测试代码:

1 package com.myproc.test;
 2 
 3 import java.util.Date;
 4 
 5 import org.hibernate.Session;
 6 import org.hibernate.SessionFactory;
 7 import org.hibernate.Transaction;
 8 import org.hibernate.cfg.Configuration;
 9 import org.junit.Test;
10 
11 import com.myproc.domain.Article;
12 import com.myproc.domain.Reply;
13 import com.myproc.domain.Topic;
14 
15 
16 public class App {
17 
18     private static SessionFactory factory=
19             new Configuration()
20             .configure()
21             .addClass(Article.class)
22             .buildSessionFactory();
23     
24     @Test
25     public void test(){
26         
27         Session session=factory.openSession();
28         Transaction tran=session.beginTransaction();
29         
30         Article article=new Article();
31         article.setTitle("article");
32         article.setContext("article.......");
33         article.setPostDate(new Date());
34         
35         Topic topic=new Topic();
36         topic.setTitle("topic");
37         topic.setContext("topic.......");
38         topic.setPostDate(new Date());
39         topic.setType(2);
40         
41         Reply reply=new Reply();
42         reply.setTitle("reply");
43         reply.setContext("reply.......");
44         reply.setPostDate(new Date());
45         reply.setFloor(1);
46         
47         session.save(article);
48         session.save(topic);
49         session.save(reply);
50         
51         tran.commit();
52         session.close();
53     }
54 }

在数据库中我们可以看到结果:

第二种方式:joined-subclass

这种方式的特点:有三张表,其中父类对应的表存储公共属性,其它各自的表存储各自的信息,并且在该表中用一个外键引用父类对应的表的主键,如下图:

代码实现:在上例中,我们只需要修改Article.hbm.xml文件,内容如下:

1 <?xml version="1.0"?>
 2 
 3 <!DOCTYPE hibernate-mapping PUBLIC
 4         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 5         "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 6 <hibernate-mapping package="com.myproc.domain">
 7     <class name="Article" table="t_article" >
 8         <id name="id" column="Id" type="integer">
 9             <generator class="native"></generator>
10         </id>
11         <property name="title"  type="string"></property>
12         <property name="context" type="text" length="1000"></property>
13         <property name="postDate" type="timestamp"></property>
14         
15         <joined-subclass name="Topic" table="t_topic">
16             <!-- 指定子类的外键 -->
17             <key column="id"></key>
18             <property name="type"></property>
19         </joined-subclass>
20         
21         <joined-subclass name="Reply" table="t_reply">
22             <key column="id"></key>
23             <property name="floor"></property>
24         </joined-subclass>
25     </class>
26 </hibernate-mapping>

当执行测试代码后:

在数据库会自动生成3张表

t_article表中数据:

t_topic

t_reply

第三种方式:union-subclass

特点:使用两张表存储数据,如下图:

同样只需要要修改Article.hbm.xml文件

1 <?xml version="1.0"?>
 2 
 3 <!DOCTYPE hibernate-mapping PUBLIC
 4         "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 5         "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 6 <hibernate-mapping package="com.myproc.domain">
 7     <!-- 这里使用abstract=“true”,表示不再数据库中创建对应的表(这里的类不一定是抽象类) -->
 8     <class name="Article" table="t_article" abstract="true">
 9         <id name="id" column="Id" type="integer">
10             <!-- 这里不能使用identity方式,在hibernate5.2版本也不支持hilo,这里使用MultipleHiLoPerTableGenerator,方式和hilo一样 -->
11             <generator class="org.hibernate.id.MultipleHiLoPerTableGenerator">
12                 <param name="max_lo">100</param>
13             </generator>
14         </id>
15         <property name="title"  type="string"></property>
16         <property name="context" type="text" length="1000"></property>
17         <property name="postDate" type="timestamp"></property>
18         
19         <union-subclass name="Topic" table="t_topic">
20             <property name="type"></property>
21         </union-subclass>
22         
23         <union-subclass name="Reply" table="t_reply"></union-subclass>
24     </class>
25 </hibernate-mapping>

在测试代码中也不要保存Article父类型的数据


原文链接:https://www.cnblogs.com/caoyc/p/5603724.html