翻譯的初衷以及爲何選擇《Entity Framework 6 Recipes》來學習,請看本系列開篇html
問題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中的第一個元素。
問題
你有兩個一對多關聯(主從複合結構關係)的實體。你要查詢全部的至少擁有一個實體與它關聯的實體。
解決方案
假設你有一個擁有博客(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/