Entity Framework提供了三种加载相关实体的方法:Lazy Loading,Eager Loading和Explicit Loading。首先我们先来看一下MSDN对三种加载实体方法的定义。

Lazy Loading:对于这种类型的加载,在您访问导航属性时,会从数据源自动加载相关实体。 使用此加载类型时,请注意,如果实体尚未在 ObjectContext 中,则您访问的每个导航属性都会导致针对数据源执行一个单独的查询。

Eager Loading:当您了解应用程序需要的相关实体的图形的确切形状时,可以使用 ObjectQuery 的 Include 方法来定义查询路径,此查询路径控制将哪些相关实体作为初始查询的一部分返回。 当定义查询路径时,仅需对数据库请求一次,即可在单个结果集中返回查询路径所定义的所有实体,并且属于在路径中定义的类型的所有相关实体将随查询返回的每个对象一起加载。

Explicit Loading:将实体显式加载到 ObjectContext 需要多次往返数据库,并且可能需要多个活动结果集,但是返回的数据量仅限于所加载的实体。 可以对 EntityCollection或 EntityReference 使用 Load 方法或对 ObjectContext 使用 LoadProperty 方法,以便从数据源显式检索相关实体。 对于 Load 方法的每个调用都会打开与数据库的连接,以检索相关信息。 这可确保在没有对相关实体的显式请求时,始终不会执行查询。

下面我们就以上三种加载方式来一一进行测试

在测试之前,我们先建立一个测试用的数据库,并在其中插入一些数据:

图1

Lazy Loading

在Entity Framework4.0及其以后版本,LazyLoading是默认打开的,从数据库生成Model后,我们可以在EDMX文件空白处单击,并在属性窗口看到这一设置:

图2

也可以以XML形式打开EDMX文件,在CSDL部分看到这一设置:

 1  <!-- CSDL content -->
2 <edmx:ConceptualModels>
3 <Schema Namespace="TestModel" Alias="Self" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2008/09/edm">
4 <EntityContainer Name="TestEntities" annotation:LazyLoadingEnabled="true">
5 <EntitySet Name="Players" EntityType="TestModel.Player" />
6 <EntitySet Name="PlayerDetails" EntityType="TestModel.PlayerDetail" />
7 <EntitySet Name="Teams" EntityType="TestModel.Team" />
8 <AssociationSet Name="FK_Player_Team1" Association="TestModel.FK_Player_Team1">
9 <End Role="Team" EntitySet="Teams" />
10 <End Role="Player" EntitySet="Players" />
11 </AssociationSet>
12 <AssociationSet Name="FK_PlayerDetails_Player" Association="TestModel.FK_PlayerDetails_Player">
13 <End Role="Player" EntitySet="Players" />
14 <End Role="PlayerDetails" EntitySet="PlayerDetails" />
15 </AssociationSet>
16 </EntityContainer>

注意:Lazy Loading的设置是针对所有Model的,并非某一个Model。

下面,我们写一段简单的代码来测试一下Lazy Loading:

using (var context = new TestEntities())
{
IQueryable<Team> teams = from t in context.Teams select t;
foreach (Team t in teams)
{
Console.WriteLine(t.Players.Count());
}
Console.Read();
}

运行后的结果如下图:

图3

我们可以看到,在query语句中,我们只是要求返回所有的team信息,并没有像数据库请求加载player的信息,但在Foreach语句中,我们要求打印出每支team的player数量,却成功了,这就是Lazy Loading实现的效果。实际上,当执行Count语句时,程序会再去取请求数据库,返回player信息,这也就是说,如果我们有100支球队,程序会访问100次数据库来执行此操作。

下面我们关闭Lazy Loading来看看效果。关闭Lazy Loading有多种方法,我们可以在图2的属性窗口直接将Lazy Loading Enabled设置为False,也可以在XML代码中将Lazy Loading Enabled赋值False,以下我们用程序代码来关闭Lazy Loading并执行上面代码来看一下效果:

using (var context = new TestEntities())
{
//Disable Lazy Loading
context.ContextOptions.LazyLoadingEnabled = false; IQueryable<Team> teams = from t in context.Teams select t;
foreach (Team t in teams)
{
Console.WriteLine(t.Players.Count());
}
Console.Read();
}

执行结果如下:

图4

从执行结果我们可以看到,当执行Foreach语句时,程序并没有去查询数据库,而我们的query语句又没有向数据库请求关于player的信息,故无法打印出player的数量。

