使用Nhibernate急切加载树/层次结构

时间:2010-09-07 09:19:39

标签: nhibernate nhibernate.search

这不是一个问题,我过去几天一直在研究这个问题,并且认为我想贡献一些东西,这些东西吸引了我一直在阅读的许多不同的想法并提出了我的想法。解决问题......

问题是在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加载孩子,从这里你可以使用In语句一次加载多个实体。所以我只需要计算出属于这个层次结构的所有节点id,并使用In语句急切加载它。

因此,如果我为层次结构创建一个父表,并且每个节点都有一个层次结构ID,那么我可以使用这个hql获得该层次结构的所有节点id的列表

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

并且从这里开始使用

单独为这棵树加载所有孩子
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的声明。

可以在此处找到使用MultiCriteria进行预加载的更多详细信息..

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

希望对某人有所帮助

1 个答案:

答案 0 :(得分: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>();

我不知道这是否能完成您打算用您的方法完成的所有事情,但我发现它在处理分层数据时是一个非常有用的工具。