《Entity Framework 6 Recipes》中文翻译系列 (22) -----第五章 加载实体和导航属性之延迟加载
翻译的初衷以及为什么选择《Entity Framework 6 Recipes》来学习,请看本系列开篇
第五章 加载实体和导航属性
实体框架提供了非常棒的建模环境,它允许开发人员可视化地使用映射到数据库中的表、视图、存储过程以及关系中的实体类型。本节将向你展示如何控制查询操作中的关联实体的加载。
实体框架的默认行为是只加载应用程序直接需要的实体。通常情况下,这正是你需要的。如果实体框架通过一个或多个关联积极地加载关联实体,最终,你很有可能得到超过你需求的实体。这不但增加了内存占用,而且还影响了应用程序的性能。
在实体框架中,当加载关联实体时,你能控制并优化数据库查询执行的次数。如果在加载关联对象时精心管理的话,能提供应用程序的性能,以及对数据有更多的控制。
在本章,我们将演示加载关联数据的各种有效选项,并讲述他们的优缺点。我们会特别地讨论实体框架的默认行为 Lazy Loading(延迟加载)以及它的真正含义。然后,我们将演示在一个单独查询中,部分或者全部加载关联实体的选项。这种类型的加载,叫做Eager Loading(预先加载),它既被用来减少数据交互,也被用来控制加载哪个关联实体。
有的时候,你想延缓加载某一关联实体,因为加载它的成本太高或者不经常使用。对于这种情况,我们将介绍另一种加载关联实体的方法,它叫做Explicit Loading(显示加载)。同时演示使用Load()方法来精确控制何时加载一个或多个关联实体的多种场景。
最后,我们将简要地看看异步操作。
5-1 延迟加载关联实体
问题
你想加载一个实体,并在应用程序需要时才加载关联实体。
解决方案
假设你有如图5-1所示的模型。

