Linq to SQL嵌套对象

时间:2011-03-14 15:50:47

标签: c# .net linq performance linq-to-sql

我有一个名为Category的对象,它有一个Id,Name和OwnerId。然后我将它们嵌套以创建子类别。如果类别具有所有者ID,则它是子类别。子类别的数量是无限的,但每个项目只能有1个父项。很简单。

我的问题是,我需要在加载后访问子类别。如何使用Linq获取Owning类别。我知道所有者身份,但我不知道主人可以有多少lvls。

基本上我正在寻找一种获取Id == X的类别或子类别的方法,但这可以存在于6个级别或更深的子类别中。

我试图避免每个子类别中每个子类别的循环....

2 个答案:

答案 0 :(得分:1)

还有另一种存储/检索树层次结构的方法,如this fogbugz博文中所述:

  

原来这很酷   解决这个问题的解决方案   乔·塞尔科。而不是试图   保持一堆父母/孩子   整个数据库的关系    - 这将需要递归SQL查询来查找所有   节点的后代 - 我们标记每个节点   具有“左”和“右”值的情况   通过遍历树计算   深度优先,随着我们前进而计算。一个   节点的“左”值随时设置   在遍历期间首次出现,并且   行走时设置“正确”值   将树从节点上备份。   一张照片可能更有意义:

     

enter image description here

     

嵌套集SQL模型允许我们添加   案例层次结构而不牺牲   性能

     

这有什么用?现在我们问一下   对于具有“左”值的所有情况   在2到9之间找到所有的   B的后代在一个快速,索引   查询。 G的祖先被发现   要求“左”小于的节点   6(G自己的“左”)和“右”更大   比6.适用于所有数据库。   大大提高性能 -   特别是在查询大的时候   层次结构

Here's another post详细介绍。它是使用Sqlphp编写的,但我认为您可以获得它的要点并轻松地将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;
    }
}

这当然只有在您能够将元素确定为一个组时才有效。此解决方案是否更快也取决于组的大小。当您加载(并且不使用)的对象组非常大时,它实际上会降低应用程序的速度。