hibernate繼承關係映射到表的總結

關聯關係:採用“一對多或一對一”的映射即可;

聚集關係:採用“集和映射”,即映射Set,Bag,List,Map

繼承關係:

因爲關係數據庫的表之間不存在繼承關係,所以Hibernate提供了以下三種對繼承關係映射的方法,即在繼承關係樹中:

(1)、每個具體類(非抽象類)對應一個表:此方式中關係數據模型完全不支持對象的繼承關係。

(2)、基類(根類)對應一個表:此方式中對關係數據模型進行非常規設計,在數據庫表中加入額外的區分子類的字段,從而使關係數據模型可以支持繼承關係。

(3)、每個類對應一個表:此方式中在關係數據模型中用外鍵關係來表示繼承關係。

這三種映射方式都各自有利有弊,需要根據具體情況來選擇使用。分別說明一下:

爲了說明方便,引用一個比較經典的簡單例子

Employee類,它爲抽象類,有兩個直接子類

HourlyEmployee類,Employee的子類,繼承父類的name屬性

SalarilyEmployee類,Employee的子類,繼承父類的name屬性

Company類,它有一個employees集和屬性

在此,先這樣說明一下啊,日後有時間放個類圖上來就一目瞭然了。

 

繼承關係中每個具體類對應一個表

這是最簡單的映射方式。基類Employee沒用映射,只需要爲兩個子類提供映射關係即可。看一下映射文件:

<hibernate-mapping package="com.wjb.mypack">

    <!--Company的映射-->

    <class name="Company" table="COMPANIES">

        <id name="id" type="long" column="ID">

            <generator class="native"/>

        </id>

        <property name="name" type="string" column="NAME"/>

    </class>

    <!--HourlyEmployee的映射-->

    <class name="HouredEmployee" table="HOURLY_EMPLOYEES">

        <id name="id" type="long" column="ID">

            <generator class="native"/>

        </id>

        <!--映射從父類繼承的name屬性-->

        <property name="name" type="string" column="NAME"/>

        <property name="rate" type="double" column="RATE"/>

        <many-to-one name="company"

                column="COMPANY_ID" class="Company"/>      

    </class>

    <!--SalarilyEmployee的映射-->

    <class name="SalarilyEmployee" table="SALARILY_EMPLOYEES">

        <id name="id" type="long" column="ID">

            <generator class="native"/>

        </id>

        <!--映射從父類繼承的name屬性-->

        <property name="name" type="string" column="NAME"/>

        <property name="salary" type="double" column="SALARY"/>

        <many-to-one name="company"

                column="COMPANY_ID" class="Company"/>

    </class>

    <!--注:Employee類沒有映射,在DB中不存在對應的表-->

</hibernate-mapping>

 

可以看出,在這種映射方式中,每個子類除了映射自己的屬性外,還需要映射從父類繼承來下的屬性,這是該映射方式的一個特點。

 

基類(根類)對應一個表

這種映射方式只需爲基類Employee創建一個表即可。在表中不僅提供與Employee所有屬性的字段,還要提供與所有子類屬性對應的字段,此外還需要一個字段用於區分子類的具體類型。此時的映射文件爲:

<hibernate-mapping package="com.wjb.mypack">

    <!--Company的映射-->

    <class name="Company" table="COMPANIES">

        <id name="id" type="long" column="ID">

            <generator class="native"/>

        </id>

        <property name="name" type="string" column="NAME"/>

    </class>

    <!--Employee以及子類的映射-->

    <class name="Employee" table="EMPLOYEES">

        <id name="id" type="long" column="ID">

            <generator class="native"/>

        </id>

        <!--用於區分子類類型的字段-->

        <discriminator type="string" column="EMPLOYEE_TYPE">

        <property name="name" type="string" column="NAME"/>

        <many-to-one name="company"

                column="COMPANY_ID" class="Company"/>

        <!--子類HourlyEmployee的映射-->

        <subclass name="HourlyEmployee"

                  discriminator-value="HE">

            <property name="rate" column="RATE" type="double"/>

        </subclass>

        <!--子類SalarilyEmployee的映射-->

        <subclass name="SalarilyEmployee"

                  discriminator-value="SE">

            <property name="salary" column="SALARY" type="double"/>

        </subclass>

    </class>

    <!--注:HourlyEmployee類沒有單獨的映射,在DB中不存在對應的表-->

    <!--注:SalarilyEmployee類沒有單獨的映射,在DB中不存在對應的表-->

