c# - 在 C# 中模拟 CTE 递归

标签 c# sql entity-framework-4 recursion common-table-expression

假设有以下 CTE 返回我拥有的一些树数据(邻接模型)的级别(取自 Hierarchical data in Linq - options and performance ):

WITH hierarchy_cte(id, parent_id, data, lvl) AS
(
    SELECT id, parent_id, data, 0 AS lvl
    FROM dbo.hierarchical_table
    WHERE (parent_id IS NULL)

    UNION ALL

    SELECT t1.id, t1.parent_id, t1.data, h.lvl + 1 AS lvl
    FROM dbo.hierarchical_table AS t1 
    INNER JOIN hierarchy_cte AS h ON t1.parent_id = h.id
)
SELECT id, parent_id, data, lvl
FROM hierarchy_cte AS result

我想知道在 C# 而不是 SQL 中执行递归是否会提高性能。任何人都可以告诉我如何执行 CTE 使用递归 C# 函数执行的相同工作,假设我有一个 IQueryable,其中 Tree 是表示分层表中条目的实体?类似的东西:

public void RecurseTree(IQueryable<Tree> tree, Guid userId, Guid parentId, int level)
{
    ...
    currentNode.level = x
    ...
    Recurse(tree... ,level + 1)
}

如果使用 lambda 表达式很容易做到这一点,那就太好了。

最佳答案

通过比较,SQL Server 中的递归非常慢,但它确实有效。

我不得不说 T-SQL 有一定的局限性,但它从一开始就不打算执行所有这些操作。如果您打算针对 SQL Server 实例运行 IQueryable,我不相信有任何方法可以实现这一点,但您可以在运行代码的机器上的内存中使用 LINQ-to-Objects 以相对紧凑的方式。

这是一种方法:

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

static void Main(string[] args)
{
    var list = new List<TreeNode>{
        new TreeNode{ Id = 1 },
            new TreeNode{ Id = 4, ParentId = 1 },
            new TreeNode{ Id = 5, ParentId = 1 },
            new TreeNode{ Id = 6, ParentId = 1 },
        new TreeNode{ Id = 2 },
            new TreeNode{ Id = 7, ParentId= 2 },
                new TreeNode{ Id = 8, ParentId= 7 },
        new TreeNode{ Id = 3 },
    };

    foreach (var item in Level(list, null, 0))
    {
        Console.WriteLine("Id={0}, Level={1}", item.Key, item.Value);
    }
}

private static IEnumerable<KeyValuePair<int,int>> Level(List<TreeNode> list, int? parentId, int lvl)
{
    return list
        .Where(x => x.ParentId == parentId)
        .SelectMany(x => 
            new[] { new KeyValuePair<int, int>(x.Id, lvl) }.Concat(Level(list, x.Id, lvl + 1))
        );
}

关于c# - 在 C# 中模拟 CTE 递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6225123/

相关文章:

c# - 如何在 C# 中运行多个任务并在完成这些任务时获取事件?

sql - 如果结果为 true,则返回列名称

c# - 使用 EventArgs 中的可写属性向事件调用者提供反馈

c# - C# 循环后如何获取最后的结果

c# - 获取月初和月末日期的最简单方法是什么?

使用字符串操作的 PHP SQL 注入(inject)预防

sql - 从集合类型插入表 oracle 12c - ORA-00902 : invalid datatype

c# - 在 EF4.1 代码中,如何覆盖 Web.config 中的 ConnectionString 名称

entity-framework-4 - 带有 oracle 插入父级和子级的 Entity Framework

entity-framework-4 - 是否有 EF4 Fluent API 语法的引用?