我有一组属于树的元素。我只关心祖先,我不关心孩子。例如,我希望树看起来像这样:
我给出的唯一输入是加星标的元素。所以我有这样的事情:
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's blog post,了,但是他正在关注儿童用品,在那里,我开始给孩子用品,我正在努力工作。或者我可能和他做同样的事情但却没有意识到这一点。
编辑:添加categoriesRepository以使我更清楚地知道我正在访问数据库。
答案 0 :(得分:0)
免责声明:由于我没有使用NHibernate的经验,我现在就出去了。
Ayende's blog post使用join fetch
语句,该语句是特定于NHibernate的SQL,称为HQL。由于NHibernate只是数据库之上的另一层,并且SQL数据库不是为处理层次结构而设计的,因此仍然需要递归查询来获取整个树。
但Ayende还在one of his comments中提到,如果直接和间接关系都存储在数据库中,则查询树会更容易。他指的是这样的结构:
Ancestor Descendant IsChild
-------------------------------------------------------
Household cleaning Supplies Air fresheners True
Household cleaning Supplies Paper Towels True
Household cleaning Supplies Car Airfreshner False
Air fresheners Car Airfreshner True
Utensils Forks True
Ayende使用Level
列来指示树中节点的深度,该列可用于限制查询中树的深度。但IsChild
也将证明这一原则。
鉴于后代节点 Car Airfreshner ,您可以在一个查询中选择所有祖先节点。您可以通过检查IsChild
值来重建这些节点的父子关系。
SELECT * FROM TreeRelations WHERE Descendant = 'Car Airfreshner'
鉴于祖先节点家庭清洁用品,您可以通过选择单个查询中的所有后代来从此节点开始构建树。 IsChild
值可用于查找父子关系。
SELECT * FROM TreeRelations WHERE Ancestor = 'Household cleaning Supplies'
要获取任何给定节点的整个树,您可以组合两个查询以检索所有祖先和后代,并从中构建树:
SELECT * FROM TreeRelations WHERE Descendant = 'Entry node' OR Ancestor = 'Entry node'