最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来。

十年河东十年河西,莫欺少年穷

学无止境,精益求精  

本节探讨延迟加载和预先加载

Entity Framework作为一个优秀的ORM框架,它使得操作数据库就像操作内存中的数据一样,但是这种抽象是有性能代价的,故鱼和熊掌不能兼得。但是,通过对EF的学习,可以避免不必要的性能损失。本篇只介绍关联实体的加载的相关知识,这在我之前的文章中都有介绍。

我们已经了解到EF的关联实体加载有三种方式:Lazy Loading,Eager Loading,Explicit Loading,其中Lazy LoadingExplicit Loading都是延迟加载。Eager Loading是预先加载

延迟加载(Lazy Loading)。当实体第一次被读取时,相关数据不会被获取。但是,当你第一次尝试存取导航属性时,该导航属性所需的数据会自动加载。结果会使用多个查询发送到数据库——一次是读取实体本身,然后是每个相关的实体。DbContext类默认是使用延迟加载的。

使用延迟加载必须满足以下两个条件

1、类是由Public修饰,不能是封闭类,也就是说,不能带有Sealded修饰符

2、导航属性标记为Virtual。

如下 Score 模型满足了延迟加载的两个条件

    public class Score
{
[Key]
public int Id { get; set; } public int StudentScore { get; set; }//学生分数 public int StudentID { get; set; }//学生ID public int CourseID { get; set; }//课程ID public virtual Student Student { get; set; }//virtual关键字修饰,用于延迟加载 提高性能 只有显式调用时 才会加载 并可以代表一个Student对象 也就是 属性==对象 public virtual Course Course { get; set; }//virtual关键字修饰,用于延迟加载 提高性能 只有显式调用时 才会加载 并可以代表一个Course对象 也就是 属性==对象
}

如果您不想使用延迟加载,您可以关闭Lazy Loading,将LazyLoadingEnabled设为false,如果导航属性没有标记为virtual,Lazy Loading也是不起作用的。

        public StudentContext()
: base("StudentContext")//指定连接字符串
{
this.Configuration.LazyLoadingEnabled = false; //关闭延迟加载
}

(一)延迟加载

延迟加载就是数据不会一次性查出来,而是一条一条的查询,这样就会多次请求数据库进行查询,增加了数据库的负担。如果您的数据量打太大,建议使用预先加载,如果两张表数据量很大,建议使用延迟加载。

        public ActionResult linqTOsql()
{
using (var db = new StudentContext())
{
var Elist = db.Scores.Where(t => t.StudentScore > );
foreach (Score item in Elist)
{
//todo 延迟加载 执行多次查询
}
}
return View();
}

(二)预先加载<Eager Loading>使用Include方法关联预先加载的实体。

注:需引入:using System.Data.Entity;命名空间

预先加载就是从数据库中一次性查询所有数据,存放到内存中。如下方法采用预先加载

        public ActionResult linqTOsql()
{
using (var db = new StudentContext())
{
var Elist = from o in db.Scores.Include(t=>t.Student).Where(t=>t.StudentScore>) select o;
ViewBag.Elist = Elist;
}
return View();
}

上述代码就是将Score表和Student表左连接,然后查询学生成绩在80分以上的信息。Include()是立即查询的,像ToList()一样,不会稍后延迟优化后再加载。

如果两张表记录很大(字段多,上百万条记录),采用Include()关联两张表效率会很低,因为:它除了要做笛卡尔积,还要把数据一次性查询出来。因此:在字段多,记录多的情况下,建议使用延迟加载。

在此需要说明的是:EF中有两种表关联的方法,一种是Join()方法,一种是Include()方法

Join()方法使用说明:两表不必含有外键关系,需要代码手动指定连接外键相等(具有可拓展性,除了值相等,还能指定是>,<以及其他对两表的相应键的关系),以及结果字段。

Include()方法说明:两表必须含有外键关系,只需要指定键名对应的类属性名即可,不需指定结果字段(即全部映射)。默认搜索某表时,不会顺带查询外键表,直到真正使用时才会再读取数据库查询;若是使用 Include(),则会在读取本表时把指定的外键表信息也读出来。

