【问题标题】:EF Core included nested self-referencing listEF Core 包含嵌套的自引用列表
【发布时间】:2018-04-03 01:53:18
【问题描述】:

我有一个看起来像这样的实体:

public class Comment
{
    public Guid Id { get; set; }
    public DateTime PublishedDate { get; set; }
    public string CommentText { get; set; }
    public bool IsEdited { get; set; }
    public bool IsDeleted { get; set; }
    public ICollection<Comment> Replies { get; set; }



    public int? ParentBlogId { get; set; }
    [ForeignKey("ParentBlogId")]
    public BlogPost ParentBlog { get; set; }

    public Guid? ParentCommentId { get; set; }
    [ForeignKey("ParentCommentId")]
    public Comment ParentComment { get; set; }

    public string UserId { get; set; }
    [ForeignKey("UserId")]
    public User User { get; set; }
}

现在你看到它包含一个相同类型的 ICollection。所以一个评论下可以有多个 cmets。当我想将所有这些加载到一个漂亮的嵌套列表中时,我尝试使用它:

var comments = await _context.Comments
                .Include(x => x.User)
                .Include(x => x.Replies)
                 .ThenInclude(x => x.User).ToListAsync();

问题是这只加载了 2 层深度。所以如果我有这样的结构:

Comment
Comment
    Comment
        Comment
        Comment
    Comment
Comment

它只会加载前 2 个关卡:

Comment
Comment
    Comment
    Comment
Comment

如何让它包含子回复的所有回复?

【问题讨论】:

  • 这些都不行。如我的示例所示,急切加载不起作用。由于 Select 语句,投影也不能。显式加载不起作用,因为我想要一个列表,而不是单个对象。并且 EF Core 中不存在延迟加载
  • 我很确定_context.Comments.ToList() 将加载所有级别。你确定你没有应用一些过滤器吗?
  • 或者加载单个评论的所有孙子,例如_context.Comments.Where( r =&gt; loadedComment.Replies.Select(c =&gt; c.Id).ToList().Contains(r.ParentCommentId).AsEnumerable().Last();

标签: c# entity-framework ef-core-2.0


【解决方案1】:

我是通过调用递归方法做到的:

    public async Task<List<Comment>> GetAsync(int blogId)
    {
        var comments = await _context.Comments
            .Include(x => x.User)
            .OrderByDescending(x => x.PublishedDate)
            .Where(x => x.ParentBlog.Id == blogId && !x.IsDeleted).ToListAsync();

        comments = await GetRepliesAsync(comments);


        return comments;
    }


    private async Task<List<Comment>> GetRepliesAsync(List<Comment> comments)
    {
        foreach (var comment in comments)
        {
            var replies = await GetFromParentIdAsync(comment.Id);
            if (replies != null)
            {
                comment.Replies = await GetRepliesAsync(replies.ToList());
            }
        }

        return comments;
    }

【讨论】:

  • 我一直在将一个项目迁移到 .NET Core 3.1,唯一的挫折是处理 EntityFrameworkCore。与 EF6 相比,API 发生了重大变化并且缺少功能。 EntityFramework Plus 库有助于处理 IncludeFilter 之类的一些事情,但我一直在思考如何加载应用了过滤器的自引用表。这有所帮助,尽管由于数据库命中和查询过多,它并不理想。 EFCore 的下一个版本支持包含过滤器,我们将看看它是如何发挥作用的。谢谢。
猜你喜欢
  • 1970-01-01
  • 2021-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多