翻译的初衷以及为什么选择《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) -----第五章 加载实体和导航属性之延迟加载的更多相关文章

  1. 《Entity Framework 6 Recipes》中文翻译系列 (28) ------ 第五章 加载实体和导航属性之测试实体是否加载与显式加载关联实体

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-11  测试实体引用或实体集合是否加载 问题 你想测试关联实体或实体集合是否已经 ...

  2. 《Entity Framework 6 Recipes》中文翻译系列 (23) -----第五章 加载实体和导航属性之预先加载与Find()方法

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-2  预先加载关联实体 问题 你想在一次数据交互中加载一个实体和与它相关联实体. ...

  3. 《Entity Framework 6 Recipes》中文翻译系列 (24) ------ 第五章 加载实体和导航属性之查询内存对象

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-4  查询内存对象 问题 你想使用模型中的实体对象,如果他们已经加载到上下文中, ...

  4. 《Entity Framework 6 Recipes》中文翻译系列 (25) ------ 第五章 加载实体和导航属性之加载完整的对象图和派生类型上的导航属性

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-5  加载完整的对象图 问题 你有一个包含许多关联实体的模型,你想在一次查询中, ...

  5. 《Entity Framework 6 Recipes》中文翻译系列 (26) ------ 第五章 加载实体和导航属性之延缓加载关联实体和在别的LINQ查询操作中使用Include()方法

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-7  在别的LINQ查询操作中使用Include()方法 问题 你有一个LINQ ...

  6. 《Entity Framework 6 Recipes》中文翻译系列 (27) ------ 第五章 加载实体和导航属性之关联实体过滤、排序、执行聚合操作

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-9  关联实体过滤和排序 问题 你有一实体的实例,你想加载应用了过滤和排序的相关 ...

  7. 《Entity Framework 6 Recipes》中文翻译系列 (29) ------ 第五章 加载实体和导航属性之过滤预先加载的实体集合和修改外键关联

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 5-13  过滤预先加载的实体集合 问题 你想过滤预先加载的实体集合,另外,你想使用 ...

  8. 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述

    微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...

  9. 《Entity Framework 6 Recipes》翻译系列 (4) -----第二章 实体数据建模基础之从已存在的数据库创建模型

    不知道对EF感兴趣的并不多,还是我翻译有问题(如果是,恳请你指正),通过前几篇的反馈,阅读这个系列的人不多.不要这事到最后成了吃不讨好的事就麻烦了,废话就到这里,直奔主题. 2-2 从已存在的数据库创 ...

随机推荐

  1. iphone 尺寸and字体

    iPhone的APP界面一般由四个元素组成,分别是:状态栏.导航栏.主菜单栏以及中间的内容区域 这里取用 640×960 的尺寸设计,那我们就说说在这个尺寸下这些元素的尺寸: 状态栏:就是我们经常说的 ...

  2. 基于Docker快速搭建多节点Hadoop集群--已验证

    Docker最核心的特性之一,就是能够将任何应用包括Hadoop打包到Docker镜像中.这篇教程介绍了利用Docker在单机上快速搭建多节点 Hadoop集群的详细步骤.作者在发现目前的Hadoop ...

  3. Puppet自动化运维-资源介绍篇(4)

    1.什么是资源? 资源是Puppet最基础的元素,每个资源的定义都具有标题,类型,以及一系列的属性. 资源定义有如下的特性:   (1) Puppet使用title在编译时区分每个资源,使用命名变量在 ...

  4. C#启用管理员权限运行程序

    方法一:关闭程序重新请求打开 static class Program { [STAThread] static void Main() { Application.EnableVisualStyle ...

  5. Java基础加强之集合篇(模块记忆、精要分析)

    千里之行,始于足下.把别人的变成自己,再把自己的分享给别人,这也是一次提升的过程.本文的目的是以一篇文章从整体把握集合体系又不失一些细节上的实现,高手路过. 集合的作用与特点 Java是一门面向对象语 ...

  6. Git小记

    Git简~介 Git是一个分布式版本控制系统,其他的版本控制系统我只用过SVN,但用的时间不长.大家都知道,分布式的好处多多,而且分布式已经包含了集中式的几乎所有功能.Linus创造Git的传奇经历就 ...

  7. python基础04 运算

    数学运算 print 2+2  #加法 print 1.3-4 #剪法 print 3*5 #乘法 print 4.5/1.5 #除法 print 3**2   #乘方 print 10%3   #求 ...

  8. vertical-align和line-height的那些事

    可能是又遇到了瓶颈,好长时间感觉css上没什么可看.从来没觉得css有什么难,什么盒模型和各种流也觉得理解起来毫不费力,但好像仅限于此.对一些属性仅限于常用,有时会去做实验验证一些属性,过后就忘了.现 ...

  9. dubbo 常见错误

    1. Caused by: java.lang.reflect.MalformedParameterizedTypeException 或 Caused by: java.lang.NoSuchMet ...

  10. RecyclerView的介绍与使用

    一.什么是RecyclerView 新的视图控件,是Android-support-v7-21版本中新增的一个Widgets,官方对于它的介绍则是:RecyclerView是ListView的升级版本 ...