Entity framework 实体框架导航属性预加载/重用

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; }

当我期望可以从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 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的“神奇”绑定。