为什么在EF中导航属性默认是虚拟的

57

我在EF 6.x中使用以下POCO类。

我的问题:为什么在'Blog'实体下的'Posts'导航属性被声明为virtual?

public class Blog 
{  
    public int BlogId { get; set; }  
    public string Name { get; set; }  
    public string Url { get; set; }  
    public string Tags { get; set; }  

    public virtual ICollection<Post> Posts { get; set; }  
}

1个回答

101
如果你将导航属性定义为 virtual ,Entity Framework将在运行时创建一个新的类(动态代理),该类派生自你的类,并使用它来替代原始类。这个新创建的动态类包含逻辑,以在第一次访问时加载导航属性。这被称为“延迟加载”。它使Entity Framework避免从数据库中加载不需要的整个依赖对象树。
在某些情况下,最好使用“急切加载”,特别是如果你知道你将在某个时候与相关对象交互。
Julie Lerman真的是所有Entity Framework事物的权威,她在她的MSDN文章Demystifying Entity Framework Strategies: Loading Related Data中非常好地解释了这个过程。
使用Include进行急切加载在以下情况下非常有用:您预先知道要查询的所有核心数据的相关数据。但请记住两个潜在的缺点。如果您有太多的Includes或导航路径,则实体框架可能会生成性能不佳的查询。并且,由于使用Include编码很容易,因此应谨慎返回不必要的相关数据。 Lazy Loading非常方便地为您检索相关数据,以响应简单提及该相关数据的代码。它也使编码更简单,但您应该注意它与数据库的交互量。您可能会导致40次访问数据库,而只需要一两次。
如果您正在开发每次与服务器通信都是新上下文的Web应用程序,那么懒惰加载将仅创建不必要的开销,以维护永远不会加载的相关对象的动态类。在这些情况下,许多人将禁用延迟加载。最终,还是最好评估EF构建的SQL查询,并确定哪些选项适合您正在开发的场景。

6
我不完全同意这个观点,即在Web应用程序中懒加载没有益处。尽管在无状态应用程序中每次都会创建新的上下文,但不同的存储库调用可能需要从同一上下文中获取不同的数据。例如,在相同的订单聚合根中,您可能想要在此次加载产品集合,但在另一个方法中加载ShippingStatusHistory集合。在上下文dbset级别使用延迟加载允许您在不同的方法中选择不同的数据。 - Calvin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接