You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 03:24:18