2012-07-04 98 views
0

我需要填充一些樹層次結構並遍歷它們以建立一個類別菜單。每個類別可以有多個父代。問題是如何有效地做到這一點,並儘量避免Select N+1問題。使用NHibernate/C從數據庫預加載樹/層次結構#

目前,它是通過使用兩個表/實體實現的:

Category 
-------- 
ID 
Title 

CategoryLink 
--------- 
ID 
CategoryID 
ParentID 

理想情況下,我會用正常的對象遍歷要經過的節點,通過Category.ChildCategories去,也就是等這是可能的在一個SQL語句中完成?而且,這可以在NHibernate中完成嗎?

回答

0

Category.ChildCategories映射中指定batch-size。這將導致NHibernate以指定大小的批次獲取子項,而不是一次一個(這將緩解N + 1問題)。

如果您正在使用.hbm文件,你可以指定batch-size這樣的:

<bag name="ChildCategories" batch-size="30"> 

或使用流利的映射

HasMany(x => x.ChildCategories).KeyColumn("ParentId").BatchSize(30); 

更多信息,請參見NHibernate documentation

編輯

好吧,我相信我理解您的需求。使用以下配置

HasManyToMany<Item>(x => x.ChildCategories) 
    .Table("CategoryLink") 
    .ParentKeyColumn("ParentId") 
    .ChildKeyColumn("CategoryID") 
    .BatchSize(100) 
    .Not.LazyLoad() 
    .Fetch.Join(); 

您應該能夠使用以下行在一次調用中獲取整個層次結構。

var result = session.CreateCriteria(typeof(Category)).List(); 

出於某種原因,檢索單一品類這樣

var categoryId = 1; 
var result = session.Get<Category>(categoryId); 

導致在層次結構每級一個呼叫。我相信這應該仍然會大大減少對數據庫的調用次數,但是我無法獲得上面的示例來使用對數據庫的單個調用。

+0

我已經使用批量大小。然而,這隻能解決一個層面,而不是'n'層面。樹可以深深地說3,4或甚至更多的層次。理想情況下,我正在查看整個級別的1個查詢。 –

+0

批量大小不會完全產生有效的查詢計劃。它產生大量的單身查詢。雖然可以在性能和工程時間之間取得很好的平衡。 – usr

0

這會檢索所有類別與他們的孩子:

var result = session.Query<Category>() 
        .FetchMany(x => x.ChildCategories) 
        .ToList(); 

的問題是確定的根類是什麼。你既可以使用一個標誌,或映射反向集合(ParentCategories),並做到這一點:

var root = session.Query<Category>() 
        .FetchMany(x => x.ChildCategories) 
        .FetchMany(x => x.ParentCategories) 
        .ToList() 
        .Where(x => !x.ParentCategories.Any()); 

排序的所有應做的客戶端(即後ToList