top
Loading...
Hibernate3.0的規則應用分析
一、前言

Hibernate和Spring是兩個著名的開源框架,越來越廣泛地應用于J2EE應用程序的開發中。雖然它們各自所針對的目標不同,但是它們都有一個共同的特點:依賴性映射。Spring注重于在把對象返回到客戶之前,幫助挑選出對象間的依賴性,這樣以來大大減少了客戶端的編碼工作。Hibernate則專注于在把完整的對象模型返回到客戶之前,挑選出對象模型描述的依賴性。當直接使用JDBC來把一個數據模型映射成一個對象模型時,我們通常需要編寫大量的代碼來建造一個對象模型。Hibernate可以幫助消除這種大部分的編碼工作。

Hibernate 2.x提供了基本的表到對象的映射,正常的關聯映射(包括一對一,一對多和多對多關系),多態映射,等等。Hibernate 3.x把這種技術又推進了一層-通過使用規則、過濾、子選擇等等來加強映射的靈活性-它們提供了良好粒度的解釋特性。

在本文中,我們將向你展示規則的各種不同特性是怎樣幫助實現模型轉換的。在Hibernate 3.x之前,規則屬性只能出現在一個property元素中。雖然你還可以這樣做,但是,Hibernate 3.x提供了一個規則屬性或元素(其實,在涉及到規則使用時,這兩者是等價的),它可以應用在許多元素中,包括discriminator,many-to-one,one-to-one,element,many-to-many,map-key,map-key-many-to-many以及property。這加強了對象-關系(O-R)映射的靈活性,并因此允許對更復雜的數據模型的良好粒度解釋。

大致上有兩種場合下,必須使用規則:

1. 需要規則計算結果的場所。與元素discriminator,element,map-key,map-key-many-to-many及property等一起使用的規則屬于這一類型。

2. 借助于規則的幫助實現聯結之目的。與元素many-to-one,one-to-one及many-to-many等一起使用的規則屬于這一類型。

二、類型1:取得一個規則的計算結果

(一) Discriminator

在實際的數據模式中,經常有用一個表來描述另外一個表的情況。規則有助于在O-R映射中實現靈活的多態性。

在圖1所示的例子中,共有兩個表:Product和ProductRelease。每個產品記錄都有一個ProductReleaseID,用于參照它相應的產品發行記錄,包括產品發行名、類型、發行日期等。

在ProductRelease表中一個有趣的屬性是SubProductAllowable,其值可以是0或1。值1意味著任何該產品的發行都可以有相應的子產品,而值0意味著不允許有子產品。例如,一些產品由多種子產品配置而成,而一些產品只能是其自身。

圖2顯示了一個從該數據模型解釋出來的對象模型。其中,嵌套接口定義了getSubProducts和setSubProducts方法。類NestedProduct擴展了基類Product并實現了嵌套接口。一條產品數據記錄是屬于Product還是屬于NestedProduct依賴于它相應的產品發行記錄的SubProductAllowable的值。


圖1.產品和產品發行數據模型

圖2.產品和產品發行對象域模型

為了成功完成這個模型轉化,我們使用了一個Hibernate3.x映射,如下:

<hibernate-mapping>
<class name="Product" discriminator-value="0" lazy="false">
<id name="id" type="long"/>
<discriminator formula="(select pr.SubProductAllowable from ProductRelease pr where pr.productReleaseID=
productReleaseID)" type="integer" />
<subclass name="NestedProduct" discriminator-value="1"/>
</class>
</hibernate-mapping>

如果規則表達式計算結果是0-也就是說,不允許有相應的子產品-那么該對象將是類Product。如果結果是1,該對象將是一個NestedProduct。在表1和表2中,對于Product表中的第一個記錄(ProductID=10000001),初始化類將是一個NestedProduct,因為它通過SubProductAllowable=1參考引用一個ProductRelease記錄。對于Product表中的第二個記錄(ProductID=20000001),初始化類將是Product,因為它通過SubProductAllowable=0參考引用一個ProductRelease記錄。

S/NProductReleaseID SubProductAllowable...
1 11 1 ...
2 601 0 ...
表格1.表ProductRelease中的記錄

S/NProductIDProductReleaseID...
1 10000001 11 ...
2 20000001 601 ...
表格2.表Product中的記錄

(二) Property

一個property元素中的規則允許對象屬性包含某個派生值,如sum,average,max等等的結果,就象下面這樣:

<property name="averagePrice" formula="(select avg(pc.price) from PriceCatalogue pc, SelectedItems si where si.priceRefID=pc.priceID)"/>

此外,一個規則,根據當前記錄的某些屬性值,還有助于檢索來自于另一個表中的值。例如:

<property name="currencyName" formula="(select cur.name from currency cur where cur.id= currencyID)"/>

