英文原址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')
須要例子中完整代碼的,原文鏈接中提供有下載。