目錄
寫在前面
文檔與系列文章
對象狀态
瞬時态(Transient)
持久态(Persistent)
脫管态(Detached)
對象狀态轉換
總結
前面兩篇文章介紹了SchemaExport工具的使用,使用該工具可以根據映射檔案生成資料庫架構,這篇文章将介紹nhibernate中的三種對象狀态。
在程式運作過程中,使用對象的方式操作資料庫的同時,必然會産生一系列的持久化對象。這些對象可能是剛剛建立并準備進行存儲的,也有可能是從資料庫進行查詢得到的,為了差別這些對象,根據對象和目前Session的關聯狀态,可以将對象分為三種:
瞬時對象:對象剛剛建立,該對象沒有在資料庫中進行存儲,也沒有在ISession的緩存中。如果該對象的主鍵是自動建立的,則此時對象的辨別符為空。
持久化對象:對象已經通過Nhibernate進行了持久化,資料庫中已經存在了該對象的記錄。如果該對象自動建立主鍵,則此時對象的辨別符已被指派。
托管對象:該對象已經通過NHIbernate儲存或者從資料庫中查詢取出的,但與此對象關聯的ISession已經關閉。雖然它存在對象辨別符,且在資料庫中也有對應的記錄,但已經不被Nhibernate管理的。
[Nhibernate]體系結構
[NHibernate]ISessionFactory配置
[NHibernate]持久化類(Persistent Classes)
[NHibernate]O/R Mapping基礎
[NHibernate]集合類(Collections)映射
[NHibernate]關聯映射
[NHibernate]Parent/Child
[NHibernate]緩存(NHibernate.Caches)
[NHibernate]NHibernate.Tool.hbm2net
[NHibernate]Nullables
[NHibernate]Nhibernate如何映射sqlserver中image字段
[NHibernate]基本配置與測試
[NHibernate]HQL查詢
[NHibernate]條件查詢Criteria Query
[NHibernate]增删改操作
[NHibernate]事務
[NHibernate]并發控制
[NHibernate]元件之依賴對象
[NHibernate]一對多關系(級聯删除,級聯添加)
[NHibernate]一對多關系(關聯查詢)
[NHibernate]多對多關系(關聯查詢)
[NHibernate]延遲加載
[NHibernate]立即加載
[NHibernate]視圖處理
[NHibernate]N+1 Select查詢問題分析
[NHibernate]存儲過程的使用(一)
[NHibernate]存儲過程的使用(二)
[NHibernate]存儲過程的使用(三)
[Nhibernate]SchemaExport工具的使用(一)——通過映射檔案修改資料表
[Nhibernate]SchemaExport工具的使用(二)——建立表及其限制、存儲過程、視圖
NHibernate提供了對象狀态管理的功能,支援三種對象狀态:瞬時态(Transient)、持久态(Persistent)、脫管态(Detached)。
對象剛剛建立,還沒有來及和ISession關聯的狀态。這時瞬時對象不會被持久化到資料庫中,也不會被賦上辨別符。如果不使用則被GC銷毀。ISession接口可以将其轉換為持久狀态。
例如:剛剛建立一個Customer對象,就是一個瞬時态的對象。
1 //瞬時态對象
2 var customer = new Customer()
3 {
4 CustomerID = Guid.NewGuid(),
5 NameAddress = new Name()
6 {
7 CustomerAddress="北京",
8 CustomerName="wolfy"
9 },
10 Orders=null,
11 Version=1
12 };
剛被儲存的或剛從資料庫中加載的。對象僅在關聯的ISession生命周期内有效,在資料庫中有相應記錄并有辨別符。對象執行個體由NHibernate架構管理,如果有任何改動,在送出時,與資料庫同步,即将對象儲存更新到資料庫中。
持久對象關聯的ISession關閉後,這個對象在ISession中脫離了關系,就是脫管态了,托管對象仍然有持久對象的所有屬性,對托管對象的引用仍然有效的,我們可以繼續修改它。如果把這個對象重新關聯到ISession上,則再次轉變為持久态,在托管時期的修改會被持久化到資料庫中。
在同步資料庫的情況下執行下面的語句可以轉換對象的狀态。
ISession.Contains(object):檢查ISession中是否包含指定執行個體
添加一個ISession的重置方法
1 public static ISession ResetSession()
2 {
3 if (_session.IsOpen)
4 _session.Close();
5 _session = _sessionFactory.OpenSession(); ;
6 return _session;
7 }
瞬時态轉換為持久态
方法一:ISession.Save():儲存指定執行個體。
1 public void TransientConvertPersistent()
2 {
3 //瞬時态對象
4 var customer = new Customer()
5 {
6 CustomerID = Guid.NewGuid(),
7 NameAddress = new Name()
8 {
9 CustomerAddress="北京",
10 CustomerName="wolfy"
11 },
12 Orders=null,
13 Version=1
14 };
15 ISession session = NHibernateHelper.GetSession();
16 if (!session.Contains(customer))
17 {
18 //關聯ISession儲存到資料庫中
19 session.Save(customer);
20 }
21 //變為持久态,由于表中CustomerId字段自動增長的(如果是自動增長主鍵),儲存資料庫,CustomerId字段自動加一
22 //經過NHibernate類型轉換後傳回CustomerId屬性值,保證資料庫與執行個體對象同步
23 if (session.Contains(customer))
24 {
25
26 }
27 }
方法二:ISession.SaveOrUpdate():配置設定新辨別儲存瞬時态對象。
持久态轉換為脫管态
方法一:ISession.Evict(object):從目前ISession中删除指定執行個體
1 public void PersistentConvertDetachedEvict()
2 {
3 //得到session
4 ISession session = NHibernateHelper.GetSession();
5 //根據id得到customer對象
6 var customer = session.Get("Customer", new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
7 //如果包含customer對象則删除
8 if (session.Contains(customer))
9 {
10 session.Evict(customer);
11 }
12 }
方法二:ISession.Close():關閉目前ISession
1 public void PersistentConvertDetachedCloseTest()
2 {
3 //得到session
4 ISession session = NHibernateHelper.GetSession();
5 //根據id得到customer對象
6 var customer = session.Get("Customer", new Guid("DDF63750-3307-461B-B96A-7FF356540CB8"));
7 if (session.Contains(customer))
8 {
9 NHibernateHelper.ResetSession();
10 }
11 }
脫管态轉換為持久态
方法一:ISession.Update():更新指定執行個體。
1 public void DetachedConvertPersistentUpdateTest()
2 {
3 //得到session
4 ISession session = NHibernateHelper.GetSession();
5 //根據id得到customer對象
6 Customer customer = session.Get("Customer", new Guid("DDF63750-3307-461B-B96A-7FF356540CB8")) as Customer;
7 //重新設定ISession
8 NHibernateHelper.ResetSession();
9 //脫管态對象
10 //在脫管态下可繼續被修改
11 if (session.Contains(customer))
12 {
13 customer.NameAddress = new Name() { CustomerAddress="上海", CustomerName="wolfy"};
14 //轉變為持久态對象
15 session.Update(customer);
16 }
17 }
通過上面的例子可以看出:在托管時期的修改會被持久化到資料庫中;
注意:NHibernate如何知道重新關聯的對象是不是“髒的(修改過的)”?如果是新的ISession,ISession就不能與對象初值來比較這個對象是不是“髒的”,我們在映射檔案中定義<id>元素和<version>元素的unsaved-value屬性,NHibernate就可以自己判斷了。
如果加上一個鎖:如果在托管時期沒有修改,就不執行更新語句,隻轉換為持久态,下面的例子如果在托管時期修改對象,執行更新語句。
1 public void DetachedConvertPersistentUpdateLockTest()
2 {
3 //得到session
4 ISession session = NHibernateHelper.GetSession();
5 //根據id得到customer對象
6 Customer customer = session.Get("Customer", new Guid("DDF63750-3307-461B-B96A-7FF356540CB8")) as Customer;
7 if (session.Contains(customer))
8 {
9 NHibernateHelper.ResetSession();
10 }
11 //鎖
12 session.Lock(customer, NHibernate.LockMode.None);
13 //如果在托管時期沒有修改,就不執行更新語句,隻轉換為持久态
14 session.Update(customer);
15 }
需注意Lock鎖的使用,需要保證customer對象不為null,這裡為了測試友善就沒加上判斷。如果為null會有異常(attempt to lock null)。
方法二:ISession.Merge():合并指定執行個體。不必考慮ISession狀态,ISession中存在相同辨別的持久化對象時,NHibernate便會根據使用者給出的對象狀态覆寫原有的持久化執行個體狀态。
方法三:ISession.SaveOrUpdate():配置設定新辨別儲存瞬時态對象;更新/重新關聯脫管态對象。
本篇概念性的東西比較多,對三種狀态的了解到位,就能差別三種狀态。
參考文章
http://www.cnblogs.com/lyj/archive/2008/11/17/1335181.html
-
部落格位址:http://www.cnblogs.com/wolf-sun/
部落格版權:如果文中有不妥或者錯誤的地方還望高手的你指出,以免誤人子弟。如果覺得本文對你有所幫助不如【推薦】一下!如果你有更好的建議,不如留言一起讨論,共同進步!
再次感謝您耐心的讀完本篇文章。