如何使用LINQ按深度级别订购对象层次结构?

Mar*_*eIV 7 c# linq sorting hierarchy hierarchical-data

考虑这个层次结构

                     A
                     |
        --------------------------
        |                        |
        B                        C
        |                        |
--------|--------            ---------
|       |       |            |       |
D       E       F            G       H
|       |                    |       |
|   ---------             -------    |
|   |       |             |     |    |
I   J       K             L     M    N
Run Code Online (Sandbox Code Playgroud)

每个对象都有一个Parent属性和一个choldren的Items集合,因此,例如,E的父级为B,N为H,等等.对于父级,A的值为null.B.Items包含DF等

什么是LINQ语句,我可以根据它们的级别对它们进行排序?我不关心一个级别内的排序顺序(即DH的顺序无关紧要,但它们必须在B和C之后来到A之后.

我能想到的只有两个独立的linq语句:

  1. 对此运行聚合,计算并存储级别
  2. 对Level的结果排序运行第二个LINQ查询.

B当然很容易.这是我正在努力的事情.我当然可以在程序上做到这一点,但我必须认为这可以简化为LINQ语句.

Mar*_*zek 7

您没有指定查询的目标是什么,因此有多个正确的答案:

  1. LINQ to SQL或LINQ to Entities - 不存在对递归查询的支持,因此您必须将数据加载到内存中并执行LINQ to Objects查询,或者在数据库中使用存储过程(最有可能使用公用表)表达).您还可以在数据库中准备VIEW并将其映射到EF模型.

  2. LINQ to Objects更适合这项工作,但IMO你仍然可以通过计算深度的简单方法获得最佳效果:

    public static int GetDepth(Item item)
    {
        int d = 0;
        while ((item = item.Parent) != null)
            d++;
        return d;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    以后查询非常简单

    var results = from item in data
                  let depth = GetDepth(item)
                  orderby depth descending
                  select item;
    
    Run Code Online (Sandbox Code Playgroud)

    如果您的数据结构不同,那么只编写一个LINQ to Objects查询会很容易,而且Parent有所有子项的链接.在这种情况下,查询数据更容易,因为每个项目都有一组依赖项目,LINQ适用于集合,对象是单个项目,如您的Parent属性.我写了一篇关于使用LINQ查询对象层次结构的博客文章,你可能会发现它很有趣.