程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> NHibernate之旅(21):探索對象狀態

NHibernate之旅(21):探索對象狀態

編輯:關於.NET

本節內容

引入

對象狀態

對象狀態轉換

結語

引入

在程序運行過程中使用對象的方式對數據庫進行操作,這必然會產生一系列的持久化類的實例對象。這些對象可能是剛剛創建並准備存儲的,也可能是從數據庫中查詢的,為了區分這些對象,根據對象和當前會話的關聯狀態,我們可以把對象分為三種:

瞬時對象:對象剛剛建立。該對象在數據庫中沒有記錄,也不在ISession緩存中。如果該對象是自動生成主鍵,則該對象的對象標識符為空。

持久化對象:對象已經通過NHibernate進行了持久化,數據庫中已經存在對應的記錄。如果該對象是自動生成主鍵,則該對象的對象標識符已被賦值。

托管對象:該對象是經過NHibernate保存過或者從數據庫中取出的,但是與之關聯的ISession已經關閉。雖然它有對象標識符且數據庫中存在對應記錄,但是已經不再被NHibernate管理。

對象狀態

NHibernate提供了對象狀態管理的功能,支持三種對象狀態:瞬時態(Transient)、持久態(Persistent)、托管態(Detached)。

1.瞬時態(Transient)

對象剛剛創建,還沒有來及和ISession關聯的狀態。這時瞬時對象不會被持久化到數據庫中,也不會被賦上標識符。如果不使用則被GC銷毀。ISession接口可以將其轉換為持久狀態。

這像這樣,剛剛創建了一個Customer對象,是一個瞬時態對象:

var customer = new Customer() { Firstname = "YJing", Lastname = "Lee" };2.持久態(Persistent)

剛被保存的或剛從數據庫中加載的。對象僅在相關聯的ISession生命周期內有效,在數據庫中有相應記錄並有標識符。對象實例由NHibernate框架管理,如果有任何改動,在當然操作提交時,與數據庫同步,即將對象保存更新到數據庫中。

3.托管態(Detached)

持久對象關聯的ISession關閉後,這個對象在ISession中脫離了關系,就是托管態了,托管對象仍然有持久對象的所有屬性,對托管對象的引用仍然有效的,我們可以繼續修改它。如果把這個對象重新關聯到ISession上,則再次轉變為持久態,在托管時期的修改會被持久化到數據庫中。

對象狀態轉換

在同步數據庫的情況下執行下面的語句可以轉換對象的狀態。

測試驗證對象

ISession.Contains(object):檢查ISession中是否包含指定實例

重新設置ISession

private void ResetSession()
{
  if (_session.IsOpen)
    _session.Close();
  _session = _sessionManager.GetSession();
  _transaction.Session = _session;
}
1.瞬時態轉換持久態

方法一:ISession.Save():保存指定實例。

[Test]
public void TransientConvertPersistentTest()
{
  //瞬時態對象
  var customer = new Customer() { Firstname = "YJidng", Lastname = "Lee" };
  Assert.IsFalse(_session.Contains(customer));
  //仍然是瞬時態,CustomerId屬性值為空
  //關聯ISession保存到數據庫中
  _session.Save(customer);
  //變為持久態,由於表中CustomerId字段自動增長的,保存數據庫,CustomerId字段自動加一
  //經過NHibernate類型轉換後返回CustomerId屬性值,保證數據庫與實例對象同步
  Assert.IsTrue(_session.Contains(customer));
}

方法二:ISession.SaveOrUpdate():分配新標識保存瞬時態對象。

2.持久態轉換托管態

方法一:ISession.Evict(object):從當前ISession中刪除指定實例

[Test]
public void PersistentConvertDetachedEvictTest()
{
  Customer customer = _transaction.GetCustomerById(1);
  Assert.IsTrue(_session.Contains(customer));
  _session.Evict(customer);
  Assert.IsFalse(_session.Contains(customer));
}

方法二:ISession.Close():關閉當前ISession

[Test]
public void PersistentConvertDetachedCloseTest()
{
  Customer customer = _transaction.GetCustomerById(1);
  Assert.IsTrue(_session.Contains(customer));
  ResetSession();
  Assert.IsFalse(_session.Contains(customer));
}
3.托管態轉換持久態

方法一:ISession.Update():更新指定實例。

[Test]
public void DetachedConvertPersistentUpdateTest()
{
  Customer customer = _transaction.GetCustomerById(1);
  //持久態對象
  Assert.IsTrue(_session.Contains(customer));
  //重新設置ISession
  ResetSession();
  Assert.IsFalse(_session.Contains(customer));
  //托管態對象
  //在托管態下可繼續被修改
  customer.Firstname += "CnBlogs";
  _transaction.UpdateCustomerTransaction(customer);
  //轉變為持久態對象
  Assert.IsTrue(_session.Contains(customer));
}

看看這個例子:在托管時期的修改會被持久化到數據庫中;

注意:NHibernate如何知道重新關聯的對象是不是“髒的(修改過的)”?如果是新的ISession,ISession就不能與對象初值來比較這個對象是不是“髒的”,我們在映射文件中定義<id>元素和<version>元素的unsaved-value屬性,NHibernate就可以自己判斷了。

[Test]
public void DetachedConvertPersistentUpdateAllTest()
{
  Customer customer = _transaction.GetCustomerById(1);
  //持久態對象
  customer.Firstname += "YJingLee";
  Assert.IsTrue(_session.Contains(customer));
  //重新設置ISession
  ResetSession();
  Assert.IsFalse(_session.Contains(customer));
  //托管態對象
  //在托管態下可繼續被修改
  customer.Firstname += "CnBlogs";
  //這時一起更新
  _transaction.UpdateCustomerTransaction(customer);
  //轉變為持久態對象
  Assert.IsTrue(_session.Contains(customer));
}

這個加上一個鎖:如果在托管時期沒有修改,就不執行更新語句,只轉換為持久態,下面的例子如果在托管時期修改對象,執行更新語句。

[Test]
public void DetachedConvertPersistentUpdateLockTest()
{
  Customer customer = _transaction.GetCustomerById(1);
  Assert.IsTrue(_session.Contains(customer));
  ResetSession();
  Assert.IsFalse(_session.Contains(customer));
  //鎖
  _session.Lock(customer, NHibernate.LockMode.None);
  //如果在托管時期沒有修改,就不執行更新語句,只轉換為持久態
  //customer.Firstname += "CnBlogs";
  _transaction.UpdateCustomerTransaction(customer);
  Assert.IsTrue(_session.Contains(customer));
}

方法二:ISession.Merge():合並指定實例。不必考慮ISession狀態,ISession中存在相同標識的持久化對象時,NHibernate便會根據用戶給出的對象狀態覆蓋原有的持久化實例狀態。

方法三:ISession.SaveOrUpdate():分配新標識保存瞬時態對象;更新/重新關聯托管態對象。

以上兩個大家自己測試了!

結語

這篇初步知道了對象的狀態。雖然對象的狀態的細節由NHibernate自己維護,但是對象狀態在NHibernate應用中還是比較重要的。同時對象狀態也涉及了NHibernate緩存、離線查詢等內容。

出處:http://lyj.cnblogs.com

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved