初識Hibernate之繼承映射

     前面的兩篇文章中,我們介紹了兩張表之間的各種相互關聯映射關係,但往往我們也會遇到兩張表甚至多張表之間共有着多個相同的字段。例如:

這裏寫圖片描述

如圖,student表和teacher表共同具有id,name,age等字段,而我們的繼承映射就是這樣的一個思想,抽象出這些共有的字段爲一張父表,讓子表對其進行繼承,這樣就可以大大降低我們實體類代碼的冗餘性,增強其結構的完善。

這裏寫圖片描述

Hibernate支持以下三種數據表的生成策略:

  • 每個類分層結構一張表
  • 每個子類一張表
  • 每個具體類一張表

一、每個類分層結構一張表
     對於這種數據表的生成策略,最終Hibernate會在數據庫中生成一張數據表,這張數據表的結構會是如下的:

這裏寫圖片描述

無論你是student記錄還是teacher記錄,都會被存儲到這張集成的新表中。下面是實現代碼:

public class Person {
    private int id;
    private String name;
    //省略get,set方法
}
public class Student extends Person {
    private int grade;
    //省略get,set方法
}
public class Teacher extends Person {
    private int salary;
    //省略get,set方法
}

下面是映射配置文件的書寫:

<class name="Person" abstract="true" table="newTable">
    <id name="id">
        <generator class="assigned"/>
    </id>
    <!--指定鑑別器列的名稱和類型-->
    <discriminator column="type" type="java.lang.String"/>
    <property name="name"/>
    <!--指定集成到新表的子實體類-->
    <subclass name="Student" discriminator-value="stu">
        <!--配置繼承類中其他屬性-->
        <property name="grade"/>
    </subclass>
    <subclass name="Teacher" discriminator-value="tea">
        <property name="salary"/>
    </subclass>
</class>

abstract=”true”指定Hibernate不用將Person表生成具體表,只需要生成一張集成的新表即可。table=”newTable”則指定了新表的表名,鑑別器就是用來區分當前記錄時student或是teacher的一個標記,它會在新表中生成一個字段,而該字段的名稱和類型都在此處進行指定。

subclass標籤用於配置需要集成到新表中子實體類的一些屬性等內容。下面我們通過插入操作了解這種映射策略對具體數據庫的實際操作。

Student student = new Student();
student.setId(1);
student.setName("stu1");
student.setGrade(100);

Teacher teacher  = new Teacher();
teacher.setId(2);
teacher.setName("tea1");
teacher.setSalary(10000);

session.save(student);
session.save(teacher);

將兩條不同類型的記錄保存到數據庫中,

這裏寫圖片描述

newTable是一張綜合的表,主要由student表和teacher表集成而來,對應於student表的記錄salary字段的值爲空,對應於teacher表記錄的grade字段值爲空。那在我們取數據的時候,Hibernate該如何區分當前記錄對應的是哪個實體類的呢?

Person person = (Person)session.get(Person.class,1);
if(person instanceof Student){
    Student student1 = (Student)person;
    System.out.println("i am student,my grade is:"+student1.getGrade());
}

實際上,Hibernate使用多態來對數據記錄進行接收,無論你是Student記錄或teacher記錄,都可以被person類型接收。使用這種策略方式映射數據表只會生成一張表,但是很大的一個問題是,當很多張表進行集成的時候會導致表結構複雜混亂。

二、每個具體類映射成一張表
     這種數據表的生成策略會爲每個實體類生成一張數據表,就上述例子而言,會爲person,student,teacher都生成一張表。首先我們看映射配置文件:

<class name="Person">
    <id name="id">
        <generator class="assigned"/>
    </id>
    <property name="name"/>
    <union-subclass name="Student" table="students">
        <property name="grade"/>
    </union-subclass>
    <union-subclass name="Teacher" table="teachers">
        <property name="salary"/>
    </union-subclass>
</class>

這裏的配置其實不需要多的解釋,union-subclass告訴Hibernate當前配置的實體類是person類的子類,並用table屬性指定對應數據庫的表名。下面我們通過插入數據來看看具體生成的表的結構:

這裏寫圖片描述

很明顯,我們的person表只起到一個模板的效果並沒有什麼實際的價值,而我們students表和teachers表的id,name字段都是從person表中繼承得到的。

三、每個子類一張表
     這種數據表的生成策略的主要思想就是將公共的信息存放在父表中,子表只保存自己獨有的字段信息了。例如:

<class name="Person">
    <id name="id" column="id">
       <generator class="native"/>
    </id>
    <property name="name"/>
    <joined-subclass name="Student" table="students">
        <key column="sId" />
        <property name="grade"/>
    </joined-subclass>
    <joined-subclass name="Teacher" table="teachers">
        <key column="tId"/>
        <property name="salary"/>
    </joined-subclass>
</class>

我們使用 joined-subclass來配置繼承子類,在Hibernate生成數據表的時候會將student和teacher表的主鍵作爲外鍵關聯父表的主鍵。下面是插入數據:

Student student = new Student();
student.setName("stu1");
student.setGrade(12);

Teacher teacher = new Teacher();
teacher.setName("tea1");
teacher.setSalary(1233);

session.save(student);
session.save(teacher);

這裏寫圖片描述

顯然,我們student或者teacher表不再需要存放name或者其他共有字段的信息,只需要通過自己的主鍵去查找父表即可得到。

至此,有關繼承映射的三個策略已經介紹結束,總結不到之處,望指出。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章