zoukankan      html  css  js  c++  java
  • Entity Framework 4.1 : 贪婪加载和延迟加载


    这篇文章将讨论查询结果的加载控制。

    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],
    CASEWHEN ([Extent2].[OrderDetailID]ISNULL) THENCAST(NULLASint) ELS
    E
    1ENDAS[C1]
    FROM[dbo].[Orders]AS[Extent1]
    LEFTOUTERJOIN[dbo].[OrderDetails]AS[Extent2]ON[Extent1].[OrderID]
    =[Extent2].[OrderID]
    WHERE N'Mac'=[Extent1].[CustomerName]
    )
    AS[Project1]
    ORDERBY[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
    {
    publicint OrderID { get; set; }
    public string OrderTitle { get; set; }
    public string CustomerName { get; set; }
    publicDateTime TransactionDate { get; set; }
    public virtual List<OrderDetail> OrderDetails { get; set; }
    public virtual List<Business> Businesses { get; set; }
    }
    复制代码

    总结一下两种加载方式的特点

    贪婪加载:

    • 减少数据访问的延迟,在一次数据库的访问中返回所有的数据。
    • 你需要知道你将作什么,并且显式声明

    延迟加载:

    • 非常宽容,因为只在需要的时候加载数据,不需要预先计划
    • 可能因为数据访问的延迟而降低性能,考虑到每访问父实体的子实体时,就需要访问数据库。

    现在,什么时候我们应该使用哪种机制?我的建议是:除非需要循环中加载数据,我使用延迟加载。这样的话,可能会造成2-3 次服务器的查询,但是仍然是可以接受的,特别是考虑到贪婪加载的效率问题。

  • 相关阅读:
    双色球的概率和收益
    伽玛函数
    概率统计13——二项分布与多项分布
    贝叶斯决策理论(1)
    线性代数笔记34——左右逆和伪逆
    线性代数笔记33——基变换和图像压缩
    线性代数笔记32——线性变换及对应矩阵
    线性代数笔记31——奇异值分解
    线性代数笔记30——相似矩阵和诺尔当型
    线性代数笔记29——正定矩阵和最小值
  • 原文地址:https://www.cnblogs.com/tianboblog/p/3229228.html
Copyright © 2011-2022 走看看