代码下载位置: DataPoints2007_07.exe (1590 KB)
Browse the Code Online
![](http://i.msdn.microsoft.com/Global/Images/clear.gif)
代号为“Orcas”的 Visual Studio
®
下一版本中的 ADO.NET 以新实体框架为特色。它使开发人员可以通过对象模型(而不是逻辑/关系数据模型)专注于数据。实体框架有助于将逻辑数据架构抽象为概念模型,并且允许以多 种方式通过对象服务和名为“EntityClient”的新数据提供程序与概念模型交互。本月的专栏讨论什么是实体框架、它如何应用于应用程序以及如何基 于该框架进行设计和编程。
实体框架使用概念层、映射层和逻辑层将逻辑数据库结构抽象化。在本专栏中,我分析了这些层中每个层的用途。我还介绍了 EntityClient 和一种新语言(实体 SQL),该语言可与概念层的实体数据模型 (EDM) 交互。
EntityClient 的备选项是对象服务。具体地说,实体框架中的对象服务有助于减少开发人员需要编写的数据访问代码的数量。我还讨论并演示了如何将对象服务与实体 SQL 以及 LINQ to Entities 结合使用,以便与 EDM 中的概念实体交互和对其进行检索。
请注意,本文中的所有示例都使用 ADO.NET 和实体框架,因为它们存在于“Orcas”的 Beta 1 中。
实体框架组件
实 体框架使开发人员可以编写更少的数据访问代码,减少维护,将数据结构抽象化为更易于开展业务(标准化程度较低)的方式,并且有利于数据的持久性。当与 LINQ to Entities(稍后讨论)结合使用时,由于实体框架从概念模型中生成强类型化类,还有助于降低编译时错误的数量。
实 体框架生成开发人员能够依据其编写代码的概念模型。使用名为“EntityClient”的新数据提供程序和名为“实体 SQL”的新语言(类似于 T-SQL)可以直接与该模型交互。EntityClient 具有与熟悉的 ADO.NET 对象类似的模型,使用 EntityConnection 和 EntityCommand 对象返回 DbDataReader。开发人员的另一种方法是通过具有实体 SQL 的 ObjectQuery 对象或 LINQ to Entities 来使用对象服务。对象服务使开发人员可以利用概念模型的生成类,这些生成类提供了强类型化对象和持久性等特性(请参见
图 1
)。
![](http://i.msdn.microsoft.com/cc163399.fig01%28zh-cn%29.gif)
图 1
实体框架概述
这些数据访问技术使开发人员可以与 EDM 的概念实体交互。EDM 的各个层以 XML 文件形式存在;目前可以通过手动方式(或使用 Visual Studio 中的向导)使用命令行工具 (EDMGEN.EXE) 生成 EDM。
实体数据模型
实 体框架的核心位于其模型中。实体框架支持表示数据库中的关系架构的逻辑存储模型。关系数据库通常存储数据的方式与应用程序使用数据的方式不同。通常,这会 迫使开发人员按照数据库包含数据的结构检索数据。因此,开发人员通常将数据加载到更适合处理业务规则的业务实体中。在本示例中,以逻辑模型表示关系数据库 的构架,业务实体表示概念模型。实体框架使用映射层在模型之间搭建了桥梁。因此,实体框架的模型中有三个处于活动状态的层:
- 概念层
- 映射层
- 逻辑层
这 三层允许将数据从关系数据库映射到更加面向对象的业务模型。实体框架提供了使用 XML 文件定义这些层的方法。它还基于概念模型的架构生成了一系列类。可以针对这些类进行编程以直接与数据交互。这提供了抽象级别,因此开发人员可以针对概念模 型而不是关系模型进行编程。实体框架可将针对概念模型编码的所有命令映射到逻辑模型中(请参见
图 2
)。
![](http://i.msdn.microsoft.com/cc163399.fig02%28zh-cn%29.gif)
图 2
设计实体数据模型
(单击该图像获得较大视图)
概 念模型是使用概念架构定义语言 (CSDL) 在 XML 文件中定义的。CSDL 定义应用程序的业务层所知道的实体和关系。逻辑模型(表示数据库架构)是使用存储架构定义语言 (SSDL) 在 XML 文件中定义的。例如,您可能在概念模型中有一个实体,该实体实际上从数据库的多个表中派生其数据。概念模型和逻辑模型可按一对一的关系来关联实体。然 而,EDM 的功能是它不必以一对一的方式链接实体。映射层(是使用映射架构语言 (MSL) 定义的)实现其他两层彼此之间的映射。此映射使开发人员可以针对概念模型编写代码,并将这些指令映射到逻辑模型。
生成实体数据模型
可以将数据库作为起点生成 EDM。然后,可以手动修改 XML(或者可能使用 Visual Studio 将来版本中可能提供的模型工具)。将 ADO.NET EDM 添加到项目后,向导会指导您完成创建 EDM 的过程。
选择从“Orcas”附带的示例 Northwind 数据库中生成 EDM 后,系统将提示您一组可以建模的对象,如
图 3
所示。我选择将所有表引入到模型中,以便向导为 Northwind 中的所有表生成 CSDL、SSDL 和 MSL 文件。当然,这是纯一对一表到实体的映射。我可以通过组合实体或者通过继承调整此映射以满足业务需求。
![](http://i.msdn.microsoft.com/cc163399.fig03%28zh-cn%29.gif)
图 3
EDM 向导
(单击该图像获得较大视图)
该向导还从表示域模型的 CSDL 中生成一系列类。
图 4
通过“类视图”窗口显示了其中一些类。由于我开始使用了一对一映射,每个表均有一个对应类。EDM 向导选取了数据库中 Customers 和 Orders 之间的关系,并在概念模型中为其创建了对应的关联。因此,Customers 类包含一个名为“Orders”的导航属性,使开发人员可以从 Customers 实例向下导航到客户的任意相关的 Orders 实例。
![](http://i.msdn.microsoft.com/cc163399.fig04%28zh-cn%29.gif)
图 4
类
仔细分析 CSDL
驻留在 CSDL 文件中的元数据包含一系列实体和关系,其中实体由 EntityType 元素表示,关系由 Association 元素(即 AssociationType)表示(请注意,这与 Beta 1 中的命名方案不一致)。
图 5
显示了我先前生成的 CSDL 文件的一个片段。实体包含一系列用于定义实体的标量属性。Key 属性指示对实体很关键的属性。复合关键字通过用空格分隔每个属性名来表示。实体还可以包含名为“NavigationProperty”的一种特殊类型的 属性。这定义了如何按照关联从一个实体导航到另一个实体。
![](http://i.msdn.microsoft.com/Global/Images/clear.gif)
<EntityType Name=”Customers” Key=”CustomerID”>
<Property Name=”CustomerID” Type=”String” Nullable=”false”
MaxLength=”4000” FixedLength=”true” />
<Property Name=”CompanyName” Type=”String” Nullable=”false”
MaxLength=”4000” />
<Property Name=”ContactName” Type=”String” MaxLength=”4000” />
<Property Name=”ContactTitle” Type=”String” MaxLength=”4000” />
<Property Name=”Address” Type=”String” MaxLength=”4000” />
<Property Name=”City” Type=”String” MaxLength=”4000” />
<Property Name=”Region” Type=”String” MaxLength=”4000” />
<Property Name=”PostalCode” Type=”String” MaxLength=”4000” />
<Property Name=”Country” Type=”String” MaxLength=”4000” />
<Property Name=”Phone” Type=”String” MaxLength=”4000” />
<Property Name=”Fax” Type=”String” MaxLength=”4000” />
<NavigationProperty Name=”Orders”
Relationship=”NorthwindModel.FK_Orders_Customers”
FromRole=”Customers” ToRole=”Orders” />
</EntityType>
以下 CSDL 片段定义了 Customer 及其 Orders 之间的 AssociationType:
<Association Name=”FK_Orders_Customers”>
<End Role=”Customers” Type=
”NorthwindModel.Customers”
Multiplicity=”0..1” />
<End Role=”Orders” Type=
”NorthwindModel.Orders” Multiplicity=”*” />
</Association>
AssociationType 的 End 元素表示关联的参与者。在本示例中,一个 Customers 实体与一个 Orders 实体相关联。根据多重性定义,一个 Customers 实体还可以与任意数量的 Orders 实体相关联。
EntityType 和 AssociationType 元素定义域实体和关系的类型,而 EntitySet 和 AssociationSet 元素定义实体和关系的作用域。逻辑上应组合到一起的所有“集”都包含在 EntityContainer 元素内。(有关完整的 CSDL,请参见随附下载内容中的 NorthwindEntities.csdl 文件。)
下面的 CSDL 片段显示了 EntityContainer 及其部分内容:
<EntityContainer Name=”NorthwindEntities”>
<EntitySet Name=”Customers”
EntityType=”NorthwindModel.Customers” />
<EntitySet Name=”Orders”
EntityType=”NorthwindModel.Orders” />
<AssociationSet Name=”FK_Orders_Customers”
Association=”NorthwindModel.FK_Orders_Customers”>
<End Role=”Customers” EntitySet=”Customers” />
<End Role=”Orders” EntitySet=”Orders” />
</AssociationSet>
</EntityContainer>
此 片段显示了 EntityTypes Customers 和 Orders 的 EntitySets。此处还声明了 AssociationSet FK_Orders_Customers。本片段定义了实体 Customers 和 Orders 及其之间的关系。
映射到存储
SSDL 文件定义了数据库中关系数据的结构。在本例中,它还使用了 EntityType 和 AssociationType XML 元素来分别声明存在于数据库中的表和外键的结构。SSDL 文件的命名空间是基于 EDM 中所用数据库的名称而设置的,而其 EntityContainer 元素是以数据库架构命名的。EntityContainer 包含一系列 EntitySet 和 AssociationSet 元素,这些元素声明由 EntityType 和 AssociationType 表示的表和关系的实例。对于 SSDL 文件中的每个 EntitySet,数据库中均有一个与之对应的表。
如 果从数据库中生成 EDM 并且未对 CSDL 和 SSDL 文件进行修改就立即将其打开,则您会发现这些文件极其相似。这是因为模型是直接从数据库生成的,因此概念模型直接映射到了逻辑存储。MSL 文件包含从 CSDL 到 SSDL 的直接映射。所有针对 EDM 编写的查询均将转换为生成的 SQL 命令。实体框架还支持使用存储过程而不是生成的 SQL 查询。
EntityContainerMapping 元素用于将模型 (CSDL) 映射到存储 (SSDL)。StorageEntityContainer 属性表示存储中 EntityContainer 的名称,而 EdmEntityContainer 属性表示模型中与之相对应的 EntityContainer。将模型的 EntitySet 映射到存储的 EntitySet 需要 EntitySetMapping 元素。Name 属性定义模型中 EntitySet 的名称,而 TableName 属性定义存储中与之相对应的 EntitySet 的名称。通过 ScalarProperty 元素可将模型中的每个属性映射到存储。
图 6
显示了 MSL 片段。
![](http://i.msdn.microsoft.com/Global/Images/clear.gif)
<cs:EntitySetMapping cs:Name=”Products”>
<cs:EntityTypeMapping cs:TypeName=”NorthwindModel.Products”>
<cs:TableMappingFragment cs:TableName=”Products”>
<cs:ScalarProperty cs:Name=”ProductID” cs:ColumnName=”ProductID” />
<cs:ScalarProperty cs:Name=”ProductName”
cs:ColumnName=”ProductName” />
<cs:ScalarProperty cs:Name=”QuantityPerUnit”
cs:ColumnName=”QuantityPerUnit” />
<cs:ScalarProperty cs:Name=”UnitPrice” cs:ColumnName=”UnitPrice” />
<cs:ScalarProperty cs:Name=”UnitsInStock”
cs:ColumnName=”UnitsInStock” />
<cs:ScalarProperty cs:Name=”UnitsOnOrder”
cs:ColumnName=”UnitsOnOrder” />
<cs:ScalarProperty cs:Name=”ReorderLevel”
cs:ColumnName=”ReorderLevel” />
<!--<cs:ScalarProperty cs:Name=”Discontinued”
cs:ColumnName=”Discontinued” />-->
<cs:Condition cs:ColumnName=”Discontinued” cs:Value=”0”/>
</cs:TableMappingFragment>
</cs:EntityTypeMapping>
<!--</cs:EntitySetMapping>
<cs:EntitySetMapping cs:Name=”DiscontinuedProducts”>-->
<cs:EntityTypeMapping cs:TypeName=
”NorthwindModel.DiscontinuedProducts”>
<cs:TableMappingFragment cs:TableName=”Products”>
<cs:ScalarProperty cs:Name=”ProductID” cs:ColumnName=”ProductID” />
<cs:ScalarProperty cs:Name=”ProductName”
cs:ColumnName=”ProductName” />
<cs:ScalarProperty cs:Name=”QuantityPerUnit”
cs:ColumnName=”QuantityPerUnit” />
<cs:ScalarProperty cs:Name=”UnitPrice” cs:ColumnName=”UnitPrice” />
<cs:ScalarProperty cs:Name=”UnitsInStock”
cs:ColumnName=”UnitsInStock” />
<cs:ScalarProperty cs:Name=”UnitsOnOrder”
cs:ColumnName=”UnitsOnOrder” />
<cs:ScalarProperty cs:Name=”ReorderLevel”
cs:ColumnName=”ReorderLevel” />
<cs:Condition cs:ColumnName=”Discontinued” cs:Value=”1”/>
</cs:TableMappingFragment>
</cs:EntityTypeMapping>
</cs:EntitySetMapping>
定义继承
EDM 也支持与数据库并非纯一对一的模型。例如,使用 Northwind 数据库,您可以创建名为“DiscontinuedProducts”的类,该类继承了 Products 类的所有属性,但仅包含其 Discontinued 列为 1 的产品。(请注意,DiscontinuedProducts 类也可添加其他属性。)这是一个简单的继承方案,但它演示了如何使用 EDM 来实现继承。
在 概念模型中创建 DiscontinuedProducts 类的第一步是打开 CSDL 文件并创建新的 EntityType,将其命名为 DiscontinuedProducts,然后将其 BaseType 属性设置为 NorthwindModel.Products(即架构和基本 EntityType 名称)。派生的 EntityType 继承了 Products EntityType 的属性(包括其 Key)。因此,我无需指定 Key 属性或新派生的 EntityType 的属性。我还将注释 Products EntityType 中的 Discontinued 属性。在 CSDL 文件中要完全实现此目的所需的其他代码如下所示:
<EntityType Name=”DiscontinuedProducts”
BaseType=”NorthwindModel.Products”/>
此 过程的下一步是打开 MSL 文件并查找 Products EntitySetMapping 元素,然后删除其 TypeName 和 TableName 属性。现在将为每个具体的 EntityType 设置这些属性。然后,创建 EntityTypeMapping 子元素并将其 TypeName 设置为 NorthwindModel.Products。对于从基本 EntityType 继承的每个 EntityType,EntitySetMapping 必须包括 EntityTypeMapping 元素。创建名为“TableMappingFragment”的 EntityTypeMapping 元素的子元素,并将其 TableName 属性设置为 Products。一般而言,这些步骤会将映射从 EntitySetMapping 元素向下移到更细化的级别。
注 释 Discontinued 属性映射并添加 Condition 元素,该元素指示只包括 Discontinued 等于 0 的记录。复制整个 EntityTypeMapping XML 片段,将 Name 属性更改为 DiscontinuedProducts,并将条件的值更改为 1。
图 6
显示了 MSL 文件的新片段。
多个表之间的映射
EDM 从纯一对一模型变化为存储映射的另一种方法是将模型中的单个实体映射到存储中的多个表。示例 Northwind 数据库中的 Contacts 表和 ContactNameSplit 表之间具有一对一的关系,并且可以在模型中将两者合并为单一实体。对于本示例,我将在模型中创建一个实体,其中包括 Contacts 表中的所有列和 ContactNameSplit 表中的 Title 和 Name 列。
第一个更改是修改 CSDL 文件中的 Contacts EntityType 以包括其他两个属性:Name 和 Title。
下 一组更改比较详细。现在,必须使用 MSL 文件将模型中的这两个新属性映射到存储。必须对 Contacts EntitySet 的 EntitySetMapping 元素进行更改以表示到多个表的映射。在本示例中,我通过删除 TableName 属性和 TypeName 属性修改了 Contacts EntitySet 的现有 EntitySetMapping 标记。如果模型中的 EntitySet 与存储中的 EntitySet 形成一对一映射,则仅在 EntitySetMapping 元素中声明这些属性。
由 于 Contacts 的从模型 EntitySet 到存储 EntitySet 的映射已被删除,必须创建一个替换项。此替换项是名为“EntityTypeMapping”的子元素。必须创建两个这样的替换元素 — 分别表示来自存储的 Contacts 和 ContactNameSplit。EntityTypeMapping 元素为每个 EntitySet 定义 TypeName 属性。
每个 EntityTypeMapping 元素内部均有一个名为“TableMappingFragment”的子元素。此元素包含与存储的 EntitySet 相对应的 TableName 属性。TableMappingFragment 是定义所有 ScalarProperty 元素的位置,将模型的属性映射到存储。
图 7
显示了修改的 Contacts EntitySetMapping,它现在将 Contacts 和 ContactSplitName 表从存储映射到模型中的单一 EntitySet。
![](http://i.msdn.microsoft.com/Global/Images/clear.gif)
<cs:EntitySetMapping cs:Name=”Contacts”>
<cs:EntityTypeMapping cs:TypeName=”NorthwindModel.Contacts”>
<cs:TableMappingFragment cs:TableName=”Contacts”>
<cs:ScalarProperty cs:Name=”ContactID”
cs:ColumnName=”ContactID” />
<cs:ScalarProperty cs:Name=”ContactType”
cs:ColumnName=”ContactType” />
<cs:ScalarProperty cs:Name=”CompanyName”
cs:ColumnName=”CompanyName” />
<cs:ScalarProperty cs:Name=”ContactName”
cs:ColumnName=”ContactName” />
<cs:ScalarProperty cs:Name=”ContactTitle”
cs:ColumnName=”ContactTitle” />
<cs:ScalarProperty cs:Name=”Address” cs:ColumnName=”Address” />
<cs:ScalarProperty cs:Name=”City” cs:ColumnName=”City” />
<cs:ScalarProperty cs:Name=”Region” cs:ColumnName=”Region” />
<cs:ScalarProperty cs:Name=”PostalCode”
cs:ColumnName=”PostalCode” />
<cs:ScalarProperty cs:Name=”Country” cs:ColumnName=”Country” />
<cs:ScalarProperty cs:Name=”Phone” cs:ColumnName=”Phone” />
<cs:ScalarProperty cs:Name=”Extension”
cs:ColumnName=”Extension” />
<cs:ScalarProperty cs:Name=”Fax” cs:ColumnName=”Fax” />
<cs:ScalarProperty cs:Name=”PhotoPath”
cs:ColumnName=”PhotoPath” />
</cs:TableMappingFragment>
</cs:EntityTypeMapping>
<cs:EntityTypeMapping cs:TypeName=”ContactNameSplit”>
<cs:TableMappingFragment cs:TableName=”ContactNameSplit”>
<cs:ScalarProperty cs:Name=”ContactID” cs:ColumnName=”ID” />
<cs:ScalarProperty cs:Name=”Name” cs:ColumnName=”Name” />
<cs:ScalarProperty cs:Name=”Title” cs:ColumnName=”Title” />
</cs:TableMappingFragment>
</cs:EntityTypeMapping>
使用 EntityClient
可通过三种不同机制中的任意一种实现对实体框架的概念模型的访问(请参见
图 1
)。在此,我将介绍 EntityClient,即新的 .NET 数据提供程序。
当 EntityClient 使用自己的名为“实体 SQL”的基于文本的语言与概念模型通信时,会将其从逻辑存储中提取出来。所有使用 EntityClient 执行的实体 SQL 查询均被编译成发送到存储的命令树。查询从概念模型的实体 SQL 到存储的向下转换由实体框架处理。
EntityClient 中的类与常见的 ADO.NET 提供程序中的类相似。例如,使用 EntityCommand 对象执行 EntityClient 查询,这需要 EntityConnection 对象连接到 EDM。当 EntityClient 与 EDM 中的实体交互时,EntityClient 不返回实体的实例而返回 DbDataReader 对象中的所有结果。EntityClient 可以返回一组标准行和列,也可以通过 DbDataReader 返回更复杂的分层数据的表示形式。
图 8
显示的示例使用 EntityClient 连接到概念模型并检索来自伦敦的客户列表。EntityConnection 可以接受概念层的完整连接字符串或 App.Config 文件中连接字符串的名称。连接字符串包含元数据文件(CSDL、MSL 和 SSDL 文件)列表,以及存储的专用于数据库的连接字符串信息。此处显示了
图 8
的完整连接字符串的示例:
![](http://i.msdn.microsoft.com/Global/Images/clear.gif)
string city = “London”;
using (EntityConnection cn =
new EntityConnection(“Name=NorthwindEntities”))
{
cn.Open();
EntityCommand cmd = cn.CreateCommand();
cmd.CommandText =
“SELECT VALUE c FROM NorthwindEntities.Customers “ +
“AS c WHERE c.City = @city”;
cmd.Parameters.AddWithValue(“city”, city);
DbDataReader rdr = cmd.ExecuteReader(
CommandBehavior.SequentialAccess);
while (rdr.Read())
Console.WriteLine(rdr[“CompanyName”].ToString());
rdr.Close();
}
“metadata=./NorthwindEntities.csdl|./NorthwindEntities.ssdl|.
/NorthwindEntities.msl;provider=System.Data.SqlClient;provider connection string=’Data Source=DDVPC01
/SQLEXPRESS;Initial Catalog=Northwind;
Integrated Security=True’”
图 8
中的代码显示了如何创建 EntityConnection 对象以及如何对该对象执行 EntityCommand。使用实体 SQL 编写的查询引用 EDM 中的 Customers EntitySet。请注意,其语法被特意设置为与 T-SQL 相似。(如果您需要实体 SQL 语法的良好参考资料,请参见适用于“Orcas”Beta 1 版本的 MSDN
®
文档。)
如
图 8
所示,还可以添加 EntityParameter 对象。从 Beta 1 开始,EntityClient 不支持 DML 查询;不过,将来人们将致力于研究此问题。还可以使用其他方法执行 DML,比如 LINQ to Entities。
使用对象服务
与由 EDM 表示的数据进行交互的另一种方法是使用对象服务。通过对象服务,可以加载对象和导航在 EDM 中定义的任何关系。如
图 1
所示,对象服务使用 EntityClient 来获取数据。对象服务增添了身份解析,使用 DataSet 时,该身份解析是手动过程。它还提供了对象持久性和事件的跟踪更改以允许显式加载和保存。这将缩短与服务器的往返路程。
对象服务允许直接返回对象列表(即可同时返回投影和定义的实体)。例如,使用对象服务,您可以按 EDM 中的定义检索 List<Customers>。可以检查 Customers 对象,更改值,然后将数据再次保存到数据库中。
如果将投影与对象服务结合使用,则返回的数据将是不可更新的对象。由于投影返回实体的特定属性而不是整个实体,对象服务无法将投影数据的更新再次保存到数据库中。如果您要更新数据,更好的选择是返回整个实体而不是使用投影。
您可以使用对象服务以使用实体 SQL 执行查询,也可以使用 LINQ to Entities 编写查询。下面的示例演示了如何使用对象服务和实体 SQL 进行查询以检索 Customers 列表:
string city = “London”;
ObjectQuery<Customers> query = northwindContext.CreateQuery<Customers>(
“SELECT VALUE c FROM Customers AS c WHERE c.City = @city”,
new ObjectParameter(“city”, city));
foreach (Customers c in query) Console.WriteLine(c.CompanyName);
在 EDM 中,EntityContainer 由从 ObjectContext(在本示例中为 northwindContext)继承的类表示。ObjectContext 类实施 ObjectQuery<T> 接口,从而使其可以使用实体 SQL 或 LINQ 创建查询。
CreateQuery 方法接受参数化的实体 SQL 语句,该语句定义了将检索 Customers 实体列表的查询。通过使用 foreach 语句对 ObjectQuery<Customers> 进行迭代时将执行作用于数据库的实际 SQL 语句。
使用 LINQ to Entities
可 以在实体 SQL 中编写动态查询,并与对象服务一起使用来与 EDM 实体交互。但是,实体框架还可以与使用 LINQ to Entities 强类型化 EDM 类结合使用。例如,在刚才显示的示例中,可以将使用对象服务和实体 SQL 进行查询修改为使用 LINQ to Entities 进行查询,如下所示:
string city = “London”;
var query = from c in northwindContext.Customers
where c.City == city
select c;
foreach (Customers c in query) Console.WriteLine(c.CompanyName);
此代码示例使用由 C# 3.0 支持的强类型化 LINQ 语法替代了实体 SQL 的所有基于文本的语法。有关 LINQ 及其在 C# 和 Visual Basic
®
中所受的支持的详细信息,请参见
msdn.microsoft.com/msdnmag/issues/07/06
中 2007 年 6 月发行的
MSDN 杂志
。
现 在,回顾一下我在 EDM 中创建的名为“DiscontinuedProducts”的 EntityType,它是从 Products 中继承的。EDM 的继承功能可与 LINQ 和对象服务结合使用以检索废止产品列表。请注意,以下示例并不指定废止值等于 1 的位置。然而,将根据派生的 EntityType DiscontinuedProducts 对产品实体的类型进行检查,产品实体类型继而使用我在映射(MSL 文件)中创建的条件生成适当的 SQL 语句来仅检索废止产品:
var query = from p in northwindContext.Products
where p is DiscontinuedProducts
select p;
foreach (Products p in query) Console.WriteLine(p.ProductName);
也可以编写利用 EDM 中的内置关系(由 AssociationSet 定义)的查询。例如,可以使用以下 LINQ 查询表达式检索位于伦敦的客户的订单列表:
var query = from o in northwindContext.Orders
where o.Customers.City == “London”
select o;
foreach (Orders o in query) Console.WriteLine(o.OrderID);
此 代码示例以 Orders 实体开始并使用其名为“Customers”的导航属性以便检查 City 属性。来自伦敦以外的客户订单将全部筛选出。由于返回了 Orders 实体的列表,还可以修改实体并将其更改内容保存到数据库中。可以通过 SaveChanges 方法将更改内容保存到数据库中。
下面的示例可用于获取伦敦客户列表并将每个客户的 Country 属性设为 United Kingdom。更改内容被保存到 StateManager,但直到执行 SaveChanges 方法后才会将其写入数据库:
var query = from c in northwindContext.Customers
where c.City == “London”
select c;
foreach (Customers c in query) c.Country = “United Kingdom”;
northwindContext.SaveChanges();
您也可以创建实体的新实例并使用 ObjectContext 的 AddObject 方法将其添加到 EDM。以下示例显示了如何将新类别添加到数据库中的 Categories 表:
Categories newCat = new Categories();
newCat.CategoryName = “Other”;
northwindContext.AddObject(newCat);
northwindContext.SaveChanges();
int newCatID = newCat.CategoryID;
首 先,创建 Categories 实体的实例并设置其 CategoryName 属性。然后,使用 AddObject 方法将新类别添加到 EDM。调用 SaveChanges 方法后,便会生成 SQL 语句,用于将新类别插入到数据库中并返回新行的 CategoryID。
当 实体与其他实体建立关系后,您可能希望将新的实体与现有的实体相关联。例如,您可以创建新的 Orders 实体并将其 Customers 属性设置为现有的 Customers 实体。数据库中的 Orders 表具有 CustomerID 列,而 EDM 使用 Customers 属性通过面向对象的方法表示关系以导航到相关的 Customers 实体:
Orders newOrder = new Orders();
newOrder.OrderDate = DateTime.Today;
Customers cust = northwindContext.Customers.Where(
“it.CustomerID = ‘ALFKI’”).First();
newOrder.Customers = cust;
northwindContext.AddObject(newOrder);
northwindContext.SaveChanges();
结束语
使用实体框架,开发人员可以通过对象模型(而不是逻辑/关系数据模型)专注于数据。一旦完成 EDM 的设计并将其映射到关系存储后,就可以使用 EntityClient、ObjectServices 和 LINQ 等多种技术与对象交互。
即 将发布的 Visual Studio“Orcas”中提供的 ADO.NET 仍支持 DataSet、DataAdapter、DbConnection 和 DbCommand 等传统对象,但实体框架引进了主要的新增功能,将开辟 ADO.NET 令人兴奋的新天地。