1. 程式人生 > >【Hibernate】繼承對映

【Hibernate】繼承對映

【前言】     不知道大家是否還記得UML中的四種關係?自己回想了一下,還是沒有忘記的,分別是繼承、實現、依賴和關聯。     怎麼突然會想到這樣一個問題?是因為在學習完Hibernate關聯對映之後,緊接著又來了一個繼承對映。關聯和繼承,都屬於四種關係之一,所以,本篇部落格就先提了個問題,下面就開始繼承對映的學習。 【概述】     繼承是面嚮物件語言的三大重要特性之一,它實現了程式碼的複用。而Hibernate對於此特性在對應的物件模型配置檔案中也作出了各種配置,可將其與關係模型的關係分為三種情況:     1. 每棵類繼承樹一張表     2. 每個類一張表     3. 每個具體類一張表
    下面我們就逐一看看,它們各自生成的關係模型有著哪些不同?以下通過動物類和豬類、鳥類三者間的關係為例項,利用不同繼承對映的方法去建表。     三個類之間的關係如下所示: 【一、繼承對映之每棵類繼承樹一張表】     1. 含義:此方法的意思是不管父類擁有多少個子類,都只會根據父類去生成一張表,而各個子類中有單獨的欄位,都新增到父類生成的那張表中。     2. 設計:從圖上看,這張表至少包含的欄位有:id,name,sex,weight和height。但因為子類不止一個,如果沒有一個標識欄位,那麼就無法從資料表中看到記錄是屬於哪個子類的。所以,此張表的結構與資料應該如下: t_animal:
Id Name Sex Weight Height Type
1 小豬豬 True 200 P
2 小鳥鳥 False 100 B
    根據圖建立對應的物件模型,也就是所說的實體類,本篇部落格中實體類程式碼就不再展示了。    3. 配置及註釋:
<?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.bjpowernode.hibernate">
    <!-- 新建表,名為t_animal。不採用延遲載入 -->
    <class name="Animal" table="t_animal" lazy="false">
        <!-- 該表的主鍵欄位id,生成策略為native -->
        <id name="id">
            <generator class="native"/>
        </id>
        <!-- 在父類使用discrimination標籤,用來指定標識欄位的列名和型別 -->
        <discriminator column="type" type="string"/>
        <!-- 父類的name屬性 -->
        <property name="name"/>
        <!-- 父類的sex屬性 -->
        <property name="sex"/>
        <!-- 子類Pig,標識欄位值為P -->
        <subclass name="Pig" discriminator-value="P">
            <!--  子類Pig的weight屬性  -->
            <property name="weight"/>
        </subclass>
        <!-- 子類Bird,標識欄位值為B -->
        <subclass name="Bird" discriminator-value="B">
            <!--  子類Bird的height屬性  -->
            <property name="height"/>
        </subclass>
    </class>
</hibernate-mapping>  
     4. 結果:     5. 小結:     此種方法的結果就是資料庫中只有一張根據父類建立的表,而不同子類的子屬性也全都寫入到這張表中,增加一個區分欄位即可。     6. 優缺點:     (1)表中引入的區分子類的欄位,也就是包括了描述其他欄位的欄位。     (2)如果某個子類的某個屬性不能為空,那麼在資料庫一級不能設定該欄位not null(非空)     (3)維護起來方便,只需要修改一個表     (4)靈活性差,表中冗餘欄位會隨著子類的增多而越來越多 【二、繼承對映之每個類一張表】     1. 含義:此種方法的意思是每個類都建立一張單獨的表。     2. 設計:從圖上看,共包含三個類,則應該建立三張表:t_animal、t_pig和t_bird。三張表的結果和資料如下所示:      3. 配置即註釋:
<?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.bjpowernode.hibernate">
<!-- 建立表t-animal -->
    <class name="Animal" table="t_animal">
    <!-- 該表的主鍵欄位id,生成策略為native -->
        <id name="id">
            <generator class="native"/>
        </id>
        <!-- t_animal的屬性欄位name和sex -->
        <property name="name"/>
        <property name="sex"/>
        <!-- joined-subclass生成策略,新建表t_pig -->
        <joined-subclass name="Pig" table="t_pig">
        <!-- 指定了pig子類和animal父類之間是通過pid欄位關聯 -->
            <key column="pid"/>
            <!-- pig子類的子屬性,weight -->
            <property name="weight"/>
        </joined-subclass>
        <!-- joined-subclass生成策略,新建表t_bird -->
        <joined-subclass name="Bird" table="t_bird">
        <!-- 指定了bird子類和animal父類之間是通過bid欄位關聯 -->
            <key column="bid"/>
            <!-- bird子類的子屬性,height -->
            <property name="height"/>
        </joined-subclass>
    </class>
</hibernate-mapping> 
4. 結果:

    5. 小結:

    此種方法的結果是資料庫中每個類都對應生成一張表,父類擁有自己的屬性欄位,子類加上與父類關聯的主鍵欄位和自己的子屬性。     6. 優缺點:     (1)這種設計方式完全符合關係模型的設計原則,且不存在冗餘     (2)維護起來比較方便,對每個類的修改只需要修改其所對應的表,靈活性很好,完全是參照物件繼承的方式進行配置     (3)對於父類的查詢需要使用左外連結,對於子類查詢需要使用內連結     (4)對於子類的持久話至少要處理兩個表 【三、繼承對映之每個具體類一張表】     1. 含義:此種方法的意思是每個子類都建立一張單獨的表,而父類不生成對應的表     2. 設計:從圖上看,共包含兩個具體類,則應該建立兩張表:t_pig和t_bird。兩張表的結果和資料如下所示:      3. 配置即註釋:
<?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.bjpowernode.hibernate">
<!-- 定義該表的abstract屬性為true,則不會生成具體的表 -->
    <class name="Animal" table="t_animal" abstract="true">
        <id name="id">
        <!-- 讓應用程式在save()之前為物件分配一個標示符。這是 <generator>元素沒有指定時的預設生成策略。 -->
            <generator class="assigned"/>
        </id>
        <property name="name"/>
        <property name="sex"/>
        <!-- union-subclass生成策略,t_pig表的資訊是完整的,也就是包含id,name,sex和weight四個欄位 -->
        <union-subclass name="Pig" table="t_pig">
        <!-- 子屬性欄位weight -->
            <property name="weight"/>
        </union-subclass>
        <!-- union-subclass生成策略,t_bird表的資訊是完整的,也就是包含id,name,sex和height四個欄位 -->
        <union-subclass name="Bird" table="t_bird">
        <!-- 子屬性欄位height -->
            <property name="height"/>
        </union-subclass>
    </class>
</hibernate-mapping>  
4. 結果:

    5. 小結:

    此種方法的結果是資料庫中每個子類都對應生成一張表,每個子類的屬性是各自的子屬性加上父類的共同屬性。     6. 優缺點:      (1) 這種設計方式符合關係模型的設計原則,但有表中存在重複欄位的問題。      (2) 如果需要對基類進行修改,則需要對基類以及該類的子類所對應的所有表都進行修改               (3) 對於子類的查詢只需要訪問單獨的表,對父類查詢需要檢索所有的表,對於單個物件持久話操作只需要處理一個表     【總結】
    對於這三種繼承對映方法,目前還沒有在專案中遇到過,所以三者之間如何選擇?通常選擇什麼?都沒有概念。不過總體思想應該仍舊是:沒有最好,選擇合適的就好。也期待在專案中見到對它們的應用。