Entity Framework 4.1 之三 : 贪婪加载和延迟加载
2011-05-07 10:20
246 查看
原文名称:Entity Framework 4.1: Deep Fetch vs Lazy Load (3)
原文地址:http://vincentlauzon.wordpress.com/2011/04/11/entity-framework-4-1-deep-fetch-vs-lazy-load-3/
看到 Entity Framework 4.1 推荐英文教程,为了帮大家看起来方便一些,简单翻译一下。这是一个系列,共有 8 篇,这是第 3 篇。
Entity Framework 4.1 之一 : 基础
Entity Framework 4.1 之二 : 覆盖默认的约定
Entity Framework 4.1 之三 : 贪婪加载和延迟加载
Entity Framework 4.1 之四:复杂类型
Entity Framework 4.1 之五:多对多的关系
Entity Framework 4.1 之六:乐观并发
Entity Framework 4.1 之七:继承
Entity Framework 4.1 之八:绕过 EF 查询映射
这篇文章将讨论查询结果的加载控制。
EF4.1 允许控制对象之间的关系,当我们进行查询的时候,哪些关系的数据将会被加载到内存呢?所有相关的对象都需要吗?在一些场合可能有意义,例如,当查询的实体仅仅拥有一个相关的子实体,但是,多数情况下,你可能只需要加载部分数据,或者你喜欢的话,加载更多的数据。
默认情况下, EF4.1 仅仅加载查询中涉及的实体,但是它支持两种特性来帮助你控制加载:
贪婪加载
延迟加载
这里我指定加载某些订单,就是客户名为 Mac 的客户的订单,而且希望相关的订单明细也一起加载。
你可以这样查看实际执行的 SQL 查询
实际的 SQL 如下所示:
EF4.1 生成的 SQL 不是特别易读,但是这个查询你应该能够看懂,订单明细被一起加载了。
这带来了一个关于贪婪加载的问题:查询效率。如果你执行这样的查询来获取订单和订单明细,也可以变成写出等效的查询语句,如果喜欢的话,可以更加聪明地写出返回两个查询结果的查询,一个是订单,另外一个是订单明细。这应该更加有效,因为你不需要为每一个订单明细重复订单的信息。由于一些原因,EF 并不支持。记住这一点,因为这很容易使性能变差。
无论如何,你还可以在查询中包含更多的子集。
这样延迟加载就如你所愿了。当查询一个实体集的时候,相关的子实体也一并加载。
当 EF 访问实体的子实体的时候是如何工作的呢?你的集合是 POCO 的集合,所以,在访问的时候没有事件发生,EF 通过从你定义的实体派生一个动态的对象,然后覆盖你的子实体集合访问属性来实现。这就是为什么需要标记你的子实体集合属性为 virtual 的原因。
总结一下两种加载方式的特点
贪婪加载:
减少数据访问的延迟,在一次数据库的访问中返回所有的数据。
你需要知道你将作什么,并且显式声明
延迟加载:
非常宽容,因为只在需要的时候加载数据,不需要预先计划
可能因为数据访问的延迟而降低性能,考虑到每访问父实体的子实体时,就需要访问数据库。
现在,什么时候我们应该使用哪种机制?我的建议是:除非需要循环中加载数据,我使用延迟加载。这样的话,可能会造成2-3 次服务器的查询,但是仍然是可以接受的,特别是考虑到贪婪加载的效率问题。
原文地址:http://vincentlauzon.wordpress.com/2011/04/11/entity-framework-4-1-deep-fetch-vs-lazy-load-3/
看到 Entity Framework 4.1 推荐英文教程,为了帮大家看起来方便一些,简单翻译一下。这是一个系列,共有 8 篇,这是第 3 篇。
Entity Framework 4.1 之一 : 基础
Entity Framework 4.1 之二 : 覆盖默认的约定
Entity Framework 4.1 之三 : 贪婪加载和延迟加载
Entity Framework 4.1 之四:复杂类型
Entity Framework 4.1 之五:多对多的关系
Entity Framework 4.1 之六:乐观并发
Entity Framework 4.1 之七:继承
Entity Framework 4.1 之八:绕过 EF 查询映射
这篇文章将讨论查询结果的加载控制。
EF4.1 允许控制对象之间的关系,当我们进行查询的时候,哪些关系的数据将会被加载到内存呢?所有相关的对象都需要吗?在一些场合可能有意义,例如,当查询的实体仅仅拥有一个相关的子实体,但是,多数情况下,你可能只需要加载部分数据,或者你喜欢的话,加载更多的数据。
默认情况下, EF4.1 仅仅加载查询中涉及的实体,但是它支持两种特性来帮助你控制加载:
贪婪加载
延迟加载
贪婪加载
对于下面的查询using (var context = new MyDomainContext()) { var orders = from o in context.Orders.Include("OrderDetails") where o.CustomerName == "Mac" select o;
这里我指定加载某些订单,就是客户名为 Mac 的客户的订单,而且希望相关的订单明细也一起加载。
你可以这样查看实际执行的 SQL 查询
Console.WriteLine(orders.ToString());
实际的 SQL 如下所示:
SELECT [Project1].[OrderID] AS [OrderID], [Project1].[OrderTitle] AS [OrderTitle], [Project1].[CustomerName] AS [CustomerName], [Project1].[TransactionDate] AS [TransactionDate], [Project1].[C1] AS [C1], [Project1].[OrderDetailID] AS [OrderDetailID], [Project1].[OrderID1] AS [OrderID1], [Project1].[Cost] AS [Cost], [Project1].[ItemName] AS [ItemName] FROM ( SELECT [Extent1].[OrderID] AS [OrderID], [Extent1].[OrderTitle] AS [OrderTitle], [Extent1].[CustomerName] AS [CustomerName], [Extent1].[TransactionDate] AS [TransactionDate], [Extent2].[OrderDetailID] AS [OrderDetailID], [Extent2].[OrderID] AS [OrderID1], [Extent2].[Cost] AS [Cost], [Extent2].[ItemName] AS [ItemName], CASE WHEN ([Extent2].[OrderDetailID] IS NULL) THEN CAST(NULL AS int) ELS E 1 END AS [C1] FROM [dbo].[Orders] AS [Extent1] LEFT OUTER JOIN [dbo].[OrderDetails] AS [Extent2] ON [Extent1].[OrderID] = [Extent2].[OrderID] WHERE N'Mac' = [Extent1].[CustomerName] ) AS [Project1] ORDER BY [Project1].[OrderID] ASC, [Project1].[C1] ASC
EF4.1 生成的 SQL 不是特别易读,但是这个查询你应该能够看懂,订单明细被一起加载了。
这带来了一个关于贪婪加载的问题:查询效率。如果你执行这样的查询来获取订单和订单明细,也可以变成写出等效的查询语句,如果喜欢的话,可以更加聪明地写出返回两个查询结果的查询,一个是订单,另外一个是订单明细。这应该更加有效,因为你不需要为每一个订单明细重复订单的信息。由于一些原因,EF 并不支持。记住这一点,因为这很容易使性能变差。
无论如何,你还可以在查询中包含更多的子集。
var orders = from o in context.Orders.Include("OrderDetails").Include("Businesses") where o.CustomerName == "Mac" select o;
延迟加载
另外一个特性就是延迟加载,默认情况下,延迟加载被支持,如果你希望禁用它,必须显式声明,最好的位置是在 DbContext 的构造器中。public MyDomainContext() { this.Configuration.LazyLoadingEnabled = false; }
这样延迟加载就如你所愿了。当查询一个实体集的时候,相关的子实体也一并加载。
当 EF 访问实体的子实体的时候是如何工作的呢?你的集合是 POCO 的集合,所以,在访问的时候没有事件发生,EF 通过从你定义的实体派生一个动态的对象,然后覆盖你的子实体集合访问属性来实现。这就是为什么需要标记你的子实体集合属性为 virtual 的原因。
public class Order { public int OrderID { get; set; } public string OrderTitle { get; set; } public string CustomerName { get; set; } public DateTime TransactionDate { get; set; } public virtual List<OrderDetail> OrderDetails { get; set; } public virtual List<Business> Businesses { get; set; } }
总结一下两种加载方式的特点
贪婪加载:
减少数据访问的延迟,在一次数据库的访问中返回所有的数据。
你需要知道你将作什么,并且显式声明
延迟加载:
非常宽容,因为只在需要的时候加载数据,不需要预先计划
可能因为数据访问的延迟而降低性能,考虑到每访问父实体的子实体时,就需要访问数据库。
现在,什么时候我们应该使用哪种机制?我的建议是:除非需要循环中加载数据,我使用延迟加载。这样的话,可能会造成2-3 次服务器的查询,但是仍然是可以接受的,特别是考虑到贪婪加载的效率问题。
相关文章推荐
- Entity Framework 4.1 之三 : 贪婪加载和延迟加载
- Entity Framework 4.1 : 贪婪加载和延迟加载
- Entity Framework 4.1 之三 : 贪婪加载和延迟加载
- Entity Framework 4.1 之三 : 贪婪加载和延迟加载
- EF如何操作内存中的数据以及加载相关联表的数据:延迟加载、贪婪加载、显示加载
- EntityFramework 贪婪加载与延迟加载以及资源回收
- EF4.1之贪婪加载和延迟加载
- EF中的贪婪加载和延迟加载(懒加载)
- 【转】EntityFramework(EF)贪婪加载和延迟加载的选择和使用
- EF如何操作内存中的数据以及加载相关联表的数据:延迟加载、贪婪加载、显示加载
- Entity Framework加载相关实体——延迟加载Lazy Loading、贪婪加载Eager Loading、显示加载Explicit Loading
- 学习EF之贪婪加载和延迟加载(1)
- EF5.x Code First 表关联与贪婪加载、延迟加载
- EntityFramework(EF)贪婪加载和延迟加载的选择和使用
- EF-CodeFirst-表关系-延迟/贪婪加载
- 如何理解Hibernate的延迟加载机制?在实际应用中,延迟加载与Session关闭的矛盾是如何处理的?
- Hibernate中延迟加载和缓存
- js延迟加载
- 图片延迟加载
- Hibernate: 关于延迟加载(lazy)和强制加载 : Hibernate.initialize()