如何在ASP.NET Core 6中按自定义层级条件分组Ledgercode实体?
ASP.NET Core 6中Entity Framework Core实现Ledgercode层级分组解决方案
问题背景
现有Ledgercode实体类和LedgercodeDto数据传输类:
实体类
public class Ledgercode { public Guid Id { get; set; } public string Code { get; set; } }
Code属性为1-10位数字字符串,需按如下规则构建层级:
- 子级Code是父级Code的后续延伸(如10是1的子级,100是10的子级)
- 若不存在中间层级(如无30、300),则3000直接归为3的子级
原递归实现中,使用StartsWith导致所有前缀匹配的节点都被当作直接子级(如1的子级包含10和100),不符合层级要求。
DTO类
public class LedgercodeDto { public Guid Id { get; set; } public string Code { get; set; } public List<LedgercodeDto> Children { get; set; } public LedgercodeDto(Ledgercode ledgercode) { Id = ledgercode.Id; Code = ledgercode.Code; } }
解决方案
优化后的实现代码
public async Task<IEnumerable<LedgercodeDto>> GetLedgercodesAsync() { // 加载所有符合条件的Ledgercode并转为Dto var allLedgercodes = await _context.Ledgercodes .AsNoTracking() .Where(l => l.Code == "1" || l.Code == "3" || l.Code.StartsWith("1") || l.Code.StartsWith("3")) .Select(l => new LedgercodeDto(l)) .ToListAsync(); // 按Code长度升序排序,确保父节点优先处理 var sortedCodes = allLedgercodes.OrderBy(l => l.Code.Length).ToList(); // 构建Code到Dto的字典,用于快速查找 var codeLookup = sortedCodes.ToDictionary(dto => dto.Code); foreach (var dto in sortedCodes) { dto.Children = new List<LedgercodeDto>(); // 从最长的可能父级Code开始查找,找到第一个存在的父节点 for (int length = dto.Code.Length - 1; length >= 1; length--) { string parentCode = dto.Code.Substring(0, length); if (codeLookup.TryGetValue(parentCode, out var parentDto)) { parentDto.Children.Add(dto); break; } } } // 返回指定的根节点(1和3) return sortedCodes.Where(dto => dto.Code is "1" or "3"); }
逻辑说明
- 加载数据:一次性加载所有根节点(1、3)及其子节点,避免多次查询数据库
- 排序处理:按Code长度升序排序,确保父节点在子节点之前被处理
- 快速查找:用字典存储Code与Dto的映射,提升父节点查找效率
- 层级构建:对每个节点,从最长的前缀开始尝试匹配父节点,找到第一个存在的节点后,将当前节点加入其Children集合,确保仅关联直接父级
测试验证
针对示例数据1,10,100,1000,10000000,10000001,10000100,3,30,3095,30951809,执行后会生成目标层级结构:
-1 -10 -100 -1000 -10000000 -10000001 -10000100 -3 -30 -3095 -30951809
内容的提问来源于stack exchange,提问作者Nico Fourie
相关产品推荐
相关产品推荐

