程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 精通Hibernate之映射繼承關系六

精通Hibernate之映射繼承關系六

編輯:關於JAVA

在這種映射方式下,繼承關系樹的每個類以及接口都對應一個表。在本例中,需要創建EMPLOYEES、HE和SE表。

如圖14-6所示,EMPLOYEES表僅包含和Employee類的屬性對應的字段,HE表僅包含和HourlyEmployee類的屬性對應的字段,SE表僅包含和SalariedEmployee類的屬性對應的字段。此外,HE表和SE表都以EMPLOYEE_ID字段作為主鍵,該字段還同時作為外鍵參照EMPLOYEES表。

<id name="id" type="long" column="ID">
<generator class="increment"/>
</id>
<property name="name" type="string" column="NAME" />
<set
name="employees"
inverse="true"
lazy="true" >
<key column="COMPANY_ID" />
<one-to-many class="mypack.Employee" />
</set>
</class>
</hibernate-mapping>

Employee.hbm.xml文件用於把Employee類映射到EMPLOYEES表,在這個映射文件中,除了需要映射Employee類本身的屬性,還需要在元素中映射兩個子類的屬性。例程14-8是Employee.hbm.xml文件的代碼。

例程14-8 Employee.hbm.xml

<hibernate-mapping >
<class name="mypack.Employee" table="EMPLOYEES">
<id name="id" type="long" column="ID">
<generator class="increment"/>
</id>
<property name="name" type="string" column="NAME" />
<many-to-one
name="company"
column="COMPANY_ID"
class="mypack.Company"
/>
<joined-subclass name="mypack.HourlyEmployee" table="HOURLY_EMPLOYEES" >
<key column="EMPLOYEE_ID" />
<property name="rate" column="RATE" type="double" />
</joined-subclass>
<joined-subclass name="mypack.SalariedEmployee" table="SALARIED_EMPLOYEES" >
<key column="EMPLOYEE_ID" />
<property name="salary" column="SALARY" type="double" />
</joined-subclass>
</class>
</hibernate-mapping>

在Employee.hbm.xml文件中,兩個元素用於映射HourlyEmployee類和SalariedEmployee類,元素的子元素指定HE表和SE表中既作為主鍵又作為外鍵的EMPLOYEE_ID字段。

由於HourlyEmployee類和SalariedEmployee類沒有單獨的映射文件,因此在初始化Hibernate時,只需向Configuration對象中加入Company類和Employee類:

Configuration config = new Configuration();
config.addClass(Company.class)
.addClass(Employee.class);

也可以在單獨的映射文件中配置或元素,但此時必須顯式設定它們的extends屬性。例如可以在單獨的HourlyEmployee.hbm.xml文件中映射HourlyEmployee類:

<hibernate-mapping >
<joined-subclass
name="mypack.HourlyEmployee"
table="HOURLY_EMPLOYEES"
extends="mypack.Employee" >
……
</joined-class>
<hibernate-mapping >

由於HourlyEmployee類的映射代碼不位於Employee.hbm.xml文件中,因此在初始化Hibernate時,不僅需要向Configuration對象中加入Company類和Employee類,還需要加入HourlyEmployee類,並且必須先加入Employee父類,再加入HourlyEmployee子類:

Configuration config = new Configuration();
config.addClass(Company.class)
.addClass(Employee.class)
.addClass(HourlyEmployee.class);

如果顛倒加入Employee類和HourlyEmployee子類的順序,Hibernate在執行addClass()方法時會拋出HibernateMappingException。

14.3.2 操縱持久化對象

這種映射方式支持多態查詢,對於以下查詢語句:

List employees=session.find("from Employee");

Hibernate會檢索出所有的HourlyEmployee對象和SalariedEmployee對象。此外,也可以單獨查詢Employee類的兩個子類的實例,例如:

List hourlyEmployees=session.find("from HourlyEmployee");

