《Entity Framework 6 Recipes》中文翻譯系列 (13) -----第三章 查詢之使用Entity SQL

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

3-4使用實體SQL查詢模型

問題sql

  你想經過執行Entity SQL語句來查詢你的實體數據模型並返回強類型的對象。數據庫

解決方案express

  假設你有圖3-5所示的模型,它包含一個Customer實體類型。這個實體類型有一個Name屬性和Email屬性。你要使用Entiyt SQL查詢這個模型。編程

圖3-5 包含一個Customer實體類型的模型服務器

 

   使用Entity SQL(eSQL)查詢模型,Entity SQL是SQL在實體框架中實現的一種方言,代碼清單3-8中的模式正是使用這種方式。當在查詢底層數據存儲時,你也許更青睞LINQ-to-Entity。因爲LINQ提供了許多特性以及強類型的編程體驗。Entity SQL在經過實體數據模型,構建動態查詢底層數據存儲時提供了靈活性。框架

代碼清單3-8. 使用Object Services和EntityClient執行一個Entity SQL語句post

 1 using (var context = new EFRecipesEntities())
 2             {
 3                 // 刪除測試數據
 4                 context.Database.ExecuteSqlCommand("delete from chapter3.customer");
 5                 // 添加新的測試數據
 6                 var cus1 = new Customer
 7                 {
 8                     Name = "Robert Stevens",
 9                     Email = "rstevens@mymail.com"
10                 };
11                 var cus2 = new Customer
12                 {
13                     Name = "Julia Kerns",
14                     Email = "julia.kerns@abc.com"
15                 };
16                 var cus3 = new Customer
17                 {
18                     Name = "Nancy Whitrock",
19                     Email = "nrock@myworld.com"
20                 };
21                 context.Customers.Add(cus1);
22                 context.Customers.Add(cus2);
23                 context.Customers.Add(cus3);
24                 context.SaveChanges();
25             }
26 
27             //使用ObjectContext對象中的 object services
28             using (var context = new EFRecipesEntities())
29             {
30                 Console.WriteLine("Querying Customers with eSQL Leveraging Object Services...");
31                 string esql = "select value c from Customers as c";
32                 // 將DbContext轉換爲底層的ObjectContext, 由於DbContext沒有提供對Entity SQL查詢的支持
33                 var customers = ((IObjectContextAdapter)context).ObjectContext.CreateQuery<Customer>(esql);
34                 foreach (var customer in customers)
35                 {
36                     Console.WriteLine("{0}'s email is: {1}",
37                                        customer.Name, customer.Email);
38                 }
39             }
40 
41             Console.WriteLine(System.Environment.NewLine);
42 
43             //使用 EntityClient
44             using (var conn = new EntityConnection("name=EFRecipesEntities"))
45             {
46                 Console.WriteLine("Customers Customers with eSQL Leveraging Entity Client...");
47                 var cmd = conn.CreateCommand();
48                 conn.Open();
49                 cmd.CommandText = "select value c from EFRecipesEntities.Customers as c";
50                 using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
51                 {
52                     while (reader.Read())
53                     {
54                         Console.WriteLine("{0}'s email is: {1}",
55                                            reader.GetString(1), reader.GetString(2));
56                     }
57                 }
58             }
59 
60             Console.WriteLine("\nPress <enter> to continue...");
61             Console.ReadLine();
62         }

下面是代碼清單3-8的輸出:性能

Querying Customers with eSQL Leveraging Object Services...
Robert Stevens's email is: rstevens@mymail.com
Julia Kerns's email is: julia.kerns@abc.com
Nancy Whitrock's email is: nrock@myworld.com
Customers Customers with eSQL Leveraging Entity Client...
Robert Stevens's email is: rstevens@mymail.com
Julia Kerns's email is: julia.kerns@abc.com
Nancy Whitrock's email is: nrock@myworld.com

  