图5-1 包含Customer和与它相关联信息的实体
在模型中,有一个Customer实体,一个与它关联的CustomerType和多个与它关联的CustomerEamil。它与CustomerType的关系是一对多关系,这是一个实体引用(译注:Customer中的导航属性CustomerType)。
Customer与CustomerEmail也是一对多关系,只是这时CustomerEmail在多的这一边。这是一个实体集合(译注:Customer中的导航属性CustomerEmails)。
当把它们三个实体放在一起时,就得到一个叫做对象图(object graph)的结构。一个对象图包含单个且与之关联的实体,它们构成一个整体的逻辑单元。特别地,一个对象图是一个给定实体和与之关联实体在某一特定时刻上的视图。例如,在我们的应用操作中有一个ID为5,Name为“John Smith“的customer,它有一个类型为“perferred"的CustomerType,和一个包含10个CustomerEmails的集合。
代码清单5-1.演示了实体框架加载关联实体的默认行为,Lazy Loading(延迟加载)。
代码清单5-1. 延迟加载Customer的关联实体CustomerType和CustomerEmail的实例
using (var context = new EFRecipesEntities())
{
var customers = context.Customers;
Console.WriteLine("Customers");
Console.WriteLine("========="); // 只需要Customer实体的信息
foreach (var customer in customers)
{
Console.WriteLine("Customer name is {0}", customer.Name);
} //现在,需要使用到关联实体CustomerType和CustomerEamil的信息,
//实体框架为每个实体对象产生一个单独的查询来获取关联实体的信息。
foreach (var customer in customers)
{
Console.WriteLine("{0} is a {1}, email address(es)", customer.Name,
customer.CustomerType.Description);
foreach (var email in customer.CustomerEmails)
{
Console.WriteLine("\t{0}", email.Email);
}
} // Extra credit:
//如果你打开Sql Server Profiler,下面的查询将不会重新去数据库查询,而是返回之前查询的内存数据
//注:原书中的注释有些模糊,本行是我(付灿)增加的说明,这里还要去查询Customer表一次,但是它的关联属性,不会再去查询数据库了,而是直接从内存返回之前查询出来的对象
foreach (var customer in customers)
{
Console.WriteLine("{0} is a {1}, email address(es)", customer.Name,
customer.CustomerType.Description);
foreach (var email in customer.CustomerEmails)
{
Console.WriteLine("\t{0}", email.Email);
}
}
}
代码清单5-1的输出如下:
Customers
=========
Customer name is Joan Smith
Customer name is Bill Meyers
Joan Smith is a Web Customer, email address(es)
jsmith@gmail.com
joan@smith.com
Bill Meyers is a Retail Customer, email address(es)
bmeyers@gmail.com
Joan Smith is a Web Customer, email address(es)
jsmith@gmail.com
joan@smith.com
Bill Meyers is a Retail Customer, email address(es)
bmeyers@gmail.com
原理
默认情况下,实体框架只加载确定需要使用的实体。这就是所谓的延迟加载,这是需要记住的一条很重要的准则。相反,加载父类和所有关联的实体,这叫做Eager Loading(预先加载),它会可能会加载一个大的对象图,这远远超出了你的需求。且不说获取对象图的开销,封送,实例化。
在示例中,我们最先给出一个查询,它查询出所有的customers。有趣的是,这个查询也不是立即执行的,它是在第一个foreach语句开始枚举Customer实体时才被执行。这个延迟加载的行为是LINQ带来的。
在第一个foreach中,我们只需要Custome表中的数据,不需要CustomerType和CustomerEmail表中的数据。在这种情况下,实体框架只查询Customer表,不去查询与 Customer表关联的CustomerType和CustomerEmail表。
然后,在第二个foreach中,我们显式引用了CustomerType实体中的Description属性和CustomerEmail实体中的Email属性。在实体框架中,直接访问这些属性,会为每个关联的表生成一个查询。这对理解实体框架在关联表第一次被访问时单独生成查询很重要。一旦通过关联实体调用了查询,实体框架会将该属性标记为已加载(loaded),并在之后对该属性的访问中直接从内存返回数据,不再一次又一次地查询数据库。我们在这个示例中,一共为子数据(译注:关联实体数据)生成了4个单独的查询:
1、针对Joan Smith的CusotrmType和CustomerEmail的两条Select语句;
2、针对Bill Meyers的CusotrmType和CustomerEmail的两条Select语句;
当用户在应用中按他们的需求浏览不同的数据进,这些针对每个子表的查询工作得很好,它们能提高应用的响应时间。因为使用一系列按需获取数据的简短的查询。相反,如果使用预先加载大量数据的方式,可能导致视图加载迟缓。
然后,在你需要大量使用关联表数据时,这个方法不是你看到的这么有效。在这种情况下,Eager Loading(预先加载)可能是一种更好的选择,它在一个单独的查询中,从父表和与之关联的表中获取所有的数据。
最后一部分代码块,名为‘Extra Credit‘,演示了子属性如果已经加载,实体框架会从内存中返回数据,而不是重新查询数据库。打开SQL Server Profiler工具,运行该示例,你会发现,在'Extra Credit'部分,当子属性被引用时,代码块没有生成SQL语句。
注意 SQL Server Profiler是一个检查(监视)SQL Server中SQL语句非常棒的工具,它是免费的,包含在SQL Server Devoloper Edition和更高级的版本中:http://technet.microsoft.com/en-us/library/ms181091.aspx
实体框架交流QQ群: 458326058,欢迎有兴趣的朋友加入一起交流
谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/VolcanoCloud/
《Entity Framework 6 Recipes》中文翻译系列 (22) -----第五章 加载实体和导航属性之延迟加载的更多相关文章
- 《Entity Framework 6 Recipes》中文翻译系列 (28) ------ 第五章 加载实体和导航属性之测试实体是否加载与显式加载关联实体
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-11 测试实体引用或实体集合是否加载 问题 你想测试关联实体或实体集合是否已经 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (23) -----第五章 加载实体和导航属性之预先加载与Find()方法
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-2 预先加载关联实体 问题 你想在一次数据交互中加载一个实体和与它相关联实体. ...
- 《Entity Framework 6 Recipes》中文翻译系列 (24) ------ 第五章 加载实体和导航属性之查询内存对象
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-4 查询内存对象 问题 你想使用模型中的实体对象,如果他们已经加载到上下文中, ...
- 《Entity Framework 6 Recipes》中文翻译系列 (25) ------ 第五章 加载实体和导航属性之加载完整的对象图和派生类型上的导航属性
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-5 加载完整的对象图 问题 你有一个包含许多关联实体的模型,你想在一次查询中, ...
- 《Entity Framework 6 Recipes》中文翻译系列 (26) ------ 第五章 加载实体和导航属性之延缓加载关联实体和在别的LINQ查询操作中使用Include()方法
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-7 在别的LINQ查询操作中使用Include()方法 问题 你有一个LINQ ...
- 《Entity Framework 6 Recipes》中文翻译系列 (27) ------ 第五章 加载实体和导航属性之关联实体过滤、排序、执行聚合操作
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-9 关联实体过滤和排序 问题 你有一实体的实例,你想加载应用了过滤和排序的相关 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (29) ------ 第五章 加载实体和导航属性之过滤预先加载的实体集合和修改外键关联
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-13 过滤预先加载的实体集合 问题 你想过滤预先加载的实体集合,另外,你想使用 ...
- 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述
微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...
- 《Entity Framework 6 Recipes》翻译系列 (4) -----第二章 实体数据建模基础之从已存在的数据库创建模型
不知道对EF感兴趣的并不多,还是我翻译有问题(如果是,恳请你指正),通过前几篇的反馈,阅读这个系列的人不多.不要这事到最后成了吃不讨好的事就麻烦了,废话就到这里,直奔主题. 2-2 从已存在的数据库创 ...
随机推荐
- 注解 @RequestParam,@RequestHeader,@CookieValue,Pojo,servlet原生API
1.@RequestParam 我们的超链接:<a href="springMvc/testRequestParam">testRequestParam</a&g ...
- Service and controller in angularJs
Separation of concern is at the heart while designing an AngularJS application. Your controller must ...
- sorl入门
本教程是从别人的基础上借鉴整理的 Solr是一个独立的企业级搜索应用服务器,它对外提供API接口.用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引(solr生成倒排索引,数 ...
- java网络编程2
在通信双方中,ServerSocket是服务器端负责接收的一方,它负责监听指定端口,其构造函数如下: 1.ServerSocket() throws IOException;无参构造函数,之所以存在 ...
- 2016多校联合训练4 F - Substring 后缀数组
Description ?? is practicing his program skill, and now he is given a string, he has to calculate th ...
- python求数字位数的方法
第一种:利用str()函数将数字转化成字符串,再利用len()函数判断位长. a=Int(raw_input("the number you want type in:") b=l ...
- SPOJ DQUERY D-query(主席树)
题目 Source http://www.spoj.com/problems/DQUERY/en/ Description Given a sequence of n numbers a1, a2, ...
- 巴特沃斯(Butterworth)滤波器 (2) - 双线性变换
这里接着上篇讲一下双线性变换Bilinear Transformation,它实现了模拟信号(连续域)与数字信号(离散域)之间的转换. 双线性变换公式如下: 反推可得到: 因此可以根据连续域传递函数推 ...
- 【历史】JavaScript和Java没啥关系!————JavaScript简史
文章的开始先上张图: 图片拍摄自北京图书大厦,代表着现在国内应该是绝大部分书店的现状--Javascript书籍放在Java类当中.甚至很多业内人也一直认为Javascript是Java语言在浏览器内 ...
- PS特效精粹
冲击有力的广告效果 神奇画笔功能 + 强大的图层样式 Photoshop中的三维特效