EntityFramework:包含导航属性与包含选择属性之间的差异



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

架构

假设我有一个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));
}

它似乎不包括CCD_ 9实体。事实上,我得到了以下错误:

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的情况下实现我想要的?我想在这里进行静态类型检查。

这里发生了什么?

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

语法非常清楚:

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

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

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

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

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

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

投影和Includes相互排斥。在投影中,没有任何内容可以包含导航属性。类似以下查询:

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

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

最新更新