【问题标题】:Query children and its children until there are no children simplified查询children及其children,直到没有children简化
【发布时间】:2013-07-11 16:44:16
【问题描述】:

假设我们有一个具有以下属性的实体:

public class Foo    
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int? ParentId { get; set; }
}

孩子是具有非空 ParentId 的任何 Foo。可以有多个级别的父/子关系,此时最多为 5 个。

是否有一种简单的 LINQ 方式或通用方法可以从 Foo 开始并获取其所有子项、其子项的子项、以及子项的子项的子项等?

目前,我正在遍历初始父项的每个子项,然后再次循环以获取该子项的所有子项,等等。这很乏味,而且似乎不是完成我想要的正确方法。

【问题讨论】:

  • 你这里有一些查找表来获取孩子吗?听起来你想要一个给定的“父母”Foo 并获得它的孩子,但是没有获得孩子的机制。您在此处拥有的数据模型允许我们将树向上爬到父级,但不能遍历向下它。
  • 我只有一张桌子,Foo。给定一个 Foo 对象,为了得到它的子对象,我查询所有具有 ParentId = x 的 Foo。然后,对于这些孩子中的每一个,我查询 ParentId = 前一个父母的孩子的 ID,等等。我需要更改什么以包含一种机制,使我能够简化获取所有孩子及其孩子的过程?
  • 对不起,我忽略了这是使用实体框架。

标签: c# asp.net-mvc linq entity-framework


【解决方案1】:

我更喜欢维护一个表示层次结构中位置的字符串属性。例如,如果值为“/99/42”,那么您知道该项目属于属于 99 的父项 42。这很好的原因是因为您可以展平整个 Foos 集合并查询该字段那些以“/99”开头的,你会得到层次结构的整个分支。所以你的班级应该是这样的:

public class Foo    
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Path { get; set; } //eg: /99/42
}

希望对您有所帮助。

【讨论】:

  • +1 我喜欢这个。我想知道是否有内置方法或各种方法可以完成此操作。
  • 我不知道任何内置的东西。不过实现起来也不是太难。维护并不比您已经在做的 ParentId 事情难多少。如果您想出更简单的方法,请告诉我。
  • 与其将所有 ID 粘在一个需要解析的字符串中,不如只使用带有所有 ID 的 IEnumerable<int>(或某些特定集合)。那你就不用担心解析逻辑了。
  • @Josh 嗯,大多数树结构都引用了它们的子节点,并且可能有也可能没有引用它们的父节点。这是标准解决方案。
  • @Servy 你提到他们的孩子是什么意思? ParentId 不是对父级的引用吗?因此,要获取所有孩子,您将使用该 parentId 查询所有 Foos?
【解决方案2】:

因此,如果 all 您拥有的是一个 Foo 对象,那么不,您无法获得它的所有后代。至少,您还需要有一系列 all Foo 对象,以便找到以该对象为父对象的节点,因为您的 Foo 对象没有'还没有提到它的孩子。如果你确实有这个顺序,那么这并不是特别难。

您可以在所有 foo 的序列上使用 ToLookup 来为该 ID 值的所有子项创建 ID 查找:

var allFoos = new List<Foo>();

var childrenLookup = allFoos.ToLookup(foo => foo.ParentId);

要获取特定孩子的所有后代的序列,您现在可以进行简单的树遍历:

public static IEnumerable<Foo> Descendants(Foo foo, ILookup<int?, Foo> childrenLookup)
{
    var stack = new Stack<Foo>();
    stack.Push(foo);

    while (stack.Any())
    {
        var next = stack.Pop();
        yield return next;

        foreach (var child in childrenLookup[next.Id])
            stack.Push(child);
    }
}

【讨论】:

    猜你喜欢
    • 2019-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-16
    • 1970-01-01
    相关资源
    最近更新 更多