[Programming Entity Framework] 第3章 查询实体数据模型(EDM)(一)

http://www.cnblogs.com/sansi/archive/2012/10/18/2729337.html

 

 

Programming Entity Framework 第二版翻译索引

你可以使用各种方法查询实体数据模型。你选择有些方法是因为个人喜好,而其它的则是因为你可以利用特殊的效益。你很有可能已经听过LINQ to Entities和Entity SQL。你可以使用特殊的方法去查询,比如某些基于LINQ,而其它的基于EF的ObjectQuery类。这此查询方法中的每一个都会产生具体化的对 象。还有一种较为少数人知道的查询方法是使用EF的EntityClient API,它允许以数据流的形式将数据返回给应用程序。

在这一章中,你将有机会尝试所有这些不同的查询方式。你将使用不同的机制重复一些简单的查询,通过查看结果你能明白这些查询方法之间的差别。

在本章的结尾,你将获得对所有的查询选项和它们的基本使用的高层次的理解。在后续的章节中,你能写出更复杂的查询;你在本章中学习到的基础将使得那项任务更为容易。另外,在本章的结尾你会看到查询执行的关键课程。

虽然本章的查询示例在控制台程序中展示,你可以使用LINQPad测试这些查询并查看结果。本章的一些指导也会提到调试,这个在LINQPad中无法做到。在第56页中的侧边栏"LINQPad"查看这个工具的更多信息。

查询模型,而不是数据库

在这一章中,你将学习如何针对第2章中创建的EDM构造查询,你将学到让EF来处理这件事。这儿你将经历针对数据模型写查询与针对数据库写查询的不 同。EF会处理你查询,利用ADO.NET提供程序(在这里是System.Data.SqlClient)将EDM查询转化成目标数据库能理解的查询。 在数据库执行完查询后,结果会被装入基于模型中的实体生成的对象中。

这些返回的对象是查询处理中非常重要的部分,当然你想要开始查询,所以首先我们先来查询,然后偷看一眼幕后的事情。

你的第一个EDM查询

在第2章中,你在一个控制台程序中创建了EDM。现在你将此EDM创建你的第一个查询。你可以使用相同的工程,所以如果你关闭了它,打开它我们即将开始。本部分的代码将执行最简单的查询形式,它返回数据库的每一个Contact实体,然后在控制台窗口显示结果。

  1. 打开Program.cs文件。
  2. 在Main方法的下面加上示例3-1中的方法。在你写查询的时候,智能感知在你敲.时会给你提醒,这能加快写代码的速度。

    示例 3-1. Querying Contacts and writing out their names

private static void QueryContacts()

{

using (var context = new SampleEntities())

{

var contacts = context.Contact;

foreach (var contact in contacts)

{

Console.WriteLine("{0} {1}", contact.FirstName.Trim(), contact.LastName.Trim());

}

}

Console.Write("Press Enter...");

Console.ReadLine();

}

  1. 在Main方法中添加下面的代码:

QueryContacts();

  1. 按下F5运行这点代码。当代码读到ReadLine()方法时,所有的名称都列出在控制台窗口了。
  2. 按下回车键结果该程序的运行。

现在,我们再来运行一次查询,但是这一次我们来看看到底发生了什么。

  1. 在foreach块的结尾设置断点,就是在关闭大括号那儿。
  2. 按下F5再次运行代码。
  3. 当调试器到达断点时,将鼠标指针放置在foreach语句中的变量contact的上面,你将看到它是个Contact实体类型,参见图3-1.

  1. 接下来,将鼠标指针放置在相同语句的contacts变量之上,你看到它是 Contacts类型的System.Data.Objects.ObjectSet。System.Data.Objects是EF用于创建和管理实体 对象的API。ObjectSet是访问EntitySet(例如Contacts)时EF返回的。它从另一个被称为ObjectQuery的类继承而 来,ObjectQuery被用于组织和执行返回对象的查询。一旦ObjectQuery被执行,它就包含了你看控制台看到的Contact列表数据结 果。Context拿到返回的数据,并使用它为你生成这些Contact对象。

    因为只查询了Contacts,并没有使用过滤条件,所有的contacts在查询被执行时都从数据库被取出了。

    虽然这看起来并不像一个查询,但是它确实是查询,虽然十分简单。你下一个查询中会更进一步了解它。

  2. 你可以继续运行应用程序或按下Shift+F5键停止它。

