前語:
在Nhibernate xml 的文件配置上,一對一和多對多的配置比較簡單,容易出錯的反而是一對多(多對一)上。
1、一對一關聯關系的映射:
<one-to-one name="propertyName" class="ClassName" cascade="cascade_style" constrained="true|false" fetch="join|select" property-ref="propertyNameFromAssociatedClass" access="field|property|ClassName" formula="any sql expression" lazy="true|proxy|false" entity-name="EntityName" node="element-name|@attribute-name|element/@attribute|." embed-xml="true|false" />
序號 | 屬性 | 含義和作用 | 必須 | 默認值 |
1 | name |
映射類屬性的名字 | Y | |
2 | class |
映射的目標類。也就是與這個屬性相關聯的是哪個類 | N | |
3 | cascade |
操作時的級聯關系 。這個屬性的可選值有: all--所有的操作均進行級聯操作。 none--所有操作均不進行級聯操作 save-update--在執行 save 和 update 時進行級聯操作 delete--在執行delete時進行級聯操作 |
N | |
4 | constrained |
表明當前類對應的表與被關聯的表之間是否存在着外鍵約束。這將影響級聯操作的順序 | N | false |
5 | fetch |
設置抓取數據的策略。這個屬性的可選值有: join--外連接抓取 select--序列選擇抓取 |
N | |
6 | property-ref |
指定關聯類的屬性名,這個屬性將會和本類的主鍵相對應 | N | 關鍵類的主鍵 |
7 | access |
Hibernate 訪問這個屬性的策略 | N | property |
8 | formula |
絕大多數一對一的關聯都指向其實體的主鍵。在一些少見的情況中,可能會指向其他的 一個或多個字段,或者是一個表達式,在這些情況下,可以用一個sql公式來表示 |
N | |
9 | lazy |
指定對於此關聯對象是否使用延遲加載的策略。這個屬性的可選值有: proxy--通過代理進行關聯 true--此關聯對象采用延遲加載,在該實例變量第一次被訪問時抓取(需要運行時 字節翃的增強) false--此關聯對象不采用延遲加載。注意,如果constrained="false",則不能 使用代理,hibernate會采取預先抓取 |
N | proxy |
10 | entity-name |
被關聯類的實體名 | N |
例如,A和B之間是一對一的關系,那么反過來B和A之間的關系也是一對一的。需要在這兩個實體的映射文件中都進行
相應的配置。這樣,才能完整地表示這兩個對象之間的關系。
例如,對於Employee和Person進行主鍵一對一關聯。首先需要在Employee對象的配置文件中定義到Person對象的關聯:
<one-to-one name="person" class="Person">
然后還需要在Person對象的配置文件中定義到Employee對象的關聯:
<one-to-one name="employee" class="Employee" constrained="true">
另外,為了確保兩個對象的主鍵值是相等的,在定義主鍵的時候可以使用名稱為 foreign 的Hibernate 標識符生成策略來實現這一目的。
Person對象主鍵字段的映射信息的配置方法如下所示:
<id name="id' column="ID"> <generator class="foreign"> <param name="property">employee</param> </generator> </id>
2、一對多(雙向)關聯關系的映射:
<one-to-many class="ClassName" not-found="ignore|exception" entity-name="EntityName" node="element-name" embed-xml="true|false" />
序號 | 屬性 | 含義和作用 | 必須 | 默認值 |
1 | class | 關聯的目標類 | Y | |
2 | not-found | 指名若關聯的對象不存在,該如何處理 | N | Exception |
3 | entity-name | 被關聯的類的實體名,作為class的替代 | N |
<set name="telephones" cascade="all" table="Telephones"> <key column="User_Id"/> <one-to-many class="Telephones"/> </set>
在通常情況下,要將一對多的關聯關系配置為雙向,這樣可以方便地從任意一方進行數據的維護工作,同時也可以解決上面所提到的問題。
2、多對一(雙向)關聯關系的映射:
通常情況下,關聯關系的主控方設置為“多”的這一方,這樣就可避免需要在“多”的一方的關聯字段中先插入空值的情況出現。
多對一的關聯關系需要在“多”的這一方使用<many-to-one>來進行配置,配置的方法如下:
<many-to-one name="user" class="User" column="User_Id" />
另外,為了使“多”的這一方變為主控方,還需要在配置“一”的一方增加“inverse=true”的配置(set的屬性)。
在對象之間的關聯關系中,“inverse='false'” 的一方變為主控方,由它來負責維護對象之間的關聯關系。
3、多對多關聯關系的映射:
<many-to-many column="column_Name" class="ClassName" fetch="join|select" lazy="true|proxy|false" not-found="ignore|exception" entity-name="EntityName" formula="any sql expression" />
序號 | 屬性 | 含義和作用 | 必須 | 默認值 |
1 | column |
中間關聯表中映射到關聯目標表的關聯字段 | Y | |
2 | class |
關聯的目標類 | Y | |
3 | fetch |
設置抓取數據的策略。這個屬性的可選值有: join--外連接抓取 select--序列選擇抓取 |
N | select |
4 | lazy |
指定對於此關聯對象是否使用延遲加載的策略。這個屬性的可選值有: proxy--通過代理進行關聯 true--此關聯對象采用延遲加載,在該實例變量第一次被訪問時抓取(需要運行時 字節翃的增強) false--此關聯對象不采用延遲加載。注意,如果constrained="false",則不能 使用代理,hibernate會采取預先抓取 |
N | |
5 | not-found |
指名若關聯的對象不存在,該如何處理。這個屬性的可能取值有: exception--產生一個異常 ignore--對於不存在的應用將關聯到Null |
N | exception |
6 | entity-name |
被關聯類的實體名 | N | |
7 | formula |
絕大多數的關聯的關聯都指向其實體的主鍵。在一些少見的情況中,可能會指向其它的一個或多個字段,或者是一個 表達式,這些情況下,可以用一個sql公式來表示 |
N |
在開發中經常遇到的用戶(User)和角色(Role)的關系就是多對多的關系。一個用戶可以擁有多個角色,同時一個角色又可以被很多的
用戶所擁有。那么在描述這兩個對象之間的關系時就需要建立一個中間表User_Role來確立它們之間的關系。
首先,需要在其中一個對象(例如,User)中配置一個多對多的關聯,如下所示:
<set name="roles" table="User_Role" inverse="true" cascade="save-update" <key column="Id" /> <many-to-many column="Role_Id" class="Role"> /set>
同樣,在另一個對象(例如,Role)中需要進行如下配置:
<set name="users" table="User_Role" cascade="save-update" <key column="Id" /> <many-to-many column="User_Id" class="User"> /set>
在這里還是要再次提醒大家,對象之間的關聯關系是雙方向的,在配置的時候通常需要進行雙向配置