国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

精通Hibernate映射繼承關系之六

2019-11-18 16:12:02
字體:
來源:轉載
供稿:網友

  Company與Employee類之間為一對多多態關聯關系,如果繼承關系樹的根類對應一個表,或者每個類對應一個表,那么就能映射Company類的employees集合。本節介紹如何映射多對一多態關聯。如圖14-11所示,ClassD與ClassA為多對一多態關聯關系。

精通Hibernate映射繼承關系之六(圖一)


圖14-11 ClassD與ClassA為多對一多態關聯關系


ClassA、ClassB和ClassC構成了一棵繼承關系樹,如果繼承關系樹的根類對應一個表,或者每個類對應一個表,那么可以按以下方式映射ClassD的a屬性:

<many-to-one name="a"class="ClassA"column="A_ID"cascade="save-update" />


假定與ClassD對應的表為TABLE_D,與ClassA對應的表為TABLE_A,在TABLE_D中定義了外鍵A_ID,它參照TABLE_A表的主鍵。

ClassD對象的a屬性既可以引用ClassB對象,也可以引用ClassC對象,例如:

tx = session.beginTransaction();ClassD d=(ClassD)session.get("ClassD",id);ClassA a=d.getA();if(a instanceof ClassB)  System.out.PRintln(((ClassB)a).getB1());if(a instanceof ClassC)  System.out.println(((ClassC)a).getC1());tx.commit();

以下代碼在映射ClassD類的a屬性時使用了延遲檢索策略:


<many-to-one name="a"class="ClassA"column="A_ID"lazy="true"cascade="save-update" />


當Hibernate加載ClassD對象時,它的屬性a引用ClassA的代理類實例,在這種情況下,如果對ClassA的代理類實例進行類型轉換,會拋出ClassCastException:

ClassA a=d.getA();ClassB b=(ClassB)a; //拋出ClassCastException


解決以上問題的一種辦法是使用Session.load()方法:

ClassA a=d.getA();ClassB b=(ClassB)session.load(ClassB.class,a.getId());System.out.println(b.getB1());


當執行Session的load()方法時,Hibernate并不會訪問數據庫,而是僅僅返回ClassB的代理類實例。這種解決辦法的前提條件是必須事先知道ClassD對象實際上和ClassA的哪個子類的對象關聯。

解決以上問題的另一種辦法是顯式使用迫切左外連接檢索策略,避免Hibernate創建ClassA的代理類實例,而是直接創建ClassA的子類的實例:

tx = session.beginTransaction();ClassD d=(ClassD)session.createCriteria(ClassD.class)    .add(EXPression.eq("id",id))    .setFetchMode("a",FetchMode.EAGER)    .uniqueResult();ClassA a=d.getA();if(a instanceof ClassB)  System.out.println(((ClassB)a).getB1());if(a instanceof ClassC)  System.out.println(((ClassC)a).getC1());tx.commit();


如果繼承關系樹的具體類對應一個表,為了表達ClassD與ClassA的多態關聯,需要在TABLE_D中定義兩個字段:A_ID和A_TYPE,A_TYPE字段表示子類的類型,A_ID參照在子類對應的表中的主鍵。圖14-12顯示了表TABLE_D、TABLE_B和TABLE_C的結構。




精通Hibernate映射繼承關系之六(圖二)




圖14-12 表TABLE_D、TABLE_B和TABLE_C的結構
由于關系數據模型不允許一個表的外鍵同時參照兩個表的主鍵,因此無法對TABLE_D表的A_ID字段定義外鍵參照約束,而應該通過其他方式,如觸發器,來保證A_ID字段的參照完整性。由于TABLE_D表的A_ID字段既可能參照TABLE_B表的ID主鍵,也可能參照TABLE_C表的ID主鍵,要求TABLE_B表和TALBE_C表的ID主鍵具有相同的SQL類型。

在ClassD.hbm.xml文件中,用元素來映射ClassD的a屬性:


