天天看點

[NHibernate]一對多關系(級聯删除,級聯添加)

<a href="http://www.cnblogs.com/wolf-sun/p/4068749.html#t1" target="_blank">寫在前面</a>

<a href="http://www.cnblogs.com/wolf-sun/p/4068749.html#t2" target="_blank">文檔與系列文章</a>

<a href="http://www.cnblogs.com/wolf-sun/p/4068749.html#t3" target="_blank">一對多關系</a>

<a href="http://www.cnblogs.com/wolf-sun/p/4068749.html#t4" target="_blank">一個例子</a>

<a href="http://www.cnblogs.com/wolf-sun/p/4068749.html#t6" target="_blank">級聯删除</a>

<a href="http://www.cnblogs.com/wolf-sun/p/4068749.html#t7" target="_blank">級聯儲存</a>

<a href="http://www.cnblogs.com/wolf-sun/p/4068749.html#t5" target="_blank">總結</a>

在前面的文章中,我們隻使用了一個customer類進行舉例,而在客戶、訂單、産品中它們的關系,咱們并沒有涉及,比如一個客戶可以有一個或者多個訂單,在資料庫中變現為“主外鍵關系”,有時也喜歡稱為“父子關系”。那麼就讓我們一起學習,在nhibernate中,是如何處理這種關系的吧?

<a href="http://www.cnblogs.com/wolf-sun/p/3694592.html">[nhibernate]體系結構</a>

<a href="http://www.cnblogs.com/wolf-sun/p/3694901.html">[nhibernate]isessionfactory配置</a>

<a href="http://www.cnblogs.com/wolf-sun/p/3704012.html">[nhibernate]持久化類(persistent classes)</a>

<a href="http://www.cnblogs.com/wolf-sun/p/3705229.html">[nhibernate]o/r mapping基礎</a>

<a href="http://www.cnblogs.com/wolf-sun/p/3720259.html">[nhibernate]關聯映射</a>

<a href="http://www.cnblogs.com/wolf-sun/p/3721528.html">[nhibernate]parent/child</a>

<a href="http://www.cnblogs.com/wolf-sun/p/3724052.html">[nhibernate]緩存(nhibernate.caches)</a>

<a href="http://www.cnblogs.com/wolf-sun/p/3734249.html">[nhibernate]nhibernate.tool.hbm2net</a>

<a href="http://www.cnblogs.com/wolf-sun/p/3734313.html">[nhibernate]nullables</a>

<a href="http://www.cnblogs.com/wolf-sun/p/3956802.html">[nhibernate]nhibernate如何映射sqlserver中image字段</a>

<a href="http://www.cnblogs.com/wolf-sun/p/4046672.html">[nhibernate]條件查詢criteria query</a>

<a href="http://www.cnblogs.com/wolf-sun/p/4048048.html">[nhibernate]增删改操作</a>

<a href="http://www.cnblogs.com/wolf-sun/p/4049716.html">[nhibernate]事務</a>

<a href="http://www.cnblogs.com/wolf-sun/p/4050714.html">[nhibernate]并發控制</a>

<a href="http://www.cnblogs.com/wolf-sun/p/4067026.html">[nhibernate]元件之依賴對象</a>

首先看一下資料表的關系。

[NHibernate]一對多關系(級聯删除,級聯添加)

這裡先使用customer和order的關系為例進行說明,一個客戶可以有一個或者多個訂單的關系。

在nhibernate中定義了多種集合方式:

bag:對象集合,集合中的元素可以重複。例如:{1,2,3,4,2,3},相當于.net中的ilist和ilist&lt;t&gt;。

set:對象集合,集合中的元素必須唯一。例如:{1,3,4},相當于.net中的iset和iset&lt;t&gt;,nhibernate的iesi.collections.dll程式集提供iset集合。

list:整數索引集合,集合中的元素可以重複。例如:{{1,"zhangsan"},{2,"lisi"}},相當于.net中arraylist和list集合。

map:鍵值對集合,相當于.net中的idictionary&lt;tkey,tvalue&gt;和hashtable。

使用過entity framework的朋友都知道,在ef中使用的iset,為了保持一直,這裡也使用iset集合,也友善以後如果使用ef的時候,用起來更順手。

在nhibernate-4.0版本中,在命名空間iesi.collections.generic中已經沒有iset集合了,那麼我們使用.net中的iset代替來描述這種一對多的關系,customer.cs類代碼如下:

[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)

修改order類

[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)

在nhibernate中,可以通過映射檔案來關聯對象之間的關系。

對象之間的關系:一對一,多對一,一對多,多對多關系。

在關系中控制級聯行為(cascade behavior):級聯删除,級聯更新。

 父子關系的雙向導(bidirectional navigation)

父實體映射

父實體customer映射檔案中,定義了:

集合類型:set,bag,list,map

在儲存,更新,删除操作時的級聯行為。

關聯的控制方向:

inverse=“false”(預設)父實體負責維護關聯關系。

