[英]Include, select nested objects not returning
Hi Im new to LINQ and EF and im trying to understand why the below code doesn't return the nested entities even though I explicitly load them using the include 嗨,我是LINQ和EF的新手,我试图了解以下代码为什么不返回嵌套实体,即使我使用include显式加载它们也是如此
var x = await _context.AuthorBooks.Where(ub => ub.AuthorId == authorId)
.Include(ub => ub.Book)
.ThenInclude (b=> b.Chapters)
.Select(ub => ub.Book).ToListAsync();
AuthorBooks is the linking object and where I can apply the filter to select only books from the specific author. AuthorBooks是链接对象,在这里我可以应用过滤器以仅从特定作者中选择书籍。
I am trying to select the list of all Books with chapters for the given author but the above code returns the list of books but without the nested Chapters. 我正在尝试为给定作者选择带有章节的所有书籍的列表,但是上面的代码返回了没有嵌套章节的书籍列表。
Any help? 有什么帮助吗?
You're touching on a behavior that does exist in EF. 您正在触及EF中确实存在的行为。
The problem lies in how EF handles the loading of data. 问题在于EF如何处理数据加载。 By default, it loads all scalar properties of an object, but not the navigational properties.
默认情况下,它加载对象的所有标量属性,但不加载导航属性。
Include
influences this behavior, by telling EF to also include a specified navigational property (with all of its scalar properties) Include
通过告诉EF 还包括指定的导航属性(及其所有标量属性)来影响此行为。
But then we get to Select
. 但是随后我们进入
Select
。 When you use this, you are essentially giving a fixed list of columns that you want to retrieve. 使用此功能时,实际上是在提供要检索的固定列列表。 EF will limit itself to the fields that you mention.
EF会将自己限制在您提到的字段中。
var x1 = _context.Books.Select(b => b.Name).ToList();
This will result in a query that only retrieves a single column. 这将导致查询仅检索单个列。
var x2 = _context.AuthorBooks.Select(ab => ab.Book).ToList();
Since you're referring to a navigational property (without specifying any particular scalar property inside), EF uses its default behavior of loading all of the navigational property's scalar properties. 由于您指的是导航属性(在内部未指定任何特定的标量属性),因此EF使用其默认行为加载所有导航属性的标量属性。 The query will fetch X columns (where X is the amount of scalar properties in
Book
). 该查询将获取X列(其中X是
Book
中标量属性的数量)。
var x3 = _context.AuthorBooks.Select(ab => ab.Book.Name).ToList();
This again will result in a query that only retrieves a single column, since you reference a specific scalar property. 这再次将导致查询仅检索单个列,因为您引用了特定的标量属性。
1. Invert the query so you don't need Select
. 1.反转查询,因此您不需要
Select
。
This works for your current case, but won't work for everything. 这适用于您当前的情况,但不适用于所有情况。
var x = await _context.Books
.Include(b=> b.Chapters)
.Where(b => b.AuthorBooks.Any(ab => ab.AuthorId == authorId))
.ToListAsync();
2. Perform the Select
after retrieving the data. 2.检索数据后执行
Select
。
For your case, this will cause you to load the AuthorBook
entities, which is not ideal. 对于您的情况,这将导致您加载
AuthorBook
实体,这是不理想的。 It works, but you're fetching more data than you need. 它可以工作,但是您获取的数据超出了需要。 However, this approach is better in cases where 1. is not a viable approach
但是,这种方法在以下情况下更好1。
var x = await _context.AuthorBooks
.Include(ub => ub.Book)
.ThenInclude(b=> b.Chapters)
.Where(ub => ub.AuthorId == authorId)
//Fetch the data
.ToList()
//Now transform the result
.Select(ub => ub.Book)
.ToListAsync()
3. Explicitly add the data you want to the Select
3.明确将所需数据添加到“
Select
var x = await _context.AuthorBooks.Where(ub => ub.AuthorId == authorId)
.Select(ub => new {
Book = ub.Book,
Chapters = ub.Book.Chapters
});
Include
statements. Include
语句。 Since you're explicitly telling EF what it should retrieve, it doesn't need to rely on implicit instructions about what navigational properties it should load. 4. Add an Include
after the Select
. 4.在“
Select
之后添加一个“ Include
”。
Credits go to NetMage for mentioning it first in the comments. 感谢NetMage在评论中首先提到它。
var x = await _context.AuthorBooks.Where(ub => ub.AuthorId == authorId)
.Select(ub => ub.Book)
.Include(b => b.Chapters)
.ToListAsync();
Note that the earlier includes are not necessary since the subsequent Select
overrides them anyway. 注意,前面的包含不是必需的,因为后续的
Select
仍然会覆盖它们。
Option 4 is the cleanest solution, in my opinion. 我认为选项4是最干净的解决方案。
However, option 3 is better if you're only interested in a subset of the navigational properties. 但是,如果您只对导航属性的子集感兴趣,那么选项3更好。 For example, if you only want to get chapters with a minimum word count:
例如,如果您只想获得最少字数的章节:
var x = await _context.AuthorBooks.Where(ub => ub.AuthorId == authorId)
.Select(ub => new {
Book = ub.Book,
Chapters = ub.Book.Chapters.Where(c => c.WordCount > 1000)
});
Include
loads all related properties. Include
加载所有相关属性。 An explicit Select
give you the option of loading a subset of related properties, thus lowering the amount of data to transfer. 显式
Select
使您可以选择加载相关属性的子集,从而减少要传输的数据量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.