MVC系列学习(三)-EF的延迟加载
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 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的延迟加载的更多相关文章
- 解析ASP.NET Mvc开发之EF延迟加载
目录: 1)从明源动力到创新工场这一路走来 2)解析ASP.NET WebForm和Mvc开发的区别 3)解析ASP.NET Mvc开发之查询数据实例 ------------------------ ...
- 解析ASP.NET Mvc开发之EF延迟加载 分类: ASP.NET 2014-01-04 01:29 4017人阅读 评论(1) 收藏
目录: 从明源动力到创新工场这一路走来 解析ASP.NET WebForm和Mvc开发的区别 解析ASP.NET 和Mvc开发之查询数据实例 ----------------------------- ...
- MVC中使用EF(2):实现基本的CRUD功能
MVC中使用EF(2):实现基本的CRUD功能 By Tom Dykstra |July 30, 2013 Translated by litdwg Contoso University示例网站 ...
- ASP.NET MVC 视图(三)
ASP.NET MVC 视图(三) 前言 上篇对于Razor视图引擎和视图的类型做了大概的讲解,想必大家对视图的本身也有所了解,本篇将利用IoC框架对视图的实现进行依赖注入,在此过程过会让大家更了解的 ...
- ASP.NET MVC 路由(三)
ASP.NET MVC路由(三) 前言 通过前两篇的学习会对路由系统会有一个初步的了解,并且对路由系统中的Url规则有个简单的了解,在大家的脑海中也有个印象了,那么路由系统在ASP.NETMVC中所处 ...
- ASP.NET MVC 过滤器(三)
ASP.NET MVC 过滤器(三) 前言 本篇讲解行为过滤器的执行过程,过滤器实现.使用方式有AOP的意思,可以通过学习了解过滤器在框架中的执行过程从而获得一些AOP方面的知识(在顺序执行的过程中, ...
- 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 ...
- MVC+UnitOfWork+Repository+EF
MVC+UnitOfWork+Repository+EF UnitOfWork+Repository模式简介: 每次提交数据库都会打开一个连接,造成结果是:多个连接无法共用一个数据库级别的事务,也就无 ...
- EF使用延迟加载的本质原因
EF(Entity Framework)是微软的一个ORM框架 使用过EF的同学都知道它有一个延迟加载的功能 那么这个延迟加载的功能到底是什么? 为什么需要延迟加载? 使用延迟加载的优点和缺点又各是什 ...
随机推荐
- type="timestamp"与type="date"区别
type="timestamp"-----数据库中保存的时间为年月日时分秒 与type="date"---------数据库中保存的时间为年月日
- C# 反射基础
反射的定义:审查元数据并收集关于它的类型信息的能力.元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等. 公共语言运 ...
- [BZOJ1045][HAOI2008]糖果传递(数学分析)
题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1045 分析:均分纸牌的环状版本. 先看线性的版本: 设f[i]表示第I位从第i+1位得 ...
- log4j2.xml 的配置 及使用
log4j2.xml配置 <?xml version="1.0" encoding="UTF-8"?> <Configuration > ...
- java String长度与varchar长度匹配理解(字符和字节长度理解)
java String长度与varchar长度匹配理解(字符和字节长度理解) string中的length()长度,返回的是char的数量,每个char可以存储世界上任何类型的文字和字符,一个char ...
- SVM学习(续)核函数 & 松弛变量和惩罚因子
SVM的文章可以看:http://www.cnblogs.com/charlesblc/p/6193867.html 有写的最好的文章来自:http://www.blogjava.net/zhenan ...
- License使用成本估算
License使用成本估算 Licmanager系统的成本估算模块是以參数估算法为基础的计算机成本估算软件,内部包括多个成本估算关系式,综合反映了license的使用特征.产品项目特征以组织经济环境等 ...
- inline-block元素因基线对齐而造成上浮的问题
假设我需要实现将三个块级元素并排对齐的如下效果: 代码如下: <!DOCTYPE html> <html lang="en-US"> <head> ...
- jqury+css实现可弹出伸缩层
1.使用可弹出伸缩窗调整了之前的页面布局,使用这样的布局使整个界面看起来更加清爽也更简洁 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L ...
- Tomcat PK Resin
特征 Tomcat Resin 所属公司 Apache CAUCHO 用户数 多 少 可參考文档 多 少 与Eclipse集成复杂度 适中 较复杂. Eclipse下调试开发 简便 复杂.更新类后会自 ...