Hibernate繼承映射
在面向?qū)ο蟮某绦蝾I(lǐng)域中,類與類之間是有繼承關(guān)系的,例如Java世界中只需要extends關(guān)鍵字就可以確定這兩個(gè)類的父子關(guān)系,但是在關(guān)系數(shù)據(jù)庫(kù)的世界中,表與表之間沒有任何關(guān)鍵字可以明確指明這兩張表的父子關(guān)系,表與表是沒有繼承關(guān)系這樣的說法的。為了將程序領(lǐng)域中的繼承關(guān)系反映到數(shù)據(jù)中,Hibernate為我們提供了3種方案:
第一種方案:一個(gè)子類對(duì)應(yīng)一張表。第二種方案:使用一張表表示所有繼承體系下的類的屬性的并集。第三種方案:每個(gè)子類使用一張表只存儲(chǔ)它特有的屬性,然后與父類所對(duì)應(yīng)的表以一對(duì)一主鍵關(guān)聯(lián)的方式關(guān)聯(lián)起來。 |
現(xiàn)在假設(shè)有People、Student、Teacher三個(gè)類,父類為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
- {
- /*學(xué)生獨(dú)有的屬性*/
- private String cardId;//學(xué)號(hào)
- public String getCardId()
- {
- return cardId;
- }
- public void setCardId(String cardId)
- {
- this.cardId = cardId;
- }
- }
Teacher類:
- public class Teacher extends People
- {
- /*Teacher所獨(dú)有的屬性*/
- private int salary;//工資
- public int getSalary()
- {
- return salary;
- }
- public void setSalary(int salary)
- {
- this.salary = salary;
- }
- }
第一種方案:一個(gè)子類對(duì)應(yīng)一張表
該方案是使繼承體系中每一個(gè)子類都對(duì)應(yīng)數(shù)據(jù)庫(kù)中的一張表。示意圖如下:
每一個(gè)子類對(duì)應(yīng)的數(shù)據(jù)庫(kù)表都包含了父類的信息,并且包含了自己獨(dú)有的屬性。每個(gè)子類對(duì)應(yīng)一張表,而且這個(gè)表的信息是完備的,即包含了所有從父類繼承下來的屬性映射的字段。這種策略是使用<union-subclass>標(biāo)簽來定義子類的。
配置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>
以上配置是一個(gè)子類一張表方案的配置,<union-subclass>標(biāo)簽是用于指示出該hbm文件所表示的類的子類,如People類有兩個(gè)子類,就需要兩個(gè)<union-subclass>標(biāo)簽以此類推。<union-subclass>標(biāo)簽的"name"屬性用于指定子類的全限定名稱,"table"屬性用于指定該子類對(duì)應(yīng)的表的名稱,"extends"屬性用于指定該子類的父類,注意該屬性與<union-subclass>標(biāo)簽的位置有關(guān),若 <union-subclass>標(biāo)簽作為<class>標(biāo)簽的子標(biāo)簽,則"extends"屬性可以不設(shè)置,否則需要明確設(shè)置"extends"屬性。<class>標(biāo)簽中的"abstract"屬性如果值為true則,不會(huì)生成表結(jié)構(gòu)。如果值為false則會(huì)生成表結(jié)構(gòu),但是不會(huì)插入數(shù)據(jù)。
根據(jù)People.hbm.xml生成表結(jié)構(gòu):
- 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)
- )
可以看到一個(gè)子類對(duì)應(yīng)一張表。
這種策略是使用<subclass>標(biāo)簽來實(shí)現(xiàn)的。因?yàn)轭惱^承體系下會(huì)有許多個(gè)子類,要把多個(gè)類的信息存放在一張表中,必須有某種機(jī)制來區(qū)分哪些記錄是屬于哪個(gè)類的。Hibernate中的這種機(jī)制就是,在表中添加一個(gè)字段,用這個(gè)字段的值來進(jìn)行區(qū)分。在表中添加這個(gè)標(biāo)示列使用<discriminator>標(biāo)簽來實(shí)現(xiàn)。
該策略的示意圖:
將繼承體系中的所有類信息表示在同一張表中后,只要是這個(gè)類沒有的屬性會(huì)被自動(dòng)賦上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>標(biāo)簽用于在表中創(chuàng)建一個(gè)標(biāo)識(shí)列,其"column"屬性指定標(biāo)識(shí)列的列名,"type"指定了標(biāo)識(shí)列的類型。<subclass>標(biāo)簽用于指定該HBM文件代表類的子類,有多少子類就有多少個(gè)該標(biāo)簽,其"name"屬性指定子類的名稱,"discriminator-value"屬性指定該子類的數(shù)據(jù)的標(biāo)識(shí)列的值是什么,其"extends"屬性與<union-subclass>的"extends"屬性用法一致。
根據(jù)People.hbm.xml生成表結(jié)構(gòu):
- 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"為標(biāo)識(shí)列。
第三種方案:每個(gè)子類使用一張表只存儲(chǔ)它特有的屬性,然后與父類所對(duì)應(yīng)的表以一對(duì)一主鍵關(guān)聯(lián)的方式關(guān)聯(lián)起來。
這種策略是使用<joined-subclass>標(biāo)簽來定義子類的。父類、子類都對(duì)應(yīng)一張數(shù)據(jù)庫(kù)表。在父類對(duì)應(yīng)的數(shù)據(jù)庫(kù)表中,它存儲(chǔ)了所有記錄的公共信息,實(shí)際上該父類對(duì)應(yīng)的表會(huì)包含所有的記錄,包括父類和子類的記錄;在子類對(duì)應(yīng)的數(shù)據(jù)庫(kù)表中,這個(gè)表只定義了子類中所特有的屬性映射的字段。子類對(duì)應(yīng)的數(shù)據(jù)表與父類對(duì)應(yīng)的數(shù)據(jù)表,通過一對(duì)一主鍵關(guān)聯(lián)的方式關(guān)聯(lián)起來。
這種策略的示意圖:
people表中存儲(chǔ)了子類的所有記錄,但只記錄了他們共有的信息,而他們獨(dú)有的信息存儲(chǔ)在他們對(duì)應(yīng)的表中,一條記錄要獲得其獨(dú)有的信息,要通過people記錄的主鍵到其對(duì)應(yīng)的子表中查找主鍵值一樣的記錄然后取出它獨(dú)有的信息。
配置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>標(biāo)簽需要包含一個(gè)key標(biāo)簽,這個(gè)標(biāo)簽指定了子類和父類之間是通過哪個(gè)字段來關(guān)聯(lián)的。
根據(jù)People.hbm.xml生成表結(jié)構(gòu):
- 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)
可以看到,父類對(duì)應(yīng)的表保存公有信息,子類對(duì)應(yīng)的表保存獨(dú)有信息,子類和父類對(duì)應(yīng)的表使用一對(duì)一主鍵關(guān)聯(lián)的方式關(guān)聯(lián)起來。
原文鏈接:http://www.cnblogs.com/otomedaybreak/archive/2012/01/26/2329809.html
【編輯推薦】
- Hibernate事務(wù)與并發(fā)問題處理
- 讓Hibernate顯示SQL語句的綁定參數(shù)值
- Hibernate延遲加載剖析與代理模式應(yīng)用
- 選用Ibatis和Hibernate的區(qū)別
- Hibernate攔截器與監(jiān)聽器