何时使用Include in EF?投影中不需要?

时间:2016-06-28 18:30:48

标签: entity-framework entity-framework-core

我在Entity Framework Core中有以下内容:

public class Book {
  public Int32 Id { get; set; }
  public String Title { get; set; }
  public virtual Theme Theme { get; set; }
}

public class Theme {
  public Int32 Id { get; set; }
  public String Name { get; set; }
  public Byte[] Illustration { get; set; }
  public virtual ICollection<Ebook> Ebooks { get; set; }
}

我有以下linq查询:

List<BookModel> books = await context.Books.Select(x =>
  new BookModel {
    Id = x.Id,
    Name = x.Name,
    Theme = new ThemeModel {
      Id = x.Theme.Id,
      Name = x.Theme.Name
    }
   }).ToListAsync();

我不需要包含主题来完成这项工作,例如:

List<BookModel> books = await context.Books.Include(x => x.Theme).Select(x => ...

我什么时候需要在实体框架中使用Include?

更新

我在主题中添加了Byte []插图类型的列。在我的预测中,我不包括该列,如果我使用Include,它会加载吗?或者永远不会加载,除非我在投影中有它?

3 个答案:

答案 0 :(得分:4)

如果您Include是孩子,则会将其作为原始查询的一部分加载,从而使其更大。

如果您没有Include或在查询中以其他方式引用子项,则初始结果集较小,但您稍后引用的每个子项将通过对数据库的新请求延迟加载。

如果您在一个请求中循环浏览了1000个用户,然后每个请求他们的10张照片,那么如果您没有Include孩子,则会提出1001个数据库请求...

此外,延迟加载需要上下文尚未处理。例如,当您将实体传递给视图以进行UI渲染时,总是令人不快的惊喜。

<强>更新 以此为例,看看它失败了:

var book = await context.Books.First();
var theme = book.Theme;

然后试试这个:

var book = await context.Books.Include(b => b.Theme).First();
var theme = book.Theme;

答案 1 :(得分:4)

您不需要Include,因为您在EF上下文中工作。当你在正在创建的匿名对象中引用Theme时,那就是不使用延迟加载,那就是告诉EF进行连接。

如果您返回书籍列表并且未包含主题,那么当您尝试获取主题时,您会注意到它是空的。如果EF连接已打开并且您有延迟加载,它将转到数据库并为您抓取它。但是,如果没有打开连接,那么你必须明确地得到它。

另一方面,如果您使用Include,则可以立即获得数据。在引擎盖下,它将连接到必要的表并在那里获取数据。

您可以检查EF为您生成的SQL查询,这样可以让您更清楚。您将只看到一个SQL查询。

答案 2 :(得分:1)

在寻找微软方面对您的问题的正式答案时,我从迭戈·维加(实体框架和.NET团队的成员)made at the aspnet/Announcements github repository找到了这句话:

  

在查看用户LINQ查询时,我们看到的一个非常普遍的问题是在没有必要且无法兑现的情况下使用Include()。典型的模式通常看起来像这样:

var pids = context.Orders
    .Include(o => o.Product)
    .Where(o => o.Product.Name == "Baked Beans")
    .Select(o =>o.ProductId)
    .ToList();
     

由于在Where和Select操作中对Product导航属性的引用,因此可能会认为此处需要Include操作。但是,在EF Core中,这两件事是正交的:包括控制在最终结果中返回的实体中加载了哪些导航属性,而我们的LINQ转换器可以直接转换涉及导航属性的表达式。