(三)显式加载<Explicit Loading>有点类似于延迟加载,只是你在代码中显式地获取相关数据。当您访问一个导航属性时,它不会自动加载。你需要通过使用实体的对象状态管理器并调用集合上的Collection.Load方法或通过持有单个实体的属性的Reference.Load方法来手动加载相关数据。

数据模型更改如下:

   public class Score
{
[Key]
public int Id { get; set; } public int StudentScore { get; set; }//学生分数 public int StudentID { get; set; }//学生ID public int CourseID { get; set; }//课程ID //变成了泛型
public virtual List<Student> Student { get; set; }//virtual关键字修饰,用于延迟加载 提高性能 只有显式调用时 才会加载 并可以代表一个Student对象 也就是 属性==对象 public virtual Course Course { get; set; }//virtual关键字修饰,用于延迟加载 提高性能 只有显式调用时 才会加载 并可以代表一个Course对象 也就是 属性==对象
}

代码如下:

        public ActionResult linqTOsql()
{
using (var db = new StudentContext())
{
var Elist = db.Scores.Where(t => t.StudentScore > );
foreach (Score item in Elist)
{
var model = db.Entry(item);//Entry: 获取给定实体的 System.Data.Entity.Infrastructure.DbEntityEntry<TEntity> 对象,以便提供对与该实体有关的信息的访问以及对实体执行操作的功能。
model.Collection(t => t.Student).Load();//Score中的Student导航属性 必须为泛型集合 查询/加载实体集合
foreach (Student A in item.Student)
{ }
}
}
return View();
}

性能注意事项

如果你知道你立即需要每个实体的相关数据,预先加载通常提供最佳的性能。因为单个查询发送到数据库并一次性获取数据的效率通常比在每个实体上再发出一次查询的效率更高。例如,在上面的示例中,假定每个系有十个相关的课程,预先加载会导致只有一个查询(join联合查询)往返于数据库。延迟加载和显式加载两者都将造成11个查询和往返。在高延迟的情况下,额外的查询和往返通常是不利的。

另一方面,在某些情况下使用延迟加载的效率更高。预先加载可能会导致生成SQL Server不能有效处理的非常复杂的联接查询。或者,如果您正在处理的是需要访问的某个实体的导航属性,该属性仅为实体集的一个子集,延迟加载可能比预先加载性能更好,因为预先加载会将所有的数据全部加载,即使你不需要访问它们。如果应用程序的性能是极为重要的,你最好测试并在这两种方法之间选择一种最佳的。

延迟加载可能会屏蔽一些导致性能问题的代码。例如,代码没有指定预先或显式加载但在处理大量实体并时在每次迭代中都使用了导航属性的情况下,代码的效率可能会很低(因为会有大量的数据库往返查询)。一个在开发环境下表现良好的应用程序可能会在移动到Windows Azure SQL数据库时由于增加了延迟导致延迟加载的性能下降。你应当分析并测试以确保延迟加载是否是适当的

@陈卧龙的博客

