NHibernate no session or session was closed問題以及NH最佳實踐

項目中引入 NHibernate 的時間不長,在將項目中的數據訪問層代碼改寫成NH版本之後,遇到了 failed to lazily initialize a collection, no session or session was closed  異常。

異常起因

是在實體多對多、延遲(many-to-many lazy) 加載的過程中,調用對應字段則會拋出上述異常。後來經調試,查找資料發現這是由於我在代碼中使用了 using(ISeesion session = SessionFactory.CreateSession()) 的緣故,因爲 using 語句強制釋放資源,當lazy load 的時候就出現了問題。

園子中李永京以在他的系列教程中已經說明了這個問題,但只是順便帶過,並沒有專門講這個問題。

思考過程

many-to-many 的lazy load 非常常見,是經常使用的功能,既然在數據層中的GetXXX()方法中不能使用using等方式來釋放資源,想必就需要手動的進行釋放,當實體對象使用完畢之後,在進行Session的資源回收。

這確實很麻煩,首先我不想在我們的頁面邏輯部分還會出現 ISession 等對象,但是同時又需要資源釋放,這兩者之間是互斥的,因爲你既不想這個對象出現,而你需要手動控制這個對象。

在思考的過程中,我也想過可不可以使用 HttpModule 在BeginRequest 的時候初始化 ISession ,EndRequest 的時候關閉 ISession。但是我想,我們不能在每一次請求就各開關一次 ISession 吧,因爲並不是所有的頁面都有數據訪問的任務。這樣的開銷是一個問題。

解決方案

  自己之前也沒有接觸太多的NH,無奈之中,在StackOverflow 上面問了一下,有人給了一個鏈接,CodeProject 上面的一篇文章《NHibernate Best Practices with ASP.NET, 1.2nd Ed》下載了其中的代碼發現,他也是使用HttpModule 來實現的,看了一下正文的解釋,原來我的性能上面的顧慮是多餘的。

整體的思路如下:

HttpModule

  BeginRequest:獲取ISession對象,將其放入HttpContext.Items 中

  EndRequest:關閉ISession 對象。

DataAccess

  通過SessionManager 獲得ISession 對象,SessionManager 從HttpContext 中得到 ISession。其中SessionManager 使用了Lazy singleton 模式

總結

  整個解決過程不算繁瑣,全部重構了項目的代碼也並沒有花費太多的時間(緊緊是吧 using 語句去掉),在查找解決方案的過程中,中文資源中很少有人提到這個最佳實踐,把我遇到的問題羅列出來,也和大家分享一下,

:D

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章