翻译的初衷以及为什么选择《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. html学习第三天—— 第13,14章

    颜色值缩写 关于颜色的css样式也是可以缩写的,当你设置的颜色是16进制的色彩值时,如果每两位的值相同,可以缩写一半. 例子1: p{color:#000000;} 可以缩写为: p{color: # ...

  2. 使用SHFB(Sandcastle Help File Builder)建立MSDN风格的代码文档

    使用SHFB(Sandcastle Help File Builder)建立MSDN风格的代码文档 下载地址:http://sandcastle.codeplex.com/ 下载地址2:http:// ...

  3. 转:Delphi 函数大全

    Delphi 函数大全 - xiucaiyao的专栏 - 博客频道 - CSDN.NEThttp://blog.csdn.net/xiucaiyao/article/details/4544039 名 ...

  4. From cls答辩

    我没有想过有一天会因为wjmzbmr而开一篇. 因为看到了cls答辩的链接而震撼或是感动. 可能也跟最近身心比较疲惫有关...容易产生这样那样的感触... cls可能已不是我们这代OIER所能膜到的了 ...

  5. servlet jsp jdbc bootstrarp mvc分层模式实现的第一个项目

    登录注册界面 这是一个注册和登录的界面 用到了前端页面中自带的一点H5的标签和属性---巩固下 邮箱格式 :type="email"  不能为空:  required=" ...

  6. java-并发-线程

    浏览以下内容前,请点击并阅读 声明 软件的并发是指同时做多件事情,java平台一开始就支持并发编程,java编程语言以及类库含有对并发最基本的支持,从5.0版本开始,java平台开始包含一些高并发的A ...

  7. hive 创建三种文件类型的表

    --TextFile set hive.exec.compress.output=true; set mapred.output.compress=true; set mapred.output.co ...

  8. Excel转Html

    项目结构: 这是一个maven项目,主函数在Client类里面 当运行程序的后,控制台情况: 当我们刷新了test.html文件后,用浏览器打开效果: 说一下这个过程的设计思路: 1.读取excel文 ...

  9. 整理react native的资料

    http://blog.csdn.net/jj120522/article/details/51900016  -----RN常见的错误 http://www.mamicode.com/info-de ...

  10. VMware创建Linux虚拟机并安装CentOS(三)

    选择“创建自定义布局”手动给Linux指定系统分区.交换分区,鼠标单击“下一步”按钮继续. 首先创建交Swap分区,鼠标单击“创建”按钮,在弹出的“生成存储”对话框中,生成分区选择“标准分区”:鼠标单 ...