Hibernate 框架繼承映射

對於面向對象的程序設計語言而言,繼承和多態是兩個最基本的概念。Hibernate 的繼承映射可以理解持久化類之間的繼承關係。

Hibernate支持三種繼承映射策略:

  • 使用 subclass 進行映射:將域模型中的每一個實體對象映射到一個獨立的表中,也就是說不用在關係數據模型中考慮域模型中的繼承關係和多態。
  • 使用 joined-subclass 進行映射: 對於繼承關係中的子類使用同一個表,這就需要在數據庫表中增加額外的區分子類類型的字段。
  • 使用 union-subclass 進行映射:域模型中的每個類映射到一個表,通過關係數據模型中的外鍵來描述表之間的繼承關係。這也就相當於按照域模型的結構來建立數據庫中的表,並通過外鍵來建立表之間的繼承關係。

一、subclass

採用 subclass 的繼承映射可以實現對於繼承關係中父類和子類使用同一張表
因爲父類和子類的實例全部保存在同一個表中,因此需要在該表內增加一列,使用該列來區分每行記錄到低是哪個類的實例—-這個列被稱爲辨別者列(discriminator).
在這種映射策略下,使用 subclass 來映射子類,使用 class 或 subclass 的 discriminator-value 屬性指定辨別者列的值
所有子類定義的字段都不能有非空約束。如果爲那些字段添加非空約束,那麼父類的實例在那些列其實並沒有值,這將引起數據庫完整性衝突,導致父類的實例無法保存到數據庫中
這裏寫圖片描述

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.entities.subclass">
    <class name="Person" table="PERSON" discriminator-value="PERSON">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        <!-- 配置辨別者列 -->
        <discriminator column="TYPE" type="string"></discriminator>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        <property name="age" type="java.lang.Integer">
            <column name="AGE" />
        </property>
        <!-- 映射 Student -->
        <subclass name="Student" discriminator-value="STUDENT">
            <property name="school" type="string" column="SCHOOL" length="30"></property>
        </subclass>
    </class>
</hibernate-mapping>

HibernateTest.java

package com.hibernate.entities.subclass;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class HibernateTest {
    SessionFactory sessionFactory;
    Session session;
    Transaction transaction;

    @Before
    public void init() {
        Configuration configuration = new Configuration().configure();
        @SuppressWarnings("deprecation")
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
            .applySettings(configuration.getProperties()).buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
    }

    @After
    public void destory() {
        transaction.commit();
        session.close();
        sessionFactory.close();
    }

    /**
     * 1.查詢父類記錄,只需要查詢一張數據表
     * 2.查詢子類記錄,只需要查詢一張數據表
     * 
     * 缺點:
     * 1.使用了辨別者列
     * 2.子類獨有的字段不能添加非空約束
     * 3.若繼承層次比較深,則數據表的字段也會比較多
     */
    @Test
    public void testQuery() {
        List<Person> persons = session.createQuery("FROM Person").list();
        System.out.println(persons.size());

        List<Student> students = session.createQuery("FROM Student").list();
        System.out.println(students.size());
    }

    /**
     * 插入操作
     * 1. 對於子類對象只需把記錄插入到一張數據表中。
     * 2. 辨別者列由 Hibernate 自動維護
     */
    @Test
    public void testSave() {

        Person person = new Person();
        person.setAge(12);
        person.setName("AA");

        session.save(person);

        Student student = new Student();
        student.setAge(23);
        student.setName("BB");
        student.setSchool("china");

        session.save(student);
    }
}

二、joined-subclass

採用 joined-subclass 元素的繼承映射可以實現每個子類一張表
採用這種映射策略時,父類實例保存在父類表中,子類實例由父類表和子類表共同存儲。因爲子類實例也是一個特殊的父類實例,因此必然也包含了父類實例的屬性。於是將子類和父類共有的屬性保存在父類表中,子類增加的屬性,則保存在子類表中。
在這種映射策略下,無須使用鑑別者列,但需要爲每個子類使用 key 元素映射共有主鍵。
子類增加的屬性可以添加非空約束。因爲子類的屬性和父類的屬性沒有保存在同一個表中
這裏寫圖片描述

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.entities.joined.subclass">
    <class name="Person" table="PERSON">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        <property name="age" type="java.lang.Integer">
            <column name="AGE" />
        </property>
        <!-- 映射 Student -->
        <joined-subclass name="Student" table="STUDENT">
            <key>
                <column name="STUDENT_ID"></column>
            </key>
            <property name="school" type="string" column="SCHOOL" length="30"></property>
        </joined-subclass>
    </class>
</hibernate-mapping>

三、union-subclass

採用 union-subclass 元素可以實現將每一個實體對象映射到一個獨立的表中。
子類增加的屬性可以有非空約束 — 即父類實例的數據保存在父表中,而子類實例的數據保存在子類表中。
子類實例的數據僅保存在子類表中, 而在父類表中沒有任何記錄
在這種映射策略下,子類表的字段會比父類表的映射字段要多,因爲子類表的字段等於父類表的字段、加子類增加屬性的總和
在這種映射策略下,既不需要使用鑑別者列,也無須使用 key 元素來映射共有主鍵.
使用 union-subclass 映射策略是不可使用 identity 的主鍵生成策略, 因爲同一類繼承層次中所有實體類都需要使用同一個主鍵種子, 即多個持久化實體對應的記錄的主鍵應該是連續的. 受此影響, 也不該使用 native 主鍵生成策略, 因爲 native 會根據數據庫來選擇使用 identity 或 sequence.
這裏寫圖片描述

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.entities.union.subclass">
    <class name="Person" table="PERSON">
        <id name="id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="hilo" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        <property name="age" type="java.lang.Integer">
            <column name="AGE" />
        </property>
        <union-subclass name="Student" table="STUDENT">
            <property name="school" column="SCHOOL" type="string"></property>
        </union-subclass>
    </class>
</hibernate-mapping>

三種方式比較

這裏寫圖片描述

發佈了60 篇原創文章 · 獲贊 5 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章