《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 从已存在的数据库创 ...
随机推荐
- find out the neighbouring max D_value by counting sort in stack
#include <stdio.h> #include <malloc.h> #define MAX_STACK 10 ; // define the node of stac ...
- BZOJ 3110 [Zjoi2013]K大数查询 ——整体二分
[题目分析] 整体二分显而易见. 自己YY了一下用树状数组区间修改,区间查询的操作. 又因为一个字母调了一下午. 貌似树状数组并不需要清空,可以用一个指针来维护,可以少一个log 懒得写了. [代码] ...
- Fancybox丰富的弹出层效果
Fancybox是一款优秀的jquery插件,它能够展示丰富的弹出层效果.前面我们有文章介绍了facybox弹出层效果,相比facybox,fancybox显得功能更为齐全,它除了可以加载DIV,图片 ...
- mac linux 删除一个文件下边所有文件和文件夹
sudo rm -r -f 目录
- JAVA集合类型详解
一.前言 作为java面试的常客[集合类型]是永恒的话题:在开发中,主要了解具体的使用,没有太多的去关注具体的理论说明,掌握那几种常用的集合类型貌似也就够使用了:导致这一些集合类型的理论有可能经常的忘 ...
- 51nod 1712 区间求和
题意 给你一个长度为 \(n\) 的序列,定义这个序列的权值为 $ \sum_{1 \leq i<j \leq n} a_j - a_i $. 现在给你一个长度为 \(n\) 的序列,当$ a_ ...
- java分享第十八天-02( java结合testng,利用XML做数据源的数据驱动)
testng的功能很强大,利用@DataProvider可以做数据驱动,数据源文件可以是EXCEL,XML,YAML,甚至可以是TXT文本.在这以XML为例:备注:@DataProvider的返回值类 ...
- Java 集合类的特性
ArrayList: 元素单个,效率高,多用于查询 Vector: 元素单个,线程安全,多用于查询 LinkedList: 元素单个,多用于插入和删除 HashMap: 元素成对,元素可为空 H ...
- Centos 6.5 部署 redmine 3.3
验证ruby版本 如果有就卸载安装最新的 yum install gcc* openssl openssl-devel -y wget https://ruby.taobao.org/mirrors/ ...
- Pyserial操作串口
pySerial 介绍 封装了串口通讯模块,支持Linux.Windows.BSD(可能支持所有支持POSIX的操作系统),支持Jython(Java)和IconPython(.NET and Mon ...