ado.net EF是微软的一个ORM框架,使用过EF的同学都知道EF有一个延迟加载的技术。

如果你是一个老鸟,你可能了解一些,如果下面的学习过程中哪些方面讲解的不对,欢迎批评指教。如果一个菜鸟,那我们就一起开始今天的学习。

首先,提出以下几个问题。

何为延迟加载呢?

我们该如何使用呢?

我们为什么要使用延迟加载技术呢?

延迟加载技术有什么优、缺点呢?

好,带着上面的问题我们开始今天的学习。

1.何为延迟加载

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

2.如何使用延迟加载技术

在这里,我们添加一个实体数据模型,对应的是数据库中的Flower、Indicator两个表。具体表的定义如下所示。
下面我们就根据上面的数据模型编写一个具体的延迟加载,我们到里面一探究竟。
编写代码,截图如下所示。
 
看到我上面代码截图中标注的内容了吗?
通过上面的Lambda表达式查询出来的数据是一个实现了IQueryable接口的类,在这里是ObjectSet<Folwer>,实体集。
不相信是吗?那好,我们继续查看源码。
 
 
上面的代码说明我们通过entity.Flower查询出来的是一个ObjectSet<Flower>类型的数据。
而接下来的代码有说明,这个ObjectSet<T>类型的数据实现了IQueryable接口,按照面向接口编程的原则,当然可以使用接口对象来接收查询出来的实体集。同时也实现了IEnumable接口,也就可以使用foreach()遍历集合。
 
 
上面的都是对代码进行的解释,那么真正的延迟加载又是体现在哪里呢?
完整代码如下所示
 
 
为了方便观察,在上面的查询代码处添加断点,打开sql server profiler监视工具,运行程序,开始观察
程序在断点处停下来
 
 
继续单步调试
 
 
通过监视工具我们知道,此时并没有sql语句的查询操作。
OK,继续单步调试
 
 
 
Ok,当我们走到item2的时候发现sql语句执行了,数据查询出来了。
 对上面的过程解释一下entity.Flower.where()的时候sql语句并没执行,当我们在下面需要用到上面查询语句的结果集item2的时候sql语句真正执行了。
没错,这就是EF的延迟加载技术,只有在数据真正用到的时候才会去数据库中查询。
顺便说一下,EF实现延迟加载的核心就是因为IQueryable接口的使用。如果我们把上面的代码修改一下,如下所示。
 
 
看到上面查询的返回值了吗?是一个Flower变量。如果你再添加断点,打开监视工具可以发现,这个时候已经没有延迟加载了。
上面只是延迟加载技术的一种,我们接下来学习另一种延迟加载技术。
上面我们定义的两个表Flower和Indicator表两者之间是一对多的关系,如果我们想要查询某个Flower下的所有Indicator数据,我们应该怎么做呢?
如果放在以前,你可能会说,我们使用表之间的连接查询不就行了吗?
不错,这确实是一种方法。不过你有没有想过连接查询就是笛卡尔积查询,如果查询Flower表下的所有对应Indicator数据,这个查询量又是多少呢?
Flower表有1万条记录,Indicator表也有1万条记录,那么他们的笛卡尔积就是一亿条数据,这样的查询肯定不是高效的。
解决方法就可以操作EF的另一种延迟加载技术,实现的核心就是实体类的导航属性。
 
在开始之前,我们再看一下上面Flower和Indicator两个表的导航属性
 
 
 
 
编写具体代码如下所示。
 
 
在上面的代码foreach循环出添加断点,运行程序,打开监视工具,观察
 
 
执行到第一个foreach()循环的时候会执行一个查询,上面已经说得很清楚了。
 
 
但是一定要注意,此时并没有查询出导航属性。
 
 
执行到第二个foreach()循环的时候,我们看到又执行了一条查询语句。
这个时候你可能就疑惑了,我们并没有要求查询啊,其实,这个查询是根据导航属性自动帮助我们查询的。

这就是第二种延迟加载技术,当我们需要用到导航属性的时候,如果导航属性不存在内存中,EF会自动帮助我们把导航属性查询出来加载到内存中。

此种延迟加载技术,现在应用的非常广泛。
 
在此总结一下,只要查询结果是实现了IQueryable接口的类,查询的结果都是延迟加载的。(不知道这句话说的准确不准确)
Ok,上面介绍了为何要使用延迟加载技术,那么我们为何要使用这种技术呢?
 

3.为何要使用延迟加载技术

 
上面的长篇大论简要的解释了一下EF的延迟加载机制,说了那么多,那到底为什么需要延迟加载呢?直接取直接用不就好了?
确实,从上面的简单例子来看延迟加载貌似很多余,但是通常我们操作数据库不可能只是这么简单的。
就拿很常用的分页来说,一般是先对数据进行排序,然后按照要求跳过几行数据,在取几行数。这就不是一个简单的where方法可以实现的了
至少需要先调用order进行排序,然后skip跳过几行数据,最后take取几行数据。如果where/order/skip/take等等方法每次使用的时候就马上提交sql语句到数据库,那做一个分页查询至少要发送4次请求,也就是说要和数据库交互4次。如果使用延迟加载的话上面的where/order/skip/take方法调用的时候可以看做只是在拼凑条件,当条件满足的时候(一般就是要用数据的时候,比如说FirstOrDefault方法),在将整个拼凑好的sql语句一起提交到数据库,这样一来和数据库的交互次数由4降到了1。是不是很高效了?
当然还有其他的例子,在这里就不列举了。

