步步深入EF(二)—延迟加载

    

    EF延迟加载:就是使用Lamabda表达式或者Linq 从 EF实体对象中查询数据时,EF并不是直接将数据查询出来,而是在用到具体数据的时候才会加载到内存。

    很多资料讲的EF原理,只是延迟查询数据,是这样吗?EF本质究竟是什么呢?

 

一、本质


    1、延迟生成SQL语句
        生成的SQL语句不确定
    2、按需加载
       针对于外键属性而言,EF会在用到这个外键属性时才会去查询对应的表

二、实现方式

先来介绍几个概念:


   概念一:EntityFramework的由来

     用过EF的人都知道,我们的程序中都会引用它。它是微软自带的吗?如果是,为什么不直接封装在framework中,而是需要去引用;如果不是,那为什么会创建EF模型时自动创建它。

     解释:EntityFramework在创建EF模型,自动复制,是扩展出来的,用时复制过来,相当于微软开发的第三方程序集,不属于framework

     为什么不放在framework?

       老版本中不存在EF,新版本才有EF.为了兼容,现在老版本只需要将其引入即可,不需要重新改动。


  概念二:标准查询运算符中的Where含义

       (1)普通集合中的Where子句          

       (2)EF中DbSet返回集合的Where子句     

          //集合的标准查询运算符方法,是来自于System.Linq.Enumerable里给IEnumerable接口添加的扩展方法(即时)
            List<string> listStr = new List<string>();
            listStr.Where(i=>listStr.Contains(i));

            //上下文中dbSet返回的集合(延时)
            List<Order_Info> order = db.Order_Info.Where(u => u.OrderID == 1).ToList();  

       区别:

           普通集合的标准查询运算符方法,来自于system.linq. Enumerable  里的扩展方法,给 IEnumerable  接口添加扩展方法,

           EF里的DBSet标准查询运算符方法,来自于system.linq. Queryable  里,给IQueryable接口添加扩展方法,

           IQueryable接口

           是非常特殊,正是因为这个接口,才支持的延迟查询,dbset实现iqueryable接口

       联系:
           IQueryable和IEnumerable 是两套查询策略,封装好的方法相同,但具体实现不同。一个是即时查询,另一个是延时查询。

     概念三:延迟基于IQueryable
         本质基于IQueryable扩展类DbQuery,为IQueyable提供了很多扩展方法  

1延迟生成SQL   

 //延迟查询
DbQuery<Order_Info> i = db.Order_Info.Where(u => u.OrderID == 1) as DbQuery<Order_Info>;
Order_Info order1 = i.FirstOrDefault();
Console.WriteLine(); 

    在这里我们为什么要使用DbQuery<T>来接收呢?

首先我们来看使用db.Order_Info.Where()来获取文章列表的时候,Where()方法给我们返回一个什么类型的对象呢?我们把鼠标放在Where()方法上后,会发现Where会返回给我们一个IQueryable的泛型接口对象,如下图:

 

那我们是不是需要使用IQueryable对象来接收获取的对象呢,代码如下

//where()方法返回一个IQuery的接口  
IQueryable <Order_Info> query= db.Order_Info.Where(p => p.orderID=1); 

 


可以看到query已经取到值,但根据面向对象的原则,接口不能直接实例化,但我们的代码有没有报错,为社么呢?

根据面向对象的里氏替换原则,这里实际上是返回了一个IQueryable对象的子类对象。


里氏替换原则,子类对象可以赋值给父类对象。也就是说子类可以替换父类出现的地方。但是父类对象一定不可以替换子类对象。

也就是说Where()方法返回了一个IQueryable接口的子类对象,并且赋值给了它的父类对象IQueryable。

那么Where()到底返回了一个什么样的IQueryable的子类对象呢?

 再次看上面的局变量窗口中query的返回值类型为,如下图:



我们可以很明显的看出,query的返回类型为DbQuery类型。

那我们就用DbQuery来接收对象,代码如下:

 DbQuery<Order_Info> i = db.Order_Info.Where(u => u.OrderID == 1) as DbQuery<Order_Info>; 

因为Where()方法返回的是IQueryable对象,所以要把对象转换成DbQuery对象; 

 

       查询订单表中订单1的创建日期

            DbQuery<Order_Info> query = db.Order_Info;
            //获取订单表里的第一个订单
            Order_Info order = query.FirstOrDefault();
            
            //获取这个订单的创建日期
            if (order != null) {
                Console.WriteLine(order.CreateDate);
            }  


执行第一条语句:DbQuery<Order_Info> query = db.Order_Info;    


执行第二条语句:Order_Info order = query.FirstOrDefault();

     我们只是用到订单信息时,才去数据库查询第一条订单的信息



2、按需加载

   EF使用前:当遇到主外键相互关联的表,当需要从表中的数据时,我们必须通过主表进行查询。而我们只是需要从表数据,而必须关联到主表。这种方式是低效的。

       EF使用后:我们只需要查询数从表的数据即可

    

    查询订单表中产品1的相关信息

           DbQuery<Order_detail> query = db.Order_detail;
            //获取订单表里的第一个订单
            Order_detail order = query.FirstOrDefault();
            
            //获取这个订单的创建日期
            if (order != null) {
                Console.WriteLine(order.ProductName);
            }     
    可直接查询产品表中的数据  

三、好处


    1、生成一条语句(用的时候,根据条件拼成sql语句)

    2、不受主表约束,提高效率


    情况1:是针对产品表中的数据进行检索再排序

        db.Order_Detail.Where(u => u.OrderID == 1).OrderBy(u=>u.ProductID)

    情况2:是针对检索出来的list集合进行排序

        db.Order_Detail.Where(u => u.OrderID == 1).ToList().OrderBy(u=>u.ProductID) 

    情况1为延时查询,根据拼出的SQL语句进行查询;情况2为即时查询。

   以上只是只是简单的介绍EF的延迟加载,文中还有很多需要在学习过程中进一步完善,下篇博文会对延迟加载的优化进行深入阐述

步步深入EF(三)—优化延迟加载

    




  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值