翻译的初衷以及为什么选择《Entity Framework 6 Recipes》来学习,请看本系列开篇

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语句

 using (var context = new EFRecipesEntities())
{
// 删除测试数据
context.Database.ExecuteSqlCommand("delete from chapter3.customer");
// 添加新的测试数据
var cus1 = new Customer
{
Name = "Robert Stevens",
Email = "rstevens@mymail.com"
};
var cus2 = new Customer
{
Name = "Julia Kerns",
Email = "julia.kerns@abc.com"
};
var cus3 = new Customer
{
Name = "Nancy Whitrock",
Email = "nrock@myworld.com"
};
context.Customers.Add(cus1);
context.Customers.Add(cus2);
context.Customers.Add(cus3);
context.SaveChanges();
} //使用ObjectContext对象中的 object services
using (var context = new EFRecipesEntities())
{
Console.WriteLine("Querying Customers with eSQL Leveraging Object Services...");
string esql = "select value c from Customers as c";
// 将DbContext转换为底层的ObjectContext, 因为DbContext没有提供对Entity SQL查询的支持
var customers = ((IObjectContextAdapter)context).ObjectContext.CreateQuery<Customer>(esql);
foreach (var customer in customers)
{
Console.WriteLine("{0}'s email is: {1}",
customer.Name, customer.Email);
}
} Console.WriteLine(System.Environment.NewLine); //使用 EntityClient
using (var conn = new EntityConnection("name=EFRecipesEntities"))
{
Console.WriteLine("Customers Customers with eSQL Leveraging Entity Client...");
var cmd = conn.CreateCommand();
conn.Open();
cmd.CommandText = "select value c from EFRecipesEntities.Customers as c";
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
while (reader.Read())
{
Console.WriteLine("{0}'s email is: {1}",
reader.GetString(), reader.GetString());
}
}
} Console.WriteLine("\nPress <enter> to continue...");
Console.ReadLine();
}

下面是代码清单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投影

  // 使用object ervices,无value关键字
using (var context = new EFRecipesEntities())
{
Console.WriteLine("Customers...");
string esql = "select c.Name, c.Email from Customers as c";
var records = ((IObjectContextAdapter)context).ObjectContext.CreateQuery<DbDataRecord>(esql);
foreach (var record in records)
{
var name = record[] as string;
var email = record[] as string;
Console.WriteLine("{0}'s email is: {1}", name, email);
}
}
Console.WriteLine();
//使用EntityClient,无value关键字
using (var conn = new EntityConnection("name=EFRecipesEntities"))
{
Console.WriteLine("Customers...");
var cmd = conn.CreateCommand();
conn.Open();
cmd.CommandText = @"select c.Name, C.Email from
EFRecipesEntities.Customers as c";
using (var reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess))
{
while (reader.Read())
{
Console.WriteLine("{0}'s email is: {1}",
reader.GetString(), reader.GetString());
}
}
}

  当你使用Entity SQL 投影,返回的结果集是一个包含投影中的所有列的DbDataRecord。使用value关键字,查询返回的单独对象,是DbDataRecord中的第一个元素。

3-5 查找主从复合结构关系中的拥有从表记录的主表记录

问题
  你有两个一对多关联(主从复合结构关系)的实体。你要查询所有的至少拥有一个实体与它关联的实体。

解决方案

  假设你有一个拥有博客(BlogPost)和与之关联的评论(Comment)的模型。一些博客有很多评论,一些有少量或是没有评论。这个模型看起像图3-6。

图3-6 一个拥有博客(BlogPost)和与之关联的评论(Comment)的模型

  

  你要找出所有有评论的博客,可以使用LINQ to Entities 或者 Entity SQL。按代码清单3-10所演示的模式进行。

 using (var context = new EFRecipesEntities())
{
// 删除测试数据
context.Database.ExecuteSqlCommand("delete from chapter3.comment");
context.Database.ExecuteSqlCommand("delete from chapter3.blogpost");
// 添加新的测试数据
var post1 = new BlogPost
{
Title = "The Joy of LINQ",
Description = "101 things you always wanted to know about LINQ"
};
var post2 = new BlogPost
{
Title = "LINQ as Dinner Conversation",
Description = "What wine goes with a Lambda expression?"
};
var post3 = new BlogPost
{
Title = "LINQ and our Children",
Description = "Why we need to teach LINQ in High School"
};
var comment1 = new Comment
{
Comments = "Great post, I wish more people would talk about LINQ"
};
var comment2 = new Comment
{
Comments = "You're right, we should teach LINQ in high school!"
};
post1.Comments.Add(comment1);
post3.Comments.Add(comment2);
context.BlogPosts.Add(post1);
context.BlogPosts.Add(post2);
context.BlogPosts.Add(post3);
context.SaveChanges();
} using (var context = new EFRecipesEntities())
{
Console.WriteLine("Blog Posts with comments...(LINQ)");
var posts = from post in context.BlogPosts
where post.Comments.Any()
select post;
foreach (var post in posts)
{
Console.WriteLine("Blog Post: {0}", post.Title);
foreach (var comment in post.Comments)
{
Console.WriteLine("\t{0}", comment.Comments);
}
}
} Console.WriteLine(); using (var context = new EFRecipesEntities())
{
Console.WriteLine("Blog Posts with comments...(eSQL)");
var esql = "select value p from BlogPosts as p where exists(p.Comments)";
var posts = ((IObjectContextAdapter) context).ObjectContext.CreateQuery<BlogPost>(esql);
foreach (var post in posts)
{
Console.WriteLine("Blog Post: {0}", post.Title);
foreach (var comment in post.Comments)
{
Console.WriteLine("\t{0}", comment.Comments);
}
}
} Console.WriteLine("\nPress <enter> to continue...");
Console.ReadLine();
}

