《Entity Framework 6 Recipes》中文翻译系列 (24) ------ 第五章 加载实体和导航属性之查询内存对象
翻译的初衷以及为什么选择《Entity Framework 6 Recipes》来学习,请看本系列开篇
5-4 查询内存对象
问题
你想使用模型中的实体对象,如果他们已经加载到上下文中,便不用与数据库发生交互。另外,你想使用Code-First来管理数据访问。
解决方案
假设你有如图5-12所示的模型。

图5-12 一个包含Club实体对象的简单模型
在Visual Studio中添加一个名为Recipe4的控制台应用,并确保引用了实体框架6的库,NuGet可以很好的完成这个任务。在Reference目录上右键,并选择 Manage NeGet Packages(管理NeGet包),在Online页,定位并安装实体框架6的包。这样操作后,NeGet将下载,安装和配置实体框架6的库到你的项目中。
创建一个名为Club类,复制代码清单5-8中的属性到这个类中,创建club实体。
代码清单5-8. Club实体类
public class Club
{
public int ClubId { get; set; }
public string Name { get; set; }
public string City { get; set; }
}
接下来,创建一个名为Recipe4Context的类,并将代码清单5-9中的代码添加到其中,并确保其派生到DbContext类。
代码清单5-9. 上下文对象Recipe4Contex

1 public class Recipe4Context : DbContext
2 {
3 public Recipe4Context()
4 : base("Recipe4ConnectionString")
5 {
6 // 禁用实体框架的模型兼容性
7 Database.SetInitializer<Recipe3Context>(null);
8 }
9
10 protected override void OnModelCreating(DbModelBuilder modelBuilder)
11 {
12 modelBuilder.Entity<Club>().ToTable("Chapter5.Club");
13 }
14
15 public DbSet<Club> Clubs { get; set; }
16 }

接下来添加App.Config文件到项目中,并使用代码清单5-10中的代码添加到文件的ConnectionStrings小节下。
代码清单5-10. 连接字符串

<connectionStrings>
<add name="Recipe4ConnectionString"
connectionString="Data Source=.;
Initial Catalog=EFRecipes;
Integrated Security=True;
MultipleActiveResultSets=True"
providerName="System.Data.SqlClient" />
</connectionStrings>

