聲明
本篇中提到的Session,並非是Asp.NET中的Session,而是NHibernate中ISession。
本篇假設讀者已經對NHibernate的有一定的了解,已經成功持久化過領域模型。
你不需要親自用復制本篇的代碼去調試,因為本篇的代碼並不全,最后也有提供下載。
本篇中的單元測試用到了NUnit,如果你使用其他框架也並不影響理解。
正文 開門見山
在ASP.NET中,如果我們希望每一個HTTP的請求只打開一個Session,在請求結束時關閉這個Session。
也就是在請求期間,只用到這一個Session。或許我們可以稱他為“one session per request”。
這樣做得好處是,你可以更容易地使用延遲加載,因為當領域模型傳到表示層時,ISession在表示層仍然是打開的,並再請求結束后自動銷毀。
另外在單元測試時,並不一定有HTTP的請求,所以需要用另一種策略代替。
作法:
我們會在ASP.NET應用程序中這樣使用
HttpContext context = HttpContext.Current; if (context.Items["nhsession"] == null) { context.Items["nhsession"] = sessionFactory.OpenSession(); } return context.Items["nhsession"] as ISession;
以上代碼意思是:我們需要Session時,就從web的上下文中取,一個請求中第一次會打開一個Session並保存再web上下文,以后就不再新打開了。
但是有了這樣的一個GetSession方法后,並不代表萬事大吉了。
下面來看一下單元測試:
[Test] public void GetSessionTest() { ISession session= NHibernateHelper.GetSession(); }
報錯了,未將對象引用到實例,是哪個對象呢?HttpContext.Currtent為null。
因為建立的是類庫,這里並沒有web的上下文。那怎么辦呢?
所以在這里我使用兩套Session策略
1、在Web應用程序中,就使用剛才提到的策略。
2、在WinForm或單元測試中,使用另一種策略,每個線程用一個Session。
其實在NHibernate文檔中也有提到,在1.2以后的版本中,增加了一個GetCurrentSession()的方法,用於獲取當前Session,這個上下文只支持一個ISessionFactory。你必須自己通過CurrentSessionContext類中的靜態方法手動的把ISession實例綁定或者取消綁定到當前上下文。
修改代碼
private static void BindContext() { if (!CurrentSessionContext.HasBind(sessionFactory)) { CurrentSessionContext.Bind(sessionFactory.OpenSession()); } } private static void UnBindContext() { if (CurrentSessionContext.HasBind(sessionFactory)) { CurrentSessionContext.Unbind(sessionFactory); } } public static ISession GetCurrentSession() { BindContext(); return sessionFactory.GetCurrentSession(); }
這樣做可以避免在代碼中自己實現策略模式與IOC,NHibernate已經幫我們做好了。
修改hibernate.cfg.xml配置文件,加入一個屬性<property name="current_session_context_class">web</property>,修改這個屬性就可以修改Session策略。
也可以定義在代碼中。
sessionFactory = new Configuration().Configure() .SetProperty("current_session_context_class", currentSessionContextClass.ToString()) .BuildSessionFactory(); /// <summary> /// 當前Session上下文模式 /// 特定環境下,當前Session保存在特定的上下文中 /// </summary> public enum CurrentSessionContextClass { managed_web, call, thread_static, web }
現在,我們就可以在web應用程序中將參數設置為web,而單元測試中將參數設置為thread_static。
void Application_Start(object sender, EventArgs e) { // 在應用程序啟動時運行的代碼 NHibernateHelper.Instance(CurrentSessionContextClass.web); }
ISession session; [SetUp] public void Setup() { NHibernateHelper.Instance(CurrentSessionContextClass.thread_static); session = NHibernateHelper.GetCurrentSession(); }
下載:
最后分享一個相關的NHibernateHelper文件