asp.net EF学习系列----深入理解查询延迟加载技术

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()遍历集合。

上面的都是对代码进行的解释,那么真正的延迟加载又是体现在哪里呢?

完整代码如下所示

namespace WebApplication1
{
    public partial class EFDemo : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            using (FlowersPlatformEntities entity = new FlowersPlatformEntities())
            {

                var item2 = entity.Flower.Where(c => c.Name == "牡丹");
                foreach (var item in item2)
                {
                    Response.Write(item.Id);
                }
            }
        }
    }
}

为了方便观察,在上面的查询代码处添加断点,打开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两个表的导航属性

编写具体代码如下所示。

namespace WebApplication1
{
    public partial class EFDemo : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            using (FlowersPlatformEntities entity = new FlowersPlatformEntities())
            {

                var item2 = entity.Flower.Where(c => c.Name == "牡丹");
                foreach (var item in item2)
                {
                    foreach (var it in item.Indicator)
                    {
                         Response.Write(it.Index);
                    }
                }
            }
        }
    }
}

在上面的代码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)每次使用的时候都会去查询数据库

namespace WebApplication1
{
    public partial class EFDemo : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            using (FlowersPlatformEntities entity = new FlowersPlatformEntities())
            {

                var item2 = entity.Flower.Where(c => c.Name == "牡丹");
                foreach (var item in item2)
                {
                    Response.Write(item.Id);
                }
                foreach (var item in item2)
                {
                    Response.Write(item.Id);
                }
            }
        }
    }
}

上面的代码在程序执行的时候,你认为会执行几次的数据库查询操作?一次?两次?

我们通过监视工具来说明问题

OK,看到了吗?其实是执行了两次。每次需要使用到数据的时候都要执行查询操作。

当然,这个缺点也是可以使用缓存技术解决的

OK,终于写完了。

时间: 2024-12-27 16:16:03

asp.net EF学习系列----深入理解查询延迟加载技术的相关文章

ASP.NET MVC学习系列(二)-WebAPI请求

继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理. 这里我使用Jquery 来发起异步请求实现数据调用. 继续使用上一文章中的示例,添加一个index.html页面,添加对jquery的引用. 一.无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax({type:"get"}) 来实现: 请求的后台Action方法仍为上篇文章中的GetU

ASP.NET MVC学习系列(二)-WebAPI请求(转)

转自:http://www.cnblogs.com/babycool/p/3922738.html 继续接着上文 ASP.NET MVC学习系列(一)-WebAPI初探 来看看对于一般前台页面发起的get和post请求,我们在Web API中要如何来处理. 这里我使用Jquery 来发起异步请求实现数据调用. 继续使用上一文章中的示例,添加一个index.html页面,添加对jquery的引用. 一.无参数Get请求 一般的get请求我们可以使用jquery提供的$.get() 或者$.ajax

【Query处理学习笔记】搜索引擎查询推荐技术综述_中文信息学报2010_王斌

主要内容:对通用搜索引擎的查询推荐技术的方法.评价进行了总结 具体内容: "查询推荐"的不同英文叫法:Query Suggestion.Term Suggestion.Query Recommendation.Query Substitution.Query Rewriting 查询推荐的任务:找出和用户查询相似的query,以便更好地表达用户查询意图,供用户便捷输入 三种技术方法: 1. 基于文档的方法:通过处理query搜索出来的文档,以此作为反馈,进一步理解用户意图,扩充quer

ASP.NET Core学习系列

.NET Core ASP.NET Core ASP.NET Core学习之一 入门简介 ASP.NET Core学习之二 菜鸟踩坑 ASP.NET Core学习之三 NLog日志 ASP.NET Core学习之四 在CentOS上部署.net core LINUX学习系列 DOCKER学习系列 微服务学习系列 原文地址:https://www.cnblogs.com/xcsn/p/8306854.html

ASP.NET MVC学习系列(一)-WebAPI初探

由于即将要接手的新项目计划用ASP.NET MVC3来开发,所以最近一段时间一直在看相关的书或文章.因为之前在大学里也曾学习过MVC2开发,也做过几个简单的MVC2的小型测试项目,不过在后来工作以后主要还是开发WebForm的项目,所以MVC的东西也就逐渐的淡忘了. 经过这一段时间的系统学习,真的觉得MVC3相比于之前的MVC2还有WebForm来说,确实有一种让人欲罢不能爽歪歪的感觉.特别是Razor语法.Linq表达式等的结合运用. 为了将学习过程中遇到的一些值得留意的问题和知识点进行一个很

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

上一篇写了<Entity Farmework领域建模方式 3种编程方式>,现在就Code First 继续学习 1.数据库表的创建 新建一个MVC的项目,在引用右击管理NuGet程序包,点击浏览搜索EF安装,我这里主要是EF6.0 以上的学习 所以都安装6.0 以上的版本 接下来在Model文件夹下面创建一个Customer类 public class Customer { public int ID { get; set; } public string Name { get; set; }

ASP.NET MVC5 学习系列之模型绑定

一.理解 Model Binding Model Binding(模型绑定) 是 HTTP 请求和 Action 方法之间的桥梁,它根据 Action 方法中的 Model 类型创建 .NET 对象,并将 HTTP 请求数据经过转换赋给该对象. 为了理解 Model Binding 如何工作,我们来做个简单的Demo,像往常一样创建一个 MVC 应用程序,添加一个 HomeController,修改其中的 Index 方法如下: public ActionResult Index(int id

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

前言 在上一篇中,我们对平时进行vue开发中遇到的常用指令进行归类说明讲解,大概已经学会了怎么去实现数据绑定,以及实现动态的实现数据展示功能,运用指令,可以更好更快的进行开发.而在这一篇中,我们将通过实例,探究vue的生命周期. 万物皆有灵,世间万物都拥有灵魂,小到山河湖海,花草树木,蚂蚁到人类,以及所有的动植物,大到地球星空和宇宙,都拥有灵魂,可以说他们都是有生命的,只是他们的生命形态是我们人类所不能理解的存在.在生产中,生命周期通俗来讲,就是从自然中来回到自然中去的全过程,也就是从采集材料设

分布式缓存技术redis学习系列----深入理解Spring Redis的使用

关于spring redis框架的使用,网上的例子很多很多.但是在自己最近一段时间的使用中,发现这些教程都是入门教程,包括很多的使用方法,与spring redis丰富的api大相径庭,真是浪费了这么优秀的一个框架.Spring-data-redis为spring-data模块中对redis的支持部分,简称为"SDR",提供了基于jedis客户端API的高度封装以及与spring容器的整合,事实上jedis客户端已经足够简单和轻量级,而spring-data-redis反而具有&quo