好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

《Entity Framework 6 Recipes》中文翻译系列 (13) -----第三章 查

3-4使用实体SQL查询模型

问题

   你想通过执行Entity SQL语句来查询你的实体数据模型并返回强类型的对象。

解决方案

  假设你有图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语句

  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/

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

标签:

查看更多关于《Entity Framework 6 Recipes》中文翻译系列 (13) -----第三章 查的详细内容...

  阅读:24次