這有助于從當前貨幣表中檢索一種貨幣的名稱。很明顯,這些直接的映射能消除很多的編碼轉化問題。

(三) map-key

規則還允許map-key取任何可能的值。在下列例中(圖3),我們想要使Role_roleID成為對象模型的map-key(圖4)。


圖3.用戶角色數據模式

圖4.用戶角色對象模型

在上面的數據模式中,User和Role通過一個稱為User_has_Role的多對多的關系表被聯系在一起。為了取得一個已賦給所有角色的用戶,我們使用下列映射:

<hibernate-mapping>
<class name="User">
<id name="userID"/>
<map name="roles"
table="UserRole"/>
<key column="User_userID"/>
<map-key
formula="Role_RoleID"
type="string"/>
<many-to-many
column="Role_RoleID"
class="Role"/>
</map>
</class>
<class name="Role">
<id name="roleID"/>
</class>
</hibernate-mapping>

Role_RoleID用作多對多元素聯結列列值。然而,Hibernate并不允許Role_RoleID出現在map-key和many-to-many的列屬性中。但是借助于規則,Role_RoleID也可以用于map-key。

(四) 另外的情形:element,map-key-many-to-many以至更多

象property這樣的元素,能夠被賦于任何有效的規則表達式的計算值。

規則與map-key-many-to-many一起使用的情形類似于map-key。然而,map-key-many-to-many經常應用在三重關系表達時,這時一個map key自身就是一個參考對象,而不是一個參考屬性。

然而,有些情況下并不支持規則的使用。一些數據庫(例如Oracle7)并不支持嵌入的select語句(例如,一個select SQL語句嵌入在一個SQL語句的select部分),這時是不支持把規則用于運算結果的。因此,你需要先檢查是否支持嵌入式select SQL語句。

既然Hibernate映射得到的SQL語句要把規則表達式作為它的select目標的一部分,充分了解你的數據庫的SQL語法個性將有助于豐富你對于規則的使用,雖然它可能減弱代碼的可移植性。

三、類型2:使用規則實現聯合

(一) 多對一

在現實世界數據建模時,另外一個典型的場合是proprietary關系映射,這是一種不同于基本的一對一、一對多和多對多的關系映射。圖5中的例子說明了,一個公司可能有多個聯系人,但只有一個是缺省的聯系人。有多個聯系人的公司的情形就是一個典型的一對多關系。然而,為了識別出缺省的聯系人,ContactPerson表使用了一個屬性defaultFlag(這里1代表是,0代表不是)。


圖5.用戶角色數據模式

圖6.用戶角色對象模型



為把缺省的聯系人關系解釋成對象模型(圖6),我們使用下列的映射:

<hibernate-mapping>
<class name="Company" table="Company">
<id name="id" />
<many-to-one
name="defaultContactPerson"
property-ref="defaultContactPerson">
<column name="id"/>
<formula>1</formula>
</many-to-one>
</class>
<class name="Person" >
<id name="id" />
<properties name="defaultContactPerson">
<property name="companyID" />
<property name="defaultFlag" />
</properties>
</class>
</hibernate-mapping>

在上面,我們把companyID和defaultFlag加以組合作為一個屬性元素,并命名為defaultContactPerson,它構成了Person表的一個唯一鍵。Company類中的多對一元素與Person類中的defaultContactPerson屬性元素相聯合。結果,最后的SQL語句類似如下:

select c.id, p.id from Company c, Person p where p.companyID=c.id and p.defaultFlag=1

(二) 一對一

在Hibernate中,一對一主要用于兩個表共享相同的primary鍵的情形。對于foreign鍵關系,我們通常使用多對一來代替。然而,借助于規則,一對一也能通過一個foreign鍵把表聯接起來。例如,上面的多對一實例可以通過一對一方式作如下映射:

<hibernate-mapping>
<class name="Company" table="Company" >
<id name="id" />
<one-to-one name="defaultContactPerson"
property-ref="defaultContactPerson" >
<formula>id</formula>
<formula>1</formula>
</many-to-one>
</class>
<class name="Person" >
<id name="id" />
<properties name="defaultContactPerson">
<property name="companyID" />
<property name="defaultFlag" />
</properties>
</class>
</hibernate-mapping>

(三) 其它:多對多

規則可被用在一個多對多元素中來實現從關系表到實體表間的特殊聯結,盡管這并不經常需要。

四、小結

本文中的示例展示了使用規則的大多數場所。當需要規則計算值時,規則表達式將出現在結果SQL的select語句中。當規則作于聯合時,它將出現在結果SQL的where部分。而且,規則表達式能使用任何個性化的SQL,只要目標數據庫支持它就行。我們的最終結論就是,靈活運用規則將大大幫助從數據模型到對象模型的具有良好粒度映射的建立,而這不需要任何編碼工作。

作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