Entity Framework Core 多级自连接分类动态查询实现方案咨询
搞定多级分类动态递归查询的几个实用思路
我太懂你现在的困扰了——硬编码好几层嵌套的Select不仅写着麻烦,遇到层级变多的情况完全没法适配。下面给你几个靠谱的改造方向,从易到难,按需选择:
1. 内存递归构建树形(最快上手)
如果你的分类数据量不算超大,这绝对是最省心的方式:先把所有分类一次性拉到内存,再用递归函数动态拼出嵌套的DTO结构,完全不用依赖数据库的特殊能力。
第一步,先获取全量分类数据:
var allCategories = await Context.MultiLevelCategories.ToListAsync();
第二步,写一个递归方法生成树形结构:
private List<MultiLevelCategoryDetailsDto> BuildCategoryTree(Guid? parentId, List<MultiLevelCategory> allCategories) { return allCategories .Where(c => c.ParentCategoryId == parentId) .Select(c => new MultiLevelCategoryDetailsDto { Id = c.Id, Name = c.Name, ParentId = c.ParentCategoryId, // 递归调用自身,生成子节点的树形结构 Children = BuildCategoryTree(c.Id, allCategories) }) .ToList(); }
第三步,调用方法获取根节点(ParentId为null的分类):
var dynamicCategoryTree = BuildCategoryTree(null, allCategories);
这种方式的优点是代码简洁、逻辑直观,不用改数据库;缺点是如果分类数据量极大,一次性加载到内存会有性能压力。
2. 数据库层面递归查询(EF Core 5+ 推荐)
如果你的数据库支持递归CTE(比如SQL Server、PostgreSQL、MySQL 8+),可以让数据库直接处理递归逻辑,再把结果拿到内存组装成DTO,性能会更优:
用EF Core原生的递归查询语法(EF Core 5及以上支持):
// 定义递归查询 var recursiveQuery = Context.MultiLevelCategories .Where(c => c.ParentCategoryId == null) .Select(c => new { Category = c, Level = 0 }) .UnionAll( from c in Context.MultiLevelCategories from parent in recursiveQuery where c.ParentCategoryId == parent.Category.Id select new { Category = c, Level = parent.Level + 1 } ); // 把递归结果加载到内存 var allNodes = await recursiveQuery.Select(x => x.Category).ToListAsync(); // 再用第一步的递归方法构建树形 var dynamicCategoryTree = BuildCategoryTree(null, allNodes);
也可以直接用原生SQL的CTE查询:
var cteSql = @" WITH RecursiveCategories AS ( SELECT Id, Name, ParentCategoryId, 0 AS Level FROM MultiLevelCategories WHERE ParentCategoryId IS NULL UNION ALL SELECT c.Id, c.Name, c.ParentCategoryId, rc.Level + 1 FROM MultiLevelCategories c JOIN RecursiveCategories rc ON c.ParentCategoryId = rc.Id ) SELECT * FROM RecursiveCategories;"; var allNodes = await Context.MultiLevelCategories.FromSqlRaw(cteSql).ToListAsync(); var dynamicCategoryTree = BuildCategoryTree(null, allNodes);
这种方式的优势是数据库层面做过滤和递归,减少内存处理的数据量,适合大数据量的场景。
3. 利用HierarchyId(SQL Server专属进阶方案)
如果用的是SQL Server,可以给表加一个HierarchyId类型的字段,专门存储层级路径,查询树形结构会更高效,也不用写递归代码。不过这个需要调整数据库结构,适合长期优化的场景。
对比你原来的代码
原来的硬编码嵌套只能支持固定4层子级,而上面的动态方案可以适配任意深度的分类层级——不管后续新增多少子级,代码都不用改动,维护成本低太多。
内容的提问来源于stack exchange,提问作者hussam morjan
相关产品推荐
相关产品推荐

