1. 程式人生 > >Hibernate對映解析---繼承對映

Hibernate對映解析---繼承對映

現實世界中有很多種動物,比如:Pig(豬),Bird(鳥)等等,當我用面向物件的思想分析時,我們一般會將它們的共同部分抽取出來增加一個抽象類Animal(動物),這樣在編寫程式時Pig和Bird只需要繼承它們的父類Animal就可以省去很多重複的程式碼。Java程式碼中只需要extends關鍵字就可以輕鬆實現這種繼承關係,但是對於我們使用的關係型資料庫是沒有任何關鍵字可以指明這種繼承關係的。為了將這種繼承關係反映到資料庫中,Hibernate為我們提供了3種解決方案:

1、         每個具體類對應一張表

       該方案是使繼承體系中每一個具體的類都對應資料庫中的一張表。示意圖如下:


       每個子類對應的資料庫表都包含了父類的資訊,並且還有自己獨有的屬性,每個子類對應一張表,這個表具備完整的資訊,包含了所有父類繼承下來的屬性對映的欄位,這種策略是使用<union-subclass>標籤來定義子類的。

       注意:在儲存物件的時候id不能重複(不能使用資料庫的自增方式生成主鍵)

部分配置程式碼展示:
<?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.hibernate">  
    <class name="Animal" table="t_animal" abstract="true">  
        <id name="id">  
            <generator class="assigned"/>  
        </id>  
        <property name="name"/>  
        <property name="sex"/>  
        <union-subclass name="Pig" table="t_pig">  
            <property name="weight"/>  
        </union-subclass>  
        <union-subclass name="Bird" table="t_bird">  
            <property name="height"/>  
        </union-subclass>  
    </class>  
</hibernate-mapping>   

2、         每個類一張表

       這種策略是使用<joined-subclass>標籤來定義子類的。父類、子類都對應一張資料庫表。在父類對應的資料庫表中,它儲存了所有記錄的公共資訊,實際上該父類對應的表會包含所有的記錄,包括父類和子類的記錄;在子類對應的資料庫表中,這個表只定義了子類中所特有的屬性對映的欄位。子類對應的資料表與父類對應的資料表,通過一對一主鍵關聯的方式關聯起來。

       這種策略的示意圖:


       t_animal表中儲存了子類的所有記錄,但只記錄了他們共有的資訊,而他們獨有的資訊儲存在他們對應的表中,一條記錄要獲得其獨有的資訊,要通過t_animal記錄的主鍵到其對應的子表中查詢主鍵值一樣的記錄然後取出它獨有的資訊。

       注意:Joined-subclass標籤的name屬性是子類的全路徑名

                   Joined-subclass標籤需要包含一個key標籤,這個標籤指定了子類和父類之間是通過哪個欄位來關聯的。如:<key     column=”PARENT_KEY_ID”/>,這裡的column,實際上就是父類的主鍵對應的對映欄位名稱。
                   Joined-subclass標籤,既可以被class標籤所包含(這種包含關係正是表明了類之間的繼承關係),也可以與class標籤平 行。 當Joined-subclass標籤的定義與class標籤平行的時候,需要在Joined-subclass標籤中,新增extends屬性,裡面的值是父類的全路徑名稱。
                  子類的其它屬性,像普通類一樣,定義在joined-subclass標籤的內部。

        部分程式碼展示:

<?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.hibernate">  
    <class name="Animal" table="t_animal">  
        <id name="id">  
            <generator class="native"/>  
        </id>  
        <property name="name"/>  
        <property name="sex"/>  
        <joined-subclass name="Pig" table="t_pig">  
            <key column="pid"/>  
            <property name="weight"/>  
        </joined-subclass>  
        <joined-subclass name="Bird" table="t_bird">  
            <key column="bid"/>  
            <property name="height"/>  
        </joined-subclass>  
    </class>  
</hibernate-mapping> 

3、         每棵類繼承樹一張表

       這種策略是使用<subclass>標籤來實現的。因為類繼承體系下會有許多個子類,要把多個類的資訊存放在一張表中,必須有某種機制來區分哪些記錄是屬於哪個類的。Hibernate中的這種機制就是,在表中新增一個欄位,用這個欄位的值來進行區分。在表中新增這個標示列使用<discriminator>標籤來實現。

       該策略的示意圖:


       將繼承體系中的所有類資訊表示在同一張表中後,只要是這個類沒有的屬性會被自動賦上null。

       注意:在Subclass標籤中,用discriminator-value屬性來標明本子類的discriminator欄位(用來區分不同類的欄位)的值Subclass標籤,既可以被class標籤所包含(這種包含關係正是表明了類之間的繼承關係),也可以與class標籤平行。 當subclass標籤的定義與class標籤平行的時候,需要在subclass標籤中,新增extends屬性,裡面的值是父類的全路徑名稱。
       部分程式碼展示:

<?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.hibernate">  
    <class name="Animal" table="t_animal" lazy="false">  
        <id name="id">  
            <generator class="native"/>  
        </id>  
        <discriminator column="type" type="string"/>  
        <property name="name"/>  
        <property name="sex"/>  
        <subclass name="Pig" discriminator-value="P">  
            <property name="weight"/>  
        </subclass>  
        <subclass name="Bird" discriminator-value="B">  
            <property name="height"/>  
        </subclass>  
    </class>  
</hibernate-mapping>  
    總結:每棵類繼承樹一張表的優點效率上要好一些,因為它只有一張表,無論儲存、查詢還是更新都只對一張表操作,這樣的表結構我們都知道它有一個缺點就是冗餘欄位會多一些;每個類一張表的優點就是層次分明,但是如果繼承結構深的話,關聯就會特別的多,這樣查詢時就會關聯多張表,效率上要差一些;每個具體類一張表對於主鍵有一些限制,類似native這種自增的方式就不能使用了。所以綜合考慮我們一般使用前兩種比較多一些,到底使用哪一種我們還需要根據開發的具體需求結合這三種方式的優缺點來定。