原理學習

  有代碼清單3-8中,一開始,咱們刪除了以前數據庫中的測試數據。而後咱們建立了三個customers,並將其添加到上下文對象中,並調用SaveChanges()將數據插入到數據庫。

  使用數據庫中的客戶數據,咱們演示了兩種不一樣的,使用Entity SQL獲取數據的方法。在第一種方法中,咱們用CreateQuery()方法,該方法是在遺留的ObjectContext上下文對象中公佈的,使用它建立一個ObjectQuery對象。 注意,咱們是如何將DbContext轉換成一個ObjectContextAdapter類型,並經過它獲得底層的ObjectContext類型(記住,最新的DbContext包裝了老的Objetcontext,以此改善開發者的編程體驗)。咱們這樣作是由於DbContext不提供對 eSQL查詢的直接支持。同時也需注意,咱們使用佔位符value代替Customer類型,而後將esql做爲參數傳遞給CreateQuery()方法。當咱們枚舉customers集合時,查詢在數據庫被執行,同時,咱們把結果集合輸出到控制檯。由於集合中的每一個元素都是Customer實體類型的一個實例,因此,咱們能夠得到強類型的方式來使用每一個元素的屬性。

  在第二種方法中,咱們使用EntityClinet庫,它和咱們使用SqlClient或者ADO.NET提供的別的Client類似。 先建立一個數據庫鏈接,而後建立一個command對象,並打開數據庫鏈接。接下來,咱們用要執行的Entity SQL語句來初始化command對象。使用ExecuteReader()方法來執行command,並得到一個EntityDataReader,它與DbDataReader類似。最後,咱們使用Read()方法枚舉結果集。

  注意,在代碼清單3-8中,Entity SQL語句使用的value關鍵字。 當咱們須要獲取完整的實體時,這個關鍵字很是有用。若是咱們的Entity SQL 語句投影列的一個子集(也就是說,咱們使用Entity SQL 表達式使用或建立部分列)咱們無需使用value關鍵字。這意味着像代碼清單3-9所演示的同樣,直接使用DbDataRecord.

代碼清單3-9. 使用Object Services 和EntityClient投影

 1  // 使用object ervices,無value關鍵字
 2             using (var context = new EFRecipesEntities())
 3             {
 4                 Console.WriteLine("Customers...");
 5                 string esql = "select c.Name, c.Email from Customers as c";
 6                 var records = ((IObjectContextAdapter)context).ObjectContext.CreateQuery<DbDataRecord>(esql);
 7                 foreach (var record in records)
 8                 {
 9                     var name = record[0] as string;
10                     var email = record[1] as string;
11                     Console.WriteLine("{0}'s email is: {1}", name, email);
12                 }
13             }
14             Console.WriteLine();
15             //使用EntityClient,無value關鍵字
16             using (var conn = new EntityConnection("name=EFRecipesEntities"))
17             {
18                 Console.WriteLine("Customers...");
19                 var cmd = conn.CreateCommand();
20                 conn.Open();
21                 cmd.CommandText = @"select c.Name, C.Email from
22 EFRecipesEntities.Customers as c";
23                 using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
24                 {
25                     while (reader.Read())
26                     {
27                         Console.WriteLine("{0}'s email is: {1}",
28                         reader.GetString(0), reader.GetString(1));
29                     }
30                 }
31             }

 

  當你使用Entity SQL 投影,返回的結果集是一個包含投影中的全部列的DbDataRecord。使用value關鍵字,查詢返回的單獨對象,是DbDataRecord中的第一個元素。

 

3-5 查找主從複合結構關係中的擁有從表記錄的主表記錄

問題
  你有兩個一對多關聯(主從複合結構關係)的實體。你要查詢全部的至少擁有一個實體與它關聯的實體。

解決方案

  假設你有一個擁有博客(BlogPost)和與之關聯的評論(Comment)的模型。一些博客有不少評論,一些有少許或是沒有評論。這個模型看起像圖3-6。

