Hibernate繼承映射
在面向對象的程序領域中,類與類之間是有繼承關系的,例如Java世界中只需要extends關鍵字就可以確定這兩個類的父子關系,但是在關系數據庫的世界中,表與表之間沒有任何關鍵字可以明確指明這兩張表的父子關系,表與表是沒有繼承關系這樣的說法的。為了將程序領域中的繼承關系反映到數據中,Hibernate為我們提供了3種方案:
第一種方案:一個子類對應一張表。第二種方案:使用一張表表示所有繼承體系下的類的屬性的并集。第三種方案:每個子類使用一張表只存儲它特有的屬性,然后與父類所對應的表以一對一主鍵關聯的方式關聯起來。 |
現在假設有People、Student、Teacher三個類,父類為People,Student與Teacher為People的父類,代碼如下:
People類:
- public class People
- {
- /*父類所擁有的屬性*/
- private String id;
- private String name;
- private String sex;
- private String age;
- private Timestamp birthday;
- /*get和set方法*/
- }
Student類:
- public class Student extends People
- {
- /*學生獨有的屬性*/
- private String cardId;//學號
- public String getCardId()
- {
- return cardId;
- }
- public void setCardId(String cardId)
- {
- this.cardId = cardId;
- }
- }
Teacher類:
- public class Teacher extends People
- {
- /*Teacher所獨有的屬性*/
- private int salary;//工資
- public int getSalary()
- {
- return salary;
- }
- public void setSalary(int salary)
- {
- this.salary = salary;
- }
- }
該方案是使繼承體系中每一個子類都對應數據庫中的一張表。示意圖如下:
每一個子類對應的數據庫表都包含了父類的信息,并且包含了自己獨有的屬性。每個子類對應一張表,而且這個表的信息是完備的,即包含了所有從父類繼承下來的屬性映射的字段。這種策略是使用<union-subclass>標簽來定義子類的。
配置People.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>
- <class name="com.suxiaolei.hibernate.pojos.People" abstract="true">
- <id name="id" type="string">
- <column name="id"></column>
- <generator class="uuid"></generator>
- </id>
- <property name="name" column="name" type="string"></property>
- <property name="sex" column="sex" type="string"></property>
- <property name="age" column="age" type="string"></property>
- <property name="birthday" column="birthday" type="timestamp"></property>
- <!--
- <union-subclass name="com.suxiaolei.hibernate.pojos.Student" table="student">
- <property name="cardId" column="cardId" type="string"></property>
- </union-subclass>
- <union-subclass name="com.suxiaolei.hibernate.pojos.Teacher" table="teacher">
- <property name="salary" column="salary" type="integer"></property>
- </union-subclass>
- -->
- </class>
- <union-subclass name="com.suxiaolei.hibernate.pojos.Student"
- table="student" extends="com.suxiaolei.hibernate.pojos.People">
- <property name="cardId" column="cardId" type="string"></property>
- </union-subclass>
- <union-subclass name="com.suxiaolei.hibernate.pojos.Teacher"
- table="teacher" extends="com.suxiaolei.hibernate.pojos.People">
- <property name="salary" column="salary" type="integer"></property>
- </union-subclass>
- </hibernate-mapping>
以上配置是一個子類一張表方案的配置,<union-subclass>標簽是用于指示出該hbm文件所表示的類的子類,如People類有兩個子類,就需要兩個<union-subclass>標簽以此類推。<union-subclass>標簽的"name"屬性用于指定子類的全限定名稱,"table"屬性用于指定該子類對應的表的名稱,"extends"屬性用于指定該子類的父類,注意該屬性與<union-subclass>標簽的位置有關,若 <union-subclass>標簽作為<class>標簽的子標簽,則"extends"屬性可以不設置,否則需要明確設置"extends"屬性。<class>標簽中的"abstract"屬性如果值為true則,不會生成表結構。如果值為false則會生成表結構,但是不會插入數據。
根據People.hbm.xml生成表結構:
- drop table if exists student
- drop table if exists teacher
- create table student (
- id varchar(255) not null,
- name varchar(255),
- sex varchar(255),
- age varchar(255),
- birthday datetime,
- cardId varchar(255),
- primary key (id)
- )
- create table teacher (
- id varchar(255) not null,
- name varchar(255),
- sex varchar(255),
- age varchar(255),
- birthday datetime,
- salary integer,
- primary key (id)
- )
可以看到一個子類對應一張表。
這種策略是使用<subclass>標簽來實現的。因為類繼承體系下會有許多個子類,要把多個類的信息存放在一張表中,必須有某種機制來區分哪些記錄是屬于哪個類的。Hibernate中的這種機制就是,在表中添加一個字段,用這個字段的值來進行區分。在表中添加這個標示列使用<discriminator>標簽來實現。
該策略的示意圖:
將繼承體系中的所有類信息表示在同一張表中后,只要是這個類沒有的屬性會被自動賦上null。
配置People.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>
- <class name="com.suxiaolei.hibernate.pojos.People" table="people">
- <id name="id" type="string">
- <column name="id"></column>
- <generator class="uuid"></generator>
- </id>
- <discriminator column="peopleType" type="string"></discriminator>
- <property name="name" column="name" type="string"></property>
- <property name="sex" column="sex" type="string"></property>
- <property name="age" column="age" type="string"></property>
- <property name="birthday" column="birthday" type="timestamp"></property>
- <subclass name="com.suxiaolei.hibernate.pojos.Student" discriminator-value="student">
- <property name="cardId" column="cardId" type="string"></property>
- </subclass>
- <subclass name="com.suxiaolei.hibernate.pojos.Teacher" discriminator-value="teacher">
- <property name="salary" column="salary" type="string"></property>
- </subclass>
- </class>
- </hibernate-mapping>
<discriminator>標簽用于在表中創建一個標識列,其"column"屬性指定標識列的列名,"type"指定了標識列的類型。<subclass>標簽用于指定該HBM文件代表類的子類,有多少子類就有多少個該標簽,其"name"屬性指定子類的名稱,"discriminator-value"屬性指定該子類的數據的標識列的值是什么,其"extends"屬性與<union-subclass>的"extends"屬性用法一致。
根據People.hbm.xml生成表結構:
- drop table if exists people
- create table people (
- id varchar(255) not null,
- peopleType varchar(255) not null,
- name varchar(255),
- sex varchar(255),
- age varchar(255),
- birthday datetime,
- cardId varchar(255),
- salary varchar(255),
- primary key (id)
- )
可以看到一張表將繼承體系下的所有信息都包含了,其中"peopleType"為標識列。
第三種方案:每個子類使用一張表只存儲它特有的屬性,然后與父類所對應的表以一對一主鍵關聯的方式關聯起來。
這種策略是使用<joined-subclass>標簽來定義子類的。父類、子類都對應一張數據庫表。在父類對應的數據庫表中,它存儲了所有記錄的公共信息,實際上該父類對應的表會包含所有的記錄,包括父類和子類的記錄;在子類對應的數據庫表中,這個表只定義了子類中所特有的屬性映射的字段。子類對應的數據表與父類對應的數據表,通過一對一主鍵關聯的方式關聯起來。
這種策略的示意圖:
people表中存儲了子類的所有記錄,但只記錄了他們共有的信息,而他們獨有的信息存儲在他們對應的表中,一條記錄要獲得其獨有的信息,要通過people記錄的主鍵到其對應的子表中查找主鍵值一樣的記錄然后取出它獨有的信息。
配置People.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>
- <class name="com.suxiaolei.hibernate.pojos.People" table="people">
- <id name="id" type="string">
- <column name="id"></column>
- <generator class="uuid"></generator>
- </id>
- <property name="name" column="name" type="string"></property>
- <property name="sex" column="sex" type="string"></property>
- <property name="age" column="age" type="string"></property>
- <property name="birthday" column="birthday" type="timestamp"></property>
- <joined-subclass name="com.suxiaolei.hibernate.pojos.Student" table="student">
- <key column="id"></key>
- <property name="cardId" column="cardId" type="string"></property>
- </joined-subclass>
- <joined-subclass name="com.suxiaolei.hibernate.pojos.Teacher" table="teacher">
- <key column="id"></key>
- <property name="salary" column="salary" type="integer"></property>
- </joined-subclass>
- </class>
- </hibernate-mapping>
<joined-subclass>標簽需要包含一個key標簽,這個標簽指定了子類和父類之間是通過哪個字段來關聯的。
根據People.hbm.xml生成表結構:
- drop table if exists people
- drop table if exists student
- drop table if exists teacher
- create table people (
- id varchar(255) not null,
- name varchar(255),
- sex varchar(255),
- age varchar(255),
- birthday datetime,
- primary key (id)
- )
- create table student (
- id varchar(255) not null,
- cardId varchar(255),
- primary key (id)
- )
- create table teacher (
- id varchar(255) not null,
- salary integer,
- primary key (id)
- )
- alter table student
- add index FK8FFE823BF9D436B1 (id),
- add constraint FK8FFE823BF9D436B1
- foreign key (id)
- references people (id)
- alter table teacher
- add index FKAA31CBE2F9D436B1 (id),
- add constraint FKAA31CBE2F9D436B1
- foreign key (id)
- references people (id)
可以看到,父類對應的表保存公有信息,子類對應的表保存獨有信息,子類和父類對應的表使用一對一主鍵關聯的方式關聯起來。
原文鏈接:http://www.cnblogs.com/otomedaybreak/archive/2012/01/26/2329809.html
【編輯推薦】
- Hibernate事務與并發問題處理
- 讓Hibernate顯示SQL語句的綁定參數值
- Hibernate延遲加載剖析與代理模式應用
- 選用Ibatis和Hibernate的區別
- Hibernate攔截器與監聽器