2010-09-07 79 views
5

這不是一個問題,因爲我一直在研究這個主題的最後幾天,並且認爲我想貢獻一些能夠吸引很多不同想法的東西,我一直在閱讀和提出我的問題的解決方案...使用Nhibernate預先加載樹/層次結構

問題是渴望加載Nhibernate中的n級子對象,並且nHibernate將不知道樹的深度。我已經看到通過使用直接sql和Union All解決了這個問題,但不幸的是我無法讓它工作,通常是因爲nhibernate並不知道你已經急於加載對象。所以,我看着下面的代碼預先加載使用標準

 var children = Session.CreateCriteria<MenuNode>() 
      .SetFetchMode("Children", FetchMode.Eager) 
      .Add(Expression.Eq("Id", 1)) 
      .List<MenuNode>(); 

這將渴望負荷的孩子ID爲1的對象,從這裏你可以同時使用在聲明貪婪加載多個實體。所以我只需要計算出屬於這個層次結構的所有節點ID,並用In語句加載它。

所以,如果我創建一個父表的層次和每個節點都具有層次ID那麼我可以用這個的HQL

var sql = "select Distinct id from Nodes where (HierarchyId = :id) "; 
var ids = Session.CreateSQLQuery(sql) 
      .SetInt32("id", id) 
      .List(); 

,從這裏渴望負荷得到所有的節點ID爲這個層次的列表所有的孩子這棵樹單獨使用

var children = Session.CreateCriteria<MenuNode>() 
      .SetFetchMode("Children", FetchMode.Eager) 
      .Add(Expression.In("Id", ids)) 
      .List<MenuNode>(); 

與此唯一的問題是,你有沒有急於裝從層次結構父表,它可以正常完成節點的第一級水平..

var menu = Session.CreateCriteria<Menu>() 
      .SetFetchMode("RootNodes", FetchMode.Eager) 
      .Add(Expression.Eq("Id", id)) 
      .List<Menu>(); 

因此,在三個SQL語句中,您已經將一個子對象加載到n個級別。爲了進一步優化,我使用了多重查詢將兩個主要查詢鏈接在一起,並同時發送兩個語句。聲明撤回id的需要獨立執行撤回id的雖然。

使用多目標躍躍欲試負荷的進一步的細節可以在這裏找到..

http://nhforge.org/blogs/nhibernate/archive/2008/09/06/eager-loading-aggregate-with-many-child-collections.aspx

希望一些幫助這人

回答

2

我知道你不問問題,但我想我會分享我喜歡這樣做的方式。見http://ayende.com/Blog/archive/2009/08/28/nhibernate-tips-amp-tricks-efficiently-selecting-a-tree.aspx

return session.CreateCriteria<MenuNode>() 
    .SetFetchMode("Children", FetchMode.Join) 
    .SetResultTransformer(new DistinctRootEntityResultTransformer()) 
    .List<MenuNode>(); 

我不知道這是否實現了這個目的,你與你的方式來完成的一切,但我發現它與分層數據打交道時是一個非常有用的工具。