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实体类
1 public class Club2 {3 public int ClubId { get; set; }4 public string Name { get; set; }5 public string City { get; set; }6 }
接下来,创建一个名为Recipe4Context的类,并将代码清单5-9中的代码添加到其中,并确保其派生到DbContext类。
代码清单5-9. 上下文对象Recipe4Contex
1 public class Recipe4Context : DbContext 2 { 3 public Recipe4Context() 4 : base("Recipe4ConnectionString") 5 { 6 // 禁用实体框架的模型兼容性 7 Database.SetInitializer(null); 8 } 9 10 protected override void OnModelCreating(DbModelBuilder modelBuilder) 11 { 12 modelBuilder.Entity ().ToTable("Chapter5.Club"); 13 } 14 15 public DbSet Clubs { get; set; } 16 }
接下来添加App.Config文件到项目中,并使用代码清单5-10中的代码添加到文件的ConnectionStrings小节下。
代码清单5-10. 连接字符串
在这个模型中,我们有一个实体类型Club,你可以通过查询获取各种各样的俱乐部(Clubs). 我们可以通过查询DbSet的属性Local来减少与数据库的交互。它是对Club实体的包装。属性Local 公布了一个内存实体对象的动态集合(Observable Collection),与上下文对象保持同步。代码清单5-11演示了Local动态集合的用法。
代码清单5-11. DbSet对象中Local 属性的一般用法
1 int desertSunId; 2 3 using (var context = new Recipe4Context()) 4 { 5 var starCity = new Club {Name = "Star City Chess Club", City = "New York"}; 6 var desertSun = new Club {Name = "Desert Sun Chess Club", City = "Phoenix"}; 7 var palmTree = new Club {Name = "Palm Tree Chess Club", City = "San Diego"}; 8 9 context.Clubs.Add(starCity);10 context.Clubs.Add(desertSun);11 context.Clubs.Add(palmTree);12 13 context.SaveChanges();14 15 desertSunId = desertSun.ClubId;16 }17 18 using (var context = new Recipe4Context())19 {20 Console.WriteLine("\nLocal Collection Behavior");21 Console.WriteLine("=================");22 23 Console.WriteLine("\nNumber of Clubs Contained in Local Collection: {0}", context.Clubs.Local.Count);24 Console.WriteLine("=================");25 26 Console.WriteLine("\nClubs Retrieved from Context Object");27 Console.WriteLine("=================");28 foreach (var club in context.Clubs.Take(2))29 {30 Console.WriteLine("{0} is located in {1}", club.Name, club.City);31 }32 33 Console.WriteLine("\nClubs Contained in Context Local Collection");34 Console.WriteLine("=================");35 foreach (var club in context.Clubs.Local)36 {37 Console.WriteLine("{0} is located in {1}", club.Name, club.City);38 }39 40 context.Clubs.Find(desertSunId);41 42 Console.WriteLine("\nClubs Retrieved from Context Object - Revisted");43 Console.WriteLine("=================");44 foreach (var club in context.Clubs)45 {46 Console.WriteLine("{0} is located in {1}", club.Name, club.City);47 }48 49 Console.WriteLine("\nClubs Contained in Context Local Collection - Revisted");50 Console.WriteLine("=================");51 foreach (var club in context.Clubs.Local)52 {53 Console.WriteLine("{0} is located in {1}", club.Name, club.City);54 }55 56 //获取local集合的引用 57 var localClubs = context.Clubs.Local;58 59 // 添加一个新的 Club60 var lonesomePintId = -999;61 localClubs.Add(new Club62 {63 City = "Portland",64 Name = "Lonesome Pine",65 ClubId = lonesomePintId66 });67 68 // 删除 Desert Sun club69 localClubs.Remove(context.Clubs.Find(desertSunId));70 71 Console.WriteLine("\nClubs Contained in Context Object - After Adding and Deleting");72 Console.WriteLine("=================");73 foreach (var club in context.Clubs)74 {75 Console.WriteLine("{0} is located in {1} with a Entity State of {2}",76 club.Name, club.City, context.Entry(club).State);77 }78 79 Console.WriteLine("\nClubs Contained in Context Local Collection - After Adding and Deleting");80 Console.WriteLine("=================");81 foreach (var club in localClubs)82 {83 Console.WriteLine("{0} is located in {1} with a Entity State of {2}",84 club.Name, club.City, context.Entry(club).State);85 }86 87 Console.WriteLine("\nPressto continue...");88 Console.ReadLine();
代码清单5-11的输出如下:
Local Collection Behavior=================Number of Clubs Contained in Local Collection: 0=================Clubs Retrieved from Context Object=================Star City Chess Club is located in New YorkDesert Sun Chess Club is located in PhoenixClubs Contained in Context Local Collection=================Star City Chess Club is located in New YorkDesert Sun Chess Club is located in PhoenixClubs Retrieved from Context Object - Revisted=================Star City Chess Club is located in New YorkDesert Sun Chess Club is located in PhoenixPalm Tree Chess Club is located in San DiegoClubs Contained in Context Local Collection - Revisted=================Star City Chess Club is located in New YorkDesert Sun Chess Club is located in PhoenixPalm Tree Chess Club is located in San DiegoClubs Contained in Context Object – After Adding and Deleting=================Star City Chess Club is located in New York with a Entity State of UnchangedDesert Sun Chess Club is located in Phoenix with a Entity State of DeletedPalm Tree Chess Club is located in San Diego with a Entity State of UnchangedClubs Contained in Context Local Collection – After Adding and Deleting=================Star City Chess Club is located in New York with a Entity State of UnchangedPalm Tree Chess Club is located in San Diego with a Entity State of UnchangedLonesome 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/