翻譯的初衷以及爲何選擇《Entity Framework 6 Recipes》來學習,請看本系列開篇html
問題ios
你想使用分頁和過濾來建立查詢。sql
解決方案框架
假設你有如圖3-13所示的模型,模型中有一個Custormer實體類型。ide
圖3-13 包含一個Customer實體類型的模型函數
你有一個基於過濾條件來顯示客戶信息的應用。你的公司有許多客戶(也許數百萬!),爲了保證儘量響應的用戶體驗,你想在每一頁上只顯示必定數量的客戶。建立一個查詢,它能過慮客戶並按頁返回可控數量的結果集。如代碼清單3-26所示。學習
代碼清單3-26. 一個包含過濾和分頁的查詢測試
1 using (var context = new EFRecipesEntities()) 2 { 3 // 刪除以前的數據 4 context.Database.ExecuteSqlCommand("delete from chapter3.customer"); 5 // 添加新的測試數據 6 context.Customers.Add(new Customer 7 { 8 Name = "Roberts, Jill", 9 Email = "jroberts@abc.com" 10 }); 11 context.Customers.Add(new Customer 12 { 13 Name = "Robertson, Alice", 14 Email = "arob@gmail.com" 15 }); 16 context.Customers.Add(new Customer 17 { 18 Name = "Rogers, Steven", 19 Email = "srogers@termite.com" 20 }); 21 context.Customers.Add(new Customer 22 { 23 Name = "Roe, Allen", 24 Email = "allenr@umc.com" 25 }); 26 context.Customers.Add(new Customer 27 { 28 Name = "Jones, Chris", 29 Email = "cjones@ibp.com" 30 }); 31 context.SaveChanges(); 32 } 33 34 35 using (var context = new EFRecipesEntities()) 36 { 37 string match = "Ro"; 38 int pageIndex = 0; 39 int pageSize = 3; 40 41 var customers = context.Customers.Where(c => c.Name.StartsWith(match)) 42 //var customers = context.Customers.Where(c => c.Name.Contains(match)) 43 .OrderBy(c => c.Name) 44 .Skip(pageIndex * pageSize) 45 .Take(pageSize); 46 Console.WriteLine("Customers Ro*"); 47 foreach (var customer in customers) 48 { 49 Console.WriteLine("{0} [email: {1}]", customer.Name, customer.Email); 50 } 51 } 52 53 using (var context = new EFRecipesEntities()) 54 { 55 string match = "Ro%"; 56 int pageIndex = 0; 57 int pageSize = 3; 58 59 var esql = @"select value c from Customers as c 60 where c.Name like @Name 61 order by c.Name 62 skip @Skip limit @Limit"; 63 Console.WriteLine("\nCustomers Ro*"); 64 var customers = ((IObjectContextAdapter)context).ObjectContext.CreateQuery<Customer>(esql, new[] 65 { 66 new ObjectParameter("Name",match), 67 new ObjectParameter("Skip",pageIndex * pageSize), 68 new ObjectParameter("Limit",pageSize) 69 }); 70 foreach (var customer in customers) 71 { 72 Console.WriteLine("{0} [email: {1}]", customer.Name, customer.Email); 73 } 74 } 75 76 Console.WriteLine("\nPress <enter> to continue..."); 77 Console.ReadLine();
代碼清單3-26的輸出以下:ui
Customers Ro* Roberts, Jill [email: jroberts@abc.com] Robertson, Alice [email: arob@gmail.com] Roe, Allen [email: allenr@umc.com] Customers Ro* Roberts, Jill [email: jroberts@abc.com] Robertson, Alice [email: arob@gmail.com] Roe, Allen [email: allenr@umc.com]
原理spa
在代碼清單3-26中,針對這個問題,咱們展現了不一樣的方法。在第一種方法中,咱們使用了LINQ to Entities擴展方法建立了一個LINQ查詢。咱們使用Where()方法過濾結果集,過慮條件爲,姓以「Ro「開頭。由於咱們在lambda表達工中使用了擴展方法StartsWith()。咱們不須要使用SQL的通配符表達式「Ro%"。
過濾後,咱們使用OrderBy()方法對結果集排序,排序後的結果集經過方法Skip()來獲取。咱們使用Skip()方法跳過PageIndex頁,每頁的大小爲PageSize. 使用Take()方法來獲取受限的結果集(譯註:從結果集獲取指定頁大小的記錄數),咱們只須要獲取結果集中的一頁。
注意,在代碼塊中,咱們使用LINQ擴展方法建立了一個完整的查詢,而不是咱們以前看到的SQL查詢表達式。Skip()和Take()方法只在擴展方法中公佈,不是查詢語法。
第二種方法,咱們構建了一個完整的參數化的Entity SQL表達式,這也許是你最熟悉的方式,可是這在使用字符串和可執行代碼(C#)來表示查詢的兩種方式間產生了固有的不匹配風險。
問題
你有一個包含DateTime類型屬性的實體,你想經過DateTime類型屬性的Date部分來對實體的實例進行分組。
解決方案
假設你有如圖3-14所示的模型,模型中有一個Registration實體類型,該實體類型包含一個DateTime類型的屬性。
圖3-14 模型中有一個Registration實體類型,該實體類型包含一個DateTime類型的屬性
該示例使用Code-First方法,在代碼清單3-27中,咱們建立了一些實體。
代碼清單3-27. Registration實體類型
1 public class Registration 2 { 3 public int RegistrationId { get; set; } 4 public string StudentName { get; set; } 5 public DateTime? RegistrationDate { get; set; } 6 }
接下來,代碼清單3-28中建立了上下文對象,它是用Code-First方法訪問實體框架功能的入口。
代碼清單3-28. 上下文對象
1 public class EFRecipesEntities : DbContext 2 { 3 public EFRecipesEntities() 4 : base("ConnectionString") {} 5 public DbSet<Registration> Registrations { get; set; } 6 protected override void OnModelCreating(DbModelBuilder modelBuilder) 7 { 8 modelBuilder.Entity<Registration>().ToTable("Chapter3.Registration"); 9 base.OnModelCreating(modelBuilder); 10 } 11 }
咱們使用RegistrationDate屬性的Date部分對全部的registrations進行分組,你可能會對LINQ中的 group by RegistrationDate.Date動心.雖然能過編譯,可是你仍會獲得一個運行時錯誤,該錯誤描述Date不能轉換成SQL。 爲了能使用RegistrationDate屬性的Date部分來分組,請看代碼清單3-29.
代碼清單3-29. 使用DateTime類型屬性的Date部分對實例進行分組
1 using (var context = new EFRecipesEntities()) 2 { 3 // 刪除以前的測試數據 4 context.Database.ExecuteSqlCommand("delete from chapter3.registration"); 5 // 添加新的測試數據 6 context.Registrations.Add(new Registration 7 { 8 StudentName = "Jill Rogers", 9 RegistrationDate = DateTime.Parse("12/03/2009 9:30 pm") 10 }); 11 context.Registrations.Add(new Registration 12 { 13 StudentName = "Steven Combs", 14 RegistrationDate = DateTime.Parse("12/03/2009 10:45 am") 15 }); 16 context.Registrations.Add(new Registration 17 { 18 StudentName = "Robin Rosen", 19 RegistrationDate = DateTime.Parse("12/04/2009 11:18 am") 20 }); 21 context.Registrations.Add(new Registration 22 { 23 StudentName = "Allen Smith", 24 RegistrationDate = DateTime.Parse("12/04/2009 3:31 pm") 25 }); 26 context.SaveChanges(); 27 } 28 29 using (var context = new EFRecipesEntities()) 30 { 31 var groups = from r in context.Registrations 32 // 憑藉內置的TruncateTime函數提取Date部分 33 group r by DbFunctions.TruncateTime(r.RegistrationDate) 34 into g 35 select g; 36 foreach (var element in groups) 37 { 38 Console.WriteLine("\nRegistrations for {0}", 39 ((DateTime)element.Key).ToShortDateString()); 40 foreach (var registration in element) 41 { 42 Console.WriteLine("\t{0}", registration.StudentName); 43 } 44 } 45 } 46 47 Console.WriteLine("\nPress <enter> to continue..."); 48 Console.ReadLine();
代碼清單3-29輸出以下:
Registrations for 12/3/2009 Jill Rogers Steven Combs Registrations for 12/4/2009 Robin Rosen Allen Smit
原理
對registrations分組的分組鍵是經過Truncate()函數提RegistrationDate屬性中的Date部分。這是實體框架的內置函數,包含在DbFunctions類中,它只提取DateTime中的Date部分。內置的DbFunctions類,包含着大量的,格式化、聚合、字符串操做、日期和數字服務。它在命名空間System.Data.Entity中。遺留類,EntityFunctios,是在EF6以前的版本中使用的,它仍然能在EF6中使用,但你會獲得一個編譯警告,它建議你使用最親的DbFunctions類。咱們將在11章繼續討論它。
實體框架交流QQ羣: 458326058,歡迎有興趣的朋友加入一塊兒交流
謝謝你們的持續關注,個人博客地址:http://www.cnblogs.com/VolcanoCloud/