16

我不熟悉 SQL 和实体框架(ADO.NET 实体映射)中的这种递归。我正在做一个评论管理,我有一个Comments表格,表格包含列NewsID, CommentID, ParentCommentID, IndentLevel, CreatedTime

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

CommentID | time | ParentCommentID
Guid1     |  t1  | null
Guid4     |  t4  | Guid1
Guid2     |  t2  | null
Guid3     |  t3  | Guid2

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

到目前为止我所了解的是(来自互联网资源和以前的 stackoverflow Q/A)

  • 如图所示,这些递归查询很慢。并且使用实体框架执行此操作甚至更慢。但它可以实现。
  • 因此,可以通过在 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 
  • 但在尝试这个之前,我想尝试一下 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)); 

}

我在一个方法中使用它如下:

return ArrangeComments(commentList,null , 0);

我已经尝试过了,似乎我无处可去。尽管有关于 SQL 递归的解释,但 Linq 的示例较少,而且由于不太熟悉,对我来说也很模糊。有人可以帮我理解 Linq 中的这个 CTE 递归很棒吗

提前致谢

4

3 回答 3

29

AFAIK 在 LINQ 和 EF 中都不支持递归 CTE。解决方案是将 CTE 公开为视图。有关使用 EF 代码优先和迁移的递归或分层查询的文章展示了如何使用 EF 代码优先迁移部署此类视图。

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

于 2012-08-13T07:33:44.307 回答
5

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

在 linq-to-sql 中使用 Linq 写入 CTE 查询是不可能的 公用表表达式 (CTE)?

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

于 2012-08-13T07:34:26.027 回答
4

在花了几个小时阅读这个问题后,我决定用 C# 来完成,而不必创建数据库视图。

注意:仅将其用于非性能关键操作。来自http://nosalan.blogspot.se/2012/09/hierarchical-data-and-entity-framework-4.html的 1000 个节点性能示例。

Loading 1000 cat. with navigation properties took 15259 ms 
Loading 1000 cat. with stored procedure took 169 ms

代码:

public class Category 
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Name { get; set; }

    public int? ParentId { get; set; }

    public virtual Category Parent { get; set; }

    public virtual ICollection<Category> Children { get; set; }

    private IList<Category> allParentsList = new List<Category>();

    public IEnumerable<Category> AllParents()
    {
        var parent = Parent;
        while (!(parent is null))
        {
            allParentsList.Add(parent);
            parent = parent.Parent;
        }
        return allParentsList;
    }

    public IEnumerable<Category> AllChildren()
    {
        yield return this;
        foreach (var child in Children)
        foreach (var granChild in child.AllChildren())
        {
            yield return granChild;
        }
    }   
}
于 2017-09-14T19:43:39.137 回答