递归Linq分组

时间:2011-03-05 18:16:43

标签: linq entity-framework linq-to-entities

方案: 我有数据库表,存储另一个表的多对多关系的层次结构。一个项目可以有多个子项,也可以有多个父项。

Items    
------ 
ItemID (key)

Hierarchy
---------
MemberID (key)
ParentItemID (fk)
ChildItemID (fk)

样本层次结构:

Level1  Level2  Level3
X       A       A1
                A2
        B       B1
                X1
Y       C

我想通过层次结构中的每个 节点对所有节点进行分组。

Parent  Child
X       A1
        A2
        B1
        X1
A       A1
        A2
B       B1
        X1
Y       C
  • 请注意Parent列中没有叶节点,以及Child列如何包含叶节点。
  • 理想情况下,我希望结果采用 IEnumerable&lt; IGrouping<项目,项目&gt;&gt; 的形式,其中密钥是父级,组项目都是子级。
  • 理想情况下,我想要一个实体提供商可以转换为T-SQL的解决方案,但如果不可能,那么我需要将往返次数降至最低。
  • 我打算对在叶子节点上连接的另一个表中存在的值求和。

2 个答案:

答案 0 :(得分:1)

由于您总是要返回表中的所有项,为什么不只是创建一个递归方法来获取父项的所有子项,然后在内存项上使用它:

partial class Items
{
    public IEnumerable<Item> GetAllChildren()
    {
        //recursively or otherwise get all the children (using the Hierarchy navigation property?)
    }
}

然后:

var items = 
    from item in Items.ToList()
    group new 
    {
        item.itemID,
        item.GetAllChildren()
    } by item.itemID;

对于任何语法错误抱歉...

答案 1 :(得分:0)

好吧,如果层次结构严格为2级,你可以随时将它们联合起来,让LINQ整理出SQL(虽然需要看看它在你的数据量上运行的速度有多快,但它最终只是一次旅行):

var hlist = from h in Hierarchies
            select new {h.Parent, h.Child};

var slist = from h in Hierarchies
            join h2 in hlist on h.Parent equals h2.Child
            select new {h2.Parent, h.Child};

hlist = hlist.Union(slist);

这会为您提供一个单独的IEnumerable<{Item, Item}>列表,因此如果您想对它们进行分组,请按照以下步骤操作:

var glist = from pc in hlist.AsEnumerable()
            group pc.Child by pc.Parent into g
            select new { Parent = g.Key, Children = g };

我在这里使用了AsEnumerable(),因为我们在尝试对Union进行分组时达到了LINQ SQL提供程序的功能。如果您针对IQueryable进行尝试,它将为可资格父母运行一个基本联盟,然后为每个父母进行往返(这是您想要避免的)。无论您是否可以使用常规LINQ进行分组,都可以通过管道获得相同数量的数据。

编辑:或者,您可以构建一个将父级链接到其所有子级的视图,并将该视图用作绑定项目的基础。从理论上讲,这应该允许你/ L2S通过一次旅行对其进行分组。