ADO+ 引导数据种类的演变
ADO+ 引导数据种类的演变 目录
简介 一种公用数据操纵语言 数据种类 ADO+ 增加了哪些内容 ADO+ 的构成要素 ADO+ 命令 强类型编程 摘要
从一开始,开发软件应用程序就是为了访问某种数据库。分布式应用程序和基于 Web 的应用程序也不例外。然而在分布式方案中,由于可能存在不同的硬件和软件平台或对象模型,事情变得稍微有点复杂。尽管如此,数据就是数据,在几乎任何地方都需要得到交换和处理。
在我们进入可编程 Web 时代 — Internet 的第三个阶段 — 之前,数据访问曾是一个相对简单的问题;主要关心的问题就是选择效能成本最合算的数据库服务器。任何系统的所有模块都必须符合数据库服务器 — 一种对整个系统进行完全控制的全能实体 — 的要求。客户机/服务器应用程序一直是这种模型的典型表现形式。
近来,n 层 Microsoft® Windows® DNA 系统致力于开发能够对几乎任何种类的数据进行迅捷可靠的访问的技术,这些数据种类包括:关系型、非关系型、层次型、半结构化型、分散型、易失型等。这种数据访问的统一方法成为“通用数据访问”策略 — OLE DB 体系结构的鼓舞人心的原则。Microsoft ActiveX® Data Objects (ADO) 的出现完成了一项重大的任务:将成千上万的 Windows 开发人员从过时的客户机/服务器模型带到数据访问组件和 OLE DB 的奇妙世界。
在 Windows DNA 模型中,中间层组件通过 OLE DB 规范体贴地为我们定义的一种公用格式来获取和交换数据。这种格式以行集格式为基础,并且通常被转换为诸如 ADO 记录集之类的一种更高级的结构。
使用 ADO 记录集有得有失。一方面,它们提供了一种丰富并具有吸引力的编程接口。另一方面,它们是严格基于 COM 的,在涉及许多平台(尤其是非 Windows 平台)的分布式异构环境中无法使用。互操作性和可伸缩性是对现代 Web 系统的两个很高的要求;互操作性和可伸缩性更好的数据访问体系结构同样是最新的 ADO 版本 ADO+ 中的主要变化。
通常情况下,目前的分布式系统符合图 1 中所示的体系结构。
Web 系统的典型体系结构
表示层通常基于 HTML 3.2 输出,并能够很好地与任何较新的浏览器一起工作。网页是在 Web 服务器上使用 Active Server Pages (ASP) 构建的,并且只有在一些相当特殊的情况下才试图通过 COM、动态 HTML 和 XML 支持来提供浏览器的实际功能。
关键之处是中间层,其中通常有一层或多层业务对象获取并交换数据来响应用户的输入。这些组件可能需要彼此传递数据,并且在传递数据的过程中,它们需要一种易于使用、功能强大并为所有组件所理解的公用数据格式。ADO 记录集 — 表或视图的 ADO 表示 — 是一个相当不错的解决方案,它有几个优点,并且只有一个大的缺点。
ADO 记录集的灵活性足以使您能够毫不费力地定位记录以及使用过滤器和书签。它们还提供排序、自动分页和持久性等功能,并能在与数据源断开时工作。可以在多层之间相当高效地汇集记录集,这归功于其固有的并且极为紧凑的二进制格式 — Advanced Data Table Gram (ADTG) 格式。
断开的记录集在组件之间的传输涉及到 COM 汇集,并强制接收组件配合这一汇集。换句话说,只有 COM 对象才能使用 ADO 记录集。这在 COM/DCOM 在业务层中占主导地位的同构体系结构中不成问题。显然,当有关的服务器端组件的映射涉及到诸如大型机或 Unix 平台之类的异构节点时,就会带来很大的不便。
所谓的 Internet 的第三个阶段使这一方案离我们更近了。它预示了一个世界,在这个世界中,功能实现通过各种 Web 服务(即可以通过 HTTP 访问的环绕着我们的卫星系统)成为可能。您将需要向这些服务中的某个传递一些记录以进行进一步处理,这个方案并不是什么勉强的事情。没有什么比 Web 服务更加容易的事了 — 不管它的内部体系结构或公共编程接口如何 — 它不接受 ADO 记录集。
A目前现实中的 ADO,特别是记录集,是在 Windows 和基于 COM 的方案中操纵数据的强有力的工具。不幸的是,随着您的系统逐渐向完全的 Internet 互操作性方向演变,它们逐渐丧失了其吸引力。
在完美的情况下,应该能够在任何平台或设备上以相同的方式访问数据,并具有相同的灵活性。这样,每个平台或设备都可以根据需要自由地操纵数据。如果您通过 ADO 记录集展示数据,则您也使自己和您的应用程序陷于有限互操作性的实际风险之中。
目前,如果您通过 ADO 对数据进行访问,并希望将其传送到远程组件,您要么使用从数据访问模块获得的相同的 ADO 记录集,要么将其转换为能够通过网络传送的另外的东西,更为重要的是,能够在其最终目的地被理解。如前所述,记录集需要 COM 汇集,举例来说,COM 调用并不是总能穿过公司防火墙。此外,在对 ADO 记录集进行汇集时,总处理时间的很大部分是用于完成必要的类型转换。事实上,您必须确保记录中的所有的值映射到 COM 能够识别并知道如何进行处理的有效数据类型。
在有关的组件在物理上是分开的并在不同的机器上运行时,COM 汇集因素变得更为重要。因此,在向完全由 Internet 连接起来的世界前进的过程中,目前的 Windows 数据种类连同 ADO 记录集必须有所发展才能继续存在下去。
需要示例吗?在 MIND 的 2000 年 1 月号(英文)以及 MSDN Magazine 的 2000 年 3 月号(英文)中的 Cutting Edge 专栏中,我对将远程脚本 (RS) 用作一种从远程 ASP 页面获取数据而不定位到该页面的跨浏览器的技术进行了说明。当您以这种方式调用某一页面上的远程函数时,RS 基础结构提供将函数返回的内容发送回客户机。在大多数情况下,您需要返回一个记录集。然而,由于安全性原因,RS 甚至不会尝试连同任何其它 COM 对象对某一 ADO 记录集进行处理。因而,如果使用 RS,您必须避免使用 ADO 记录集,而应当使用数组或字符串传递所请求的信息。在 2000 年 3 月的专栏中,我通过从记录集构建一个 JavaScript 对象对这一内在的限制进行了说明。ASP 页面通过 ADO 获取数据,并在返回调用程序前将其转换为一个 JavaScript 对象:
rst = new ActiveXObject('ADODB.Recordset');rst.open('select * from employees', 'DSN=Northwind');oRS = new Recordset(rst);rst.close();return oRS;
客户机页面通过 RS 运行时接收这一对象,并可以根据需要对其进行处理,这比通过字符串或数组要容易得多。详细信息和源代码,请参见我的 2000 年 3 月 Cutting Edge 专栏文章(英文)。
我们从这里可以学到些什么吗?对于超出单一客户机或服务器端平台的数据互操作性,我们需要对 ADO 模型进行一个较小的改变。
我们需要改变是由于跨平台模块的交互作用需要一个通用数据模型。此外,我们不希望这个改变太大,原因是 ADO 内还存在若干很好的功能,放弃它们是一件可惜的事情。
JavaScript Recordset 对象,就其内在的简单性而言,不过是一个次数的标志。我们需要提取 ADO 记录集的本质,并将其重新构建成可以便利地在任意平台上进行传输和处理的另外一种东西。HTTP 提供了得到广泛接受的网络渠道。XML 将广泛接受的数据描述的基础结构集合在一起。ADO+ 是对 ADO 的较小改进,它使之成为一个用于创建分布式和数据共享应用程序的基于各种标准的编程模型。
ADO+ 增加了哪些内容?
用最抽象的话来说,ADO+ 是具有更大的可伸缩性和互操作性的 ADO。就对象模型及编程问题而言,ADO 与 ADO+ 是完全不同的两个实体。尽管这样,ADO+ 源自 ADO 并保留了它的鼓舞人心的原则。
以更多互操作性和可伸缩性充实 ADO 的关键在于断开这个概念。在允许客户机端的脚本代码实现诸如排序、过滤和文档/视图模型之类的有趣和交互式功能的同时,断开的记录集作为一种保留系统资源的方式被引入到 ADO 2.0 中。ADO+ 与 ADO 相比具有三个主要优点:互操作性、增强的可伸缩性以及强类型。此外,ADO+ 便于数据组件间的数据共享以及在表中的记录间进行导航。
ADO+ 从一开始就被设计为对断开的数据集进行操作。断开的记录集只能有益于应用程序,因为它们是数据的本地视图,能够较快地处理和传输数据。ADO+ 将 XML 用作通用的传输格式。只要接收组件运行于有 XML 分析程序可用的平台上,就可以提供许多功能,同时确保互操作性。通过 XML 进行传输时,接收者不再必须是一个 COM 对象。XML 是一种简单但却功能强大的基于文本的标准,它近来已广为业界所接受,因而,目前有理由期待差不多每个平台上都会有一个 XML 分析程序。这样的话,接收组件就不会有任何的体系结构限制。任何一对软件组件都可以共享 ADO+ 数据,只要它们同意将相同的 XML 架构用于传输数据格式。图 2 对 ADO+ 适用于现有体系结构的方式进行了说明。
DNA 方案中使用 ADO+
表示层可以通过 Win Forms 或 Web Forms(这两种编程单元专用于 Microsoft Visual Studio.NET 平台)使用或创建数据集。在任一种情况下,运行于业务层的组件都接收一个 XML 流并进行任意处理。这些组件可以重新构建一个 ADO+ 环境,也可以将数据按原始 XML 处理并使其适合于发送到物理数据存储器中。业务组件可以获取 ADO+ 数据,将其转换为 XML,然后将其发送回客户机。任何可以理解 XML 的应用程序都可以在任一点上介入这一架构。
可伸缩性是分布式系统在不丧失效率的情况下对数目逐渐增长的客户机进行服务的能力。可伸缩性是一个常与数据库有关的术语,这是由于分布式系统很大程度上依赖于数据库。可伸缩性无论对于数据库服务器还是对于封装了数据访问操作的任何软件制品都是一个可以持续存在的问题。可伸缩性的最大敌人就是对关键资源的滥用。在分布式系统中,关键通常意味着有限。数据库连接就是可以影响可伸缩性的关键资源的一个示例。固定数目的连接的可用性对系统的增长及其能力形成了一个实际的限制。好的软件了解这种情况并采取适当措施限制其影响。ADO+ 对这一问题的处理是怎样优于 ADO 的呢?并不是说 ADO 是不可伸缩的,而是说对断开的和内存中的表的内在使用(这是 ADO+ 的特征)使 ADO+ 成为内在具有更大可伸缩性的解决方案。它具有更大可伸缩性的原因在于断开的数据集不在很长的时间内保留锁或保持打开连接。如果使用 ADO,您必须编写代码才能获得这一功能;而使用 ADO+ 则会免费获得这一功能。
将 XML 用作数据集的传输语言可以比 ADO 更有效地进行数据共享。首先,绕过诸如记录集之类的 COM 对象所必需的 COM 汇集使组件可以使用它们要使用的任意数据类型的集合。这还会带来更好的性能,因为不再需要确保记录符合标准的 COM 数据类型的数据类型转换。XML 和 HTTP 的使用还允许数据跳过防火墙。正常情况下,防火墙允许 HTTP 数据包通过,但会阻止任何试图经由端口号不是 80 的端口进来的任何其它内容通过。
ADO+ 的构成要素
现在我要介绍主要的 ADO+ 对象。我们以所有内容的起源开始,即 DataSet 对象。
数据集是 ADO 记录集的演化。数据集不过是数据库的断开连接的内存中的视图。就您可以拥有动态创建的数据集和数据表而不需要来自数据库管理系统 (DBMS) 的任何信息而言,数据集与数据源没有任何严格意义上的关系。换句话说,数据集使用了一些添加到 ADO 记录集中的功能:断开时工作的能力以及计划性地创建并以任何种类数据进行置入。数据集可以包含任意数目的表,每个表通常(但不总是)对应于一个数据库表或视图。DataTable 对象对应的表不过是一些行与列的集合。每一行保留其原始状态及其当前状态。
ADO 记录集一直经常以一种充当某种超级数组的通用数据类型出现。同样,ADO+ 数据集是一种提供以下功能的超级记录集:
一种容纳数据的更好和更丰富的编程接口。
一种不需要与实际数据源的任何内在绑定而提供更为广义的数据视图的对象模型。
一种用于输入和输出的基于 XML 的标准控制台。 ADO 记录集基本上是一种(可能是分层的)记录集合,它带有一些特定方法,用于完成一些有趣功能。其中包括包括滚动、排序、过滤、书签。记录集本质上是表在内存中的副本。而数据集看起来更象 SQL Server 或 Access 数据库,它是一个包含更多表、特定视图和外键关系的实体。
数据集对象模型反映了这一较大的范围,它允许您查看跨越多个数据表、关系、扩展属性和行的多个集合的可用数据 — 这还可用于说明非持久数据或只是来自不是数据库的另一个持久存储介质的数据。
ADO 记录集允许您将内容保存到 XML 中,并从一个外部 XML 文件重新构建该内容。然而,采用的缺省 XML 架构是针对导出/导入 ADO 记录集而优化的,而不是针对实际数据交换。ADO XML 架构包含许多关于列类型和位置以及其它元数据的信息。如果您希望从某一 XML 文档中重新构建记录集,则这些信息是至关重要的,但如果您只是希望传递数据并使接收者使用它,则这些信息没有什么用处。有了 ADO+ 数据集,XML 架构更为精练,因为被表示的对象与关系数据库没有直接关系,尽管对象可以用来精密地再现数据库。ADO+ 数据集对数据进行描述,而 ADO 记录集则对由某一表中获取的一个记录集合进行描述。这就是 ADO+ 数据模型的动人之处。
ADO+ XML 架构只是再现表以及数据集中定义的关系,构建一个 DataSet 对象的责任则留给 ADO+ 运行时完成。ADO XML 格式由于过于具体而无法真正实现互操作。它还由于过于繁琐,如果不进行数据压缩的人工干预,它就无法进行高效的汇集。ADO+ 数据集体系结构的鼓舞人心的原则与导致我创建 JavaScript 的 Recordset 对象的原因之间存在一种底层的相似之处。在这两种情形中,您都将数据说明(例如,一个 XML 字符串)转换为一个专用于平台的操作对象(即一个 JavaScript 对象)。在这样做的过程中,您安全地将您的数据从一层发送到另一层,而不考虑安装的操作系统或软件。
ADO+ 命令
尽管 DataSet 对象提供一个内存中数据存储的工具,您还需要另一个工具对各种表进行创建和初始化。这一工具就是 DataSetCommand 对象,它代表一个将使用连接和命令的细节隐藏起来的集中式控制台。DataSetCommand 对象允许某一 DataSet 对象与源数据存储器间的数据检索和保存。它负责从物理存储器中提取数据,然后将其推送到各数据表和关系中。DataSetCommand 对象还负责向实际数据库传输任何更新、插入或删除操作。DataSetCommand 对象通过底层 OLE DB 提供者能够理解的 SQL 命令或命令字符串完成这一功能。DataSetCommand 对象以两种形式存在:
SQLDataSetCommand 对象
ADODataSetCommand 对象 它们可以被当作在数据表和数据源中的对应表之间的代理。数据源是用于 SQLDataSetCommand 对象的 SQL Server 7.0(或更新版本)以及用于 ADODataSetCommand 对象的任何其它 OLE DB 提供者。
一般说来,ADO+ 能够识别并处理两种类型的数据源:SQL Server 7.0(及更新版本)以及可以通过 OLE DB 提供者进行访问的任何数据源。这些又称为被管理的提供者。
作为使用 DataSetCommand 对象的一种替换(如代码示例 1 中所示),您可以通过使用诸如连接和命令之类的较为熟悉的对象,直接对被管理的提供者进行操作。
Dim oDS as DataSetDim oCMD as SQLDataSetCommandoDS = New DataSetoCMD = new SQLDataSetCommand('Select * from employees', strConn)oCMD.FillDataSet(oDS, 'EmployeesList')Dim oRow as DataRow For Each oRow in oDS.Tables(0).Rows Console.WriteLine(oRow(0).ToString())Next
通过查看这种类型的 ADO+ 代码,您会发现它与旧式的 ADO 编程没有多大的差别。它具有新的对象、新的编程接口、经过改进的新功能,但代码模式相同。如代码示例 2 中所示。
Dim oCN As SQLConnectionDim oCMD As SQLCommandDim oDR As ADODataReaderoCN = New SQLConnection(strNWind)oCMD = New SQLCommand('MyStoredProc 'Davolio'', oCN)oCMD.CommandType = CommandType.StoredProcedureTry oCN.Open() oCMD.Execute(oDR) While oDR.Read Console.WriteLine(oDR('LastName').ToString)) End WhileCatch e As Exception Console.WriteLine(e.ToString)Finally oDR.Close() oCN.Close()End Try
请注意,上述代码具有 Microsoft Visual Basic® 7.0 引入的一些语法元素的特征 — 特别是最终取代了 On Error 机制的 Try-Catch 结构。ADO+ 代码充分利用了提供诸如 Console 之类的系统对象的.NET 运行时服务。
还有什么特殊的功能可以帮助您确定革新的 DataSetCommand 方法是否优于使用传统的 ADO 吗?通过使用 DataSetCommand 对象与数据源进行通信,基本上与通过使用 ADO 连接和命令相同,并带有一个重要的推论:所有的 ADO+ 对象,如 DataSetCommand 对象,都可以通过派生新的、更专用的类而进行定制。因此,举例来说,您可以控制将数据集的更改传送到数据库的方式,以及(比方说)优化性能、对数据进行压缩或加密、执行数据验证以及许多其它功能。
您通过 ADO 对数据库对象和类似 Recordset 和 Fields 的集合进行操作。除了将实际数据视为某种参数外,这种方法没有什么错误:
Set oRS = New ADODB.RecordsetoRS.Open strSQL, strConnWhile Not oRS.EOFMsgBox oRS('FirstName') & ' ' & oRS('LastName')oRS.MoveNextWend
在上述 ADO 代码片断中,第一个和最后一个名称被用作进入 Recordset 和 Fields 集合的入口点。由于 Visual Basic 的缺省属性,您可以编写相对容易阅读的代码。依照 ADO,某一给定记录字段的“完整对象模型路径”应为:
oRS.Fields('firstname').value
此外,ADO 总是使用 Variant 数据类型,以便与基于脚本的环境(特别是 ASP)相一致。
ADO+ 通过提供借助数据的自然名称对存储于数据集中的数据进行访问的能力,使数据库编程更进了一步。如果要在某一数据集中寻址某一表,您可以使用该表的 ADO+ 名称并对使用列和行的名称对列和行进行访问,而不是通过基于集合的方法。此外,所有的有关变量都拥有一个特定的(与 Variant 相对)数据类型。这称为强类型编程。上面显示的对一个 Employees 表中的 FirstName 和 LastName 和 LastName 进行操纵的代码可以按下面的形式重新编写:
MsgBox Employees.FirstName & ' ' & Employees.LastName
一种具有类型的 DataSet 即是一个自 DataSet 继承的类。采用数据集的强类型版本是有益的,原因是 IDE 自身可以实时地向您通知可能的类型不匹配错误,而且 Microsoft IntelliSense® 技术可以随时向您建议一些方法和属性。