使用Entity Framework Fluent语法或内联语法编写递归CTE

diy*_*da_ 12 c# linq sql-server entity-framework

我是SQL和实体框架(ADO.NET实体映射)中的新递归.我正在进行评论管理,我有一个Comments表,表包含列NewsID, CommentID, ParentCommentID, IndentLevel, CreatedTime.

我正在尝试获取特定新闻项目的评论列表,其中所有评论都是根据父母和创建时间下的孩子排列的,如下所示:

CommentID | time | ParentCommentID
Guid1     |  t1  | null
Guid4     |  t4  | Guid1
Guid2     |  t2  | null
Guid3     |  t3  | Guid2
Run Code Online (Sandbox Code Playgroud)

必须优先考虑子父母关系,然后是创建时间.

到目前为止我所倾向的是(来自互联网资源和之前的stackoverflow Q/A)

  • 如图所示,这些递归查询很慢.使用Entity Framework执行此操作甚至更慢.但它可以实现.
  • 因此,可以通过在SQL Server中创建存储过程并使用功能导入来调用它来完成.另一件事是在实体框架中使用Linq.
  • 在SQL Server中,它以此格式使用

SQL:

WITH cte_name ( column_name [,...n] ) 
AS 
( 
CTE_query_definition –- Anchor member is defined. 
UNION ALL 
CTE_query_definition –- Recursive member is defined referencing cte_name. 
) 
-- Statement using the CTE 
SELECT * 
FROM cte_name 
Run Code Online (Sandbox Code Playgroud)
  • 但在尝试之前我想试试Linq.

为此,我参考了这个链接,我有了这个想法:https: //stackoverflow.com/a/6225373/892788

但我试图理解代码但是徒劳无功.有人能给我一个关于在实体框架中编写递归CTE的更好更详细的解释吗?

private IEnumerable<NewsComment> ArrangeComments(IEnumerable<NewsComment> commentsList, string parentNewsComntID, int level) 
{
        Guid parentNewsCommentID;
        if (parentNewsComntID != null)
        {
            parentNewsCommentID = new Guid(parentNewsComntID);
        }
        else
            parentNewsCommentID = Guid.Empty;

        return commentsList.Where(x => x.ParentCommentID == parentNewsCommentID).SelectMany(x => new[] { x }.Concat(ArrangeComments(commentsList, x.NewsCommentID.ToString(), level + 1)); 

}
Run Code Online (Sandbox Code Playgroud)

我在下面的方法中使用它如下:

return ArrangeComments(commentList,null , 0);
Run Code Online (Sandbox Code Playgroud)

我试过了它们,似乎我无处可去.虽然有关于SQL递归的解释,Linq的例子较少,而且由于不太熟悉而对我来说含糊不清.有人可以帮我理解Linq中的这个CTE递归很棒

提前致谢

Rem*_*anu 25

AFAIK不支持LINQ和EF中的递归CTE.解决方案是将CTE作为视图公开.有关使用EF Code First和Migrations的递归或分层查询的文章显示了如何使用EF代码首次迁移来部署此类视图.

尝试通过递归客户端迭代来模拟CTE不会扩展到大型数据集并导致与服务器的繁琐交换.请注意您的EF代码IEnumerable不返回IQueryable,这意味着它实现了每个级别,然后将每个条目的下一级连接为单独的请求.基于LINQ的解决方案将适用于具有有限条目数的浅层次结构(并且注意许多项目可以具有这样的数据布局,用户帖子/答案是典型示例),但是在具有许多元素的深层次结构下将崩溃.

  • 非常感谢.我已经选择了这个项目.我提出了另一个解决方案,我引入了一个索引:AA AB AC用于家长评论,AAAB AAAC用于AA评论的孩子,就像明智一样.这可用于每条评论26*26儿童评论.因此,当我们获取列表时,我们只需将其升序并获取列表. (2认同)
  • @Diode 非常简洁的解决方案 (2认同)

Mar*_*rty 5

将 CTE 查询放到 StoredProcedure 中,然后从 Code 中调用它。EF 提供了这样做的所有方法(调用 SP 并检索结果)。我为自己做了同样的事情,效果很好。

在 linq-to-sql 中不可能使用 Linq 写入 CTE 查询

Sample ArrangeComments 是一个调用自身的递归过程,但我敢于质疑它的性能。它从数据库中提取记录,然后在内存中应用操作。

  • 我试过了,效果很好。但是当我们考虑性能时,为排列好的评论创建视图更方便。因为将元素添加到已经排序的列表中比一遍又一遍地递归要少。非常感谢您的回答。 (2认同)