【问题标题】:Recursive Linq Grouping递归 Linq 分组
【发布时间】:2011-03-07 06:57:06
【问题描述】:

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

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
  • 注意父列中没有叶节点,子列只有包含叶节点。
  • 理想情况下,我希望结果采用 IEnumerableIGrouping<Item, Item>> 的形式,其中键是父项,组项都是子项。
  • 理想情况下,我想要一个实体提供程序可以转换为 T-SQL 的解决方案,但如果这不可能,那么我需要将往返行程保持在最低限度。
  • 我打算对叶节点上连接的另一个表中存在的值求和。

【问题讨论】:

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


    【解决方案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)它适用于单元测试,但我仍然需要针对数据库对其进行测试。如果效果好,我会接受你的回答。
    【解决方案2】:

    好吧,如果层次结构是严格的 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&lt;{Item, Item}&gt; 列表,因此如果您想对它们进行分组,您只需继续:

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

    我在这里使用了AsEnumerable(),因为我们达到了 LINQ SQL 提供程序的能力并尝试对联合进行分组。如果您针对 IQueryable 尝试它,它将为符合条件的父母运行一个基本的联合,然后为每个父母进行一次往返(这是您想要避免的)。您是否可以使用常规 LINQ 进行分组取决于您自己,无论哪种方式都必须通过管道传输相同数量的数据。

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

    【讨论】:

    • 我喜欢你的回答,但是至少会有 4 个级别,并且层次结构将是表驱动的(用户可配置),因此在运行时可以有任意数量的级别。出于这个原因,我将尝试使用递归,但我担心往返会影响性能。我稍后会跟进。
    • 您的层次结构有多大?如果你想减少往返,我认为你应该考虑一下这个 linq 框。您可能想要探索的一些选项: 1. 使用 sql server 层次结构支持并构建一个视图以生成您将在一次调用中获取的结果 2. 如果层次结构表不是太大,只需将整个内容加载到一个勺子中并建立一个层次分组客户端?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-05
    • 2012-01-29
    • 2011-06-16
    • 2017-08-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多