José Blakeley, David Campbell, Jim Gray, S. Muralidhar, Anil Nori
适用于:
ADO.NET
.NET 语言集成查询 (LINQ)
SQL Server
摘要:通过将抽象级别从逻辑(关系)级别提高到概念(实体)级别来消除应用程序和数据服务(例如,作为 SQL Server 产品一部分提供的报告、分析和复制服务)两方面的阻抗失谐。
![*](http://img.microsoft.com/library/gallery/templates/MNP2.Common/images/3squares.gif)
本页内容
![]() |
摘要 |
![]() |
简介 |
![]() |
阻抗失谐 |
![]() |
数据库建模层 |
![]() |
数据服务演变 |
![]() |
设想 |
![]() |
使概念级别成为现实 |
![]() |
实体框架体系结构 |
![]() |
参考资料 |
摘要
技 术和行业的明显发展趋势已从根本上改变了应用程序的生成方式。在 10 至 20 年前,很多行业 (LOB) 应用程序是以一个关系数据库系统为中心作为各个整体构建而成,而如今它们必须与其他系统相关联并从多种异类源生成和使用数据。业务流程已经从半自动式发展 为自治式。面向服务的体系结构 (SOA) 提出了新的一致性和共同协作要求。较高级的数据服务(例如报告、数据挖掘、分析、同步和复杂的集成)已从非主流发展为主流。
所有现代应 用程序体系结构都有一个共同的主题,就是需要将数据从一种形式转换为另一种形式以使数据形式适用于现有任务。如今的各应用程序都具备大量数据转换程序。有 一种常见转换通常封装为应用程序内部的一个专用数据访问层,旨在将应用程序对象与关系行之间的阻抗失谐程度降至最低。但对导航对象-xml 和关系-xml 的其他映射依然存在。这种阻抗失谐并不是应用程序所特有的。既然 SQL Server 已经演化为一个产品,它必须在其中提供的所有服务领域添加这些建模和映射机制。这些映射多数以点对点的形式生成,并且每个映射都需要使用一个不同方法来描 述点对点转换。
有一个基本见解是,多数传统的以数据为中心的服务(例如查询、复制、ETL)已经在逻辑架构级别上得以实现。但是,大部 分最适合在人工产物上运行的以数据为中心的新式服务通常都与一个概念数据模型相关联。我们的数据平台设想精髓是将遍及数种产品的 Microsoft 数据服务从其各自的逻辑架构级别提升到概念架构级别。将概念架构层具体化使我们可以围绕常见抽象来创建服务,并在我们的多数数据服务之间共享工具、定义和 模型。在本文中,我们将论证这种转变将如何深刻影响我们在整个应用程序平台范围内实现价值的能力。
本文侧重讨论对数据的编程,以及如何 通过将抽象级别从逻辑(关系)级别提高到概念(实体)级别来消除应用程序和数据服务(例如作为 SQL Server 产品一部分提供的报告、分析、复制服务)两方面的阻抗失谐。概念数据模型通过创建以下要素得以实现:作为第一类概念包含各实体和关系的扩展关系模型 [称为实体数据模型 (EDM)]、一种用于 EDM 的查询语言、一个从概念级别转变为逻辑(关系)级别的综合性映射引擎、以及一组帮助创建实体-对象、对象-xml、实体-xml 转换程序的模型驱动工具。所有这些服务都统称为“实体框架”。C# 和 Visual Basic 中的 ADO.NET(即实体框架)和 .NET 语言集成查询 (LINQ) 的创新代表了 Microsoft 的下一代数据访问平台。
简介
Microsoft 数据访问设想支持一系列产品和服务,以便客户从所有数据派生值,即通过存档生成。尽管设想陈述中未包含明确的用语,但设想的目标是为应用程序(解决方案)所有层的数据提供产品和服务。这样一个完整的数据平台必须具备下列特征:
所有层的数据。 一个完整的数据平台应在每一处都提供数据管理和数据访问服务。在客户端-服务器领域中,“每一处”包括客户端和数据服务器上的数据服务;在企业领域中, “每一处”包括数据服务器层、应用程序服务器(中间)层和客户端层;在移动领域中则包括移动设备层;而在下一代 Web (Cloud) 领域中则包括共享 Web 空间中的数据。
所有类型的数据。各应用程序所合并的各种数据在日益增多,例如 XML、电子邮件、日历、文件、文档和结构化业务数据。Microsoft 数据访问设想支持一个集成式存储设想,即可以存储和管理所有此类数据,并对其进行保护、搜索、查询、分析、共享和同步等。这样一个集成式存储设想包含了核 心数据管理功能和一个应用程序开发平台。
统一式数据访问。尽管位于不同层的应用程序需要不同类型的数据管理服务,但它们在应 用程序开发环境(编程模型和工具)中都要求(需要)实现显著的一致性。通常,同一应用程序可能会部署于多个层(例如在设备上和在台式计算机上),这就极度 需要一次性开发并在不同层上进行部署。另外,由于应用程序规模需要增大且应用程序会将各层向上移动,因此必须可以在无需(明显)更改应用程序的情况下扩大 数据库(例如从 SQL Everywhere 到 SQL Express 再到 SQL Server)。支持统一的应用程序开发需要以下条件:丰富的数据建模以匹配应用程序数据所需的抽象、丰富且一致的编程环境以及用于所有数据的工具。
端对端业务见解。端对端业务见解指的是关于实现更有效决策的所有内容。它涉及到我们的客户在收集、清理、存储和准备要用于决策过程的业务数据时所应用的技术。它还涉及到业务用户和信息工作人员在收集决策的必需信息时访问、分析、直观化和报告数据所应具备的经验。
无处不在的数据服务。 各应用程序通过接近于应用程序视角的抽象在遍及所有层中数据的一些服务(定制)开发方面投入了大量精力,这些服务包括数据安全性、同步、数据交换(或 Web 服务)的序列化、分析、报告等等。Microsoft 数据访问设想预期通过一种统一的方式对所有层中的数据提供上述服务。
丰富的“功能”。 无论是对于企业、公司还是家庭用户,数据都是一项关键资产。客户的希望是,数据要始终可用、数据必须受到保护、必须可以进行访问,并且他们的应用程序必须 具备可伸缩性和可支持性。Microsoft 数据访问设想意味着对所有数据实现丰富“功能”。另外,它还简化了对所有数据的管理,从而明显缩减了数据的总体拥有成本。
阻抗失谐
下 一代数据访问平台所处理的一个关键问题就是众所周知的应用程序阻抗失谐问题。想一下当今数据访问应用程序的编写方式。在过去的 10 到 15 年中,数据访问代码没有发生明显变化。ODBC 中采用的数据访问模式仍然存在于 OLE-DB、JDBC 和 ADO.NET 中。以下是目前 ADO.NET 的一个示例,在其他 API 中可编写类似示例。
class DataAccess
{
static void GetNewOrders(DateTime date, int qty) {
using (SqlConnection con =
new SqlConnection(Settings.Default.NWDB)) {
con.Open();
SqlCommand cmd = con.CreateCommand();
cmd.CommandText = @"
SELECT o.OrderDate, o.OrderID, SUM(d.Quantity) as Total
FROM Orders AS o
LEFT JOIN [Order Details] AS d ON o.OrderID = d.OrderID
WHERE o.OrderDate >= @date
GROUP BY o.OrderID
HAVING Total >= 1000";
cmd.Parameters.AddWithValue("@date", date);
DbDataReader r = cmd.ExecuteReader();
while (r.Read()) {
Console.WriteLine("{0:d}:\t{1}:\t{2}", r["OrderDate"],
r["OrderID"], r["Total"]);
}
}
}
}
就开发人员而言,上述代码体现了几点不便之处。查询由编程语言难以理解的文本字符串表示。查询中包括整合标准化订单和订单明细表格中各 行所需的左外连接,并且这个查询不直接与业务请求相关。结果以非类型数据记录形式返回。有一种更完善的代码充分利用了 ADO.NET 中的实体框架以及 .NET 语言集成查询 (LINQ) 中的语言集成创新,其如下所示:
class DataAccess
{
static void GetNewOrders(DateTime date, int qty) {
using (NorthWindDB nw = new NorthWindDB ()) {
var orders = from o in nw.Orders
where o.OrderDate > date
select new { o.orderID,
o.OrderDate, Total = o.OrderLines.Sum(l => l.Quantity);
foreach (SalesOrder o in orders) {
Console.WriteLine("{0:d}\t{1}\t{2}",
o.OrderDate, o.OrderId, o.Total);
}
}
}
}
尽管 NET 应用程序往往将数据作为 CLR 对象来访问,但多数数据服务(如报告和复制)更倾向于将数据作为实体值进行访问。此类数据服务将动态生成对实体的查询,如下所示:
MapCommand cmd = con.CreateCommand();
cmd.CommandText = @"
SELECT o.OrderDate, o.OrderId, o.Total
FROM (SELECT o.OrderId,
SUM(o.OrderDetails..Quantity) AS Total,
FROM Orders AS o
WHERE o.OrderDate >= @date) AS o
WHERE o.Total >= 1000";
cmd.Parameters.AddWithValue("@date", date);
对于各应用程序和数据服务,强烈需要在概念级别处理数据并将各机制内置在其开发框架中,以将这些概念轻松转换为对于应用程序更合乎逻辑的对象。
通 过解决长期存在的阻抗失谐问题,ADO.NET 和 LINQ 中实体框架所引入的创新为应用程序开发人员开辟了一个振奋人心的新天地,与此同时,我们作为平台供应商的责任就是以一种演化式方式(即在 ADO.NET 2.0 中保持现有代码投资)来引入这些创新。尤其是,我们将确保无需重写现有应用程序就可充分利用实体框架的某些优点,例如丰富的概念模型、逻辑(关系)架构中 ADO.NET 代码的数据独立性,以及牢固确立于 SQL 中的实体查询语言。我们将确保 ADO.NET 应用程序可在适当时候不失时机地采用实体框架功能。实体框架的一个重要设计目标就是为开发人员提供精密细致的控制和可扩展性。这意味着我们不会提供一个不 产生效果的只完成 80% 的解决方案,而是会允许基于实体框架编写的应用程序可在需要时延伸到更低级别的 ADO.NET 组件。在实体基础上集成 LINQ 使 ADO.NET 开发人员可以体验到 LINQ 的创新以及由实体框架提供的从关系映射到实体映射的强大映射功能。
数据库建模层
要说明下一代数据平台的高级建模功能,我们需要介绍一些基本的数据库设计概念。当今用于生成数据库设计的主流信息建模方法将信息模型分解为以下所述的四个主要级别:物理级别、逻辑(关系)级别、概念级别以及编程或表示级别。
物理模型级别
物 理模型用于描述在物理资源(如内存、线路或磁盘)中如何表现数据。有关该层要讨论的概念包括记录格式、文件分区和组、堆栈以及索引。在本文档中说明物理模 型主要是为了顾及完整性,因为它对于应用程序通常是不可见的。对物理模型的更改通常不会影响到应用程序逻辑,而且这些更改只按照应用程序的执行方式来显 现。应用程序通常关注的是下面所述的逻辑或关系数据模型。
逻辑模型级别
逻辑数据模型是一个完整且精确的目 标域信息模型。由于关系模型占有支配地位,因此它通常都是逻辑数据模型的目标表现形式。有关逻辑级别要讨论的概念包括表格、行以及主键外键约束。在该层会 用到数据库标准化概念(即数据的垂直分区)。事实上,找到可体现出高度标准化的关系架构并非难事。在过去的 20 年中,逻辑模型级别已经成为关系数据库应用程序的目标。逻辑级别与物理级别之间的映射完全在应用程序范围之外发生,并且由关系数据库系统隐式执行。将在逻 辑级别环境下编写的应用程序与在物理级别进行的更改(例如添加或撤消索引以及对记录的物理重组)进行隔离的能力指的就是数据独立性,且被视为关系模型的主 要优点之一。在关系数据库系统中,SQL 查询语言通过表格和视图运行,但(通常情况下)无需了解物理层中可用的各种索引。
如今在关系 架构中时而体现出的高度标准化有助于满足重要的应用程序要求,例如数据一致性以及更新和 OLTP 性能方面所提高的并行性。但是,标准化也为各应用程序提出了难题,因为逻辑级别的数据过于零碎,并且应用程序逻辑需要将多个表格中的行聚合到更近似于应用 程序域的人工产物的更高级实体中。在下一部分中介绍的概念级别旨在解决这些难题。
概念模型级别
概念模型从问题域及其关系中捕获核心信息实体。一个有名的概念模型是由 Peter Chen 在 1976 年引入的“实体-关系模型”[CHEN76]。UML 是概念模型一个更近期的示例 [UML]。
多 数重要的应用程序在应用程序开发生命周期早期都会涉及到概念设计阶段。现在,许多人都将“概念”解释为“抽象”,这是因为概念数据模型是在一个与代码以及 用于实现应用程序的逻辑关系架构没有任何关联的数据库设计工具内部获得的。随着时间的推移,通常“一成不变”的数据库设计图会与应用程序实现的实际情况日 益脱节。不过,概念数据模型能够与逻辑关系模型一样现实、精确并侧重于应用程序域的具体“概念”。因此,没有理由不在数据库系统中以具体形式嵌入一个概念 模型。Microsoft 数据访问设想的目标之一就是使概念数据模型成为数据平台的一个具体功能。
多数人将概念模型向逻辑模型的转换 任务联想为向逻辑关系模型的“标准形式”转换。实际情况不一定是这样,我们将在稍后说明。就像关系系统在逻辑级别与物理级别之间提供数据独立性一样,实现 概念模型的系统也可以在概念级别与逻辑级别之间提供数据独立性。将面向概念级别的应用程序与逻辑级别的更改相隔离是一个迫切的需要。由 “Microsoft 开发者部门”近期实施的一项调查表明,将应用程序与(关系)逻辑级别的更改相隔离在功能需求中排在前几位。
数据 平台中的概念模型包含在“实体数据模型”(EDM) 中 [EDM]。EDM 中的核心概念是实体和关系。实体是“实体类型”的实例(例如 Customer、Employee),即含有一个关键字的充分结构化记录。实体关键字基于“实体类型”属性的子集形成。关键字(例如 CustId、EmpId)是唯一标识和更新实体实例以及允许实例参与到关系中的一个基本概念。实体将被归入各“实体集”中(例如,Customers 是 Customer 实例的集合)。关系用于关联各实体实例,属于“关系类型”的实例(例如 Employee WorksFor Department)。关系将被归入到各“关系集”中。
EDM 与 eSQL 查询语言 [ESQL] 配合使用,后者由 SQL 演化而来,旨在实现面向集合的声明式查询以及对实体和关系的更新。EDM 同样也可以与其他查询语言配合使用。EDM 和 eSQL 结合起来共同表示数据平台的一个概念数据模型和查询语言,目标是使业务应用程序(例如 CRM 和 ERP)、数据服务(例如报告、分析和同步)以及各应用程序可以在更接近于其需要的抽象和语义级别对数据进行建模和处理。EDM 是一个基于值的概念模型。它未包含任何类型的行为。它同时也是下一部分所述的编程/表示级别的基础。
编程和表示级别
概 念模型的实体和关系通常需要根据现有任务以不同形式表现。某些实体需要转换为可按照实现应用程序业务逻辑所用编程语言进行处理的对象。某些实体需要转换为 XML 流以作为 Web 服务调用的一种序列化格式。其他实体需要针对 UI 数据绑定目的而转换为内存中结构,例如列表、字典或数据表格。当然,不存在通用的编程模型或表示形式,因此应用程序需要灵活的机制来将各实体转换为各种表 示形式。
通常,某一特定表示或编程模型的拥护者会认为他们独特的“表示”视图是唯一正确的选择。我们认为不存在“唯一适合的表示模 型”,真正的价值在于使概念级别成为现实,然后可以将该模型用作各种表示模型以及其他高级服务之间相互映射的基础。多数开发人员以及我们将在稍后指出的多 数现代服务想要讨论的是“订单”(请参见图 1)之类的高级概念,而不是在关系数据库架构中标准化的几个表格。他们想要对订单进行查询、保护、编程和报告。多数开发人员在设计其应用程序时都在暗中考 虑有关订单的问题。他们可能只在头脑中思考,也可能将其体现在 UML 图表或白色书写板中。订单可以在表示/编程级别表现为封装了订单关联状态和逻辑的 Visual Basic 或 C# 中的一个类实例,也可以表现为用于与 Web 服务通信的 XML 流。
![a](http://www.microsoft.com/china/MSDN/library/data/dataAccess/art/nxtgen01L.gif)
图 1:订单的物理视图、逻辑视图、概念视图以及多个编程和表示视图(单击图像可查看大图片)
数据服务演变
本 节介绍了可激发对更高级别数据模型和数据平台需求的平台切换。我们将从两个方面来对此加以了解:作为产品的应用程序演变和 SQL Server 演变。关键在于,在“第 2 节”中介绍的阻抗失谐问题并非是应用程序所特有的,在构建较高级别数据服务(如,报告和复制)时其也是一个很棘手的问题。
应用程序演变
10-20 年前的基于数据的应用程序通常已结构化为数据块;逻辑已由动词对象功能分解的封闭系统与逻辑架构级别上的数据库系统进行交互。让我们以一个订单输入系统为例。
大约 1985 年的订单输入
20 年前围绕关系数据库管理系统 (RDBMS) 而建立的典型订单输入系统中的逻辑是围绕动词对象功能进行分区的,而动词对象功能又同用户与系统的交互方式相关联。事实上,通过“屏幕”或“窗体”的用户 交互模式成为了逻辑的主要分解 - 会有新订单屏幕和更新客户屏幕。系统可能还支持 SKU、库存等的成批更新。请参见图 2。
关键在于, 应用程序逻辑已牢牢地绑定到了逻辑关系架构。新订单屏幕会引用现有客户,从产品、订单和订单明细中收集订单信息。屏幕的提交会开始一个操作,并调用逻辑以 将新订单插入到“订单”表格中,该表格中含有日期、订单状态、客户 ID、接收方地址、发票方等。新订单例程还会将一些行项目插入到订单明细表格中。由于许多第一代的 RDBMS 不支持数据库级别上的外键约束检查,因此,应用程序逻辑必须确保每个新订单都具有有效的客户 ID,或者确保删除订单标题行需要删除所有关联的订单明细。更新主数据(如 SKU 和价格信息)的批处理过程在逻辑架构级别上同样有效。人们通常会编写批处理程序来直接与逻辑架构进行交互,以执行这些更新。还需重点指出的一点是,实际 上,在 20 年前,所有数据库服务(插入、删除、查询、批量加载)也都是在逻辑架构级别上构建的。编程语言不直接支持高级别抽象的表示 - 对象不存在。
![a](http://www.microsoft.com/china/MSDN/library/data/dataAccess/art/nxtgen02L.gif)
图 2:大约 1985 年的订单输入系统(单击图像可查看大图片)
这些应用程序的特征就是均为封闭系统,其逻辑数据一致性由应用程序逻辑来维护,而该应用程序逻辑是在逻辑架构级别实现的。订单之所以是订单,就是因为新订单逻辑确保其如此。
大约 2005 年的订单输入
许多重要趋势已确定了基于数据的现代应用程序的分解和部署方式。首当其冲的就是面向对象的分解、服务级别应用程序合成以及更高级别的数据服务。
面向对象的分解
面 向对象的方法通过将逻辑与“业务对象”相关联来替换动词对象功能分解。业务对象通常遵循作为概念架构模型一部分而创建的概念“实体”分解。实体(例如, “客户”、“订单”、“ProductMaster”)将成为业务对象。在概念架构设计期间获得的业务对象实体之间的关系将实现为业务对象上的方法。因 此,“客户”业务对象具有一个名为“GetOpenOrders”的方法,该方法可返回该客户未结订单的集合。由于业务对象的出现,另一个抽象层被添加到 了应用程序中,且业务对象维护了客户实体的状态(可隐式或显式地检索或保留到数据库),而不是将新订单屏幕中收集的自由变量分成几行几列发送到数据库。
服务级别应用程序合成
20 年前的订单输入应用程序通常被实现为围绕 RDBMS 的单个块。通常会通过批处理作业在逻辑架构级别对引用和资源数据(例如,价格、商品台帐类和真实库存)进行更新,这些批处理作业会将其他系统中的数据提取 到平面文件中,然后再通过逻辑架构级别的批量加载实用程序将它们加载到订单输入系统中。
如今的订单输入系统更可能是由其他系统所提供的服务 构成。将根据需要对这些服务进行调用。此外,订单输入系统必须对服务请求和其他系统启动的事件做出响应。让我们来看一看库存管理。订单输入系统更有可能会 将服务请求发送到分发系统来检查库存级别,而不是每天都从其他系统获取库存级别的成批更新。或者,订单管理系统可能只从分发系统接收库存级别通知,例如, “有库存”或“订货不足”。这些库存级别通知的状态信息可能相当明确,例如,“库存低”通知可使订单管理系统知道以当前的预期销售情况看,只有 3 天的可用库存。或者,“订货不足”库存通知可指示下次递送应到达分发处的时间。关键是“StockNotification”为概念实体。在我们的订单输 入系统中,“StockNotification”可能作为业务对象驻留在内存中;存储在系统间的持久队列中;保存在数据库中以便后续分析评估供应商的业 绩;或者序列化为作为 Web 服务“名词”的 XML,等等。在所有这些形式中,“StockNotification”仍包含相同的概念结构;不过,其逻辑架构、物理表示和可以绑定到其当前表示的服 务取决于当前使用上下文。这就意味着,这些概念实体的以数据为中心的视图可以抽取和提供对这些实体进行控制的其他平台服务。实际上,用来表示当今应用程序 中概念状态的数据需要映射到各种表示中,并需要绑定到应用程序中的各种服务。
了解如今的订单输入系统
当想 到上面的分解、合成和服务时,我们就会发现,概念实体是当今应用程序的重要部分。也可以很容易地看出这些实体是如何必须被映射到各种表示和绑定到各种服务 的。现在还没有正确的表示或服务绑定。XML、“关系”和“对象”表示都很重要,但一个表示还不够。最初设计系统时,我们想到了 “StockNotifications”。我们如何使它们变得真实并且在整个系统中使用对它们的概念理解?无论它们是存储在用于分析的多维数据库中、系 统间的持久队列中、中间层缓存中、业务对象等等?
图 3 着重介绍了订单输入系统中的几个实体,从而抓住了此问题的实质。请注意,概念级别实体已变得真实。另请注意,概念实体正在与各种逻辑架构格式进行通信并映 射到其中,例如,持久存储的关系,“提交订单”服务上持久消息队列的消息以及“库存更新”和“订单状态”Web 服务的可能 XML。
![a](http://www.microsoft.com/china/MSDN/library/data/dataAccess/art/nxtgen03L.gif)
图 3:大约 2005 年的订单输入系统(单击图像可查看大图片)
SQL Server 演变
20 年前由“数据平台”提供的数据服务范围非常狭小,仅仅着眼于 RDBMS 中的逻辑架构。这些服务包括查询和更新、琐碎事务以及批量操作(例如,备份和加载/提取)。
SQL Server 本身是从传统的 RDBMS 演变到完整数据平台的,该数据平台可针对在概念架构级别上实现的实体提供许多高价值的数据服务。虽然提供服务(例如,报告、分析、单个产品中的数据集成以 及实现它们之间的协作)是一项有意识的业务策略,但获取这些服务的方法和描述其所操作实体的相应方式具有更大的随机性 - 许多时候,会对在尝试提供针对逻辑架构级别的更高级别数据服务时所识别出的问题进行响应。
有两个大的示例说明了对 SQL Server 中当前所提供服务的具体实体表示的需要。合并复制的逻辑记录和报告生成器的语义模型。
SQL Server 中早期版本的合并复制是为对各行进行多主复制而提供的。在该早期模式下,多个代理可独立地对行进行更新;更改可能会冲突;各种冲突解决机制将随模型一起提 供。此以行为中心的服务具有一个基本的缺陷 - 它不会捕获这样一个事实:实体在系统间流动时可确保其隐式的一致性。在关系数据库系统中,并发控制系统的 ACID 保证即为可防止混乱的关键所在。如果订单由一个订单标题和 5 条订单明细组成,如果已插入了这 5 条订单明细中的 3 条,则并发控制系统所提供的隔离会阻止系统上的其他代理查看或处理处于不一致状态的订单。在事务中,数据库在逻辑上经常处于不一致状态 - 例如,仅插入了 5 条订单明细中的 3 条,或者在某次转帐中,金额记入到另一帐户贷方之前其已从某一帐户借方转出。系统中的其他代理只会看到一致的“之前状态”或“之后状态”。由于合并复制是 在逻辑架构或行级别操作的,因此无法捕获到以下情况:虽然已将表示新订单的数据插入到了某个系统上的单个隔离事务中,但在复制时将以隔离的方式对其进行安 装。因此,如果在传送了 5 条订单明细中的 3 条后复制传送失败,则用来选取并处理不一致新订单的订单处理系统将无法得知该操作尚未完成。为了弥补这一缺陷,复制服务引入了“逻辑记录”,作为用来描述 和定义实体间一致性边界的方式,这些实体由逻辑架构级别上的多个相关行组成。“逻辑记录”是在与合并复制关联的 SQL 目录部分中进行定义的。没有适当的定义“逻辑记录”方面的设计时工具体验,例如,包括其“订单明细”的“订单”- 应用程序通过一系列存储的过程调用来实现此操作。
“报告生成器”(RB) 是 SQL Server 提供概念实体级别数据服务的另外一个示例。SQL Server Reporting Services (SSRS) 已经向 SQL 产品中添加了不可思议的值。由于它是在逻辑架构级别进行操作的,因此,编写报告需要了解如何构建逻辑架构级别的查询 - 例如,创建订单状态报告需要了解如何编写组成订单的许多表格之间的连接。一旦发布了 SSRS,对于不要求开发人员激发 Visual Studio 和为报告编写 SQL 查询的终端用户报告编写环境而言,存在不可思议的要求。终端用户和分析人员希望直接对“客户”、“订单”、“销售”等编写报告。他们是以商业概念或 “域”、级别考虑问题的业务人员,他们希望在此级别而不是在逻辑架构级别表示他们的查询。实际上,所有的“终端用户”和“英语查询”报告环境均需如此。因 此 SQL Server 小组创建了一种方法,可用来描述概念实体并将其映射到逻辑架构层,我们称之为“语义模型定义语言”(SMDL)。
这些服务仅是 SQL Server 所提供的众多映射服务中的两个服务 -“统一维度模型”(UDM) 提供了许多逻辑数据模型的多维视图抽象。BI 工具在其上有效的“数据源视图”(DSV) 也提供了概念视图映射技术。
关 键之处在于,SQL Server 获得成功的一个主要推动力就是它在概念架构级别提供更高级别的数据服务。目前,所有这些服务都具有各自的工具,以描述概念实体并将他们向下映射到底层逻辑 架构级别。如果问题域中有一个“客户”,那么,在对其进行定义时,您需要将一种方法用于合并复制,将另一种方法用于报告生成器,等等。
图 4 显示的是 6.0 版中的 SQL Server - 实际上为传统的 RDBMS,其中所有以数据为中心的服务都是在逻辑架构级别提供的。图 5 说明了 SQL Server 演变为数据平台的过程,该数据平台具有许多高价值的数据服务,可通过多种方法来具体化概念实体并将其映射到底层逻辑架构。
![a](http://www.microsoft.com/china/MSDN/library/data/dataAccess/art/nxtgen04.gif)
图 4:SQL Server 1995
![a](http://www.microsoft.com/china/MSDN/library/data/dataAccess/art/nxtgen05.gif)
图 5:SQL Server 2005
其他数据服务
虽 然我们已激发了使概念级别变得真实的要求,但从 SQL 数据平台的角度来看,以下这一点是显而易见的:从概念级别的真实服务映射到任意数量的逻辑和编程/表现表示操作正在多个区域中发生。以 Web 服务序列化“数据合同”为例,它在 CLR 对象状态表示和其序列化的 XML 表单之间进行映射。如果在进行“合同至上”服务开发,则服务联系人中的名词是实体的真实状态表示 - 请回忆一下“StockNotification”的示例。此趋势将继续:
• |
数据库“搜索”。许多人正在致力于执行对结构化存储的“搜索”- 实际上是在尝试在查询语言和搜索表达式之间搭起一座桥梁。尝试在逻辑关系架构上执行数据库搜索时,存在两个很棘手的问题: |
• |
返 回结果是什么?当匹配作为邮政编码的 98052 时,返回不关联的地址不是很有用。那么,当搜索表达式显示为“customer zip 98052”时,会返回怎样的值呢?若表达式为“Pizza zip 98052”,结果又会怎样呢?请注意,使概念级别变得真实既有助于帮助了解搜索表达式的语义,又有助于具体化返回结果。 |
• |
如 何在数据库搜索时实现安全方案?我们必须假设搜索表达式域囊括了整个数据库。那么,我们如何实现数据库中未覆盖的那部分内容的安全性呢?基于对底层逻辑架 构访问进行的授权只能这样了。如果我们能够将授权方案从逻辑架构级别提升至概念级别,就可以真正地解决此问题了 - 只有这样,我们才能确保以下内容的安全:“客户”、“订单”和“ProductMaster”。 |
• |
Office 文档作为内容模型:Office 12 在从表示格式模型转至内容模型方面迈出了一大步。因此,可将 Office 文档视为一个实体容器,其可将结构化的、半结构化的和未结构化的数据收集到一起。如果我们已具有了一个保险领域的真实概念模型,则可以通过将实体从设计器 拖动到 InfoPath 设计图面中来创建一个用于处理索赔的 InfoPath 表单。调节者可转至索赔场景并填写用来创建和引用如下实体的表单:“持保人”、“索赔”、“策略”、“申领人”等。他们也可以捕捉未结构化的数据,例如: 场景草图、伤害照片等。可将此内容丰富的文档“提交”到具有丰富概念(如“持保人”、“索赔”、“日期”、“位置”等)的应用程序平台。可直接在这些概念 的顶层建立服务 - 对某些人而言,编写列有去年在某一特定“位置”发生的“事件”的报告是件很容易的事情。可以很容易地从文档中提取索赔信息,并将这些信息用作启动新索赔过 程的 Web 服务中的名词。请注意,在平台中使用以数据为中心的文档与通过平台生产以数据为中心的文档都将在此新领域中被启用。 |
设想
那么,对于下一代数据访问的设想是什么呢?也就是说,应该认识到技术与应用程序的明显发展趋势正在促使我们在概念架构级别而不是逻辑架构级别提供更加丰富的服务,并抓住此次机会提供一个更加广阔的平台,以通过在其上实现广泛的平台价值来将概念架构变为现实。
应该提升哪些服务?概要:
1. |
数 据建模 - 我们需要提供一个可以定义实体结构本质的数据模型,在某种程度上允许这些实体用各种逻辑表现形式表现。此模型必须要有具体的表现形式,以使我们能够在这一 级别处理数据并生成真正的设计时工具和相关运行时支持。此平台需要具备一种供实体和关系使用的基于集合的查询和更新语言。请注意,实体数据模型是用于体现 值而非对象的概念模型。这一点特别重要,因为数据平台需要在最高可用语义级别管理数据而同时又无需受某一表示层的特定机制约束。这将使其他数据服务(例如 报告、复制和分析)可以充分利用支持概念级别的映射和查询基础结构。 |
||||||||
2. |
映 射 - 具备一个具体的实体模型,使我们可以建立对各种逻辑和表示表现的一系列映射。当然,也存在默认映射,但我们平台的部分价值在于提供在外部表现之间相互映射 的工具,而无论是组合产品目录、按照内部规范标准将采购订单表格标准化还是提供对各种操作系统的异类同步作为主数据管理解决方案都是如此。 |
||||||||
3. |
设 计时工具 - 目前基于实体的工具所生成的模型主要用于绘图器,这样建模工作中产生的大图片就被长期贴在墙上的某个位置以等待迅速过时。有些人使用这些工具为关系数据库 实现生成逻辑或物理设计,但也不过如此而已。我们的数据访问工具应该进行分层和分解以满足整个基本实体模型的多种需要:
|
||||||||
4. |
转换运行时 - 只要我们可以描述映射并对其编码,便可以生成工具以自动将实体映射到多个表现中。我们可以从数据库中检索“customer”、将其识别为对象、将其作为 XML 呈现以通过 Web 服务体现,所有这些都通过一种由映射描述驱动的声明式方式来完成。 |
||||||||
5. |
综 合性编程模型 - 我们需要能够弥合不同逻辑表现(XML、关系、对象)之间间隙的编程模型。实际上,通过在概念级别开发编程语言和 API,我们能够使编程人员从不同逻辑模型之间存在的阻抗失谐中解脱出来。另外,这些编程模型应根据应用程序的部署、性能和可伸缩性要求支持开发可在数据 存储区内部或外部运行的应用程序业务逻辑。 |
||||||||
6. |
面向概念级别的数据服务。以下是一些具体示例:
|
此 时,您应该明确了促使我们向概念级别服务发展的原因。我们身边到处都有事实根据,从我们所生成的“烟囱式”系统到模型、工具以及从概念实体向逻辑和物理表 现的转换。我们提出的数据访问设想力求通过将这些“烟囱式“系统统一到一个协调的跨产品多版本查询中来建立有效的平台切换。
使概念级别成为现实
这一部分概述如何定义概念模型并对其进行操作。我们使用 Northwind 数据库修改后的版本以便于您熟悉。
生成概念模型
第 一步是定义您的概念模型。EDM 代表此类模型的一个正式的设计运行时表达式。EDM 允许根据实体和关系描述模型。在理想情况下,应该有两种用于从头开始定义模型的方式。一种是通过手写模型的 XML 序列化形式(如下所示)来显式定义模型。另一种是通过图形化 EDM 设计器工具来实现。
<?xml version="1.0"?>
<Schema Namespace="CNorthwind"
xmlns="urn:schemas-microsoft-com:windows:storage">
<!-
典型的实体定义,具备标识 [关键字] 和一些成员
-->
<EntityType Name="Product" Key="ProductID">
<Property Name="ProductID" Type="System.Int32" Nullable="false" />
<Property Name="ProductName" Type="System.String"
Nullable="false" Size="max" />
<Property Name="QuantityPerUnit" Type="System.String"
Nullable="false" Size="max" />
<Property Name="ReorderLevel" Type="System.Int16" Nullable="false" />
<Property Name="UnitPrice" Type="System.Decimal" Nullable="false" />
<Property Name="UnitsInStock" Type="System.Int16" Nullable="false" />
<Property Name="UnitsOnOrder" Type="System.Int16" Nullable="false" />
</EntityType>
<!-
派生产品,可以映射 TPH、TPC、TPT
-->
<EntityType Name="DiscontinuedProduct" BaseType="Product">
<Property Name="DiscReason" Type="System.String"
Nullable="false" Size="max" />
</EntityType>
<!-
复杂类型只定义结构而不定义标识。可以
在 0 个或更多实体定义中内嵌使用
-->
<ComplexType Name="CtAddress" >
<Property Name="Address" Type="System.String"
Nullable="false" Size="max" />
<Property Name="City" Type="System.String"
Nullable="false" Size="max" />
<Property Name="PostalCode" Type="System.String"
Nullable="false" Size="max" />
<Property Name="Region" Type="System.String"
Nullable="false" Size="max" />
<Property Name="Fax" Type="System.String"
Nullable="false" Size="max" />
<Property Name="Country" Type="System.String"
Nullable="false" Size="max" />
<Property Name="Phone" Type="System.String"
Nullable="false" Size="max" />
</ComplexType>
<EntityType Name="Customer" Key="CustomerID">
<!- 地址是引用内嵌式复杂类型的成员 -->
<Property Name="Address" Type="CNorthwind.CtAddress"
Nullable="false" />
<Property Name="CompanyName" Type="System.String"
Nullable="false" Size="max" />
<Property Name="ContactName" Type="System.String"
Nullable="false" Size="max" />
<Property Name="ContactTitle" Type="System.String"
Nullable="false" Size="max" />
<Property Name="CustomerID" Type="System.String"
Nullable="false" Size="max" />
</EntityType>
<!-
Product [如上定义] 和 OrderDetails [出于简明需要而未显示] 之间
关联的示例
-->
<Association Name="Order_DetailsProducts">
<End Name="Product" Type="Product" Multiplicity="1" />
<End Name="Order_Details" Type="OrderDetail" Multiplicity="*" />
</Association>
<!-
实体容器可定义
EntitySets(某一类型(可能)多形态实例的集合)和
AssociationSets(用于关联两个或更多实体实例的逻辑链接表)的
逻辑封装
-->
<EntityContainerType Name="CNorthwind">
<Property Name="Products" Type="EntitySet(Product)" />
<Property Name="Customers" Type="EntitySet(Customer)" />
<Property Name="Order_Details" Type="EntitySet(OrderDetail)" />
<Property Name="Orders" Type="EntitySet(Order)" />
<Property Name="Order_DetailsOrders"
Type="RelationshipSet(Order_DetailsOrders)">
<End Name="Order" Extent="Orders" />
<End Name="Order_Details" Extent="Order_Details" />
</Property>
<Property Name="Order_DetailsProducts"
Type="RelationshipSet(Order_DetailsProducts)">
<End Name="Product" Extent="Products" />
<End Name="Order_Details" Extent="Order_Details" />
</Property>
</EntityContainerType>
</Schema>
应用映射
一旦具备了 EDM 概念模型,只要已经定义了目标存储区,我们便可以映射到该目标存储区的逻辑架构模型。
![a](http://www.microsoft.com/china/MSDN/library/data/dataAccess/art/nxtgen06L.gif)
图 6:Northwind 实体数据模型(单击图像可查看大图片)
当然,该模型可通过 SQL DDL 表达,例如,“员工表”可能如下所示:
CREATE TABLE [dbo].[Employees](
[EmployeeID] [int] NOT NULL,
[LastName] [nvarchar](20)
COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[FirstName] [nvarchar](10)
COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Title] [nvarchar](30) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[Extension] [nvarchar](4) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[Notes] [nvarchar](max) COLLATE SQL_Latin1_General_CP1_CI_AS NULL,
[ReportsTo] [int] NULL,
CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED
(
[EmployeeID] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
对于概念 EDM,可以手写显式映射或使用映射工具。图 7 表现的是某一运行中的映射设计工具,它正将上述 EDM 概念模型映射到经过修改的 Northwind 逻辑架构。
左 侧项代表 EDM 模型的构造。右侧项代表存储区的逻辑模型构造。在此示例中,我们可以看出修改 Northwind 的促动因素之一。目的是反映存储区内不同表中垂直分区数据的共用策略。尽管能够实现此目的,但理想情况下,您会考虑将数据作为单一实体而无需连接或了解逻 辑模型。类似 Employee 的实体可跨存储区中的多个表进行定义和映射。以下是映射的序列化形式(请注意,我们是在 EntitySet 级别映射且允许使用用于表达表的表段以及在某一指定 EntitySet 内组成实体的连接条件):
<EntitySetMapping cdm:Name='Employees'>
<EntityTypeMapping cdm:TypeName='IsTypeOf(CNorthwind.Employee)'>
<TableMappingFragment cdm:TableName='ContactInfo'>
<EntityKey>
<ScalarProperty cdm:Name='EmployeeID'
cdm:ColumnName='EmployeeID' />
</EntityKey>
<ScalarProperty cdm:Name='Address' cdm:ColumnName='Address' />
<ScalarProperty cdm:Name='City' cdm:ColumnName='City' />
<ScalarProperty cdm:Name='Country' cdm:ColumnName='Country' />
<ScalarProperty cdm:Name='PostalCode'
cdm:ColumnName='PostalCode' />
<ScalarProperty cdm:Name='Region' cdm:ColumnName='Region' />
</TableMappingFragment>
</EntityTypeMapping>
<EntityTypeMapping cdm:TypeName='IsTypeOf(CNorthwind.Employee)'>
<TableMappingFragment cdm:TableName='Employees'>
<EntityKey>
<ScalarProperty cdm:Name='EmployeeID'
cdm:ColumnName='EmployeeID' />
</EntityKey>
<ScalarProperty cdm:Name='Extension'
cdm:ColumnName='Extension' />
<ScalarProperty cdm:Name='FirstName'
cdm:ColumnName='FirstName' />
<ScalarProperty cdm:Name='LastName' cdm:ColumnName='LastName' />
<ScalarProperty cdm:Name='Notes' cdm:ColumnName='Notes' />
<ScalarProperty cdm:Name='ReportsTo'
cdm:ColumnName='ReportsTo' />
<ScalarProperty cdm:Name='Title' cdm:ColumnName='Title' />
</TableMappingFragment>
</EntityTypeMapping>
<EntityTypeMapping cdm:TypeName='IsTypeOf(CNorthwind.Employee)'>
<TableMappingFragment cdm:TableName='PersonalInfo'>
<EntityKey>
<ScalarProperty cdm:Name='EmployeeID'
cdm:ColumnName='EmployeeID' />
</EntityKey>
<ScalarProperty cdm:Name='BirthDate'
cdm:ColumnName='BirthDate' />
<ScalarProperty cdm:Name='HireDate' cdm:ColumnName='HireDate' />
<ScalarProperty cdm:Name='HomePhone'
cdm:ColumnName='HomePhone' />
<ScalarProperty cdm:Name='Photo' cdm:ColumnName='Photo' />
<ScalarProperty cdm:Name='TitleOfCourtesy'
cdm:ColumnName='TitleOfCourtesy' />
</TableMappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
![a](http://www.microsoft.com/china/MSDN/library/data/dataAccess/art/nxtgen07L.gif)
图 7:概念到逻辑映射工具(单击图像可查看大图片)
自动生成类
具 备概念级别实际上对于许多应用程序来说已经足够,因为它提供了存在于一种易用模式上下文(ADO.NET 命令、连接和数据读取器)之内的域模型,并考虑到了自返回值变为自我描述式之后的多种后期绑定情况。但是,许多应用程序更倾向于对象编程层。这可以通过由 EDM 描述驱动的代码生成来轻松实现。在 Visual Studio 内,您可以利用 ADO.NET 感知编译任务来生成相应代码。鉴于对象与概念级别之间的灵活性和数据独立性已得到提高,在类与概念模型之间可能还存在另一级别的映射。只要能定义一个合法 映射,这将使根据这些类生成的应用程序可以在各版本的概念模型环境下重新使用。对于类与概念模型之间的映射,约束条件已减至最少,且遵循保持往返程同一性 和保真度的原则。下图例示了同一解决方案中的各个类。
![a](http://www.microsoft.com/china/MSDN/library/data/dataAccess/art/nxtgen08L.gif)
图 8:代表编程级别的自动生成类(单击图像可查看大图片)
类与概念模型之间的映射是一个成员方面的直接映射,其代码段如下所示:
<ObjectMapping cdm:CLRTypeName="CNorthwind.Product"
cdm:CdmTypeName="CNorthwind.Product">
<MemberMapping cdm:CLRMember="ProductID" cdm:CLRAlias="ProductID"
cdm:CdmMember="ProductID" />
<MemberMapping cdm:CLRMember="ProductName" cdm:CLRAlias="ProductName"
cdm:CdmMember="ProductName" />
<MemberMapping cdm:CLRMember="QuantityPerUnit"
cdm:CLRAlias="QuantityPerUnit"
cdm:CdmMember="QuantityPerUnit" />
<MemberMapping cdm:CLRMember="ReorderLevel" cdm:CLRAlias="ReorderLevel"
cdm:CdmMember="ReorderLevel" />
<MemberMapping cdm:CLRMember="UnitPrice" cdm:CLRAlias="UnitPrice"
cdm:CdmMember="UnitPrice" />
<MemberMapping cdm:CLRMember="UnitsInStock" cdm:CLRAlias="UnitsInStock"
cdm:CdmMember="UnitsInStock" />
<MemberMapping cdm:CLRMember="UnitsOnOrder" cdm:CLRAlias="UnitsOnOrder"
cdm:CdmMember="UnitsOnOrder" />
</ObjectMapping>
<ObjectMapping cdm:CLRTypeName="CNorthwind.Shipper"
cdm:CdmTypeName="CNorthwind.Shipper">
<MemberMapping cdm:CLRMember="CompanyName" cdm:CLRAlias="CompanyName"
cdm:CdmMember="CompanyName" />
<MemberMapping cdm:CLRMember="Phone" cdm:CLRAlias="Phone"
cdm:CdmMember="Phone" />
<MemberMapping cdm:CLRMember="ShipperID" cdm:CLRAlias="ShipperID"
cdm:CdmMember="ShipperID" />
</ObjectMapping>
使用对象
您可以与各对象进行交互,并对对象定期执行“创建、读取、更新、删除”(CRUD) 操作,在以下示例中,我们将对某一指定时间点之后雇佣的所有“员工”进行查询:
public void DoObjectQueries(DateTime date)
{
//--- 获得连接
MapConnection conn =
new MapConnectionFactory().GetMapConnection();
Northwind nw = new Northwind(conn,conn.MetadataWorkspace);
var employees = from e in nw.Employees where e.HireDate > date
select e;
foreach( Employee e in employees )
{
Console.WriteLine(e.FirstName);
}
}
同样,我们可以为每个人提供一次晋升,然后将此更改保存到存储区中:
MapConnection conn =
new MapConnectionFactory().GetMapConnection();
Northwind nw = new Northwind(conn,conn.MetadataWorkspace);
var employees = from e in nw.Employees where e.HireDate > date
select e;
foreach( Employee e in employees )
{
Console.WriteLine(e.FirstName);
e.Title = "manager";
}
nw.SaveChanges();
在这种情况下,此交互的有趣部分就是 Northwind 实例上的 SaveChanges() 调用。Northwind 实例是 ObjectContext 的特殊化形式,并为状态管理等类似任务提供顶级上下文。在这种特定情况下,从存储区检索的实例在默认状态下将作缓存处理,在调用保存更改时,该类型(此时 对该类型作缓存处理)的更改将通过更新管道传送到存储区。
使用值
有许多 ISV 和框架开发人员喜欢使用 .NET 数据提供程序;MapProvider 便专为此类使用情况而设计。Map Provider 具备一个连接和一个命令,在您调用 MapCommand.ExecuteReader() 时,它会返回一个 DbDataReader。使用 MapCommand 进行查询的示例如下:
public void DoObjectQueries(DateTime date)
{
//--- 获得连接
using (MapConnection conn =
new MapConnectionFactory().GetMapConnection())
{
conn.Open();
MapCommand command = conn.CreateCommand();
command.CommandText = @"
Select value e from Employees
as e where e.HireDate>@HireDate";
command.Parameters.Add(new MapParameter("HireDate",date));
DbDataReader reader = command.ExecuteReader();
while(reader.Read())
{
//--- 此时执行所需操作
}
}
}
实体框架体系结构
本部分简要介绍作为 ADO.NET 一部分而建立的实体框架体系结构。可在 [ARCH] 中找到该体系结构的详细说明。ADO.NET 实体框架(参见图 1)的主要功能组件包括:
数据源特定的提供程序。 实体框架建立于 ADO.NET 数据提供程序模型之上。SqlClient 是 Microsoft SQL Server 数据库产品(包括 SQL Server 2000 和 SQL Server 2005)专用于存储的提供程序。WCFClient 是将来的提供程序,通过它可以从 Web 服务访问数据。在接口方面,ADO.NET 提供程序模型包含连接、命令和 DataReader 对象。桥接器(如上所述)中的新 SqlGen 服务通过规范命令生成专用于存储的 SQL 文本。
映射提供程序。实体框架包含一个新的数据提供程序,即映射 提供程序。此提供程序中容纳的服务实现了从概念构造到逻辑构造的映射转换。映射提供程序是一个基于值的客户端视图运行时环境,其中,依据 EDM 实体和关系访问数据,并使用 eSQL 语言进行数据查询。映射提供程序包括下列服务:
EDM/eSQL。映射提供程序依据 EDM 值处理和公开数据。使用基于实体的 SQL 语言(称为 eSQL)来对查询和更新进行公式化表示。
映射。视图映射是映射提供程序的关键服务之一,该子系统实现了双向视图,借此,应用程序可以依据实体和关系而非行和表来操纵数据。从表到实体的映射通过映射定义语言以声明的方式进行指定。
查询和更新管道。查询和更新请求通过映射提供程序的命令对象,以 eSQL 文本或规范命令树的形式指定给映射提供程序。
专用于存储的桥接器。桥接器组件是一项支持查询管道的查询执行功能的服务。桥接器以命令树作为输入,依据底层存储所支持的查询功能生成一个或多个等效的命令树作为输出。
元数据服务。 元数据服务支持映射提供程序内部运行组件的所有元数据发现活动。与 EDM 概念(实体、关系、实体集、关系集)、存储概念(表、列、约束)和映射概念相关联的所有元数据均通过元数据接口予以公开。元数据服务组件还可作为支持模型 驱动应用程序设计的域建模工具之间的联系桥梁。
事务。映射提供程序可以与底层存储的事务功能集成在一起。
API。映射提供程序的 API 遵循基于连接、命令和 DataReader 对象的 ADO.NET 提供程序模型。与其他专用于存储的提供程序一样,映射提供程序接受 eSQL 文本或规范树形式的命令。命令的结果以 DataReader 对象形式返回
偶尔连接的组件。实体框架增强了 ADO.NET 数据集所引入的制定完善的分离式编程模型。除了在类型化和非类型化数据集方面提供更强的编程体验之外,实体框架还利用 EDM 在实体和实体集的缓存集合方面提供了丰富的分离式编程体验。
嵌入式数据库。数据平台将具备低内存占用、可嵌入数据库引擎的能力,以便为需要丰富中间层缓存及分离式编程体验的应用程序提供更加丰富的服务。该嵌入式数据库包括一个简单的查询处理器,并且具备非授权性持久能力,从而可以实现大型的中间层数据缓存。
设计和元数据工具。 该数据平台可以与域设计器集成在一起来实现模型驱动式应用程序开发。这些工具包括 EDM、映射及查询建模器。注意,通过 EDM 驱动的映射工具已创建了一系列工具生成的映射,用以从用户定义的实体(如资产或客户)映射到与各种平台服务相关联的一系列逻辑架构及表现格式。它们可能表 示 Sharepoint 列表定义、业务对象的绑定、合并复制逻辑记录,也可能表示 Web 服务或工作流中所使用的 XML 表示形式。在任何情况下,实体均只需定义一次,与数据平台相关联的工具可以生成相应的逻辑架构定义。
编程层。ADO.NET 允许在映射提供程序所公开的基于值的实体数据服务层上插接多个编程层。对象服务组件就是这样一个用于使 CLR 对象现于表面的编程层。编程层可以采用多种机制与实体框架进行交互。其中一种重要的机制便是 LINQ 表达式树。我们期望将来还可以在实体服务之上建立其它编程面。
服务。将会在实体框架之上建立丰富的 SQL 数据服务,如报告、复制、业务分析。
![a](http://www.microsoft.com/china/MSDN/library/data/dataAccess/art/nxtgen09L.gif)
图 9:实体框架体系结构(单击图像可查看大图片)
参考资料
[CHEN76] Chen, Peter Pin-Shan.The Entity-Relationship Model - toward a unified view of data, ACM Transactions on Database Systems, Vol. 1, Issue 1, March 1976, pp. 9-36.
[UML] Unified Modeling Language. http://www.uml.org/.
[EDM] Entity Data Model.ADO.NET Technical Preview, June 2006
[ARCH] ADO.NET Entity Framework Architecture.ADO.NET Technical Preview, June 2006.
[ADO.NET] ADO.NET Tech Preview Overview, June 2006.
![返回页首](http://www.microsoft.com/library/gallery/templates/MNP2.Common/images/arrow_px_up.gif)