4.延迟加载技术的优缺点

 
优点在上面讲解第二类延迟加载技术和为何要使用延迟加载技术的时候已经说过了,下面我们主要来说一下EF延迟加载技术的缺点。
缺点:
(1)每次使用的时候都会去查询数据库 
 
 
上面的代码在程序执行的时候,你认为会执行几次的数据库查询操作?一次?两次?
我们通过监视工具来说明问题
 
 
OK,看到了吗?其实是执行了两次。每次需要使用到数据的时候都要执行查询操作。
当然,这个缺点也是可以使用缓存技术解决的
 
 

ado.net EF学习系列----深入理解查询延迟加载技术(转载)的更多相关文章

  1. EF 学习系列二 数据库表的创建和表关系配置(Fluent API、Data Annotations、约定)

    上一篇写了<Entity Farmework领域建模方式 3种编程方式>,现在就Code First 继续学习 1.数据库表的创建 新建一个MVC的项目,在引用右击管理NuGet程序包,点 ...

  2. LINQ学习系列-----3.1 查询非泛型集合

    一.问题起源 LINQ to object在设计时,是配合IEnumerable<T>接口的泛型集合类型使用的,例如字典.数组.List<T>等,但是对于继承了IEnumera ...

  3. ADO.NET EF 4.2 中的查询缓存(避免查询缓存)

    在WinForm系统中遇到了个问题,Form1是查询窗口,根据条件查询出所有数据,双击列表后创建弹出Form2窗口编辑单个记录,但编辑后保存后,在Form2中查询到的还是旧的数据,实际数据库中已经更新 ...

  4. Vue学习系列(四)——理解生命周期和钩子

    前言 在上一篇中,我们对平时进行vue开发中遇到的常用指令进行归类说明讲解,大概已经学会了怎么去实现数据绑定,以及实现动态的实现数据展示功能,运用指令,可以更好更快的进行开发.而在这一篇中,我们将通过 ...

  5. LINQ学习系列-----3.1 查询非泛型集合和多个分组

    一.查询非泛型集合 1.问题起源 LINQ to object在设计时,是配合IEnumerable<T>接口的泛型集合类型使用的,例如字典.数组.List<T>等,但是对于继 ...

  6. EF 学习系列三 数据操作数据加载及EF中执行Sql

    1.实体状态 我们通过EF来对数据库进行操作并持久化到数据库,那么EF必然通过EF上下文来维护实体的状态,明确知道每一个状态所对应的操作.也就是说EF通过上下文负责跟踪实体的状态.EF实体状态存在命名 ...

  7. 【EF学习笔记11】----------查询中常用的扩展方法

    先来看一下我们的表结构: 首先毫无疑问的要创建我们的上下文对象: using (var db = new Entities()) { //执行操作 } Average 平均值: //查询平均分 Con ...

  8. EF学习系列

    http://www.cnblogs.com/Wayou/archive/2012/09/20/EF_CodeFirst.html http://kb.cnblogs.com/zt/ef/#

  9. 【SQL Server 学习系列】-- SQL查询数据库表字段值不为空或Null的所有列

    ) set @TableName = 'Agency' -- 表名 declare @querySql nvarchar(max) set @querySql = 'select ' ) declar ...

随机推荐

  1. 如何生成唯一的server Id,server_id为何不能重复?

    我们都知道MySQL用server-id来唯一的标识某个数据库实例,并在链式或双主复制结构中用它来避免sql语句的无限循环.这篇文章分享下我对server-id的理解,然后比较和权衡生成唯一serve ...

  2. 【CLR】解析AppDomain

    目录结构: contents structure [+] 什么是AppDomain 跨越AppDomain边界访问对象 按引用封送(Marshal-by-Reference) 按值封送(Marshal ...

  3. Rocket Typist for Mac(增强型文本快速输入工具)破解版安装

    1.软件简介    Rocket Typist 是 macOS 系统上一款增强型文本快速输入工具,我们可以利用这款工具预先设置保存好很多日常生活学习或是工作中常用的文本片段,还能设定部分内容为变量,当 ...

  4. ASP.NET MVC 自定义处理JSON ActionResult类

    1.统一JSON格式处理方式,同时指定ContentType类型,解决低版本浏览器获取json时ContentType为application/json提示下载的问题. public abstract ...

  5. xml解析、写入遇到的坑

    前言 最近在看一个线上xml文件导出的问题,需求如下: 从我们平台导出一个后缀为tmx的术语语料数据(实际内容为xml文件),然后导入到其他第三方平台发现无法导入. 从其他平台导入的tmx文件无法导入 ...

  6. Java多线程并发最佳实践

    使用本地变量 尽量使用本地变量,而不是创建一个类或实例的变量. 使用不可变类 String.Integer等.不可变类可以降低代码中需要的同步数量. 最小化锁的作用域范围:S=1/(1-a+a/n) ...

  7. linux每日命令(32):gzip命令

    减少文件大小有两个明显的好处,一是可以减少存储空间,二是通过网络传输文件时,可以减少传输的时间.gzip是在Linux系统中经常使用的一个对文件进行压缩和解压缩的命令,既方便又好用.gzip不仅可以用 ...

  8. 如何搭建WebRTC信令服务器

    WebRTC 有一整套规范,如怎样使用它的接口.使用SDP进行媒体协商.通过ICE收集地址并进行连通性检测等等.除此之外,WebRTC还需要房间服务器将多端聚集到一起管理,以及信令服务器进行信令数据交 ...

  9. ESN 与 MEID

    ESN (Electronic Serial Numbers):电子序列号.在CDMA 系统中,是鉴别一个物理硬件设备唯一的标识.也就是说每个手机都用这个唯一的ID来鉴别自己, 就跟人的身份证一样.一 ...

  10. Java注解小记

    java注解是jdk1.5以后新出的特性,注解提升了Java语言的表达能力,有效地实现了应用功能和底层功能的分离,框架/库的程序员可以专注于底层实现. 1.Java内置注解 主要有三个: @Overr ...