繁体   English   中英

使用NHibernate / C#从数据库中预加载树/层次结构

[英]preloading a tree / hierarchy from database using NHibernate / C#

我需要填充一些树层次结构并遍历它们,以建立类别菜单。 每个类别可以有1个以上的父对象。 问题是如何有效地执行此操作,并尝试避免“ Select N+1问题。

当前,它是通过使用两个表/实体来实现的:

Category
--------
ID
Title

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

理想情况下,我将使用普通的对象遍历来遍历节点,即遍历Category.ChildCategories等。这是否可能在一个SQL语句中完成? 而且,这可以在NHibernate中完成吗?

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文档

编辑

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

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);

导致层次结构中每个级别调用一次。 我相信这仍然可以大大减少对数据库的调用次数,但是我无法获得上面的示例来处理对数据库的单个调用。

这将检索所有带有其子类别的类别:

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之后)进行

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM