翻譯的初衷以及為什么選擇《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實體類
1 public class Club 2 { 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<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 屬性的一般用法
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 // 添加一個新的 Club 60 var lonesomePintId = -999; 61 localClubs.Add(new Club 62 { 63 City = "Portland", 64 Name = "Lonesome Pine", 65 ClubId = lonesomePintId 66 }); 67 68 // 刪除 Desert Sun club 69 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("\nPress <enter> to 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 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/