我在 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 in Entity Framework?
更新
我在主题中添加了一列 Byte[] Illustration 类型的列。在我的投影中,我没有包含该列,因此如果我使用“包含”,它会被加载吗?或者永远不会加载,除非我把它放在投影中?
在从 Microsoft 方面寻找您的问题的官方答案时,我发现了 Diego Vega(实体框架和 .NET 团队的一部分)的这句话 在 aspnet/Announcements github 上发表 存储库:
在查看用户 LINQ 查询时,我们看到的一个非常常见的问题是使用 Include(),这是不必要的,也不能被尊重。典型的模式通常看起来像这样:
var pids = context.Orders .Include(o => o.Product) .Where(o => o.Product.Name == "Baked Beans") .Select(o =>o.ProductId) .ToList();
人们可能会认为此处的 Include 操作是必需的,因为在Where 和Select 操作中引用了Product 导航属性。然而,在 EF Core 中,这两件事是正交的:包括在最终结果返回的实体中加载导航属性的控件,并且我们的 LINQ 翻译器可以直接翻译涉及导航属性的表达式。
您不需要 Include,因为您是在 EF 上下文中工作。当您在创建的匿名对象中引用 Theme 时,这不是使用延迟加载,而是告诉 EF 进行联接。
如果您返回书籍列表并且不包含主题,那么当您尝试获取主题时,您会发现它是空的。如果 EF 连接打开并且您有延迟加载,它将转到数据库并为您抓取它。但是,如果连接未打开,那么您必须显式获取它。
另一方面,如果您使用 Include,您会立即获得数据。在幕后,它将执行 JOIN 到必要的表并在那里获取数据。
您可以检查 EF 为您生成的 SQL 查询,这会让您更清楚。您只会看到一个 SQL 查询。
如果您
Include
是一个子项,它会作为原始查询的一部分加载,这会使其更大。
如果您不
Include
或在查询中以其他方式引用子项,则初始结果集会较小,但您稍后引用的每个子项将通过对数据库的新请求进行延迟加载。
如果您在一个请求中循环访问 1000 个用户,然后分别询问他们的 10 张照片,那么如果您不这样做,您将发出 1001 个数据库请求
Include
孩子...
此外,延迟加载要求上下文尚未被释放。例如,当您将实体传递给视图以进行 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;