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. HDU 4902 (牛叉的线段树)

    Nice boat Problem Description There is an old country and the king fell in love with a devil. The de ...

  2. PatentTips – Shader Interfaces

    BACKGROUND Today's graphic processing units (GPUs) host all of the computations necessary to generat ...

  3. [BZOJ1096][ZJOI2007]仓库建设(斜率优化DP)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1096 分析: 假设1~10,如果在3 6 10建立仓库,那么当前建立仓库决策下的最优值 ...

  4. 深入解析Microsoft Sql server 2008

    http://blog.csdn.net/downmoon/article/details/5256548

  5. javascript中数组的定义及使用

    js <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.o ...

  6. JavaScript初探之——图片移动

    在我们打开页面的时候我们看到的大部分页面都是动态的,曾经学习VB的时候要实现一些动态的画面第一个想到的就是用Flash,如今学习了BS的东西,才算是开眼界了,刚刚学习了一个动画的效果,给大家展示一下. ...

  7. LeetCode 771. Jewels and Stones (宝石与石头)

    题目标签:Hash Table 这一题很简单,题目给了两个string:J 和 S. 只要把J 里面的 char 放入HashSet,再遍历S找出有多少个石头是宝石. Java Solution: R ...

  8. 1245 最小的N个和(前k小ai+bi)

    1245 最小的N个和  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果     题目描述 Description 有两个长度为 N ...

  9. js对象和json的区别

    他们两个没有什么关联只不过可以相互转换而已,就像json可以转化为java对象一样 注意:json只有字符串形式(就是我们常说的json字符串:key/value值和数组形式的字符串),没有什么jso ...

  10. codility MinAbsSum

    For a given array A of N integers and a sequence S of N integers from the set {−1, 1}, we define val ...