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

