標籤:style blog http io os 使用 ar strong for
本節內容
- 引入
- NHibernate中的集合類型
- 建立父子關係
- 父子關聯映射
- 結語
引入
通過前幾篇文章的介紹,基本上瞭解了NHibernate,但是在NHibernate中映射關係是NHibernate中的亮點,也是最難掌握的技術。從這篇開始學習這些東西,我將圖文結合來說明這裡奧秘的知識。
前幾篇,我們的例子只使用了一個簡單的Customer對象。但是在客戶/訂單/產品的經典組合中,他們的關係非常複雜?讓我們先回顧在第二篇中建立的資料模型。
在圖上,我已經清晰的標註了表之間的關係,首先分析Customer和Order之間的“外鍵關係”或者稱作“父子關係”、“一對多關聯性”。在分析之前先初步瞭解NHibernate中的集合。
NHibernate中的集合類型
NHibernate支援/定義的幾種類型的集合:
Bag:對象集合,每個元素可以重複。例如{1,2,2,6,0,0},在.Net中相當於IList或者IList<T>實現。
Set:對象集合,每個元素必須唯一。例如{1,2,5,6},在.Net中相當於ISet或者ISet<T>實現,Iesi.Collections.dll程式集提供ISet集合。
List:整數索引對象集合,每個元素可以重複。例如{{1,"YJingLee"},{2,"CnBlogs"},{3,"LiYongJing"}},在.Net中相當於ArraryList或者List<T>實現。
Map:索引值對集合。例如{{"YJingLee",5},{"CnBlogs",7},{"LiYongJing",6}},在.Net中相當於HashTable或者IDictionary<Tkey,TValue>實現。
實際上,我們大多數情況下使用Set集合類型,因為這個類型和關係型資料庫模型比較接近。
建立父子關係
直接看下面一幅圖的兩張表:
上面兩張表關係表達的意思是:Customer有一個或多個Orders,Orders屬於一個Customer。一般而言,我們稱Customer為“父”,Order稱為“子”。Customer和Order之間關係就有幾種說法:“外鍵關係”、“父子關係”、“一對多關聯性”都可以。
1.Customer有一個或多個Orders
在物件模型中:在Customer類中把Orders作為一個集合,這時可以說Customer對象包含了Orders集合。在.NET中通常這樣表述:
public class Customer{ //...... public IList<Order> Orders{ get; set; }}
訪問對象方式:通過子集合訪問:Customer.Orders[...]
在NHibernate中,通常而言使用Iesi.Collections.dll程式集中的ISet集合,現在修改Customer.cs類,首先需要引用這個程式集,Customer.cs類代碼如下:
using Iesi.Collections.Generic;namespace DomainModel.Entities{ public class Customer { public virtual int CustomerId { get; set; } public virtual string Firstname { get; set; } public virtual string Lastname { get; set; } //一對多關聯性:Customer有一個或多個Orders public virtual ISet<Order> Orders { get; set; } }}
2.Order屬於一個Customer
在物件模型中:在Order類中把Customer作為單一對象,這時可以說Order對象包含了一個Customer。在.NET中通常這樣表述:
public class Order{ //...... public Customer Customer{ get; set; }}
其訪問對象方式:通過父物件成員訪問:Order.Customer
我們在項目DomainModel層的Entities檔案夾中建立Order.cs類,編寫代碼如下:
namespace DomainModel.Entities{ public class Order { public virtual int OrderId { get; set; } public virtual DateTime OrderDate { get; set; } //多對一關聯性:Orders屬於一個Customer public virtual Customer Customer { get; set; } }}
好了,我們現在完成持久類了,下面看看這兩個類如何映射。
父子關聯映射
在NHibernate中,我們可以通過對應檔來關聯對象之間的關係。對應檔定義了:
- 對象之間關係:一對一、一對多、多對一、多對多關係。
- 在關係中控制級聯行為(Cascade behavior):串聯更新、串聯刪除
- 父子之間的雙嚮導航(bidirectional navigation)
1.父實體映射
父實體(Customer)映射定義了:
- 集合類型(Bag、Set、List、Map)
- 在儲存、更新、刪除操作時的級聯行為
- 關聯的控制方向:
- Inverse="false"(預設):父實體負責維護關聯關係
- Inverse="true":子實體負責維護關聯關係
- 與子實體關聯的關係(一對多、多對一、多對多)
這些具體的設定是NHibernate中的痛點所在,以後慢慢討論這些不同設定下的奧秘之處。
這一篇初步建立Customer與Order的一對多關聯性,修改Customer.hbm.xml對應檔如下:
<?xml version="1.0" encoding="utf-8" ?><hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel"> <class name ="DomainModel.Entities.Customer,DomainModel" table="Customer"> <id name="CustomerId" column="CustomerId" type="Int32" unsaved-value="0"> <generator class ="native"></generator> </id> <property name="Firstname" column ="Firstname" type="string" length="50" not-null="false"/> <property name ="Lastname" column="Lastname" type="string" length="50" not-null="false"/> <!--一對多關聯性:Customer有一個或多個Orders--> <set name="Orders" table="`Order`" generic="true" inverse="true"> <key column="Customer" foreign-key="FK_CustomerOrders"/> <one-to-many class="DomainModel.Entities.Order,DomainModel"/> </set> </class></hibernate-mapping>
可以看到,在“父”端映射使用Set元素,標明屬性名稱、表名、子實體負責維護關聯關係。
2.子實體映射
子實體(Order)映射定義的東西就是父實體少了:與父實體關聯的(多對一、一對多、多對多) 關係,並用一個指標來導航到父實體。
在“子”端通過many-to-one元素定義與“父”端的關聯,從“子”端角度看這種關聯式模式是多對一關聯(實際上是對Customer對象的引用)。下面看看many-to-one元素映射屬性:
看看這些映射屬性具體有什麼意義:
- access(預設property):可選field、property、nosetter、ClassName值。NHibernate訪問屬性的策略。
- cascade(可選):指明哪些操作會從父物件級聯到關聯的對象。可選all、save-update、delete、none值。除none之外其它將使指定的操作延伸到關聯的(子)對象。
- class(預設通過反射得到屬性類型):關聯類別的名字。
- column(預設屬性名):列名。
- fetch(預設select):可選select和join值,select:用單獨的查詢抓取關聯;join:總是用外串連抓取關聯。
- foreign-key:外鍵名稱,使用SchemaExport工具產生的名稱。
- index:......
- update,insert(預設true):指定對應的欄位是否包含在用於UPDATE或INSERT 的SQL語句中。如果二者都是false,則這是一個純粹的 “外源性(derived)”關聯,它的值是通過映射到同一個(或多個)欄位的某些其他特性得到或者通過觸發器其他程式得到。
- lazy:可選false和proxy值。是否延遲,不延遲還是使用代理延遲。
- name:屬性名稱propertyName。
- not-found:可選ignore和exception值。找不到忽略或者拋出異常。
- not-null:可選true和false值。
- outer-join:可選auto、true、false值。
- property-ref(可選):指定關聯類別的一個屬性名稱,這個屬性會和外鍵相對應。如果沒有指定,會使用對方關聯類別的主鍵。這個屬性通常在遺留的資料庫系統使用,可能有外鍵指向對方關聯表的某個非主鍵欄位(但是應該是一個唯一關鍵字)的情況下,是非常不好的關聯式模式。比如說,假設Customer類有唯一的CustomerId,它並不是主鍵。這一點在NHibernate源碼中有了充分的體驗。
- unique:可選true和false值。控制NHibernate通過SchemaExport工具產生DDL的過程。
- unique-key(可選):使用DDL為外鍵欄位產生一個唯一約束。
我們來建立“子”端到“父”端的映射,建立Order.hbm.xml檔案,編寫代碼如下:
<?xml version="1.0" encoding="utf-8" ?><hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="DomainModel" namespace="DomainModel"> <class name="DomainModel.Entities.Order,DomainModel" table="`Order`" > <id name="OrderId" column="OrderId" type="Int32" unsaved-value="0"> <generator class="native" /> </id> <property name="OrderDate" column="OrderDate" type="DateTime" not-null="true" /> <!--多對一關聯性:Orders屬於一個Customer--> <many-to-one name="Customer" column="Customer" not-null="true" class="DomainModel.Entities.Customer,DomainModel" foreign-key="FK_CustomerOrders" /> </class></hibernate-mapping>
關於如何關聯看看上面的屬性就一目瞭然了。
[轉]NHibernate之旅(9):探索父子關係(一對多關聯性)