在这个模型中,我们有一个实体类型Club,你可以通过查询获取各种各样的俱乐部(Clubs). 我们可以通过查询DbSet的属性Local来减少与数据库的交互。它是对Club实体的包装。属性Local 公布了一个内存实体对象的动态集合(Observable Collection),与上下文对象保持同步。代码清单5-11演示了Local动态集合的用法。
代码清单5-11. DbSet对象中Local 属性的一般用法
int desertSunId;
using (var context = new Recipe4Context())
{
var starCity = new Club {Name = "Star City Chess Club", City = "New York"};
var desertSun = new Club {Name = "Desert Sun Chess Club", City = "Phoenix"};
var palmTree = new Club {Name = "Palm Tree Chess Club", City = "San Diego"};
context.Clubs.Add(starCity);
context.Clubs.Add(desertSun);
context.Clubs.Add(palmTree);
context.SaveChanges();
desertSunId = desertSun.ClubId;
}
using (var context = new Recipe4Context())
{
Console.WriteLine("\nLocal Collection Behavior");
Console.WriteLine("=================");
Console.WriteLine("\nNumber of Clubs Contained in Local Collection: {0}", context.Clubs.Local.Count);
Console.WriteLine("=================");
Console.WriteLine("\nClubs Retrieved from Context Object");
Console.WriteLine("=================");
foreach (var club in context.Clubs.Take())
{
Console.WriteLine("{0} is located in {1}", club.Name, club.City);
}
Console.WriteLine("\nClubs Contained in Context Local Collection");
Console.WriteLine("=================");
foreach (var club in context.Clubs.Local)
{
Console.WriteLine("{0} is located in {1}", club.Name, club.City);
}
context.Clubs.Find(desertSunId);
Console.WriteLine("\nClubs Retrieved from Context Object - Revisted");
Console.WriteLine("=================");
foreach (var club in context.Clubs)
{
Console.WriteLine("{0} is located in {1}", club.Name, club.City);
}
Console.WriteLine("\nClubs Contained in Context Local Collection - Revisted");
Console.WriteLine("=================");
foreach (var club in context.Clubs.Local)
{
Console.WriteLine("{0} is located in {1}", club.Name, club.City);
}
//获取local集合的引用
var localClubs = context.Clubs.Local;
// 添加一个新的 Club
var lonesomePintId = -;
localClubs.Add(new Club
{
City = "Portland",
Name = "Lonesome Pine",
ClubId = lonesomePintId
});
// 删除 Desert Sun club
localClubs.Remove(context.Clubs.Find(desertSunId));
Console.WriteLine("\nClubs Contained in Context Object - After Adding and Deleting");
Console.WriteLine("=================");
foreach (var club in context.Clubs)
{
Console.WriteLine("{0} is located in {1} with a Entity State of {2}",
club.Name, club.City, context.Entry(club).State);
}
Console.WriteLine("\nClubs Contained in Context Local Collection - After Adding and Deleting");
Console.WriteLine("=================");
foreach (var club in localClubs)
{
Console.WriteLine("{0} is located in {1} with a Entity State of {2}",
club.Name, club.City, context.Entry(club).State);
}
Console.WriteLine("\nPress <enter> to continue...");
Console.ReadLine();
代码清单5-11的输出如下:
Local Collection Behavior
=================
Number of Clubs Contained in Local Collection:
=================
Clubs Retrieved from Context Object
=================
Star City Chess Club is located in New York
Desert Sun Chess Club is located in Phoenix
Clubs Contained in Context Local Collection
=================
Star City Chess Club is located in New York
Desert Sun Chess Club is located in Phoenix
Clubs Retrieved from Context Object - Revisted
=================
Star City Chess Club is located in New York
Desert Sun Chess Club is located in Phoenix
Palm Tree Chess Club is located in San Diego
Clubs Contained in Context Local Collection - Revisted
=================
Star City Chess Club is located in New York
Desert Sun Chess Club is located in Phoenix
Palm Tree Chess Club is located in San Diego
Clubs Contained in Context Object – After Adding and Deleting
=================
Star City Chess Club is located in New York with a Entity State of Unchanged
Desert Sun Chess Club is located in Phoenix with a Entity State of Deleted
Palm Tree Chess Club is located in San Diego with a Entity State of Unchanged
Clubs Contained in Context Local Collection – After Adding and Deleting
=================
Star City Chess Club is located in New York with a Entity State of Unchanged
Palm Tree Chess Club is located in San Diego with a Entity State of Unchanged
Lonesome Pine is located in Portland with a Entity State of Added
原理
这个示例使用Club实体对象。开始,我们从Local属性公布的动态集合中获取Club实体对象的数量。注意,图5-13没有SQL查询产生,因为一个对Local属性的查询,是不会产生针对数据库的SQL查询的。

图5-13 访问Local动态集合,不会产生一个SQL查询
现在,结果为0,因为我们还没有通过上下文对象执行一个关于Clubs的查询。记住,Local动态集合会自动地与上下文对象保持同步。
接下来,我们通过上下文对象在数据库中查询前面两个Club实体。并循环输出他们的名称和地点。如图5-14所示。

图5-14 查询上下文对象,总是产生一个SQL查询
随后,我们立即循环相应的Local集合,得到了相同的结果。记住,结果集完全一样,因为Local集合自动与DbContext保持同步。如果新的实体被获取到上下文,通过这些实体,Loacal集合会被自动更新。注意,图5-15中,当访问Local集合时,没有SQL查询生成。

图5-15 访问 local集合,没有生成SQL语句
为了进一步演示Local属性的默认行为,我们通过上下文查询获取第三个Club实体,我们又一次循环上下文对象和Local集合,同样得到了相同的结果。图5-16中,通过查询上下文对象的查询产生了一个SQL语句,图5-17中,能通查询Local集合的查询,没有产生任何SQL语句。

图5-16 查询上下文对象,总是产生一个SQL查询

图5-17 访问 local集合,没有生成SQL语句
接下来,我们添加一个名为 Lonesone Pine Club实体到Local集合中,同时,我们从Local集合中删除Desert Sun Club. 然后我们枚举上下文对象中的Clubs,正如期望的那样,一个SQL查询产生了,如图5-18所示。

图5-18 查询上下文对象,总是产生一个SQL查询
有趣的是,我们看到,在上下文中Desert Sun Club已经被标记为删除,但我们没有看到最新添加的Lonesome Pine Club对象。记住,Lonesome Pine Club已经被添加到上下文中,但我们还没有调用SaveChanges()方法更新到底层据库中。
然而,当我们枚举Local集合时,没有产生针对底层数据库的查询,如图5-19所示。相反,我们看到了最新添加的Lonesome Pine Club对象,但我们不再看到标记为删除的Desert Sun Club对象。 Loacl集合的默认行为是,隐藏任何标记为删除的对象,因为这些对象不于有效。

图5-19 访问 local集合,没有生成SQL语句
本质:访问Local集合不会产生针对底层数据库的SQL查询,访问上下中的属性集合总是会产生一个被发送到数据库中的SQL是查询。
总之,名为Local的属性公布的实体集,是一个动态的集合(Observale Collection)(译注:也有人译为,可观察的集合,但综合该对象的作用和功能来看,个人认为译为动态集合更恰当一些),它是上下文内容的一个镜像。正如本小节演示的那样,查询Local集合非常有效,因为它不会产生针对底层数据库的SQL查询。
实体框架交流QQ群: 458326058,欢迎有兴趣的朋友加入一起交流
谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/VolcanoCloud/
《Entity Framework 6 Recipes》中文翻译系列 (24) ------ 第五章 加载实体和导航属性之查询内存对象的更多相关文章
- 《Entity Framework 6 Recipes》中文翻译系列 (22) -----第五章 加载实体和导航属性之延迟加载
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第五章 加载实体和导航属性 实体框架提供了非常棒的建模环境,它允许开发人员可视化地使 ...
- 《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》中文翻译系列 (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 从已存在的数据库创 ...
随机推荐
- vue-cli
vue-cli 脚手架 vue-loader 作用:提供基本项目结构 本身集成了很多项目模板:simple,webpack ,webpack-simple; simple:几乎没什么用: webp ...
- Asp.Net中使用OpenRowSet操作Excel表,导入Sql Server(实例)
有两种接口可供选择:Microsoft.Jet.OLEDB.4.0(以下简称 Jet 引擎)和Microsoft.ACE.OLEDB.12.0(以下简称 ACE 引擎). Jet 引擎大家都很熟悉,可 ...
- httpclient 无信任证书使用https
1.当不需要使用任何证书访问https网页时,只需配置信任任何证书 HttpClient http = new HttpClient(); String url = "https://pay ...
- hibernate框架int和Integer类型区别
hibernate 框架在定义实体时,int类型最好定义为Inttger类型,因为在注入时int是值类型不允许为空.
- 【NEUQACM OJ】1018: A+B again
1018: A+B again 题目描述 谷学长有一个非常简单的问题给你,给你两个整数A和B,你的任务是计算A+B. 输入 输入的第一行包含一个整数T(T<=20)表示测试实例的个数,然后2*T ...
- oracle EXP导出一张表时使用query参数指定where条件
oracle exp 导出一个表的部分内容,使用query参数可加上SQL的where条件进行过滤 注意:如果需要使用到日期字符串格式等单引号,需要使用双引号将where条件括起来,而且双引号要用\做 ...
- JSTL标签库
JSP页面作为内嵌java的Html简化了Servlet在控制页面显示的语法,但JSP脚本中的表达式功能不够强大,语法也稍显繁杂,EL(Expression Language)表达式语言的出现能够大大 ...
- TopCoder SRM 639 Div.2 500 AliceGameEasy
题意: 一个游戏有n轮,有A和B比赛,谁在第 i 轮得胜,就获得 i 分,给出x,y,问A得x分,B得y分有没有可能,如果有,输出A最少赢的盘数 解题思路: 首先判断n(n+1)/2 = (x+y)是 ...
- windows消息机制详解(转载)
消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了.例如,单击鼠标.改变窗口尺寸.按下键盘上的一个键都会使Windows发送一个消息给应用程序.消息本身是作为一个记录传递给应用程序的 ...
- 20155315庄艺霖--对做中学的理解及对c语言和Java的看法
关于做中学的理解及技能训练的思考 在写这篇博客之前,我首先阅读了娄老师的博客,对做中学的概念很感兴趣.我们常说知识要学以致用,做中学强调的是在用的过程中有新的收获和体会来进一步巩固学习.细数我学过的课 ...