EF Core递归模型同级节点按Name字段字母排序实现方法
问题描述
当前开发环境为 .NET Core 3.1 + Microsoft.EntityFrameworkCore 3.1.9,定义了如下递归分类模型:
[Table("category", Schema = "test")] public partial class Category { public Category() { InverseIdParentNavigation = new HashSet<Category>(); } [Key] [Column("id")] public int Id { get; set; } [Column("id_parent")] public int? IdParent { get; set; } [Required] [Column("name")] [StringLength(128)] public string Name { get; set; } [ForeignKey(nameof(IdParent))] [InverseProperty(nameof(Category.InverseIdParentNavigation))] public virtual Category IdParentNavigation { get; set; } [InverseProperty(nameof(Category.IdParentNavigation))] public virtual ICollection<Category> InverseIdParentNavigation { get; set; } }
需要实现分类层级内按Name字段字母顺序排序,预期排序结构如下:
Root_1 j k l Root_2 a b a b c
具体排序规则:
- 0级根节点:
Root_1 < Root_2 - 1级子节点:
j < k < l、a < b < c - 2级子节点:
a < b
实现方案
根据业务中分类层级是否固定,选择对应方案即可。
方案1:固定层级场景(推荐,数据库侧排序性能更好)
如果业务上分类层级是固定的(比如最多3级),直接在查询时通过Include给每一层子集合指定排序规则,EF Core 3.1原生支持集合导航属性加载时排序:
// 示例为最多3级分类的场景 var categories = await _context.Category // 先筛选所有根节点(无父节点) .Where(c => c.IdParent == null) // 根节点排序 .OrderBy(c => c.Name) // 加载1级子节点并按Name排序 .Include(c => c.InverseIdParentNavigation.OrderBy(child => child.Name)) // 加载2级子节点并按Name排序 .ThenInclude(child => child.InverseIdParentNavigation.OrderBy(grandChild => grandChild.Name)) // 存在更深层级时,继续追加ThenInclude配置对应层级排序即可 .ToListAsync();
方案2:动态层级场景(内存递归排序,适配任意深度)
如果分类层级不固定,无法提前写死ThenInclude的层数,可以先把全量分类数据查询到内存,再递归组装排序后的树形结构:
// 第一步:查询全部分类,基础排序在数据库侧完成减少内存计算 var allCategories = await _context.Category .AsNoTracking() .OrderBy(c => c.Name) .ToListAsync(); // 递归方法:获取指定父节点下排序完成的所有子节点 List<Category> BuildSortedCategoryTree(int? parentId) { var currentLevelNodes = allCategories .Where(c => c.IdParent == parentId) .ToList(); foreach (var node in currentLevelNodes) { // 递归给当前节点赋值排序后的子集合 node.InverseIdParentNavigation = BuildSortedCategoryTree(node.Id); } return currentLevelNodes; } // 传入parentId为null,得到所有排序完成的根节点集合 var sortedResult = BuildSortedCategoryTree(null);
这个方案不受层级深度限制,任意层级的节点都会严格按照Name字段字母顺序升序排列,和预期结果完全一致。
内容的提问来源于stack exchange,提问作者Aleks Vujic
相关产品推荐
相关产品推荐

