2010-09-07 51 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>(); 

我不知道这是否实现了这个目的,你与你的方式来完成的一切,但我发现它与分层数据打交道时是一个非常有用的工具。