You need to enable JavaScript to run this app. C# 如何优化LINQ查询以递归构建最多三级TreeView对象集合
优惠活动
大模型
产品
解决方案
定价
更多

C# 如何优化LINQ查询以递归构建最多三级TreeView对象集合

原代码存在的核心问题
  • 性能浪费:三层嵌套查询每一层都遍历全量models集合,数据量较大时会产生多次全集合扫描,整体时间复杂度为O(3n),没有利用哈希索引的查找优势。
  • 逻辑错误:第三层孙节点的查询条件写为where grand.Id == child.Id,完全不符合父子关联规则,只会匹配Id和子节点一致的对象,根本无法正确挂载孙级节点,正确的关联逻辑应该是孙节点的ParentId等于子节点的Id。
  • 代码冗余:三层嵌套里重复写了三遍从原始对象映射属性的逻辑,后续要调整字段映射,需要同时修改三处代码,维护成本高。
  • 耦合性强:层级判断硬编码在嵌套查询里,写死了三级结构,后续如果层级规则调整,需要大段修改嵌套查询逻辑。
  • 方法无返回:原GetItems方法返回值为void,构建完成的lists变量没有对外输出,实际业务拿不到构建好的树形结构。
优化实现方案

核心优化思路

  1. 用ToLookup预构建按ParentId分组的子节点索引,把子节点查找的时间复杂度从O(n)降到O(1),整个索引构建只需要一次全集合遍历。
  2. 抽取公共的节点映射方法,消除重复的属性赋值代码。
  3. 把硬编码的三层嵌套改成递归挂载的逻辑,修正原有的关联查询错误,同时兼容后续层级调整。

优化后代码

public class TreeView
{
    public TreeView()
    {
        Children = new List<TreeView>();
    }

    public int Id { get; set; }
    public int ParentId { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public List<TreeView> Children { get; set; }
}

public static class TreeBuildHelper
{
    // 公共节点映射逻辑,避免重复赋值
    private static TreeView MapNode(TreeView source)
    {
        return new TreeView
        {
            Id = source.Id,
            ParentId = source.ParentId,
            Name = source.Name,
            Address = source.Address
        };
    }

    // 递归挂载子节点
    private static void MountChildren(TreeView parent, ILookup<int, TreeView> childIndex)
    {
        // 直接从预构建的索引取当前节点的所有直接子节点
        foreach (var childSource in childIndex[parent.Id])
        {
            var childNode = MapNode(childSource);
            // 递归挂载当前子节点的下级
            MountChildren(childNode, childIndex);
            parent.Children.Add(childNode);
        }
    }

    public static List<TreeView> GetItems(List<TreeView> models)
    {
        const int rootId = 10;
        // 预构建按ParentId分组的子节点索引,仅一次全集合遍历
        var childIndex = models.ToLookup(m => m.ParentId);
        
        // 查找根节点
        var rootSource = models.First(m => m.Id == rootId);
        var rootNode = MapNode(rootSource);
        
        // 递归构建完整树形结构
        MountChildren(rootNode, childIndex);
        return new List<TreeView> { rootNode };
    }
}

额外说明

  • 因为业务约束层级最多为三级,这套递归实现完全可以覆盖需求,不会出现无限递归的问题。如果后续需要限制最大递归深度,只需要在MountChildren方法里加层级计数判断即可。
  • 原代码中给子节点硬编码赋值ParentId = mod.Id的逻辑也同步做了修正,直接使用源数据本身的ParentId值,避免人为赋值覆盖真实数据。

内容的提问来源于stack exchange,提问作者mnu-nasir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.02 00:36:04