【问题标题】:EntityFramework: Discrepency between Includes with Navigation Property vs. Includes with Select?实体框架:包含导航属性与包含与选择之间的差异?
【发布时间】:2022-01-12 23:12:35
【问题描述】:

这更像是一个语法问题,而不是实际的错误或错误,因为我终于得到了我想要的工作。但我想了解并改进我当前的解决方案。

架构

假设我有一个Users 表,与表Posts 具有一对多关系,还有一个Authors 的一对一关系表——每个Post 一个。

我想编写一个自定义存储库函数来获取所有Users、所有Posts、每个Author 每个Post

尝试 #1(不起作用)

我想我可以这样做:

public IQueryable<User> GetUsersWithPostsAndAuthors()
{
    var query = GetAll();

    // include all details on user object
    return query
        .Include(user => user.Posts.Select(x => x.Author));
}

它似乎不包括Author 实体。实际上,我收到以下错误:

Lambda expression used inside Include is not valid.

尝试 #2(也不起作用)

然后我想也许那些Posts需要先在查询中,所以我尝试了这个:

public IQueryable<User> GetUsersWithPostsAndAuthors()
{
    var query = GetAll();

    // include all details on user object
    return query
        .Include(user => user.Posts)
        .Include(user => user.Posts.Select(x => x.Author)
}

不幸的是,我得到了同样的错误:

Lambda expression used inside Include is not valid.

尝试 #3(成功!)

但是,如果我使用Include 的版本,您可以提供string navigationPropertyPath(实际上我不喜欢它,因为它只是一个硬编码的字符串),如下所示:

public IQueryable<User> GetUsersWithPostsAndAuthors()
{
    var query = GetAll();

    // include all details on user object
    return query
        .Include(user => user.Posts)
        .Include("Posts.Author");
}

查询按预期工作!

这里发生了什么?我认为Select 投影与Include 的作用相同。 (而且 Stackoverflow 上似乎有一些答案暗示了这一点。)

更重要的是,有没有一种方法可以实现我想要的,而无需在 Include 调用中对 Posts.Author 进行硬编码?我想在这里进行静态类型检查。

【问题讨论】:

  • query.Include(user =&gt; user.Posts).ThenInclude(post =&gt; post.Author) 是您正在寻找的。您可以在 Microsoft Docs 中找到此文档以及更多详细文档

标签: c# entity-framework-core


【解决方案1】:

这是怎么回事?

无意冒犯,只是不太了解Include 的用途。它仅用于包含导航属性,而不用于投影。

语法很清楚:

  • Include 用于查询根目录之外的导航属性:

    .Include(user => user.Posts)
    
  • ThenInclude 用于包含导航属性的导航属性:

    .Include(user => user.Posts).ThenInclude(p => p.Author)
    

后一个示例等效于.Include("Posts.Author"),但由于编译时检查,首选 lambda 语法。在旧的 EF6 版本中没有 ThenInclude,包含更多级别的语法如您所写:.Include(user =&gt; user.Posts.Select(x =&gt; x.Author))

投影是 LINQ 查询中的 Select,而不是 Include 语句中的。例如:

return query.Select(u => new { u.Id, u.Name });

Projections 和Includes 相互排斥。在投影中没有可以包含导航属性的内容。像这样的查询:

return query
    .Include(u => u.Posts)
    .Select(u => new 
    {
        u.Id, 
        u.Name,
        Posts = u.Posts.Select(p => p.Title)
    });

将完全忽略Include。在生成的 SQL 中没有它的踪迹:只会查询 Post.Title,而不是像 Include 那样查询所有的 Post 字段。

【讨论】:

  • Select 的使用可能表明它们来自 EF6 并且不知道 ThenInclude 替换。
  • @Ivan Yep,补充说。
  • @fullStackChris 只是好奇,你能举一些你提到的“一些答案”的例子吗?我经常注意到这确实是一个令人困惑的领域。我在this answer 写了更多关于这个领域的文章。
  • 啊,我完全不知道ThenInclude!非常好!这里有两个帖子让我误入歧途,尽管我意识到他们最初的问题与我想要的有点不同(或者可能不是?):stackoverflow.com/questions/23469481/… 和这里:stackoverflow.com/questions/24120039/…
  • @fullStackChris 这些帖子适用于与 EF Core 不同的 EF6(“经典”EF)。 EF6 使用(并且仍然使用)Select syntax 来解析包含集合元素属性的编译时 lambda。 EF Core 简单介绍并使用了一个特殊的方法ThenInclude 来解决同样的语法问题。
猜你喜欢
  • 1970-01-01
  • 2013-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-02-15
  • 1970-01-01
相关资源
最近更新 更多