[英]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.