最后我们来总结一下Lazy Loading的优势和劣势:当打开Lazy Loading时,我们可以不用去在意某实体是否已经加载,不会出现在调用某一实体时,出现null的尴尬,省去程序员不少心力,但同时劣势也非常明显,如果我们有大量实体,且频繁去调用相关实体,程序就会频繁地访问数据库,这很显然地会影响程序的性能。

下一次我们会来分析关闭Lazy Loading的情况下,如何显示加载相关实体,即Explicit Loading。

上一回我们在《Entity Framework加载相关实体——Lazy Loading》分析了Lazy Loading,这一回我们来分析一下在关闭Lazy Loading的情况下,如果显式加载实体。

数据库我们依旧使用Lazy Loading中使用的数据库。之前我们分析过来,当Lazy Loading关闭时,执行以下代码是无法得到结果的,因为Player的信息并没有被加载。

1  using (TestEntities context = new TestEntities())
2 {
3 IQueryable<Team> teams = from t in context.Teams select t;
4 foreach (Team t in teams)
5 {
6 Console.WriteLine(t.Players.Count());
7 }
8 Console.Read();
9 }

如果我们想要得到t.Players.Count()的结果,我们可以显式地加载Player信息:

 1 using (TestEntities context = new TestEntities())
2 {
3 IQueryable<Team> teams = from t in context.Teams select t;
4 foreach (Team t in teams)
5 {
6 //explicitly loading players
7 t.Players.Load();
8 Console.WriteLine(t.Players.Count());
9 }
10 Console.Read();
11 }

当t.Players.Load()执行时,Object Service会向数据库发出请求返回该team的所有player信息。

我们也可以从many端加载与它相对应的one端,在这个例子中也就是从Player加载与该player相对应的team信息。这里需要用到TeamReference:

 1  using (TestEntities context = new TestEntities())
2 {
3 IQueryable<Player> players = from p in context.Players select p;
4 foreach (Player p in players)
5 {
6 if (p.Age > 30)
7 {
8 p.TeamReference.Load();
9 Console.WriteLine(p.PlayerName + " -> " + p.Team.TeamName);
10 }
11 }
12 Console.Read();
13 }

执行结果如下:

当我们打出p.后会发现,智能提示中出现了Team和TeamReference,这里我们选择TeamReference,因为EF将p.Team认为就是一个Team实体。

无论使用Lazy Loading还是将Load方法放入foreach循环语句,都会导致程序频繁访问数据库,导致程序性能下降。我们可以选择性地加载需要的实体,例如上面代码,我们只加载年龄超过30岁的球员所在球队的信息。

至此,Lazy Loading和Explicit Loading都已经分析完了,下一次我们来分析加载相关实体的最后一种形式Eager Loading.

在前面两回我们分别分析了Lazy LoadingExplicit Loading,这一回我们来分析一下Eager Loading。

在某些情况下,我们可能事先知道要需要加载某些实体的相关实体,这时我们就可以用Include方法来在加载实体的查询语句中把相关实体也一并查询出来。下面我们还用前两回使用的数据库来写一个例子来分析一下Eager Loading:

 1 using (var context = new TestEntities())
2 {
3 var players = from p in context.Players.Include("Team").Include("PlayerDetails") where (p.PlayerDetails.Any(d => d.Height > 200)) select p;
4 foreach (var v in players)
5 {
6 string output = string.Format("Team: {0} Player: {1}", v.Team.TeamName, v.PlayerName);
7 Console.WriteLine(output);
8 }
9 Console.Read();
10 }

以上代码,我们查询出了身高在2米以上的球员的名字和所在球队,在查询Player信息的同时,也查询了Team表和PlayerDetails表的信息,将三个表的信息全部加载了进来。这里我们需要注意,我们可以控制将哪些相关实体加载入内,但不能够对Include进来的实体进行筛选,如以下代码:

1 var teams = from t in context.Teams.Include("Players") where (t.TeamID == 1) select t;

我们可以选择加载哪些球队,却不能选择加载球队的哪些球员,该球队的所有球员都将被加载进来。

至此,Entity Framework加载相关实体的三种形式全部分析完毕!

