1.什么叫延迟加载

字面上可以理解为,一个动作本该立即执行的动作,没有立即执行

2.从代码上理解

static void Main(string[] args)
{
//执行该语句的时候,查看sql监视器,发现并没有生成sql语句
IEnumerable<Student> stu = dbContext.Students.Where(s => s.Id == 1).Select(s => s);
//只有当 使用的时候 ,才生成sql语句
Student student = stu.FirstOrDefault();
}

只有对象被使用了,才生成sql语句

3.寻找原因,什么原因导致延迟加载

先理解两个Where()方法:

a.集合的Where()

List<string> listStr = new List<string>()
{
"A",
"BB",
"CCC"
};
string bb = listStr.Where(s => s.Length == 2).Select(s => s).FirstOrDefault();

转到Where的定义,发现 集合 中的Where方法 实际上是IEnumerable的扩展方法,该接口继承与IEnumerable

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate);
public interface IEnumerable<out T> : IEnumerable

b.DbSet中的Where方法

dbContext.Students是DbSet<Student>类型,所以此处说 DbSet的中Where方法

var stu = dbContext.Students.Where(s => s.Id == 1);
public partial class SchoolEntities : DbContext
{
public virtual DbSet<Student> Students { get; set; }
}

dbContext.Students是DbSet<T>类型的,转到DbSet<T>定义看看

此处的Where()是IQueryable的扩展方法,继承与IQueryable

public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate);
public interface IQueryable<out T> : IEnumerable<T>, IQueryable, IEnumerable
public interface IQueryable : IEnumerable

 

c.IEnumerable与IQueryable的区别

var s1 = dbContext.Students.Where(s => s.Id == 1);

var s2 = s1.Where(s => s.Age > 0);

var s3 = s2.Select(s => s).FirstOrDefault();

用sql监视器查看,发现总共就执行了一次sql查询

得出结论:

1.实现EF延迟加载 的 实际上是IQueryable上的扩展方法,更具体的话是DbQuery类型来实现的

2.IEnumerable<T>将命令直接执行,第一次执行后的结果,保存到内存,不会拼接命令树

3.IQueryable<T>将语句拼接成一个命令树,当用到的时候,再执行

4.两种操作都只访问了一次数据库

4.为什么要有延迟加载

a.无法确定 本次查询条件 是否 已经添加结束

DbQuery<Student> s1 = dbContext.Students.Where(s => s.Id == 1).Where(s => s.Age > 0) as DbQuery<Student>;

每次添加 查询条件的时候,都只是返回 包含所有添加条件的 DbQuery对象,只有最后使用的时候,才根据条件生成相应的sql语句

b.对于外键实体,按需加载

本次需要用到的两张 具有 主外键关系的两张表如下

var tea = dbContext.Teachers.Where(t => t.tId == 1);
//生成sql语句,如图 代码一
Teacher teacher = tea.FirstOrDefault();
//生成sql语句,如图 代码二
string className = teacher.TeachClass.cName;

代码一,如下图:

SELECT TOP (1)
[Extent1].[tId] AS [tId],
[Extent1].[tName] AS [tName],
[Extent1].[tAge] AS [tAge],
[Extent1].[tClass] AS [tClass]
FROM [dbo].[Teacher] AS [Extent1]
WHERE 1 = [Extent1].[tId]

代码二,如下图:

