在C#中模拟CTE递归

假设有以下CTE返回我所拥有的某些树数据(邻接模型)的级别(取自Linq中的分层数据 – 选项和性能 ):

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中进行递归是否会有任何性能提升。 任何人都可以告诉我如何使用递归C#函数执行CTE所做的相同工作,假设我有一个IQueryable,其中Tree是一个表示分层表中条目的实体? 有点像:

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

很容易看到使用lambda表达式很容易做到这一点。

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

我不得不说T-SQL有些限制,但它从来没有打算首先做所有这些操作。 我不相信你有任何办法可以通过IQueryable实现这一点,如果你想对你的SQL Server实例运行这个,但你可以在运行代码的机器上的内存中使用LINQ-to-Objects相对紧凑的方式。

这是一种方法:

 class TreeNode { public int Id; public int? ParentId; } static void Main(string[] args) { var list = new List{ 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> Level(List list, int? parentId, int lvl) { return list .Where(x => x.ParentId == parentId) .SelectMany(x => new[] { new KeyValuePair(x.Id, lvl) }.Concat(Level(list, x.Id, lvl + 1)) ); } 

真正的递归lambdas(并通过推论, Expression s)在技术上是可能的,但非常疯狂 。 我也希望任何解析器(L2S,EF等)除了LINQ-to-Objects之外只是疯狂试图解开它。

简而言之:您最好将此视为Expression不支持的机制。

最后,请注意,仅仅因为您正在编写Expression并不意味着您在C#中执行它 – 事实上,可能恰恰相反:如果您正在积极编写Expression (而不是委托或程序代码),我会认为它是去解析器(除非你使用.AsQueryable()将它推送到LINQ-to-Objects)。