现在你知道这个查询返回ObjectSet,你可以重写代码,使用显示的类型申明类型。用这种办法,你可以在代码(例如,context.Contacts)没有明察显示返回类型时指定类型,这使得你或其它人在以后能更好的理解代码。

    ObjectSet<Contact> contacts = context.Contacts;

注:ObjectSet在 System.Data.Objects命名空间下。或者在代码行中指定它,或者可以在代码文件开始时增加命名空间,C#用using System.Data.Object,或者VB使用 Imports System.Data.Objects。

上下文和类来自哪儿?

既然已经进入代码了,肯定会有所疑问。举个例子,Contact类型来自哪里?如何从XML文件中得到.NET强类型对象?为什么context.Contacts是自身的查询,还有context到底是什么?

EDM设计工具的一个特性就是设计器会基于模型自动执行代码生成。模型的Designer.cs文件在解决方案管理器中附加在模型上,如图3-1所示。

有解决方案管理器中展开.edmx文件查看生成的代码文件,打开文件看看都有些什么。

注:因为文件是自动生成的,你并不直接编辑它。你将在第11章学习到如何自定义这个文件中的类。

生成器读取模型中的概念层,然后从它创建出基于EntityContainer的ObjectContext,然后为模型中的每一个实体创建实体类。如图3-3。

生成的代码文件中包含四个类。图3-4在VS的类设计视图中展示了这些类。你可以在类设计器中打开一个类,通过在解决方案管理器中右键单击类,选择查看类图。

在默认视图中点击右上角展开的第一个类是SampleEntities。这个类采用了模型的EntityContainer名称。其它的是每个实体,Address,Contact和vOfficeAddresses。

ObjectContext类,SmapleEntities

当你在第2章查看模型的XML视图时,你看到包含了EntitySets和AssociationsSets的EntityContainer。

SampleEntities类代表了EntityCOntainer, 它继承自EF的类型ObjectContext。这就是为什么在示例中使用了变量context。AsmpleEntities有三个属 性,Addresses, Contacts和vOfficeAddresses,它们是模型中定义的EntitySets。由代码生成创建的三个AddTo方法提供了给 context新曾对象实例的手段,然后他们被插入到数据库中。这些AddTo方法为了向后兼容.NET 3.5中的EF版本。在.NET 4中,你应该使用ObjectSet提供的Add方法,这在后面的章节中将学到。

注:我的习惯是在使用EF写代码时使用"context"做为ObjectContext实例的变量名。

再仔细看看Contacts属性,你看到它返回了Contact类型的ObjectSet:

Public ObjectSet<Contact> Contacts

注:针对VB开发人员,如果你不熟悉泛型的语法,C#使用尖挂号表示类型,而VB使用得数形式加关键词Of。前面的代码使用VB看起来如下:

Public Property Contacts As ObjectSet(Of Contact)

我们查询的基础是ObjectSet,不论是否像示例3-1那样想查询所有的Contact实体,还是你将在3-2示例中所做的那样请求一个子集。写针对ObjectSet的查询与写基于数据库的表的数据库查询是一样的。

实体类

在模型中定义的三个实体是三个实体类的来源。每个类都从EF的EntityObject继承而来,并且包含基于模型中定义的属性的属性,必要时还包括Contact.Addresses和Address.Contact导航属性。参见图3-5

但是在Address类中有新的内容:ContactReference,它是另一种访问Contact属性的途径。你将在第19章中学到 EntityReference属性的细节。这些类有更多的成员,但是它与本章中做的查询不相关,我们会在本书的后续章节中详细讲解它们。

深入了解:不要害怕深入解析生成的代码文件,但是记住你所做的任何改变中,能随时重写模型的是修改和保存。

使用LINQ to Entities查询

