《Entity Framework 6 Recipes》中文翻譯系列 (17) -----第三章 查詢之分頁、過濾和使用DateTime中的日期部分分組

翻譯的初衷以及爲何選擇《Entity Framework 6 Recipes》來學習,請看本系列開篇html

3-12 分頁和過濾

問題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#)來表示查詢的兩種方式間產生了固有的不匹配風險。

 

 

3-13 按日期分組

問題

  你有一個包含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/

相關文章
相關標籤/搜索