Entity framework 实体框架导航属性预加载/重用
当我期望可以从EF缓存抓取对象时,为什么实体框架会执行查询 使用这些简单的模型类:Entity framework 实体框架导航属性预加载/重用,entity-framework,linq,eager-loading,Entity Framework,Linq,Eager Loading,当我期望可以从EF缓存抓取对象时,为什么实体框架会执行查询 使用这些简单的模型类: public class Blog { public int Id { get; set; } public string Name { get; set; } public virtual ICollection<Post> Posts { get; set; } } public class Post { public int Id { get; set; }
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
public string Content { get; set; }
public virtual Blog Blog { get; set; }
}
public class BlogDbContext : DbContext
{
public BlogDbContext() : base("BlogDbContext") {}
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
}
公共类博客
{
公共int Id{get;set;}
公共字符串名称{get;set;}
公共虚拟ICollection Posts{get;set;}
}
公营职位
{
公共int Id{get;set;}
公共字符串内容{get;set;}
公共虚拟博客{get;set;}
}
公共类BlogDbContext:DbContext
{
public BlogDbContext():base(“BlogDbContext”){}
公共数据库集博客{get;set;}
公共DbSet Posts{get;set;}
}
我分析了以下操作的查询
public class HomeController : Controller
{
public ActionResult Index()
{
var ctx = new BlogDbContext();
// expecting posts are retrieved and cached by EF
var posts = ctx.Posts.ToList();
var blogs = ctx.Blogs.ToList();
var wholeContent = "";
foreach (var blog in blogs)
foreach (var post in blog.Posts) // <- query is executed
wholeContent += post.Content;
return Content(wholeContent);
}
}
公共类HomeController:控制器
{
公共行动结果索引()
{
var ctx=new BlogDbContext();
//EF检索并缓存预期的帖子
var posts=ctx.posts.ToList();
var blogs=ctx.blogs.ToList();
var wholeContent=“”;
foreach(博客中的var博客)
foreach(blog.Posts中的var post)/当您启用延迟加载时,EF仍将重新加载集合导航属性。可能是因为EF不知道您是否真的加载了所有帖子。例如
var post = db.Posts.First();
var relatedPosts = post.Blog.Posts.ToList();
这将是一个棘手的问题,因为博客上已经加载了一篇文章,但显然其他的都需要抓取
在任何情况下,当依赖更改跟踪器来修复导航属性时,无论如何都应该禁用延迟加载
using (var db = new BlogDbContext())
{
db.Configuration.LazyLoadingEnabled = false;
. . .
如果您有导航属性,请考虑在查询中利用它们为Automapper提供一个动态对象以映射到ViewModel/DTO,而不是依赖于急加载或等待延迟加载的顶级实体
这是通过发出.Select()来完成的在您的查询中。要使用一个提取订单详细信息的简单示例,包括客户名称、订单行中的产品名称和数量列表以及交货地址,其中订单引用了客户,而该客户有交货地址、订单行集合,每个订单行都有一个产品
var orderDetails = dbContext.Orders
.Where(o => /* Insert criteria */)
.Select(o => new
{
o.OrderId,
o.OrderNumber,
o.Customer.CustomerId,
CustomerName = x.Customer.FullName,
o.Customer.DeliveryAddress, // Address entity if no further dependencies, or extract fields/relations from the Address.
o.OrderLines.Select( ol = > new
{
ol.OrderLineId,
ProductName = ol.Product.Name,
ol.Quantity
}
}).ToList(); // Ready to feed into Automapper.
使用~20 includes,您的选择无疑会更加复杂,但我们的想法是向SQL Server提供一个查询,以检索您想要的数据,然后您可以将这些数据输入Automapper,在其中导航,任何子关系都可以通过EF展平或简化,并返回给您的映射器,以充实到生成的mod中埃尔斯
<> P>随着系统的增长,你也要考虑使用分页/W跳过,而不是使用托勒斯,或者至少杠杆来确保你的数据量有一个上限。托利特是我在EF代码中寻找的一个主要性能巨魔,因为它的误用会杀死应用程序。但是我们知道我们加载了所有需要的数据,禁用LazyLoadingEnabled可以实现EF的“神奇”绑定。