</hibernate-mapping>

 

可以看出,來個子類沒有單獨的映射,在DB中沒有對應的表存在。而只有一個記錄所有自身屬性和子類所有屬性的表,在子類爲HourlyEmployee的時候,SALARY字段將爲NULL,同樣子類爲SalarilyEmployee的時候,RATE字段將爲NULL。那麼,如果業務邏輯要求SalariedEmployee對象的rate屬性不允許爲null,顯然無法在EMPLOYEES表中爲SALARY字段定義not null約束,可見這種映射方式無法保證關係數據模型的數據完整性。

 

 

每個類對應一個表

這種方式爲基類和子類分別創建表,即EMPLOYEES、HE和SE三個表。EMPLOYEES只包含Employee自己屬性的字段,每個子類的表也同樣只包含自己類屬性的字段。此外,HE表和SE表都以EMPLOYEE_ID字段作爲主鍵,該字段還同時作爲外鍵參照EMPLOYEES表。

HourlyEmployee和SalarilyEmployee沒有獨立的映射配置,但是在DB中有相應的表存在,這是其一個特點。

<hibernate-mapping package="com.wjb.mypack">

    <!--Company的映射-->

    <class name="Company" table="COMPANIES">

        <id name="id" type="long" column="ID">

            <generator class="native"/>

        </id>

        <property name="name" type="string" column="NAME"/>

    </class>

    <!--Employee以及子類的映射-->

    <class name="Employee" table="EMPLOYEES">

        <id name="id" type="long" column="ID">

            <generator class="native"/>

        </id>

        <property name="name" type="string" column="NAME"/>

        <many-to-one name="company"

                column="COMPANY_ID" class="Company"/>

        <!--子類HourlyEmployee的映射-->

        <joined-subclass name="HourlyEmployee" table="HE">

            <key column="EMPLOYEE_ID"/>

            <property name="rate" column="RATE" type="double"/>

        </subclass>

        <!--子類SalarilyEmployee的映射-->

        <joined-subclass name="SalarilyEmployee" table="SE">

            <key column="EMPLOYEE_ID"/>

            <property name="salary" column="SALARY" type="double"/>

        </subclass>

    </class>

    <!--注:HourlyEmployee類沒有單獨的映射,但在DB中有對應的表-->

    <!--注:SalarilyEmployee類沒有單獨的映射,但在DB中有對應的表-->

</hibernate-mapping>

 

可見,兩個<joined-subclass>元素用於映射兩個子類,<joined-subclass>元素的<key>子元素指定HE表和SE表中既作爲主鍵又作爲外鍵的EMPLOYEE_ID字段。

 

三種映射方式的比較和選擇

爲了方便說明爲三種方式按順序標號爲[1][2][3]。

1、複雜度:

    [1]包含重複字段;

    [2]簡單;

    [3]表較多且之間有外鍵約束;

2、查詢性能:

    [1]若查詢父類需查所有子類表;

    [2]效率高;

    [3]需要表內連接或左外連接;

3、可維護性:

    [1]若父類屬性變化需要修改所有子類對應的表;

    [2]只需修改一個表;

    [3]若某個類屬性變化只修改這個類對應的表;

綜上,選擇時,可以參考以下原則:

1、子類屬性不是非常多時,優先考慮[2],因爲其性能最佳。

2、子類屬性非常多,且對性能要求不是很嚴格時,優先考慮[3]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章