下面是代码清单3-10的输出:

 Blog Posts with comments...(LINQ)
Blog Post: The Joy of LINQ
Great post, I wish more people would talk about LINQ
Blog Post: LINQ and our Children
You're right, we should teach LINQ in high school!
Blog Posts with comments...(ESQL)
Blog Post: The Joy of LINQ
Great post, I wish more people would talk about LINQ
Blog Post: LINQ and our Children
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的更多相关文章

  1. 《Entity Framework 6 Recipes》中文翻译系列 (11) -----第三章 查询之异步查询

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第三章 查询 前一章,我们展示了常见数据库场景的建模方式,本章将向你展示如何查询实体 ...

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

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-2使用原生SQL语句更新 问题 你想在实体框架中使用原生的SQL语句,来更新底层 ...

  3. 《Entity Framework 6 Recipes》中文翻译系列 (14) -----第三章 查询之查询中设置默认值和存储过程返回多结果集

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-6在查询中设置默认值 问题 你有这样一个用例,当查询返回null值时,给相应属性 ...

  4. 《Entity Framework 6 Recipes》中文翻译系列 (15) -----第三章 查询之与列表值比较和过滤关联实体

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-8与列表值比较 问题 你想查询一个实体,条件是给定的列表中包含指定属性的值. 解 ...

  5. 《Entity Framework 6 Recipes》中文翻译系列 (16) -----第三章 查询之左连接和在TPH中通过派生类排序

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-10应用左连接 问题 你想使用左外连接来合并两个实体的属性. 解决方案 假设你有 ...

  6. 《Entity Framework 6 Recipes》中文翻译系列 (17) -----第三章 查询之分页、过滤和使用DateTime中的日期部分分组

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-12 分页和过滤 问题 你想使用分页和过滤来创建查询. 解决方案 假设你有如图3 ...

  7. 《Entity Framework 6 Recipes》中文翻译系列 (18) -----第三章 查询之结果集扁平化和多属性分组

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-14  结果集扁平化 问题 你有一对多关联的两个实体,你想通过一个查询,获取关联 ...

  8. 《Entity Framework 6 Recipes》中文翻译系列 (19) -----第三章 查询之使用位操作和多属性连接(join)

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-16  过滤中使用位操作 问题 你想在查询的过滤条件中使用位操作. 解决方案 假 ...

  9. 《Entity Framework 6 Recipes》翻译系列 (1) -----第一章 开始使用实体框架之历史和框架简述

    微软的Entity Framework 受到越来越多人的关注和使用,Entity Framework7.0版本也即将发行.虽然已经开源,可遗憾的是,国内没有关于它的书籍,更不用说好书了,可能是因为EF ...

随机推荐

  1. JS—事件对象

    在触发DOM上的某个事件时,会产生一个事件对象event.这个对象中包含着所有与事件有关的信息.包括导致事件的元素,事件的类型以及其他与特定事件相关的信息. 举例鼠标操作导致的事件对象中,会包含鼠标位 ...

  2. hoj 2662 经典状压dp // MyFirst 状压dp

    题目链接:http://acm.hit.edu.cn/hoj/problem/view?id=2662 1.引言:用dp解决一个问题的时候很重要的一环就是状态的表示,一般来说,一个数组即可保存状态. ...

  3. Vue - class与style绑定

    1.通过v-bind绑定一个class A:直接绑定 B:通过v-bind绑定一个对象 C:绑定一个返回对象的计算属性 D:绑定一个数组对象 2.绑定内联样式 A:直接子啊属性名上面绑定 B:绑定到一 ...

  4. QT5之三大重要窗体

    当创建项目时,会发现编辑器提供三个基类,分别为:QMainWindow.QWidget.QDialog,三个基类的区别说明如下.1.QMainWindowQMainWindow类提供一个有菜单条.锚接 ...

  5. bzoj1103树状数组水题

    (卧槽,居然规定了修改的两点直接相连,亏我想半天) 非常水的题,用dfs序(而且不用重复,应该是直接规模为n的dfs序)+树状数组可以轻松水 收获:树状数组一遍A(没啥好骄傲的,那么简单的东西) #i ...

  6. STM32之PWM君

    PWM..英语好的人估计又知道这三个大写字母代表哪三个英语单词了.小弟不才,就说中文意思好了:脉冲宽度调制,玩过飞思卡尔的人估计对PWM非常的不陌生吧.电机驱动需要PWM,控制舵机的转向需要PWM,总 ...

  7. DSY2287*消失之物

    Description ftiasch 有 N 个物品, 体积分别是 W1, W2, ..., WN. 由于她的疏忽, 第 i 个物品丢失了. "要使用剩下的 N - 1 物品装满容积为 x ...

  8. java并发编程(十五)内存可见两种方式 加锁和volatile

    1.volatile变量是一种稍弱的同步机制在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比synchronized关键字更轻量级的同步机制. ...

  9. 高级sql注入

    1. 避开输入过滤 输入过滤存在于外部和内部,外部属于web应用防火墙WAF,入侵防御系统IPS,入侵检测系统IDS,内部属于代码中对输入进行过滤 过滤select,insert等sql关键字和' | ...

  10. CSS篇之DIV+CSS布局

    <div></div> div与其他标签一样,也是一个XHTML所支持的标签. div是XHTML中指定的,远门用于布局设计的容器标记. 简单的CSS布局 头部 内容 页脚 & ...