LINQ to Entities查询语法比EntitySQL更容易学习和使用,如果你在别处使用过LINQ,你可能已经非常熟悉它了。LINQ to Entities能满足你大部分的查询需求。

LINQ是在.NET 3.5时增加到VB和C#中的语言增加。LINQ代表了Language INtegrated Query,LINQ to Entities是它的一个实现。

注:虽然F#自身没有支持LINQ,由F#小组创建的F#增加包提供了LINQ查询。

注:LINQ原来编写了用来在所有的CLR对象中提供 独立的查询语言。现在它有很多实现。你刚刚就使用了一种实现与实体对象工作。VS和.NET运行时也包含LINQ to SQL,一种直接面对SQLServer数据库的查询实现。很多第三方厂商都编写了LINQ提供程序。

使用LINQ查询能获得非常多的创建性,你也很容易就找到很多关于LINQr书籍。当你开始学习它时,理解最基础的结构将非常有帮助。

编写你的第一个LINQ to Entities查询

前面提到的查询使用了一种提供查询的捷径。但是它并不像真正的查询。现在你将使用LINQ运算符编写LINQ to Entities查询。

移除你之前步骤中的断点。在创建contacts内存变量的代码行上,使用3-2示例中的查询取代context.Contacts,它获取了contacts的一个子集。

示例 3-2. A LINQ to Entities query in VB and C#

var contacts = from c in context.Contact

where c.FirstName == "Rebort"

select c;

注:在书写LINQ查询时,你会发现VB和C#语法间的不同。除了大小写外,注意VB没有显示要求使用select操作符,而C#必须使用。

再次运行程序,你将看到只有一小部分的contacts被列出,它们的first name都为Robert。

集成到LINQ查询中最明显的符号就是当你敲你的查询时,智能感知会提供帮助。例如,为变量c提供可选项FirstName。那是因为当你在查询开 始指定Contacts时,编译器能确定那个集合中的项是Contact项。当你在后面的SELECT和WHERE子句敲c时,智能感知能列出它建议的 Contact的属性。

为什么LINQ从From开始?

LINQ查询从FROM子句开始,而不是从我们所熟知的另的查询语言的SELECT子句。当LINQ被创建时,查询语句确实是从SELECT子句开始的。然而,微软的开发人员很快意识到识别正在使用的类型能够使智能感知在剩余的查询中提供更有意义的建议。

据微软早期参与LINQ的成员Y.Alan Griver透露,当微软的开发人员为了智能感知修改语法时,他们开玩笑地称这个语法为"Yoda speak"。

在查询中,c只是任意的变量名,让你在查询后面引用你需要的东西。它被称为控制变量。控制变量提供了另一种方式让智能感知和编译能够使LINQ对于开发人员更具效率。

LINQPad

LINQPad是由O'Reilly作者,Joseph Albahari(他有作品:LINQ Pocket Reference [http://oreilly.com/catalog/9780596519254/], C# 4.0 in a Nutshell[http://oreilly.com/catalog/9780596800963/]等等)编写的强大的工具。它原本编写用来使用 LINQ to Objects,但是后来,Joseph增加了对LINQ to SQL和EF(Entity SQL和LINQ to Entities)的支持。它是在应用程序之外测试查询非常好的方法。

你可以在http://www.linqpad.net免费下载LINQPad。有一个便宜的(同时也是值得的)更新允许在这个工具中使用智能感知。在LINQPad网站和下载里,你将找到很多非常棒的教程说明,说明如何使用LINQPad及如何有EF中使用它。

这章中的很多示例只有查询。在LINQPad中有很多非常好的查询测试。其它的示例涉及到了查询之外的任务,你可能希望根据指令在控制台程序中执行这些。

好文要顶 关注我 收藏该文
1
0
(请您对文章做出评价)

« 上一篇:[Programming Entity Framework] 第2章 探究实体数据模型(EDM)(三)
» 下一篇:[Programming Entity Framework] 第3章 查询实体数据模型(EDM)(二)

posted on 2016-02-12 18:12  wdcwy  阅读(248)  评论(0编辑  收藏  举报

导航