这更多的是一个语法问题,而不是一个实际的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
字段