<any name="a"meta-type="string"id-type="long"cascade="save-update"><meta-value value="B" class="ClassB" /><meta-value value="C" class="ClassC" /><column name="A_TYPE" /><column name="A_ID" /></any>


元素的meta-type屬性指定TABLE_D中A_TYPE字段的類型,id-type屬性指定TABLE_D中A_ID字段的類型,子元素設定A_TYPE字段的可選值。在本例中,如果A_TYPE字段取值為"B",表示為ClassB的對象,A_ID字段參照TABLE_B表中的ID主鍵;如果A_TYPE字段取值為"C",表示為ClassC的對象,A_ID字段參照TABLE_C表中的ID主鍵。子元素指定TABLE_D表中的A_TYPE字段和A_ID字段,必須先指定A_TYPE字段,再指定A_ID字段。

小結

本章介紹了映射繼承關系的三種方式:

繼承關系樹的每個具體類對應一個表:在具體類對應的表中,不僅包含和具體類的屬性對應的字段,還包含和具體類的父類的屬性對應的字段。這種映射方式不支持多態關聯和多態查詢。

繼承關系樹的根類對應一個表:在根類對應的表中,不僅包含和根類的屬性對應的字段,還包含和所有子類的屬性對應的字段。

這種映射方式支持多態關聯和多態查詢,并且能獲得最佳查詢性能,缺點是需要對關系數據模型進行非常規設計,在數據庫表中加入額外的區分各個子類的字段,此外,不能為所有子類的屬性對應的字段定義not null約束。

繼承關系樹的每個類對應一個表:在每個類對應的表中只需包含和這個類本身的屬性對應的字段,子類對應的表參照父類對應的表。

這種映射方式支持多態關聯和多態查詢,而且符合關系數據模型的常規設計規則,缺點是它的查詢性能不如第二種映射方式。在這種映射方式下,必須通過表的內連接或左外連接來實現多態查詢和多態關聯。
在默認情況下,對于簡單的繼承關系樹可以采用根類對應一個表的映射方式。如果必須保證關系數據模型的數據完整性,可以采用每個類對應一個表的映射方式。對于復雜的繼承關系樹,可以將它分解為幾棵子樹,對每棵子樹采用不同的映射方式。

當然,在設計域模型時,應該盡量避免設計過分復雜的繼承關系,這不僅會增加把域模型映射到關系數據模型的難度,而且也會增加在java程序代碼中操縱持久化對象的復雜度。

對于不同的映射方式,必須創建不同的關系數據模型和映射文件,但是域模型是一樣的,域模型中的持久化類的實現也都一樣。

只要具備Java編程基礎知識,就能創建具有繼承關系的持久化類,因此本章沒有詳細介紹這些持久化類的創建過程,在此僅提醒一點,子類的完整構造方法不僅負責初始化子類本身的屬性,還應該負責初始化從父類中繼承的屬性,例如以下是HourlyEmployee類的構造方法:

public class HourlyEmployee extends Employee{private double rate;    /** 完整構造方法*/public HourlyEmployee(String name, double rate,Company company) {super(name,company);this.rate=rate;}/** 默認構造方法*/public HourlyEmployee() {}……}


Hibernate只會訪問持久化類的默認構造方法,永遠不會訪問其他形式的構造方法。提供以上形式的完整構造方法,主要是為Java應用的編程提供方便。

(出處:http://m.survivalescaperooms.com)



發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 利川市| 张家界市| 龙山县| 余江县| 德安县| 永康市| 同仁县| 焦作市| 库尔勒市| 广南县| 浙江省| 商河县| 通山县| 通城县| 高要市| 大理市| 华亭县| 建水县| 高邮市| 闽清县| 屯留县| 垫江县| 苏尼特左旗| 洛扎县| 呼伦贝尔市| 静乐县| 从化市| 墨脱县| 西峡县| 腾冲县| 阿拉善左旗| 聊城市| 那坡县| 申扎县| 南岸区| 武义县| 芦山县| 龙陵县| 辽阳县| 长岛县| 岗巴县|