EF 延迟加载和预先加载
最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来。
十年河东十年河西,莫欺少年穷
学无止境,精益求精
本节探讨延迟加载和预先加载
Entity Framework作为一个优秀的ORM框架,它使得操作数据库就像操作内存中的数据一样,但是这种抽象是有性能代价的,故鱼和熊掌不能兼得。但是,通过对EF的学习,可以避免不必要的性能损失。本篇只介绍关联实体的加载的相关知识,这在我之前的文章中都有介绍。
我们已经了解到EF的关联实体加载有三种方式:Lazy Loading,Eager Loading,Explicit Loading,其中Lazy Loading和Explicit 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 延迟加载和预先加载的更多相关文章
- EF中的预先加载和延迟加载
延迟加载(Lazy Loading):当实体第一次被读取时,相关数据不会被获取,只会读取本身.延迟加载的数据不会一次性查出来,而是一条一条的查询,这样就会多次请求数据库进行查询. 预先加载<Ea ...
- Entity Framework Code First -- 延迟加载和预先加载
还是以这两个表为例子 country包含零个或多个city, 这个外键关系是我后来加上去,原来没有. 然后再用Power Tool逆向, 产生如下代码 1: using System.Componen ...
- EF延迟加载和懒加载
EF默认是延迟加载的 延迟加载就是刚开始只会读取当前实体对应表的数据 关联表的数据不会读取 只有下面条件用到了才会再去读取 所以可能会造成N次读取数据库 需要在实体的属性加virtual关键字 延迟 ...
- [翻译][MVC 5 + EF 6] 7:加载相关数据
原文:Reading Related Data with the Entity Framework in an ASP.NET MVC Application 1.延迟(Lazy)加载.预先(Eage ...
- Entity Framework入门教程(8)---预先加载、延迟加载、显示加载
1.预先加载 预先加载:在对一种类型的实体进行查询时,将相关的实体作为查询的一部分一起加载.预先加载可以使用Include()方法实现. 1.加载一个相关实体类型 栗子:使用Include()方法从数 ...
- EF如何操作内存中的数据以及加载相关联表的数据:延迟加载、贪婪加载、显示加载
之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需要用的,这个系列讲讲如何使用EF操作数据库.老版本的EF主要是通过Ob ...
- EF如何操作内存中的数据和加载外键数据:延迟加载、贪婪加载、显示加载
EF如何操作内存中的数据和加载外键数据:延迟加载.贪婪加载.显示加载 之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需 ...
- 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性)
一. 简介 上一个章节中,也介绍了立即加载和延迟加载,但上一个章节是针对单表而言的,不含外键,立即也好,延迟也好,都是指单表中的数据.但本章节重点介绍的三种加载方式均是针对含(导航属性.外键)的情况下 ...
- ASP.NET MVC深入浅出(被替换) 第一节: 结合EF的本地缓存属性来介绍【EF增删改操作】的几种形式 第三节: EF调用普通SQL语句的两类封装(ExecuteSqlCommand和SqlQuery ) 第四节: EF调用存储过程的通用写法和DBFirst模式子类调用的特有写法 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性) 第十节: EF的三种追踪
ASP.NET MVC深入浅出(被替换) 一. 谈情怀-ASP.NET体系 从事.Net开发以来,最先接触的Web开发框架是Asp.Net WebForm,该框架高度封装,为了隐藏Http的无状态 ...
随机推荐
- 【转】hibernate缓存:一级缓存和二级缓存
什么是缓存? 缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用程序的运行性能.Hibernate在进行 ...
- Linux服务器init 5启动图形界面,报错Retrigger failed udev events的解决方法
1.开启linux系统的桌面环境,使用startx未成功,报如下错误: 提示:Retrigger failed udev events [root@ /]# startx xauth: creatin ...
- 前台处理json字符串的几种方法(转)
原文地址http://www.css88.com/archives/3919 比如我有两个变量,我要将a转换成字符串,将b转换成JSON对象: var a={"name":&quo ...
- pat甲级题解(更新到1013)
1001. A+B Format (20) 注意负数,没别的了. 用scanf来补 前导0 和 前导的空格 很方便. #include <iostream> #include <cs ...
- jQuery对数据和对象的操作
<script type="text/javascript" src="jquery-1.8.2.min.js"></script> & ...
- PHP中面向对象的关键字
php面向对象中常用的关键字有final.static.const (1)final: 1,final不能修饰成员属性 2,final只能修饰类和方法 作用: 使用final修饰的类不能被子类继承 使 ...
- ios7迎来完美越狱,果粉狂欢!
[我要]最近一则iOS7可以完美越狱的消息,可是乐坏了期待已久的果粉们.据科技博客网站Gizmodo报道,越狱专家Evasi0n团队最近攻破苹果的 iOS7系统,赶在圣诞前发布了iOS7的越狱.消息一 ...
- ArcMap 10.3 AddIN找不到插件
现象:VS 2012写的AddIn插件,编译通过,安装成功 ArcGIS 10.3的AddIN Manager中,可以看到该插件 可是在自定义中却找不到.检索不到该插件. 解决方法:.net Fram ...
- Django URL name详解
我们基于上一节的代码来开始这一节的内容. 上节源代码:zqxt_views(django 1.4 - django 1.10).zip [更新于 2016-09-06 00:13:23] 1. 打开 ...
- 【转】Maven Jetty 插件的问题(css/js等目录死锁)的解决
Maven Jetty 插件的问题(css/js等目录死锁,不能自动刷新)的解决: 1. 打开下面的目录:C:\Users\用户名\.m2\repository\org\eclipse\jetty ...