[翻譯] hibernate映射繼承關係(一):一張表對應一整棵類繼承樹

英文原址html

網上這個主題的文章不在少數,這個系列的文章的部分價值在於給出了註解模式(Annotation)的例子。文章易懂,權當加強記憶,捎帶着練習下翻譯(翻譯不當之處請指出)。  java

Hibernate中繼承關係的簡介sql

java是一種面嚮對象語言,它能夠實現繼承關係。然而,繼承倒是"對象模型-關係模型"不匹配的最顯而易見的方面之一。面向對象系統可以輕鬆的對「is a」和「has a」關係進行建模。而關係模型只能表達兩個實體間的"has a"關係。hibernate可以把有關聯的表映射爲對象,但你須要根據須要來選擇不一樣的映射策略。數據庫

Hibernate繼承關係映射策略分爲三種:一張表對應一整棵類繼承樹、一個類對應一張表、每個具體類對應一張表。session

之一:一張表對應一整棵類繼承樹(子類和父類共享同一張表)app

假設咱們有一個 Person 類及其子類 Employee. 每一個類包括以下屬性:性能

* class Person
        - firstname
        - lastname

* class Employee
        - joining_date
        - department_name

在「一張表對應一整棵類繼承樹這種模式中,繼承樹上的全部類的數據都存儲在一張表上,鑑別器字段(discriminator )是惟一的標識每一個類的關鍵字段。spa

下面是「一張表對應一整棵類繼承樹模式的優勢和缺點:.net

優勢hibernate

這種模式提供了最好的性能,由於即便在深層繼承的狀況下,檢索一條子類數據,也只須要一次select操做。

缺點

對於任何一個子類的變動,好比增刪改某字段,都將致使數據庫表的變動。 

建表語句

CREATE TABLE `person` (
    `person_id` BIGINT(10) NOT NULL AUTO_INCREMENT,
    `firstname` VARCHAR(50) NULL DEFAULT NULL,
    `lastname` VARCHAR(50) NULL DEFAULT NULL,
    `joining_date` DATE NULL DEFAULT NULL,
    `department_name` VARCHAR(50) NULL DEFAULT NULL,
    `discriminator` VARCHAR(20) NOT NULL,
    PRIMARY KEY (`person_id`)
)

PERSON表被用來同時存儲 Employee  Person 對象. 

Hibernate 繼承: XML 映射 

下面的例子展現瞭如何用XML方式映射  Employee  Person 實體類

Person.java 

package net.viralpatel.hibernate;
 
public class Person {
 
    private Long personId;
    private String firstname;
    private String lastname;
 
    // Constructors and Getter/Setter methods,
}

Employee.java

package net.viralpatel.hibernate;
 
import java.util.Date;
 
public class Employee extends Person {
 
    private Date joiningDate;
    private String departmentName;
 
    // Constructors and Getter/Setter methods,
}

Person.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
 
<hibernate-mapping package="net.viralpatel.hibernate">
 
    <class name="Person" table="PERSON" discriminator-value="P">
        <id name="personId" column="PERSON_ID">
            <generator class="native" />
        </id>
 
        <discriminator column="DISCRIMINATOR" type="string" />
 
        <property name="firstname" />
        <property name="lastname" column="lastname" />
 
        <subclass name="Employee" extends="Person" discriminator-value="E">
                <property name="departmentName" column="department_name" />
                <property name="joiningDate" type="date" column="joining_date" />
        </subclass>
    </class>
</hibernate-mapping>

注意這裏只定義了一個 hibernate 映射文件 Person.hbm.xml.

Person  Employee 類都定義在這同一個文件中.

<discriminator> 標籤用來指定鑑別器列,包括列名和類型.

<subclass> 標籤用於映射子類 Employee. 注意咱們沒有用常規的 <class>標籤來映射 Employee ,由於它位於繼承關係樹下端。

Person 類的鑑別器的值被指定爲 「P」 ,相應的 Employee 「E」,這樣Hibernate將要持久化person  employee時,相應的「P」「E」將被置入鑑別器字段。

 Hibernate 繼承: 註解映射

 下面的例子展現瞭如何用JPA註解方式來映射 Employee  Person 實體類。

 Person.java 

package net.viralpatel.hibernate;
 
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
 
@Entity
@Table(name = "PERSON")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="discriminator",
    discriminatorType=DiscriminatorType.STRING
)
@DiscriminatorValue(value="P")
public class Person {
 
    @Id
    @GeneratedValue
    @Column(name = "PERSON_ID")
    private Long personId;
 
    @Column(name = "FIRSTNAME")
    private String firstname;
 
    @Column(name = "LASTNAME")
    private String lastname;
 
    // Constructors and Getter/Setter methods,
}

Person 類是繼承樹的根類,因此咱們使用了下面一些註解使其成爲根類。

@Inheritance – 定義一個實體類繼承樹的繼承策略,這個註解只能定義在繼承樹的根類上。

@DiscriminatorColumn – 用於當@Inheritance 的值被定義爲 SINGLE_TABLE  JOINED 時,指定鑑別器列。 此註解只能用於兩種類:1、繼承樹的根類,2、繼承樹的某子類,而且該子類定義了本身繼承策略。

若是在須要鑑別器列的時候,沒有使用@DiscriminatorColumn註解,那麼鑑別器列的名稱將默認爲「DTYPE」,類型將默認爲「STRING」。

@DiscriminatorValue – 用於指定給定實體類所對應的鑑別器列的具體值。 DiscriminatorValue 註解只能用在具體的實體類中。若是使用了鑑別器列,可是沒有使用 DiscriminatorValue 註解,一個鑑別器值生成器將生效併產生一個鑑別器值來表明這個類。若是鑑別器列的類型是 STRING,  鑑別器列的值默認是該類的名稱。若是不採用默認值,那麼應該在繼承樹的每一個類中都使用該註解。

 Employee.java 

package net.viralpatel.hibernate;
 
import java.util.Date;
 
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Table;
 
@Entity
@Table(name="PERSON")
@DiscriminatorValue("E")
public class Employee extends Person {
 
    @Column(name="joining_date")
    private Date joiningDate;
 
    @Column(name="department_name")
    private String departmentName;
 
    // Constructors and Getter/Setter methods,
}

Employee類是Person類的子類,因此在映射時,使用@DiscriminatorValue註解來定義鑑別器的值,此例中,「E」將被置入鑑別器列。 

 MainClass

 package net.viralpatel.hibernate;

import java.util.Date;
 
import org.hibernate.Session;
import org.hibernate.SessionFactory;
 
public class Main {
 
    public static void main(String[] args) {
 
        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session session = sf.openSession();
        session.beginTransaction();
 
        Person person = new Person("Steve", "Balmer");
        session.save(person);
 
        Employee employee = new Employee("James", "Gosling", "Marketing", new Date());
        session.save(employee);
 
        session.getTransaction().commit();
        session.close();
 
    }
}

Main class 用來持久化 Person     Employee類的實例。注意兩個類都存儲在PERSON表中,鑑別器列用於區分兩個實體。

 輸出結果

Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME, discriminator) values (?, ?, 'P')
Hibernate: insert into EMPLOYEE (FIRSTNAME, LASTNAME, department_name, joining_date, discriminator) values (?, ?, ?, ?, 'E')

 

須要例子中完整代碼的,原文鏈接中提供有下載。

相關文章
相關標籤/搜索