【问题标题】:Linq infinite nested queryLinq 无限嵌套查询
【发布时间】:2012-06-19 09:25:26
【问题描述】:

我需要通过 linq 获取嵌套集合的一个节点。

这是嵌套类:

public class Group
{

    public int Id { get; set; }

    public string Description { get; set; }

    public int ParentId { get; set; }

    public List<Group> Groups { get; set; }

}

此类的每个实例都可以在 Groups 方法中具有多个实例,依此类推。每个实例都通过 ParentId 属性链接。

我需要,有一个 Group 类的实例,检索他的父亲。我试过这个:

var parent = _repositoryGroups
.Where(g => g.Id == [my Group instance].ParentId)
.SelectMany(g => g.Groups)
.FirstOrDefault()

我不知道为什么,但它并不总是找到父实例并且它从第二层开始寻找(但这不是一个真正的问题)。

在这个嵌套类的所有深处找到元素的最佳方法是什么?

谢谢

【问题讨论】:

  • 我认为您在滥用 SelectMany。如果您删除该行,它应该可以工作
  • 我同意@Schiavini。如果没有SelectMany,查询将返回第一个具有所需 id 的组(返回父亲)。从该父项中选择所有组,然后取第一个组,看起来它会返回父项的第一个子项,显然不是父项。
  • 如果没有SelectMany,它将无法工作。它只检索第一级下的组...
  • 如果我理解你的问题,你只想要父母对吗?如果您想要父级的所有子级,请删除 FirstOrDefault 然后
  • 第 1 组 -> 第 2 组 -> 第 3 组 是的,我只想要父母。我的存储库中只有一个元素(第 1 组),我想知道第 3 组的父亲。我需要循环所有嵌套组,直到 Id 属性等于我的子元素的 ParentId。谢谢。

标签: c# linq nested


【解决方案1】:

现在听起来您想要递归地获取某个组的所有孩子。

所以你可以:

private IEnumerable<Group> EnumerateChildren(Group parent)
{
    if (parent.Groups != null)
    {
        foreach (var g in parent.Groups)
        {
            yield return g;

            foreach (var sub in EnumerateChildren(g))
            {
                yield return sub;
            }
        }
    }
}

如果您只想获取某个组的父级:

private Group GetParent(Group child)
{
    _repositoryGroups.Where(g => g.Id == child.ParentId).FirstOrDefault();
}

如果您需要获取某个组的超级父级(...的父级的父级的父级):

private Group GetSuperParent(Group child)
{
    parent = GetParent(child);

    while (parent != null)
    {
        child = parent;
        parent = GetParent(child);
    }

    return child;
}

最重要的是,我建议如果您能做到这一点,请保留对父级的引用,而不是其 Id。如果它没有父亲,就让它为空。省去了很多麻烦。很多。

【讨论】:

  • 它是children,而不是childs :-)
  • 我自己一直都喜欢它 :-)
  • @BigYellowCactus 现已修复:D
【解决方案2】:

如果你想上去你的结构并找到父母的最后一个父母,你可以使用这段代码:

var group = [my Group instance];

while(group.ParentId > 0)
{
    group = _repositoryGroups.First(g => g.Id == group.ParentId);
}

这假设您的 ID 大于零,并且 id>0 将始终具有有效的父级。

【讨论】:

  • 不保证有效 I​​D 大于零,也不保证该组一定有父亲,这将导致 First 因找不到任何 ID 而抛出异常。
  • 确实,我只是在答案中添加了我的假设
  • 我会考虑使用 FirstOrDefault,检查 null,并抛出“RepositoryGroups 已损坏 - 未找到父级”或类似的自定义异常,如果您仍然采用假设方法。跨度>
  • 这确实是一种有效的方法,但是我认为这段代码更容易理解,并且 Linq 抛出的 Exeption 就足够了。我相信这是一个品味问题。无论如何,我完全同意你关于引用父母而不是 ID 的评论。 Id 是一种误解,源于面向对象编程和关系数据库之间的差距。
【解决方案3】:

对不起各位,也许我没有很好地解释我的问题。我开发了这个解决方案来启发你的答案:

private static Group GetGroupFather(IEnumerable<Group> groups, Group child)

{

    foreach (var group in groups)
{

    // try to nested search
    var result = GetGroupFather(group.Groups, child);

    if (result != null) return result;

    // check in the current level
    if (group.Id == child.ParentId)

        return group;

}

return null;

}

如果您使用 linq 有更好的解决方案,请告诉我。

【讨论】:

  • 子对象根本没有变化。你不能用_repositoryGroups.FirstOrDefault(g =&gt; g.Id == child.ParentId)吗?
  • 我使用孩子只是为了获取父ID。我无法使用您的代码,因为它仅从_repositoryGroups 的第一级而不是从嵌套情况中检索组,例如,_repositoryGroups[0].Groups[2].Groups[1].Groups[2].id == child.ParentId
猜你喜欢
  • 1970-01-01
  • 2021-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多