C# 避免笛卡尔爆炸而不拆分所有包含项

C# 避免笛卡尔爆炸而不拆分所有包含项,c#,entity-framework-core,C#,Entity Framework Core,我有一个实体Post,它与Author和Comment有一对多的关系。我想加载所有Posts,并将第一个作者和所有评论加入其中。包含Include的代码如下所示: Post[]posts=ctx.posts.Include(p=>p.Authors.Take(1)).Include(p=>p.Comments.ToArray(); 此查询存在笛卡尔爆炸问题。如果Post拥有n注释,作者和注释将在结果集中重复n次 解决方案#1 在EF Core 5.0中,我可以使用一个,但当我想加载Postwi

我有一个实体
Post
,它与
Author
Comment
有一对多的关系。我想加载所有
Post
s,并将第一个
作者和所有
评论加入其中。包含
Include
的代码如下所示:

Post[]posts=ctx.posts.Include(p=>p.Authors.Take(1)).Include(p=>p.Comments.ToArray();
此查询存在笛卡尔爆炸问题。如果
Post
拥有
n
注释
作者
注释
将在结果集中重复
n

解决方案#1 在EF Core 5.0中,我可以使用一个,但当我想加载
Post
with
Author
,然后加载所有
注释时,会生成3个查询

解决方案#2 首先,用
Author
加载
Post
,然后在Post上迭代他们的评论,但这将生成
n+1
查询

Post[]posts=ctx.posts.Include(p=>p.Authors.Take(1)).ToArray();
foreach(以职位为单位的职位)
ctx.Entry(post.Collection)(p=>p.Comments.Load();
解决方案#3 首先,使用
Author
加载
Post
,然后收集所有Post ID以生成单个查询来加载注释

Dictionary postsbyd=ctx.Posts.Include(p=>p.Authors.Take(1)).todictionary(p=>p.Id);
Comment[]comments=ctx.comments.Where(c=>postsById.ContainsKey(c.PostId)).ToArray();
foreach(注释中的注释)
postsById[comment.posted].Comments.Add(comment);//如何避免重新添加评论?

这个解决方案只会生成2个查询,没有任何重复的数据,但我如何避免将评论再次添加到帖子中?有没有比这3个建议的解决方案更好的方法?

我会添加另一个选项。因为我是
linq2db
中渴望加载的作者。我很确定它只会运行两个查询

所以只需安装这个扩展(EF Core 3.1.x的3.x版本和EF Core 5.x的5.x版本)

然后尝试以下查询:

Post[]posts=ctx.posts
.Include(p=>p.Author)
.Include(p=>p.Comments)
.ToLinqToDB()
.ToArray();

此外,这种方法还应适用于AutoMapper的
ProjectTo
和完全自定义的投影。我知道自定义投影不适用于
AsSplitQuery
(因为我尝试过它)

我找到了一种方法,使解决方案#2只适用于此处的两个查询:

intpostids=new[]{3,4};
Post[]posts=ctx.posts
.Include(p=>p.Authors.Take(1))
.Where(p=>postIds.Contains(p.Id))
.ToArray();
//此行自动填充同一DbContext中的POST注释。
ctx.评论
其中(c=>postIds.Contains(c.PostId))
.Load();

EF知道如何处理结果集。你总是得到独特的帖子。似乎您正在尝试解决一个不存在的问题。我遇到了一个类似的问题-
Include
中的交叉连接最终会随着相关记录数量的增加,从SQL查询中产生大量结果集。对于这些类型的查询,我最终切换到ADO——这让我可以手动拆分查询,并同时运行它们(因为EF不是线程安全的)。性能的提升日以继夜。@GertArnold我这里的问题不是正确性,而是性能。我想对帖子和作者进行一次查询,对评论进行第二次查询。我注意到我的例子过于简单化了。对于一对一关系,EF core知道它不必创建新查询,只需使用联接即可。我编辑了我的示例以反映我的问题。Post现在与Author有一对多的关系,我希望帖子中有他们的第一位作者和他们的所有评论。@我希望避免编写任何SQL,因为我在开发环境中使用内存提供程序。是的,我现在明白了,但从您的第一篇描述中看不出这一点,它似乎集中在数据复制上(这当然会影响性能,尤其是使用重复的长字符串)。看起来您对EFC相关问题的所有答案都是使用Linq2Db桥接:-)我应该承认这可能是“正确”的事情。为什么不呢。人们之所以选择简洁,是因为EF Core不会像新手一样支持某些事情或这样做。更糟糕的是,我偶尔会关注他们的问题。翻译包含5-6个包含项的LINQ查询需要20秒,这太糟糕了。好消息是这样做不会损害数据库服务器;)@伊凡斯托夫,和他们战斗;)我真的不明白为什么它是被禁止的。这很容易,可以挽救生命(几周)。通常,我们的扩展用户会准确地说:“您的扩展是救命恩人”,我为此感到自豪;)@GertArnold,明白了。我是新来的,所以有些细微差别仍然不是直观的。