本節的范例程序位於配套光盤的sourcecode\chapter14\14.3目錄下,運行該程序前,需要在SAMPLEDB數據庫中手工創建COMPANIES表、EMPLOYEES表、HE表和SE表,然後加入測試數據,相關的SQL腳本文件為\14.3\schema\sampledb.sql。

在DOS命令行下進入chapter14根目錄,然後輸入命令:

ant -file build3.xml run

就會運行BusinessService類。BusinessService的main()方法調用test()方法,test()方法依次調用以下方法:

findAllHourlyEmployees():檢索數據庫中所有的HourlyEmployee對象。

findAllEmployees():檢索數據庫中所有的Employee對象。

loadCompany():加載一個Company對象。

saveEmployee():保存一個Employee對象。

(1)運行findAllHourlyEmployees()方法,它的代碼如下:

tx = session.beginTransaction();
List results=session.find("from HourlyEmployee");
tx.commit();
return results;

在運行Session的find()方法時,Hibernate執行以下select語句:

select * from HOURLY_EMPLOYEES he inner join EMPLOYEES e
on he.EMPLOYEE_ID=e.ID;
select * from COMPANIES where ID=1;

Hibernate通過HE表與EMPLOYEES表的內連接獲得HourlyEmployee對象的所有屬性值,此外,在加載HourlyEmployee對象時,還會同時加載與它關聯的Company對象。

(2)運行findAllEmployees()方法,它的代碼如下:

tx = session.beginTransaction();
List results=session.find("from Employee");
tx.commit();
return results;
在運行Session的find()方法時,Hibernate執行以下select語句:
select * from EMPLOYEES e
left outer join HOURLY_EMPLOYEES he on e.ID=he.EMPLOYEE_ID
left outer join SALARIED_EMPLOYEES se on e.ID=se.EMPLOYEE_ID;
select * from COMPANIES where ID=1;

Hibernate把EMPLOYEES表與HE表以及SE表進行左外連接,從而獲得HourlyEmployee對象和SalariedEmployee對象的所有屬性值。在這種映射方式下,Hibernate支持多態查詢,對於以上查詢語句獲得的查詢結果,如果HE表的EMPLOYEE_ID字段不為null,就創建HoulyEmployee實例,如果SE表的EMPLOYEE_ID字段不為null,就創建SalariedEmployee實例,這些實例所關聯的Company對象也被加載。(3)運行loadCompany()方法,它的代碼如下:

tx = session.beginTransaction();
Company company=(Company)session.load(Company.class,new Long(id));
Hibernate.initialize(company.getEmployees());
tx.commit();

這種映射方式支持多態關聯。如果在Company.hbm.xml文件中對employees集合設置了立即檢索策略,那麼Session的load()方法加載的Company對象的employees集合中包含所有關聯的Employee對象。由於本書提供的Company.hbm.xml文件對employees集合設置了延遲檢索策略,因此以上程序代碼還通過Hibernate類的靜態initialize()方法來顯式初始化employees集合。

(4)運行saveEmployee(Employee employee)方法,它的代碼如下:

tx = session.beginTransaction();
session.save(employee);
tx.commit();

在test()方法中,創建了一個HourlyEmployee實例,然後調用saveEmployee()方法保存這個實例:

Employee employee=new HourlyEmployee("Mary",300,company);

saveEmployee(employee);

Session的save()方法能判斷employee變量實際引用的實例的類型,如果employee變量引用HourlyEmployee實例,就執行如下insert語句:

insert into EMPLOYEES (ID,NAME, COMPANY_ID) values (5, 'Mary', 1);

insert into HOURLY_EMPLOYEES (EMPLOYEE_ID ,RATE) values (5, 300);

可見,每保存一個HourlyEmployee對象,需要分別向EMPLOYEES表和HE表插入一條記錄,EMPLOYEES表的記錄和HE表的記錄共享同一個主鍵。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved