EF 延迟加载和预先加载

时间:2022-09-21 08:05:05

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

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

学无止境,精益求精  

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

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. &lbrack;翻译&rsqb;&lbrack;MVC 5 &plus; EF 6&rsqb; 7:加载相关数据

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

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

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

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

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

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

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

  8. 第六节&colon; EF高级属性&lpar;二&rpar; 之延迟加载、立即加载、显示加载&lpar;含导航属性&rpar;

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

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

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

随机推荐

  1. HTML5开发手机应用--viewport的作用

    在用HTML5开发手机应用或手机网页时,<head>部分总会有如下一段代码,这段代码到底什么意思呢.在网上,大家会得到很多答案.我从网上搜集了部分介绍,整理一下,以留备用. <met ...

  2. html slelect 标签默认值

    <select name="channelCode" id="channelCode" class="all_input" style ...

  3. css内容样式属性

    设置元素的最大高度.最小高度.最大宽度.最小宽度,用max-height.min-height.max-width.min-width. visibility:设置元素是否可见.visible和hid ...

  4. Windows Azure Platform Introduction &lpar;11&rpar; 了解Org ID、Windows Azure订阅、账户

    <Windows Azure Platform 系列文章目录> 了解和掌握Windows Azure相关的基础知识是非常重要的. 问题1:什么叫做Org ID Org ID是Azure C ...

  5. 【GoLang】GoLang 遍历 map、slice、array方法

    代码示例: map1 := make(map[string]string) map1["a"] = "AAA" map1["b"] = &q ...

  6. 数据结构-List

    Lis的实现: /////////////////////////////////////////////////////////////////////////////// // // FileNa ...

  7. 什么是S-OFF&comma;什么是S-ON&comma;HBOOT命令&comma;玩转Android

    什么是S-OFF?S代表 Security Lock,是安全锁,保护锁的意思.S-OFF就是安全保护关,S-ON就是安全保护开.Secure Lock 就是安全锁.是硬件设计厂商用于保护固件不被刷写而 ...

  8. simpleDateFormat日期格式转换

    1------------------------------------------------------------------------------------- package com.n ...

  9. 【C语言】浅谈可变参数与printf函数

    一.何谓可变参数 int printf( const char* format, ...); 这是使用过C语言的人所再熟悉不过的printf函数原型,它的参数中就有固定参数format和可变参数(用& ...

  10. qwe框架- CNN 实现

    CNN实现 概述 我在qwe中有两种,第一种是按照Ng课程中的写法,多层循环嵌套得到每次的"小方格",然后WX+b,这样的做法是最简单,直观.但是效率极其慢.基本跑个10张以内图片 ...