圖3-6 一個擁有博客(BlogPost)和與之關聯的評論(Comment)的模型

  

  你要找出全部有評論的博客,可使用LINQ to Entities 或者 Entity SQL。按代碼清單3-10所演示的模式進行。

 1 using (var context = new EFRecipesEntities())
 2             {
 3                 // 刪除測試數據
 4                 context.Database.ExecuteSqlCommand("delete from chapter3.comment");
 5                 context.Database.ExecuteSqlCommand("delete from chapter3.blogpost");
 6                 // 添加新的測試數據
 7                 var post1 = new BlogPost
 8                 {
 9                     Title = "The Joy of LINQ",
10                     Description = "101 things you always wanted to know about LINQ"
11                 };
12                 var post2 = new BlogPost
13                 {
14                     Title = "LINQ as Dinner Conversation",
15                     Description = "What wine goes with a Lambda expression?"
16                 };
17                 var post3 = new BlogPost
18                 {
19                     Title = "LINQ and our Children",
20                     Description = "Why we need to teach LINQ in High School"
21                 };
22                 var comment1 = new Comment
23                 {
24                     Comments = "Great post, I wish more people would talk about LINQ"
25                 };
26                 var comment2 = new Comment
27                 {
28                     Comments = "You're right, we should teach LINQ in high school!"
29                 };
30                 post1.Comments.Add(comment1);
31                 post3.Comments.Add(comment2);
32                 context.BlogPosts.Add(post1);
33                 context.BlogPosts.Add(post2);
34                 context.BlogPosts.Add(post3);
35                 context.SaveChanges();
36             }
37 
38             using (var context = new EFRecipesEntities())
39             {
40                 Console.WriteLine("Blog Posts with comments...(LINQ)");
41                 var posts = from post in context.BlogPosts
42                     where post.Comments.Any()
43                     select post;
44                 foreach (var post in posts)
45                 {
46                     Console.WriteLine("Blog Post: {0}", post.Title);
47                     foreach (var comment in post.Comments)
48                     {
49                         Console.WriteLine("\t{0}", comment.Comments);
50                     }
51                 }
52             }
53 
54             Console.WriteLine();
55 
56             using (var context = new EFRecipesEntities())
57             {
58                 Console.WriteLine("Blog Posts with comments...(eSQL)");
59                 var esql = "select value p from BlogPosts as p where exists(p.Comments)";
60                 var posts = ((IObjectContextAdapter) context).ObjectContext.CreateQuery<BlogPost>(esql);
61                 foreach (var post in posts)
62                 {
63                     Console.WriteLine("Blog Post: {0}", post.Title);
64                     foreach (var comment in post.Comments)
65                     {
66                         Console.WriteLine("\t{0}", comment.Comments);
67                     }
68                 }
69             }
70 
71             Console.WriteLine("\nPress <enter> to continue...");
72             Console.ReadLine();
73         }

下面是代碼清單3-10的輸出:

 1 Blog Posts with comments...(LINQ)
 2 Blog Post: The Joy of LINQ
 3 Great post, I wish more people would talk about LINQ
 4 Blog Post: LINQ and our Children
 5 You're right, we should teach LINQ in high school!
 6 Blog Posts with comments...(ESQL)
 7 Blog Post: The Joy of LINQ
 8 Great post, I wish more people would talk about LINQ
 9 Blog Post: LINQ and our Children
10 You're right, we should teach LINQ in high school! 

 

原理

  在代碼清單3-10中,咱們先刪除以前的測試數據,而後插入新的博客和評論到數據庫,爲了確保查詢正確,咱們讓其中一篇博客沒有任何評論。

  在LINQ查詢中,咱們在where從句中憑藉LINQ擴展方法Any(),來判斷給定的博客是否有評論。 查找全部Any()方法返回true的博客。在這種用法中,咱們枚舉Any()方法返回true的每一篇有評論的博客。並且,這正是咱們所須要的:至少包含一個評論的博客。

  在Entity SQL 方法中,咱們在where從句中使用了SQL exist()操做符,來判斷給定的博客是否有評論。

  固然,咱們還有別的方法也能獲取到相同的結果。例如,咱們能夠在LINQ查詢的where從句中使用Count()方法,來檢查評論的數量是否大於0.在Entity SQL 方法中,咱們能夠在where從句中使用count(select value 1 from p.Comments)>0。這兩種方法均可以正常運行,可是,代碼清單3-10中的方法更加簡潔,從性能的角度來看,Any()和Exist()不須要在服務器中枚舉整個集合(意思是說,當找到第一個評論後,處理過程就開始轉移到下一篇博客)。然而Count()須要在服務器中枚舉整個集合(意思是說,儘管已經查到了一條評論了,仍然要枚舉每一條評論)。


 

實體框架交流QQ羣:  458326058,歡迎有興趣的朋友加入一塊兒交流

謝謝你們的持續關注,個人博客地址:http://www.cnblogs.com/VolcanoCloud/

相關文章
相關標籤/搜索