EntityFramework:包含导航 属性 与包含 Select 之间存在差异?
EntityFramework: Discrepency between Includes with Navigation Property vs. Includes with Select?
这更像是一个语法问题,而不是实际的错误或错误,因为我终于得到了我想要的工作。但我想了解并改进我目前的解决方案。
架构
假设我有一个 Users
table,与 table Posts
有一对多的关系,还有一个一对一的关系Authors
的关系 table - 每个 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
的效果相同。 (在 Whosebug 上似乎有一些答案表明了这一点。)
更重要的是,有没有一种方法可以在不对 Include
调用中的 Posts.Author
进行硬编码的情况下完成我想要的?我想在这里进行静态类型检查。
What is going on here?
无意冒犯,只是不太明白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)
});
将完全忽略Include
。在生成的 SQL 中没有它的踪迹:只有 Post.Title
会被查询,而不是所有 Post
字段,就像 Include
会做的那样。
这更像是一个语法问题,而不是实际的错误或错误,因为我终于得到了我想要的工作。但我想了解并改进我目前的解决方案。
架构
假设我有一个 Users
table,与 table Posts
有一对多的关系,还有一个一对一的关系Authors
的关系 table - 每个 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
的效果相同。 (在 Whosebug 上似乎有一些答案表明了这一点。)
更重要的是,有没有一种方法可以在不对 Include
调用中的 Posts.Author
进行硬编码的情况下完成我想要的?我想在这里进行静态类型检查。
What is going on here?
无意冒犯,只是不太明白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)
});
将完全忽略Include
。在生成的 SQL 中没有它的踪迹:只有 Post.Title
会被查询,而不是所有 Post
字段,就像 Include
会做的那样。