inverse=“true”子實體負責維護關聯關系。

與子實體的關系:一對多,多對一,多對多。

修改customer.hbm.xml映射檔案,描述一個客戶對應多個訂單的關系

[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)

添加order.hbm.xml映射檔案

[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)

many-to-one節點屬性介紹:

子實體(order)映射定義:與父實體關聯的(多對一、一對多、多對多) 關系,并用一個指針來導航到父實體。

在“子”端通過many-to-one元素定義與“父”端的關聯,從“子”端角度看這種關系模型是多對一關聯(實際上是對customer對象的引用)。下面看看many-to-one元素映射屬性:

[NHibernate]一對多關系(級聯删除,級聯添加)

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為外鍵字段生成一個唯一限制。

編寫orderdata.cs代碼,添加order。

[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)

測試頁面addcustomer.aspx

[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)

addorder.aspx.cs

[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)

添加訂單生成的sql

[NHibernate]一對多關系(級聯删除,級聯添加)

使用單例模式修改nhibernatehelper

[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)

不然有可能出現下面的異常

illegal attempt to associate a collection with two open sessions

 在級聯删除過程中遇到的問題

1,設定customer.hbm.xml中set屬性inverse=“true”,必須設定cascade屬性。

此時添加訂單,生成的資料如下圖所示

[NHibernate]一對多關系(級聯删除,級聯添加)

當删除customerid=‘3042b445-d3ac-4cc0-bdff-311982e4265a’的客戶資訊時。

生成的sql語句

如果不設定cascade屬性,會産生如下異常

[NHibernate]一對多關系(級聯删除,級聯添加)

因為inverse=“true”子實體負責維護關聯關系。此時你删除customer中的記錄時,由于在order表中有對應于該客戶的訂單資訊,會違反外鍵限制。

2、設定customer.hbm.xml中set屬性inverse=“false”時。

此時如果删除customer,則屬于該客戶的訂單,會将訂單表中的customerid置為null。

[NHibernate]一對多關系(級聯删除,級聯添加)

删除customerid=‘b0387b7e-c9f3-4970-9429-955dddc2acaa’

[NHibernate]一對多關系(級聯删除,級聯添加)

看一下生成的sql語句

此時通過sql語句也可以看到,如果是父實體負責維護關聯關系,會在子表中将外鍵置為null,如果你的外鍵不允許為null,肯定會有異常的。

如果加上cascade="all"屬性

[NHibernate]一對多關系(級聯删除,級聯添加)

通過生成的sql語句,你會發現此時仍會修改外鍵為null,然後再去删除

如果在注重效率的情況下,這中方式沒有采用子實體維護關聯關系的方式效率高。

通過上面的分析,不管是父實體維護關聯關系還是子實體維護關聯關系,為映射set節點加上cascade屬性是必須的。

 一個簡單的例子,在添加客戶的時候,直接為使用者添加訂單。

[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)

此時的customer.hbm.xml映射中set節點的配置如下

生成的sql語句為

[NHibernate]一對多關系(級聯删除,級聯添加)

你會發現,添加的一個客戶資訊,對應添加兩個order,添加order後會執行update

[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(級聯删除,級聯添加)

這确實有點奇怪了,難道是為了在插入後通過修改外鍵,來保證這種外鍵限制嗎?

為了一探究竟,對比一下,inverse=true的情況

此時生成的sql

[NHibernate]一對多關系(級聯删除,級聯添加)

可以通過子實體來維護級聯關系,更符合程式員的邏輯習慣,并且效率上更好一些。

a) 

inverse="false" 

cascade="all" 

結果:customer和order都删了 

b) 

inverse="true" 

c) 

不設定inverse 

不設定cascade 

結果:customer删除了,order的customer設為了空 

d) 

設定cascade ="delete" 

e) 

設定cascade ="save-update" 

f) 

設定cascade ="all-delete-orphan" 

結果:customer和order都删了

通過上面的級聯删除與添加分析,建議使用inverse="true" cascade="all"的情況,因為此時更符合咱們的思維方式,效率上也更好。

參考文章

<a href="http://www.cnblogs.com/lyj/archive/2008/10/24/1319052.html">http://www.cnblogs.com/lyj/archive/2008/10/24/1319052.html</a>

<a href="http://home.cnblogs.com/group/topic/39307.html">http://home.cnblogs.com/group/topic/39307.html</a>

部落格位址:

<a href="http://www.cnblogs.com/wolf-sun">http://www.cnblogs.com/wolf-sun/</a>

部落格版權:

本文以學習、研究和分享為主,歡迎轉載,但必須在文章頁面明顯位置給出原文連接配接。

如果文中有不妥或者錯誤的地方還望高手的你指出,以免誤人子弟。如果覺得本文對你有所幫助不如【推薦】一下!如果你有更好的建議,不如留言一起讨論,共同進步!

再次感謝您耐心的讀完本篇文章。

轉載:http://www.cnblogs.com/wolf-sun/p/4068749.html