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

如何用Entity LINQ按ID和深度层级筛选递归子节点结果

树形节点的层级筛选解决方案(Entity Framework LINQ)

嘿,我来帮你搞定这个问题!看起来你需要在Entity Framework中实现基于指定节点和深度的树形结构筛选,我之前也处理过类似的需求,给你两种实用的方案:

先明确实体类

首先假设你的数据库表对应的EF实体类是这样的(和你的表结构对应):

public class TreeNode
{
    public int Id { get; set; }
    public int? ParentId { get; set; }
}

方案1:用EF Core递归CTE(推荐,性能最优)

如果你用的是EF Core 3.0及以上版本,递归CTE(公共表表达式)是最高效的方式,它能在单次数据库查询中完成层级遍历:

public IEnumerable<TreeNode> GetNodesByDepth(int targetId, int depth)
{
    using var context = new YourDbContext(); // 替换成你的DbContext类

    // 递归CTE查询,完全匹配你的示例需求
    var query = context.TreeNodes
        .FromSqlRaw($@"
            WITH RecursiveNodeHierarchy AS (
                -- 第一步:获取目标节点的直接子节点(对应示例中的level 1)
                SELECT ParentId, Id, 1 AS CurrentLevel
                FROM TreeNodes
                WHERE ParentId = {targetId}
                UNION ALL
                -- 第二步:递归获取下一级子节点,直到达到指定深度
                SELECT tn.ParentId, tn.Id, rnh.CurrentLevel + 1
                FROM TreeNodes tn
                JOIN RecursiveNodeHierarchy rnh ON tn.ParentId = rnh.Id
                WHERE rnh.CurrentLevel + 1 <= {depth}
            )
            SELECT ParentId, Id FROM RecursiveNodeHierarchy
        ")
        .ToList();

    return query;
}

对应你的示例验证:

  • 当传入targetId=2、depth=2时:
    1. 先获取ParentId=2的节点(也就是ID=3,CurrentLevel=1)
    2. 再递归获取ParentId=3的节点(ID=4、5、6,CurrentLevel=2)
      最终结果完全匹配你给出的示例。
  • 当传入targetId=3、depth=2时:
    1. 先获取ParentId=3的节点(ID=4、5、6,CurrentLevel=1)
    2. 再递归获取ParentId=4的节点(ID=7,CurrentLevel=2)
      正好是你要的结果。

方案2:纯LINQ递归(兼容所有EF版本,适合小数据量)

如果你的项目用的是旧版EF,或者不想写原生SQL,可以用纯LINQ的递归方法。不过要注意:这种方法会多次查询数据库,数据量大时性能会受影响。

public IEnumerable<TreeNode> GetNodesByDepth(int targetId, int depth)
{
    using var context = new YourDbContext();
    var result = new List<TreeNode>();

    // 先获取目标节点的第一层子节点
    var firstLevelChildren = context.TreeNodes.Where(n => n.ParentId == targetId).ToList();
    result.AddRange(firstLevelChildren);

    // 递归获取后续层级的子节点
    foreach (var child in firstLevelChildren)
    {
        GetChildNodesRecursive(context, child.Id, depth - 1, result);
    }

    return result;
}

private void GetChildNodesRecursive(YourDbContext context, int parentId, int remainingDepth, List<TreeNode> result)
{
    if (remainingDepth <= 1) return; // 已经达到指定深度,停止递归

    var children = context.TreeNodes.Where(n => n.ParentId == parentId).ToList();
    result.AddRange(children);

    foreach (var child in children)
    {
        GetChildNodesRecursive(context, child.Id, remainingDepth - 1, result);
    }
}

说明:

  • 这里的remainingDepth初始是depth,每递归一层减1,直到剩余深度为1时停止(因为第一层已经获取过了)。
  • 这个方法逻辑直观,适合节点数量不多的场景。

额外提示

如果你需要包含目标节点本身(比如深度层级包含目标节点在内),只需要调整CTE的初始查询部分:

-- 初始查询改为获取目标节点本身,层级设为0
SELECT ParentId, Id, 0 AS CurrentLevel
FROM TreeNodes
WHERE Id = {targetId}
-- 递归条件改为 CurrentLevel + 1 < {depth}
WHERE rnh.CurrentLevel + 1 < {depth}

这样就能包含目标节点,以及之后depth-1层的所有子节点。

内容的提问来源于stack exchange,提问作者user998405

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:59:08