Entity Framework加载相关实体——延迟加载Lazy Loading、贪婪加载Eager Loading、显示加载Explicit Loading的更多相关文章

  1. 《Entity Framework 6 Recipes》中文翻译系列 (43) ------ 第八章 POCO之使用POCO加载实体

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 8-2  使用POCO加载关联实体 问题 你想使用POCO预先加载关联实体. 解决方 ...

  2. Entity Framework 第三篇 实体特性声明

    Entity Framework中对实体的特性声明有着严格的要求 1.实体必须要有主键特性,但是如果实体没有主键特性那怎么办? public int ExecuteSqlCommand(string ...

  3. Entity Framework应用:根据实体的EntityState状态实现增删改查

    在上一篇文章中,我们讲解了使用EF实现简单的增删改成,在这篇文章中我们使用实体的EntityState状态来优化数据的增删改查. 一.修改数据 上篇文章中的修改数据的方法是EF官方推荐的方式,即先查询 ...

  4. Entity Framework Core一键生成实体命令

    打开Vs中工具——Nug包管理器——程序包管理控制台 设置启动项目为存储实体模型的类库或控制台 Scaffold-DbContext  "数据库连接字符串" Microsoft.E ...

  5. Entity Framework关联实体的三种加载方法

    推荐文章 EF性能之关联加载 总结很好 一:介绍三种加载方式 Entity Framework作为一个优秀的ORM框架,它使得操作数据库就像操作内存中的数据一样,但是这种抽象是有性能代价的,故鱼和熊掌 ...

  6. Entity Framework Code First实体关联数据加载

    在项目过程中,两个实体数据之间在往往并非完全独立的,而是存在一定的关联关系,如一对一.一对多及多对多等关联.存在关联关系的实体,经常根据一个实体的实例来查询获取与之关联的另外实体的实例. Entity ...

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

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

  8. Entity Framework入门教程(8)---预先加载、延迟加载、显示加载

    1.预先加载 预先加载:在对一种类型的实体进行查询时,将相关的实体作为查询的一部分一起加载.预先加载可以使用Include()方法实现. 1.加载一个相关实体类型 栗子:使用Include()方法从数 ...

  9. Entity Framework学习笔记(五)----Linq查询(2)---贪婪加载

    请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,我们使用了Linq对Entity Framework进行了一个查询,但是通过学习我们却发现了懒加载给我来的性能上的 ...

随机推荐

  1. 认识node.js:express(一)

    express是node.js官方推荐的框架. 安装 npm install express -g 命令中的 “-g” 表示全局(global) 由于新版本(4.x.x)的express的命令集中到了 ...

  2. [LeetCode141]Linked List Cycle

    题目:Given a linked list, determine if it has a cycle in it. 判断一个链表是否有环 代码: /** * Definition for singl ...

  3. iOS_67控件外观对照

    iOS 7 button无边框,操作栏透明,控制器全屏 Tab Bar 对照 iOS 7                                                         ...

  4. Windows Server 2008 R2 SP1 下载地址

    Windows Server 2008 R2 SP1 http://download.microsoft.com/download/0/A/F/0AFB5316-3062-494A-AB78-7FB0 ...

  5. POJ 1699 Best Sequence (DFS+预处理)

    意甲冠军:看图片是晶莹剔透的,正确的, N连接到第一序列(同样的序列部分).总序列获得最短. 主题链接:http://poj.org/problem?id=1699 ~~~~ 思路就是:将N个序列首尾 ...

  6. cocos2D(五岁以下儿童)---- CCNode

    本将主要介绍下CCNode这个类.CCNode是全部节点的基类,当中包含我们经常使用的CCScene(场景).CCLayer(图层).CCSprite(精灵)等.它是一个不可以可视化显示的抽象类,仅仅 ...

  7. SQL Server 2008性能故障排查(四)——TempDB

    原文:SQL Server 2008性能故障排查(四)--TempDB 接着上一章:I/O TempDB: TempDB是一个全局数据库,存储内部和用户对象还有零食表.对象.在SQLServer操作过 ...

  8. 【Unity 3D】学习笔记三十五:游戏实例——摄像机切换镜头

    摄像机切换镜头 在游戏中常常会切换摄像机来观察某一个游戏对象,能够说.在3D游戏开发中,摄像头的切换是不可或缺的. 这次我们学习总结下摄像机怎么切换镜头. 代码: private var Camera ...

  9. JavaScript 比量 Chrome 核心 360 浏览器(关闭和技巧)

    (原因:我相信你会找到360浏览器非常多web会有上述项目的一些问题,不管是"兼容模式"依然是"快速模式".问题也可能存在.非常多用户都装了360杀毒软件,基本 ...

  10. JSP简单的练习-功能标签

    <!-- userfn.jsp --> <%@ page contentType="text/html;charset=gb2312" %> <%@ ...