當我們的兩個或多個實體類是相似的,或者說他們有很多相同的屬性時,我們通常抽象出父類,子類繼承的方式去實作,以面相對象的特點對實體類進行抽象,封裝和繼承。我們之前學了Hibernate的關系映射,讓我們可以直接面向對象開發,而不是面向資料庫,如何将繼承父類的這種關系反映到資料庫中呢,我們來看Hibernate提供的三種映射政策:
映射1-每棵類繼承樹對應一張表
映射2-每個類一張表
映射3-每個具體類一張表
我們下面以一個簡單的例子說明
首先看我們的類圖
Pig和Bird都繼承自Animal,通過這個簡單的關系來看繼承映射:
映射1-每棵類繼承樹對應一張表
每棵類繼承樹對應一張表,上面的類圖就是一棵類繼承樹吧,隻映射出一張表,如下:
這是如何做到的,直接看我們的映射檔案:
<hibernate-mapping package="com.bjpowernode.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>
在我們的表中有一個Type字段,他不對應任何一個實體的屬性。Hibernate用這個列自動初始化對應的類并相應進行填充。
<discriminator column="type"type="string"/>,通過discriminator 設定type鑒别字段,在子類中使用discriminator-value屬性辨別每條資料所對應的類。
映射2-每個類一張表
這種政策是使用joined-subclass标簽來定義子類的。父類、子類,每個類都對應一張資料庫表。
在父類對應的資料庫表中,實際上會存儲所有的記錄,包括父類和子類的記錄;在子類對應的資料庫表中,這個表隻定義了子類中所特有的屬性映射的字段。子類與父類,通過相同的主鍵值來關聯。如下圖:
下面具體的用法:
<hibernate-mapping package="com.bjpowernode.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>
需要注意的:
(1)父類用普通的<class>标簽定義即可
(2)父類不再需要定義discriminator字段
(3)子類用<joined-subclass>标簽定義,在定義joined-subclass的時候,需要注意如下幾點:
Joined-subclass标簽的name屬性是子類的全路徑名
Joined-subclass标簽需要包含一個key标簽,這個标簽指定了子類和父類之間是通過哪個字段來關聯的。
此政策特點:
Hibernate每次初始化和填充對象時,會讀取多個表,如果繼承層次多了,性能就會收到影響。
映射3-每個具體類一張表
每個具體類一個表,抽象類沒有表。
這種政策使用union-subclass标簽來定義子類的。每個子類對應一張表,而且這個表包含了所有從父類繼承下來的屬性映射的字段(這就是它跟joined-subclass的不同之處,joined-subclass定義的子類的表,隻包含子類特有屬性映射的字段)。
下面具體的用法:
<hibernate-mapping package="com.bjpowernode.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>
需要注意的:
(1) Union-subclass标簽不再需要包含key标簽(與joined-subclass不同)
(2) Union-subclass标簽,可以包含在class标簽裡,說明是繼承的class類,也可以不包含在class标簽中,但需要添加extends屬性,值裡是父類的全路徑。
(3) 此政策,子類會繼承父類的所有屬性,而子類的其它屬性,可以定義在Union-subclass标簽的内部。
總結
Hibernate 映射政策的三個政策自己的優勢與不足,根據不同的情況去使用,但不管哪種政策,在實作的整個過程中,我們的業務對象與Hibernate持續性架構之間沒有聯系,三個政策完全通過Hibernate的xml配置管理,很展現了Hibernate的靈活性,值得我們學習。