2011-03-03 121 views
0

在我的類中使用lazy =「true」會導致我的應用程序完美工作,但性能很糟糕。當我從一個教程創建這個教程時,我只是想盡快開始工作。 (我使用這個教程:http://geekswithblogs.net/BobPalmer/archive/2010/04/23/mapping-object-relationships---quickstart-with-nhibernate-part-3.aspx這是非常有用的東西,快速工作)懶惰加載不與NHibernate合作

我不需要它來加載所有這些多對一的類,當我只需要使用一個對象,所以重新開啓延遲加載是有意義的。然後,我查看了這些對象,除了主對象內的多對一類的例外外,什麼也看不到。當我嘗試以供以後使用這些屬性,我得到以下錯誤:

"Could not initialize proxy - no Session." 

我猜這意味着,本次會議是封閉的,所以想偷懶加載額外的對象時失敗。我的會話提供看起來像這樣(爲教程一樣):

class SessionProvider { 
    private static ISessionFactory _sessionFactory; 
    private static Configuration _config; 

    public static ISessionFactory SessionFactory { 
     get { 
      if (_sessionFactory == null) { 
       _sessionFactory = Config.BuildSessionFactory(); 
      } 
      return _sessionFactory; 
     } 
    } 

    private static Configuration Config { 
     get { 
      if (_config == null) { 
       _config = new Configuration(); 
       _config.AddAssembly(Assembly.GetCallingAssembly()); 
      } 
      return _config; 
     } 
    } 
} 

然後用我的存儲庫這樣的:

using (var session = GetSession()) { ... } 

從這個函數獲取會話:

private static ISession GetSession() { 
     return SessionProvider.SessionFactory.OpenSession(); 
} 

所以我的問題是,我期望在這裏做什麼?保持會話打開?使其在所有存儲庫中保持靜態?我沒有足夠的經驗與NHibernate瞭解如何工作呢。我現在的首要任務是隻從數據庫中讀取數據,如果這有什麼不同。這是一個代碼庫,最終將在我們的網站和各種C#.Net應用程序中使用。

回答

2

推薦的方法是使用unit of work pattern。如果你知道你會事先需要特定的實體,你的另一個選擇是使用急切的加載。

+0

這兩篇文章有助於:http://blogs.hibernatingrhinos.com/nhibernate/archive/0001/01/01/the-repository-pattern.aspx和http://nhforge.org/wikis/patternsandpractices/nhibernate-和-the-unit-of-work-pattern.aspx我會將此標記爲答案,但我想知道更多關於當我嘗試在Web應用程序和Windows應用程序中使用它時會發生什麼情況。我是否應該創建一些內容,以根據應用程序類型在兩個會話之間切換以提供模式? – Chris 2011-03-07 16:10:55

+0

對於您想要的Windows應用程序:使用斷開連接的會話,或者每個屏幕有一個會話(您仍然可以在此使用工作單元模式)。但是,你應該真的考慮擁有一臺服務器,這樣你就不會有太多的客戶端在同一個數據庫上。 – jonnii 2011-03-07 16:19:29

+0

是的,但我也將在Web應用程序中使用它。如何檢查應用程序是否在ASP.Net應用程序中運行?我看到我需要檢查HttpContext,但默認情況下它未啓用。我假設只是啓用它並檢查它是否爲空將不是這裏的最佳做法。 – Chris 2011-03-08 14:48:43

0

你不會說你的應用程序是一個web應用程序(例如ASP.NET MVC)還是一個控制檯/ GUI /服務應用程序。 MVC web應用程序中延遲加載ORM的一個常見問題是會話在控制器的操作方法結束時被關閉,代理實體對象被傳遞給視圖,該視圖然後嘗試枚舉一些延遲加載的集合,該集合由於會話已被處置。對此的解決方案被稱爲'Open Session in View'模式(至少在Java世界中),它通常涉及使用過濾器在Web請求開始時打開會話,確保會話被傳遞給任何控制器或其他對象請求它(這通常由您的IoC容器管理),那麼當視圖執行並且延遲加載屬性時會話仍然是活動的。

在一些系統中,在Java和.Net上都使用過Hibernate,我一般認爲懶加載是一個詛咒。雖然它很方便,但它經常需要額外的管道工作(例如支持'開放式會議視圖'模式),並經常殺死性能。對於那些你知道很可能被訪問的集合使用急切加載可能會更好。分析需要急切加載哪些集合會迫使您更好地理解應用程序的數據訪問配置文件,這將有助於您更好地理解應用程序的性能特徵,這隻會是一件好事!

+0

這是一個類庫,將用於ASP.Net應用程序和其他Windows應用程序。雖然我現在實際嘗試執行的操作可能會更好地通過存儲過程完成,但我仍然想知道如何使用延遲加載來處理這個問題,因爲如果我不這樣做,它會再次出現。 – Chris 2011-03-07 14:21:58

1

您正在通過在存儲庫中打開和關閉會話來管理會話。它不僅打破了延遲加載,而且損害了性能。

相反,會話管理應該使用更粗粒度的方法來完成。

例如,對於Web應用程序,一個推薦模式的session-per-請求(會話被打開,通過一個模塊或全局處理程序關閉,並綁定到的HttpContext)

只是仰望的session-per - 請求,有很多例子。

0

簡單的問題是,當您試圖訪問實體的關聯會話時,要訪問尚未加載的值。

NHibernate的Session對象旨在遵循工作單元模式。也就是說,您要爲每個要完成的單位創建一個會話。

說白了,你必須保持Session實例活着(不處理),直到你完成與該會話相關的對象。這意味着你的會話對象成爲你的工作範圍:

using(var session = GetSession()) 
{ 
    // Load some objects. 
    // Manipulate some values. 
    // Commit changes. 
} 

的NHibernate的會議必須處理類似於數據庫事務,在這裏完成了較寬的操作所需的所有步驟必須在會議的範圍內完成。