• EF之贪婪加载和延迟加载


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

         在使用EF(Entity Framework)的过程中,很多时候我们会进行查询的操作,因此知道哪些数据会被加载到内存当中就至关重要。在多多的情况下,你可能并并不需要加载全部的数据,而是只要加载一部分的数据即可。

         默认情况下,EF仅仅加载查询中涉及的实体,但是它支持两种特性来帮助你控制加载:

              1.贪婪加载

              2.延迟加载 

    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
        从上面个的SQL语句中可以看出想要查询一次Order表里面的数据就要对应的将OrderDetail里面的数据一起全都查出来。这么做的效率是十分低的,我们可以通过自己来写sql语句来完成。

    2.延迟加载:

    优点:

          仅在需要的时候加载数据,不需要预先计划,从而避免了各种复杂的外连接、索引、视图操作带来的低效率问题

    缺点:

           多次与数据库交互访问,导致性能降低,考虑到每访问父实体的子实体时,就需要访问数据库

    使用方式:

          分为两步:

          第一:

                    在需要的延迟加载的属性前加上virtual,该属性的类型可以是任务的集合类型 ICOLOOCT<T>或者是0、1..1关联属性

                    如,更新Category实体类,使之支持延迟加载

    1
    2
    3
    4
    5
    6
    7
    public class Category{  
         public int CategoryID { getset; }   
         public string CategoryName { getset; }   
         public string Description { getset; }  
         public byte[] Picture { getset; }  
         public virtual List<Product> Products { getset; }
         ...

            第二:  在context构造器中开启延迟加载功能

    public NorthwindContext() : base("name=NorthwindEntities""NorthwindEntities")

    {

     ContextOptions.LazyLoadingEnabled = true;

    _categories = CreateObjectSet<Category>();

     _products = CreateObjectSet<Product>();

    }

           由于集合是 POCO 的集合,所以,在访问的时候没有事件发生,EF 通过从你定义的实体派生一个动态的对象,然后覆盖你的子实体集合,通过访问属性来实现。这就是为什么需要标记你的子实体集        合属性为 virtual 的原因。 

    阻止延迟加载解决方案:

           Tolist(),返回的东西是个内存级的对象,就是说强迫它在这里执行一次SQL语句,查询到的东西放在Web服务器内存里,这里达到了缓存的效果,从而阻止了延迟加载

    无论走的多远,都应该时常回过头看看。之所以写这个博客,主要的原因是为了记录自己的成长痕迹和所学到的技术,以便于日后的反思。
  • 相关阅读:
    Web应用程序使用Hibernate
    Hibernate使用注释
    Hibernate入门程序
    Hibernate体系结构
    Spring MVC文件上传教程
    Spring MVC配置静态资源和资源包教程
    Spring MVC4使用Servlet3 MultiPartConfigElement文件上传实例
    Spring4 MVC文件下载实例
    Spring4 MVC+Hibernate4 Many-to-many连接表+MySQL+Maven实例
    Spring4 MVC+Hibernate4+MySQL+Maven使用注解集成实例
  • 原文地址:https://www.cnblogs.com/FredWang/p/4205456.html
Copyright © 2020-2023  润新知