EF 延迟加载和预先加载的更多相关文章

  1. EF中的预先加载和延迟加载

    延迟加载(Lazy Loading):当实体第一次被读取时,相关数据不会被获取,只会读取本身.延迟加载的数据不会一次性查出来,而是一条一条的查询,这样就会多次请求数据库进行查询. 预先加载<Ea ...

  2. Entity Framework Code First -- 延迟加载和预先加载

    还是以这两个表为例子 country包含零个或多个city, 这个外键关系是我后来加上去,原来没有. 然后再用Power Tool逆向, 产生如下代码 1: using System.Componen ...

  3. EF延迟加载和懒加载

    EF默认是延迟加载的 延迟加载就是刚开始只会读取当前实体对应表的数据 关联表的数据不会读取 只有下面条件用到了才会再去读取 所以可能会造成N次读取数据库  需要在实体的属性加virtual关键字 延迟 ...

  4. [翻译][MVC 5 + EF 6] 7:加载相关数据

    原文:Reading Related Data with the Entity Framework in an ASP.NET MVC Application 1.延迟(Lazy)加载.预先(Eage ...

  5. Entity Framework入门教程(8)---预先加载、延迟加载、显示加载

    1.预先加载 预先加载:在对一种类型的实体进行查询时,将相关的实体作为查询的一部分一起加载.预先加载可以使用Include()方法实现. 1.加载一个相关实体类型 栗子:使用Include()方法从数 ...

  6. EF如何操作内存中的数据以及加载相关联表的数据:延迟加载、贪婪加载、显示加载

    之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需要用的,这个系列讲讲如何使用EF操作数据库.老版本的EF主要是通过Ob ...

  7. EF如何操作内存中的数据和加载外键数据:延迟加载、贪婪加载、显示加载

    EF如何操作内存中的数据和加载外键数据:延迟加载.贪婪加载.显示加载 之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需 ...

  8. 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性)

    一. 简介 上一个章节中,也介绍了立即加载和延迟加载,但上一个章节是针对单表而言的,不含外键,立即也好,延迟也好,都是指单表中的数据.但本章节重点介绍的三种加载方式均是针对含(导航属性.外键)的情况下 ...

  9. ASP.NET MVC深入浅出(被替换) 第一节: 结合EF的本地缓存属性来介绍【EF增删改操作】的几种形式 第三节: EF调用普通SQL语句的两类封装(ExecuteSqlCommand和SqlQuery ) 第四节: EF调用存储过程的通用写法和DBFirst模式子类调用的特有写法 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性) 第十节: EF的三种追踪

    ASP.NET MVC深入浅出(被替换)   一. 谈情怀-ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态 ...

随机推荐

  1. 最短路径—Dijkstra算法和Floyd算法

    原文链接:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/31/2615833.html 最后边附有我根据文中Dijkstra算法的描述使用jav ...

  2. jq点击显示,再点击隐藏

    每次都会遇到的问题: <script> $("button").click(function(){ if($(".div").css("d ...

  3. mysql数据库链接与创建

    有童鞋问到说,环境搭建好了,mysql也安装了,但是就是进不去数据库,也启动不了,一直报错,那么下面这边就说下如何用Navicat链接上创建的数据库 首先 1)在xshell里进入mysql,命令是: ...

  4. curl运行json串,代理转发格式

    curl -b 'uin=o0450654733; skey=@tq9xjRvYy' -H "Content-Type: application/json" -X POST -d ...

  5. Shell 编程基础之 && 与 ||

    一.引言 Shell 在执行某个命令的时候,会返回一个返回值,该返回值保存在 shell 变量 $? 中.当 $? == 0 时,表示执行成功:当 $? == 1 时,表示执行失败.有时候,下一条命令 ...

  6. .NET简谈接口

    自从面向对象开发方式的出现,抽象的概念就开始日新月异的发展,面向对象编程.面向接口编程.面向组件编程等等:这一系列的概念都是软件工程所追求的思想范畴,高类聚低耦合. 今天我要简谈的是面向对象里面非常重 ...

  7. PHP的开发环境

    快速搭建工作环境,测试环境,开始PHP的编程之旅. liunx CentOS 6.4安装配置LAMP服务器(Apache+PHP5+MySQL) 准备篇: 1.配置防火墙,开启80端口.3306端口v ...

  8. Java并发编程底层实现原理 - volatile

    Java语言规范第三版中对volatile的定义如下: Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致性的更新,线程应该确保通过排他锁 单独获得这个变量. volatile有时候 ...

  9. 【emWin】例程十:bmp图片显示

    实验指导书及代码包下载: 链接:http://pan.baidu.com/s/1i5fr2Ep 密码:vlvt 实验现象:

  10. hihoCoder 1183 连通性一·割边与割点(Tarjan求割点与割边)

    #1183 : 连通性一·割边与割点 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 还记得上次小Hi和小Ho学校被黑客攻击的事情么,那一次攻击最后造成了学校网络数据的丢 ...