首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >包含,选择不返回的嵌套对象。

问包含,选择不返回的嵌套对象。
EN

Stack Overflow用户
提问于 2018-05-11 12:51:47
回答 1查看 213关注 0票数 0

嗨,我是LINQ、EF和Im的新手,我试图理解为什么下面的代码不返回嵌套实体,即使我使用include显式地加载它们

代码语言:javascript
复制
 var x = await _context.AuthorBooks.Where(ub => ub.AuthorId == authorId)
                                .Include(ub => ub.Book)
                                    .ThenInclude (b=> b.Chapters)
                                    .Select(ub => ub.Book).ToListAsync();

AuthorBooks是链接对象,我可以在其中应用过滤器,只从特定作者中选择书籍。

我试图为给定的作者选择带章节的所有图书的列表,但是上面的代码返回书籍列表,但是没有嵌套的章节。

有什么帮助吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-14 14:49:19

解释

你在触及EF中确实存在的一种行为。

问题在于EF如何处理数据加载。默认情况下,它加载对象的所有标量属性,但不加载导航属性。

Include通过告诉EF还包括指定的导航属性(以及它的所有标量属性)来影响这种行为。

但是我们到了Select。当您使用它时,本质上是给出要检索的固定的列列表。EF将仅限于您提到的字段。

代码语言:javascript
复制
var x1 = _context.Books.Select(b => b.Name).ToList();

这将导致只检索单个列的查询。

代码语言:javascript
复制
var x2 = _context.AuthorBooks.Select(ab => ab.Book).ToList();

由于您指的是导航属性(没有在其中指定任何特定的标量属性),EF使用它的默认行为加载导航属性的所有标量属性。查询将获取X列(其中X是Book中标量属性的数量)。

代码语言:javascript
复制
var x3 = _context.AuthorBooks.Select(ab => ab.Book.Name).ToList();

这将再次导致只检索单个列的查询,因为您引用了特定的标量属性。

解决方案

Select**.** 1.反转查询,因此不需要

这对你目前的情况是有效的,但并不适用于所有的情况。

代码语言:javascript
复制
 var x = await _context.Books
                        .Include(b=> b.Chapters)
                        .Where(b => b.AuthorBooks.Any(ab => ab.AuthorId == authorId))
                        .ToListAsync();

Select 2.在检索数据后执行.

对于您的情况,这将导致加载AuthorBook实体,这是不理想的。这是可行的,但您获取的数据比您需要的多。但是,在1.不是可行方法的情况下,这种方法更好

代码语言:javascript
复制
 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()

Select 3.显式地将想要的数据添加到

代码语言:javascript
复制
 var x = await _context.AuthorBooks.Where(ub => ub.AuthorId == authorId)
                                .Select(ub => new {
                                           Book = ub.Book,
                                           Chapters = ub.Book.Chapters
                                        });
  • 注意您是如何不需要Include语句的。因为您正在显式地告诉EF它应该检索什么,所以它不需要依赖于关于应该加载哪些导航属性的隐式说明。
  • 您可以使用元组或类来代替任何名称类型。返回类型由您来决定,只需确保显式引用所需的所有数据(所有引用的实体都将自动加载标量属性)。

4.在Include Select**.**之后添加

由于NetMage在评论中首先提到了它,所以可以使用Credits。

代码语言:javascript
复制
 var x = await _context.AuthorBooks.Where(ub => ub.AuthorId == authorId)
                                .Select(ub => ub.Book)
                                .Include(b => b.Chapters)
                                .ToListAsync();

请注意,前面的包含并不是必需的,因为后续的Select无论如何都会重写它们。

在我看来,选项4是最干净的解决方案。

但是,如果只对导航属性的子集感兴趣,则选项3更好。例如,如果您只想获得具有最小字数的章节:

代码语言:javascript
复制
 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加载所有相关属性。显式Select为您提供了加载相关属性子集的选项,从而降低了要传输的数据量。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50292776

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档