《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 从已存在的数据库创 ...
随机推荐
- PHP开发笔记:二维数组根据某一项来进行排序
比如说我们现在有一个二维数组: $arr = array( ‘d' => array(‘id' => 5, ‘name' => 1, ‘age' => 7), ‘b' => ...
- php sprintf 函数的用法
sprintf() 函数把格式化的字符串写入变量中. arg1.arg2.++ 参数将被插入到主字符串中的百分号(%)符号处.该函数是逐步执行的.在第一个 % 符号处,插入 arg1,在第二个 % 符 ...
- 代码中使用StoryBoard和DoubleAnimation的方法
TranslateTransformを対象に.DoubleAnimation型のアニメーションを使用して.TranslateTransform.Xプロパティを ”-1 * Imageコントロールの幅” ...
- 常用.NET库使用总结
Json.NET 获取类实例对应的jtoken:JObject.FromObject() 获取数组实例对应的jtoken:JArray.FromObject() Json.NET将枚举转换为int R ...
- 【原】iOS学习之应用之间的操作
关于应用之间的相互操作,小编一直觉得非常高大上,在一次面试中被面试官一顿暴虐,今天小编就决定学习一下!经过一顿度娘,找到一些博客,不过都比较凌乱,我就打算自己整理一下! 首先要说的是每一个APP都可以 ...
- 转载:Chrome调试折腾记_(1)调试控制中心快捷键详解!!!
转载:http://blog.csdn.net/crper/article/details/48098625 大多浏览器的调试功能的启用快捷键都一致…按下F12;还是熟悉的味道; 或者直接 Ctrl ...
- router路由去掉#!的踩坑记
项目中在研究去掉router#!的过程中的踩坑过程.
- Linux Shell中单引号、双引号、反引号的区别【转载】
linux shell可以识别4种不同类型的引字符号: 单引号字符' 双引号字符" 反斜杠字符\ 反引号字符` 1. 单引号 ( '' )# grep Susan phonebook Sus ...
- Erlang error handling
Erlang error handling Contents Preface try-catch Process link Erlang-way error handling OTP supervis ...
- Smart3D系列教程5之 《案例实战演练2——大区域的地形三维重建》
一.前言 Wish3D出品的Smart3D系列教程中,前面一讲说明了小物件的照片三维重建,相信大家对建模的流程有了一定的了解.这次讲解中,我们将演示说明以一组无人机倾斜摄影照片为原始数据,通过Smar ...