我有一个名为Category的对象,它有一个Id,Name和OwnerId。然后我将它们嵌套以创建子类别。如果类别具有所有者ID,则它是子类别。子类别的数量是无限的,但每个项目只能有1个父项。很简单。
我的问题是,我需要在加载后访问子类别。如何使用Linq获取Owning类别。我知道所有者身份,但我不知道主人可以有多少lvls。
基本上我正在寻找一种获取Id == X的类别或子类别的方法,但这可以存在于6个级别或更深的子类别中。
我试图避免每个子类别中每个子类别的循环....
答案 0 :(得分:1)
还有另一种存储/检索树层次结构的方法,如this fogbugz博文中所述:
原来这很酷 解决这个问题的解决方案 乔·塞尔科。而不是试图 保持一堆父母/孩子 整个数据库的关系 - 这将需要递归SQL查询来查找所有 节点的后代 - 我们标记每个节点 具有“左”和“右”值的情况 通过遍历树计算 深度优先,随着我们前进而计算。一个 节点的“左”值随时设置 在遍历期间首次出现,并且 行走时设置“正确”值 将树从节点上备份。 一张照片可能更有意义:
嵌套集SQL模型允许我们添加 案例层次结构而不牺牲 性能
这有什么用?现在我们问一下 对于具有“左”值的所有情况 在2到9之间找到所有的 B的后代在一个快速,索引 查询。 G的祖先被发现 要求“左”小于的节点 6(G自己的“左”)和“右”更大 比6.适用于所有数据库。 大大提高性能 - 特别是在查询大的时候 层次结构
Here's another post详细介绍。它是使用Sql
和php
编写的,但我认为您可以获得它的要点并轻松地将Linq转换为Sql。
答案 1 :(得分:0)
在MS SQL 2005及更高版本中,您可以创建递归查询。但是在LINQ to SQL中,你运气不好。如果不对数据库中的数据进行重构,则无法在单个数据库调用中遍历树。
然而......我能想到的解决方法有1个。如果能够将单个树(或树的一部分)的所有Category
元素组合在一起,则可以在单个语句中预加载整个树的该部分。之后,您将能够遍历树的该部分,而不会触发对数据库的新调用。它看起来像这样:
// Load the category that will be used as starting point.
var subCategory = db.Categories.Single(c => c.Id == 56);
// Performance: Load the complete group in one go.
var categories = (
from category in db.Categories
where category.GroupId == subCategory.GroupId
select category)
.ToArray();
// Traverse the tree and get the top-most parent (if any).
var parent = subCategory.GetParents().LastOrDefault();
// Extension method to get the parents.
public static IEnumerable<Category> GetParents(
this Category category)
{
while (category.Parent != null)
{
// NOTE: cat.Parent will not cause a database call
// when the Parent is already loaded by L2S.
yield return cat.Parent;
category = category.Parent;
}
}
这当然只有在您能够将元素确定为一个组时才有效。此解决方案是否更快也取决于组的大小。当您加载(并且不使用)的对象组非常大时,它实际上会降低应用程序的速度。