2012-03-28 60 views
0

如果不使用分頁查詢,NHibernate可以通過映射中的提示在單個數據庫命中中加載整個對象和相關對象。但是,如果您正在使用分頁,它會創建大量的數據庫調用。如何在對象圖上改善對分頁查詢的Nhibernate性能

例如我有一個Invoice對象和一個InvoiceLine對象,以便發票有一個List的發票行。 發票流利的映射是

HasMany(x => x.Lines) 
    .Table("InvoiceLine") 
    .KeyColumn("InvoiceId") 
    .Fetch.Join() 
    .Not.LazyLoad(); 

的Not.LazyLoad選項的偉大工程加載一個發票時,下載在一個單一的數據庫轟動了整個對象圖......但如果我想運行就像一個分頁查詢

_invoiceQuery.Skip(200).Take(100); 

然後NHibernate的第一次加載所有的100張發票的單發命中......然後訪問數據庫100分多次,在每一次以一個發票的發票行。

有什麼辦法來減少這2支安打,即

  1. 負載發票
  2. 加載所有InvoiceLines在發票(1)?

我曾嘗試通過加載所需要的發票ID列表到一個查詢,然後使用

_invoiceQuery.Where(x => requiredIds.Contains(x.Id)); 

但似乎NHibernate的降低包含約束到SQL時有同樣的問題,手動強制問題。

...或者我必須接受我需要使用不同的工具嗎?

回答

0

根據我的經驗,在使用分頁列表和預先獲取時,NHibernate不是很好。請記住,最終您的查詢將作爲TSQL執行,並返回一堆連接的數據行。現在,NHibernate能夠將這些數據轉換回根實體及其關聯的子項。麻煩的是,NHibernate如何知道,直到它已經從DB返回它需要在它的TOP子句中指定多少行以檢索所需的根實體數量?

同樣,考慮強制使用Session.QueryOver和Left.JoinAlias進行連接的情況。您可以指定要檢索的行數,但它只是,而不是實體

通常我會解決你的情況類似的方式向你怎麼有 - 通過使用兩個查詢。你可以發佈多一點的代碼?這裏有幾個方法,你可以這樣做:

  1. 創建初始查詢返回指定的100個發票ID的投影,然後在一個單獨的命中去拿,他們的ID被包含在該列表

    發票
  2. 創建初始查詢返回指定的100張發票(lazyload invoicelines),然後在單獨的命中檢索invoice的invoiceID包含在第一個列表的ID中。你應該能夠擊中數據庫兩次,並在代碼後面結合父/子實體。與雖然手工合併實體小心一點 - 如果你打算如果你在報告數據的視圖只是有興趣做可能是值得讓個別實體剛從分貝第一

任何CRUD (即沒有CUD操作),也許考慮映射到一個自定義數據庫視圖,而不是

+0

我真的不能接受這個答案,因爲「你應該能夠擊中數據庫兩次,並在代碼後面結婚父/子實體「。誤解了我的問題的最後一點:NHibernate翻譯'_invoiceQuery.Where(x => requiredIds.Contains(x.Id));'到100個單獨的數據庫命中。 – perfectionist 2014-11-28 10:00:50