2010-10-06 39 views
4

我有一个类叫做Structure有没有一种方法,使用LINQ/EF获取父/子层次结构中最顶级的项目?

public class Structure 
{ 
    public int StructureId { get; set; } 
    public Structure Parent { get; set; } 
} 

正如你所看到的,Structure有父Structure。这个层次结构中可以有无限数量的结构。

有没有什么办法,使用LINQ(与实体框架),在这个层次结构中获得最顶级的结构?

目前,我不得不击中数据库几次,以找到最上面的父母。最顶端的母公司是一个Structure用空Parent属性:

Structure structure = structureRepository.Get(id); 
while (structure.Parent != null) 
{ 
    structure = structureRepository.Get(structure.Parent.StructureId); 
} 

// When we're here; `structure` is now the top most parent. 

那么,有没有任何优雅的方式来做到这一点使用LINQ/Lambda表达式?理想的情况下,开始用下面的代码:

var structureQuery = from item in context.Structures 
        where item.StructureId == structureId 
        select item; 

我只是希望能够写出像下面这样我只火了一个数据库命中:

structureQuery = Magic(structureQuery); 
Structure topMostParent = structureQuery.Single(); 
+0

我不认为这是可能的,但我很好奇其他人可能想出的解决方案...... – jeroenh 2010-10-06 15:22:39

+1

哪个数据库,MSSQL? – 2010-10-06 15:22:59

+0

@Nick - MS SQL 2005. @jeroenh - 是的,我也不这么认为。我编写了当前完成这项工作的存储过程,并且它自己碰到了数据库几次。 – GenericTypeTea 2010-10-06 15:24:09

回答

2

我想我会得到最好的是从结构加载整个层次一重击我想要的顶部父:

var structureQuery = from item in context.Structures 
         .Include(x => x.Parent) 
        where item.StructureId == structureId 
        select item; 

然后,只需使用代码:

while (structure.Parent != null) 
{ 
    structure = structure.Parent; 
} 
-1

我喜欢这个问题,并能没有想到这样做的方式。但是,您是否可以在存储库类上实现这个功能?毕竟,顶端应该只有一个,如果需要它,那么也许它应该是structureRepository.GetRoot()什么的。

+0

感谢您的输入,但它在我的资源库中(我给出的代码是一个示例,而不是我的资源库类),这不是答案;也许你应该删除它并将其表示为注释:)。 – GenericTypeTea 2010-10-06 15:25:29

-4

你可以使用LINQ取结构,例如

  var first3Customers = (
       from c in customers 
       select new {c.CustomerID, c.CustomerName}) 
      .Take(2); 
+2

你真的读过这个问题吗? – jeroenh 2010-10-06 15:37:05

+0

哈哈哈!我想(希望)有人的同伴压力徽章瞄准在这里... – teedyay 2010-10-06 16:15:26

0

我有类似的情况。我没有设法直接用LINQ/EF解决它。相反,我通过使用递归公用表表达式创建数据库视图来解决,如here所述。我创建了一个用户定义的函数,它将所有父项应用于子项(反之亦然),然后创建一个使用此用户定义函数的视图,该函数已导入到EF对象上下文中。

(免责声明:简化代码,我其实没有测试这个)

我有两个表,说MyTable的(包含所有项目),并含有childID的,的ParentId关系

然后我定义MyParentChildTable以下UDF:

CREATE FUNCTION dbo.fn_getsupertree(@childid AS INT) 
    RETURNS @TREE TABLE 
(
    ChildId INT NOT NULL 
    ,ParentId INT NULL 
    ,Level INT NOT NULL 
) 
AS 
BEGIN 
    WITH Parent_Tree(ChildId, ParentId) 
    AS 
    ( 
    -- Anchor Member (AM) 
    SELECT ChildId, ParentId, 0 
    FROM MyParentChildTable 
    WHERE ChildId = @childid 

    UNION all 

    -- Recursive Member (RM) 
    SELECT info.ChildId, info.ParentId, tree.[Level]+1 
    FROM MyParentChildTable AS info 
     JOIN Parent_Tree AS tree 
     ON info.ChildId = tree.ParentId 
) 
    INSERT INTO @TREE 
    SELECT * FROM Parent_Tree; 

    RETURN 
END 

和以下观点:

CREATE VIEW VwSuperTree AS (
SELECT tree.* 
FROM MyTable 
CROSS APPLY fn_getsupertree(MyTable.Id) as tree 
) 
GO 

这给了我每个孩子,所有父母都有他们的“树木级别”(直接父母有1级,父母父母有2级,等等)。从这个角度来看,查询具有最高级别的项目很容易。我只是在我的EF上下文中导入了视图,以便能够使用LINQ查询它。

+0

是的,我已经有类似的东西了。我目前正试图将尽可能多的存储过程转移到EF。这可能是那些必须作为存储过程保留的那些之一。 – GenericTypeTea 2010-10-06 15:39:29

2

这不是一个直接的答案,但是您遇到的问题与您存储树的方式有关。有几种方法通过对数据进行不同的结构来简化查询。

一个是使用Nested Set Hierarchy,它可以简化树中的多种查询。

另一种方法是存储祖先/后裔/深度元组的非均值表。然后,该查询将查找具有当前结构的元组作为具有最大深度的后代。

+0

我正在使用MS SQL 2005.从未听说过NSHs。 – GenericTypeTea 2010-10-06 15:48:11

+1

@GenericTypeTea这不是数据库引擎功能,只是构建数据的一种方式,以便可以使用标准SQL轻松查询。下面是关于SQL Server的讨论:http://blogs.msdn.com/b/anthonybloesch/archive/2006/02/15/hierarchies-in-sql-server-2005.aspx – 2010-10-06 17:21:01

+0

有趣的方法 – jeroenh 2010-10-06 17:42:31

相关问题