exec sp_executesql N'SELECT
[Extent1].[cId] AS [cId],
[Extent1].[cName] AS [cName]
FROM [dbo].[TeachClass] AS [Extent1]
WHERE [Extent1].[cId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1

观察,得出结论:

1.按需加载:在第一次执行的时候,因为没有用到外键属性,所以生成sql语句的时候,不会去去查询 TeachClass表

2.当EF需要用到外键属性的时候,才会去加载 相应的表

c.按需加载的缺点:

实例代码如下:

DbQuery<Teacher> teachers = dbContext.Teachers;
StringBuilder sbTeacher=new StringBuilder(100);
foreach (Teacher tea in teachers)
{
//每次调用 外键表Teachers上 的 外键实体时,都会去查询数据库
//EF有个优化,相同的外键实体只查一次,即TeachClass相同只查一次
sbTeacher.Append(tea.TeachClass.cName);
}

生成的SQL脚本如下:

exec sp_executesql N'SELECT
[Extent1].[cId] AS [cId],
[Extent1].[cName] AS [cName]
FROM [dbo].[TeachClass] AS [Extent1]
WHERE [Extent1].[cId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=1

第二次,和第三次,因为TeachClass的值相同,则只查询了一次

exec sp_executesql N'SELECT
[Extent1].[cId] AS [cId],
[Extent1].[cName] AS [cName]
FROM [dbo].[TeachClass] AS [Extent1]
WHERE [Extent1].[cId] = @EntityKeyValue1',N'@EntityKeyValue1 int',@EntityKeyValue1=2

5.连接查询

既然EF是只有用到外键实体的时候,才加载相应表,那么如果我们要连接两张表要怎么做

a.通过Include方法

DbQuery<Teacher> teachers = dbContext.Teachers.Include("TeachClass");
StringBuilder sbTeacher=new StringBuilder(100);
foreach (Teacher tea in teachers)
{
//只有第一次 查询的使用,将数据查询 并保存到内存中,
//接下来的操作只是在内存中读取,并没有读取数据库
sbTeacher.Append(tea.TeachClass.cName);
}

查看sql语句,发现 EF为我们生成 left outer  join ,连接了两张表

SELECT
[Extent1].[tId] AS [tId],
[Extent1].[tName] AS [tName],
[Extent1].[tAge] AS [tAge],
[Extent1].[tClass] AS [tClass],
[Extent2].[cId] AS [cId],
[Extent2].[cName] AS [cName]
FROM [dbo].[Teacher] AS [Extent1]
LEFT OUTER JOIN [dbo].[TeachClass] AS [Extent2] ON [Extent1].[tClass] = [Extent2].[cId]

b.生成 join 的另一种方式

var teachers = dbContext.Teachers.Select(t => new {tName = t.tName, ClassName = t.TeachClass.cName}).ToList();

生成的sql语句如下

SELECT
1 AS [C1],
[Extent1].[tName] AS [tName],
[Extent2].[cName] AS [cName]
FROM [dbo].[Teacher] AS [Extent1]
LEFT OUTER JOIN [dbo].[TeachClass] AS [Extent2] ON [Extent1].[tClass] = [Extent2].[cId]

MVC系列学习(三)-EF的延迟加载的更多相关文章

  1. 解析ASP.NET Mvc开发之EF延迟加载

    目录: 1)从明源动力到创新工场这一路走来 2)解析ASP.NET WebForm和Mvc开发的区别 3)解析ASP.NET Mvc开发之查询数据实例 ------------------------ ...

  2. 解析ASP.NET Mvc开发之EF延迟加载 分类: ASP.NET 2014-01-04 01:29 4017人阅读 评论(1) 收藏

    目录: 从明源动力到创新工场这一路走来 解析ASP.NET WebForm和Mvc开发的区别 解析ASP.NET 和Mvc开发之查询数据实例 ----------------------------- ...

  3. MVC中使用EF(2):实现基本的CRUD功能

    MVC中使用EF(2):实现基本的CRUD功能 By  Tom Dykstra |July 30, 2013 Translated by litdwg   Contoso University示例网站 ...

  4. ASP.NET MVC 视图(三)

    ASP.NET MVC 视图(三) 前言 上篇对于Razor视图引擎和视图的类型做了大概的讲解,想必大家对视图的本身也有所了解,本篇将利用IoC框架对视图的实现进行依赖注入,在此过程过会让大家更了解的 ...

  5. ASP.NET MVC 路由(三)

    ASP.NET MVC路由(三) 前言 通过前两篇的学习会对路由系统会有一个初步的了解,并且对路由系统中的Url规则有个简单的了解,在大家的脑海中也有个印象了,那么路由系统在ASP.NETMVC中所处 ...

  6. ASP.NET MVC 过滤器(三)

    ASP.NET MVC 过滤器(三) 前言 本篇讲解行为过滤器的执行过程,过滤器实现.使用方式有AOP的意思,可以通过学习了解过滤器在框架中的执行过程从而获得一些AOP方面的知识(在顺序执行的过程中, ...

  7. ASP.NET MVC 5 with EF 6 上传文件

        参考   ASP.NET MVC 5 with EF 6 - Working With Files Rename, Resize, Upload Image (ASP.NET MVC) ASP ...

  8. MVC+UnitOfWork+Repository+EF

    MVC+UnitOfWork+Repository+EF UnitOfWork+Repository模式简介: 每次提交数据库都会打开一个连接,造成结果是:多个连接无法共用一个数据库级别的事务,也就无 ...

  9. EF使用延迟加载的本质原因

    EF(Entity Framework)是微软的一个ORM框架 使用过EF的同学都知道它有一个延迟加载的功能 那么这个延迟加载的功能到底是什么? 为什么需要延迟加载? 使用延迟加载的优点和缺点又各是什 ...

随机推荐

  1. 10.3andXE7的DEVExpress18.2.1记录备查

    记录备查: win10 DEVExpress18.2.1用DevExpressVCL一键编译安装工具_v10.3.2 - 2018-12-12.exe(包括help,备份...升级系统不用重新安装控件 ...

  2. BNUOJ 13358 Binary Apple Tree

    Binary Apple Tree Time Limit: 1000ms Memory Limit: 16384KB This problem will be judged on Ural. Orig ...

  3. 九度oj 题目1066:字符串排序

    题目1066:字符串排序 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:6487 解决:2670 题目描述: 输入一个长度不超过20的字符串,对所输入的字符串,按照ASCII码的大小从小到 ...

  4. Sigmoid Function

    本系列文章由 @yhl_leo 出品,转载请注明出处. 文章链接: http://blog.csdn.net/yhl_leo/article/details/51734189 Sigmodi 函数是一 ...

  5. github & Front-end JavaScript frameworks

    github & Front-end JavaScript frameworks https://github.com/collections/front-end-javascript-fra ...

  6. jQuery动态添加表格1

    用jquery的append方法在指定行的后面新增一行tr,会把新增的行的html追加到指定行的html里面 content +="<tr><td>123</t ...

  7. [bzoj 1047][HAOI2007]理想正方形(单调队列)

    题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1047 分析: 第一感觉二维线段树当然没问题但是挺慢的. 注意到要求的正方形形中的最大最小边长是 ...

  8. SVM学习(续)核函数 & 松弛变量和惩罚因子

    SVM的文章可以看:http://www.cnblogs.com/charlesblc/p/6193867.html 有写的最好的文章来自:http://www.blogjava.net/zhenan ...

  9. 1. 找出数组中的单身狗OddOccurrencesInArray Find value that occurs in odd number of elements.

    找出数组中的单身狗: 1. OddOccurrencesInArray Find value that occurs in odd number of elements. A non-empty ze ...

  10. Domain-specific language 领域特定语言

    https://en.wikipedia.org/wiki/Domain-specific_language A domain-specific language (DSL) is a compute ...