如何在仅给定子元素的情况下用 C# 构建树?
我有一组属于树的元素。我只关心祖先,不关心孩子。例如,我希望树看起来像这样:
- 烧烤用品*
- 家居清洁用品
- 空气清新剂
- 纸巾*
- 餐具
- 叉子*
- 1. Car Airfreshner*
我得到的唯一输入是带星号的元素。所以我有这样的东西:
List<Categories> categories = new List<Categories>("Forks", "Paper Towels", "Car Airfreshner", "Barbeque Supplies");
类别看起来像这样:
string Id;
Category Parent;
IList<Category> Children;
Category RootNode; // e.g., "Household cleaning supplies"
不幸的是,完整的树相当大......〜17,000 个项目。但该列表基本上永远不会改变,所以如果我必须做任何事情来修改它以使其更容易访问,我愿意这样做。
我正在使用 NHibernate,并且尝试了几种方法:
public IList<Categories> CompleteTree(IList<Categories> inputList) {
var result = new List<Categories>();
foreach (var item in inputList) {
var recursiveItem = categoryRepository.Get(item);
while (recursiveItem != null) {
result.Add(recursiveItem);
recursiveItem = item.Parent;
}
}
return result;
}
无论如何,这对数据库的影响很大?如果有任何巧妙的代码的话,我正在使用 NHibernate 2。
我见过 Ayende 的博客文章, 但他正在研究儿童项目,我从儿童项目开始,然后我正在努力向上。或者我可能会做和他一样的事情,但只是没有意识到。
编辑:添加了categoriesRepository,以便更清楚地表明我正在访问数据库。
I have a set of elements that belong to a tree. I only care about the ancestors, I don't care about the children. For example I want the tree to look like this:
- Barbeque Supplies*
- Household cleaning Supplies
- Air fresheners
- Paper Towels*
- Utensils
- Forks*
1. Car Airfreshner*
The only input I'm given are the starred elements. So I have something like this:
List<Categories> categories = new List<Categories>("Forks", "Paper Towels", "Car Airfreshner", "Barbeque Supplies");
Categories looks like this:
string Id;
Category Parent;
IList<Category> Children;
Category RootNode; // e.g., "Household cleaning supplies"
Unfortunately, the complete tree is rather large ... ~17,000 items. But the list basically never changes, so if I have to do anything to massage it to make access easier, I'm willing to do that.
I'm using NHibernate and I've tried a couple of methods:
public IList<Categories> CompleteTree(IList<Categories> inputList) {
var result = new List<Categories>();
foreach (var item in inputList) {
var recursiveItem = categoryRepository.Get(item);
while (recursiveItem != null) {
result.Add(recursiveItem);
recursiveItem = item.Parent;
}
}
return result;
}
That hits the database a lot, anyway around this? I'm using NHibernate 2 if there's any slick code for that.
I've seen Ayende's blog post, but he's going down children items, where I'm given the child items to start out with and I'm working my way up. Or I could be doing the same thing as him but just don't realize it.
Edit: added categoriesRepository to make it more clear that I'm hitting the database.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
免责声明:由于我没有 NHibernate 的经验,所以我在这里冒险。
Ayende 的博客post 使用
join fetch
语句,这是 NHibernate 特定的 SQL,称为 HQL。由于 NHibernate 只是数据库之上的另一层,而 SQL 数据库并不是为处理层次结构而设计的,因此它仍然需要递归查询来获取整个树。但 Ayende 还在 他的评论之一认为,如果直接关系和间接关系都存储在数据库中,查询树会更容易。他提到了这样的结构:
Ayende 使用
Level
列来指示树中节点的深度,这可用于限制查询中树的深度。但IsChild
也会演示其原理。查找祖先
给定后代节点 Car Airfreshner,您可以在一个查询中选择所有祖先节点。您可以通过检查
IsChild
值从这些节点重建父子关系。创建树
给定祖先节点“Household Cleaning Supplies”,您可以通过在单个查询中选择所有后代来构建从此节点开始的树。
IsChild
值可用于查找父子关系。两个查询组合
要获取任何给定节点的整个树,您可以组合两个查询来检索所有祖先和后代,并从中构建一棵树:
Disclaimer: As I have no experience with NHibernate, I'm going out on a limb here.
Ayende's blog post uses a
join fetch
statement, which is NHibernate-specific SQL, called HQL. Since NHibernate is just another layer on top of the database and SQL databases aren't designed to handle hierarchies, it would still require recursive queries to fetch the entire tree.But Ayende also mentions in one of his comments that it's easier to query a tree, if both the direct and indirect relations are stored in the database. He refers to a structure like this:
Ayende uses a
Level
column that indicates the depth of a node in the tree, which could be used to limit the depth of the tree in the query. ButIsChild
will demonstrate the principle as well.Finding ancestors
Given the descendant node Car Airfreshner, you can select all ancestor nodes in one query. You can reconstruct parent-child relations from these nodes by checking the
IsChild
value.Creating a tree
Given the ancestor node Household cleaning Supplies, you can build a tree starting from this node by selecting all the descendants in a single query. The
IsChild
value can be used to find parent-child relations.Both queries combined
To get the entire tree for any given node, you can combine both queries to retrieve all ancestors and descendants and build a tree from that: