从 ADO 迁移到 ADO.NET(一) 近年来,在基于 Windows 的应用程序中,作为实现数据存取的首选方法,ADO 起着举足轻重的作用。目前有大量 ADO 应用程序在使用中,同时大量的开发人员 都通晓 ADO 的开发。随着.NET Framework的出现,ADO 的改进版 ADO.NET 也随之出炉。尽管 ADO 和 ADO.NET 之间有许多相似之处,但二者的操作方法 以及实现基础有很大的差别。为了帮助你实现向 ADO.NET 的平滑迁移,我们是考察一下在 ADO.NET 中如何实现某些公共任务。 我将讨论几种数据访问方案,演示如何利用 ADO 来实现这些方案,同时演示如何用C#在 ASP.NET 中借助 ADO.NET 来解决同样的问题。我 将从二者与数据源连接的相似之处开始,继而我将细致地探讨 ADO 的 Recordset 对象如何演变发展为 ADO.NET 中许多与众不同的面向对象和方法 的特性。最后,我将揭示 firehose 游标,如何从行集中返回一个单值,以及如何处理 XML 等。 ADO 的演变 有些传统的 ADO 特性,如建立与数据源的连接在两个 ADO 版本之间改变很小。其它一些功能则变化很大,譬如表示一个非连接的行集(rowset),将行集保存为XML,将行集转化为一个层次行集(hierarchical rowset)。促成这些重大改变的一个原因是在 ADO 后期引入 XML 和数据整形(data-shaping)特性,而在 ADO.NET 里,这些特性在当初设计时就将这些特性内建在其中了。 与更早的数据访问工具如 DAO 和 RDO 相比,传统的 ADO 是很轻量级的,而使 ADO 能在n层应用程序开发中和 Visual Basic 6.0 一起得以流行的原因之一 是其简单性、易于导航的对象模式。ADO 的 Connection、Command 对象以相对比较直白的方式转变为 ADO.NET 的 Connection 、Command 对象,但是 ADO 的 Recordset 对象的特性转换到 ADO.NET 中后变成了几个不同的对象和方法。 ADO 之所以成为一个强大而通用的数据访问工具,部分原因是其对 XML 的支持以及管理非连接行集的能力。ADO 的 Recordset 可以 是与其数据源断开连接的,只要将其 CursorLocation 属性设置为 adUseClient,将 CursorType 属性设置为 adOpenStatic, 将 LockType 属性设置为 adLockBatchOptimistic 即可。一旦记录集(recordset)被打开和加载后,通过将其 ActiveConnection 属性 设置为 Nothing,使记录集保持为非连接状态。 ''''---Disconnecting an ADO Recordset oRs.CursorLocation = adUseClient oRs.CursorType = adOpenStatic oRs.LockType = adLockBatchOptimistic ''''— Or use adLockReadOnly oRS.OpenSet oRS.ActiveConnection = Nothing起初 XML 功能并未集成在 ADO 中,随着 XML 的流行,在 ADO 后期版本中增加了对 XML 的支持。ADO Recordset 对象中的 Save 方法可以将记录集的行和列保存为一个预定义的 XML 大纲(schema),并将其保存为一个文件或流。使用 XML 大纲并不灵活,但是这是试图将一个 ADO 行集(rowset)保存为 XML 的第一次尝试,并且让开发者对未来的开发方向有个较清晰的认识。Recordset 也可以从一个 XML 文件中加载,前提是其使用同样的XML大纲。下列代码演示 ADO 如何将一个记录集保存为一个 XML 文件: .Save "c:/MyRowSet.xml", adPersistXML类似于 ASP 页面上的 Response 对象输出,行集可以保存为一个流。例如, 某些 ASP 代码可以接受一个请求,检索一个行集,将行集以流的形式发送给 Response 对象,后者将结果返给客户端。下列代码演示如何将一个记录集的内容保存为一个 Stream 对象。也可以将 Save 方法的第一个参数置为 Response 对象,这样就可以将 XML 行集流输出给浏览器: Dim oStm As ADODB.StreamSet oStm = New ADODB.Stream oRs.Save oStm, adPersistXML 传统的 ADO 和 ASP 均支持流处理。当然,在.NET中,Web services 同样支持流,并且 Web Services 提供了比传统的 ADO 和 ASP 多得多的功能。实际上,Web Services 是一项处理数据请求并将数据以 XML 形式通过 HTTP 传输的技术。ADO 可以以流形式保存 XML,不过这是 ADO 后来的完善措施(afterthought)。而 ADO.NET 的 DataSet 对象通过 WriteXml 和 WriteXmlSchema 方法将其内容输出为一个 XML 文件或流。因此,ADO 的 Recordset 的 Save 方法是经过改进以适于将其内容输出为一个 XML,而 ADO.NET 的 DataSet 一开始就具有此特性。 ADO 中的 Recordset,其行为(功能)依赖其属性设置的不同而不同,而在 ADO.NET 中 Recordset 被分解成许多不同的对象和方法。 从而避免了 Recordset 大而全的弊端,着眼于使各个对象各司其职,因此 ADO.NET 中的这种分解可以显著提高效率。ADO 中的 Recordset 可以是个连接的行集也可以是个非连接的行集。它可以充当一个前 向(forward-only)只读的游标,或者允许行集中位置的前移、后移和向中间移动。ADO 的 Recordset 允许对数据修改直接在数据库中完成,允许保存数据修改并以批处理形式发送给数据库。问题在于 ADO 的 Recordset 承担了太多的功能。ADO.NET 中将这些功能分解为多个对象去 分别完成特定的任务,因而 ADO Recordset 的功能被分为 DataSet 对象、DataReader 对象、DataAdapter 和 Command 对象。 前向、只读游标要求与数据源一直处于连接状态。ADO.NET 使用 DataReader 对象确保当其打开时,就一直处于连接状态。DataReader 专为 某一数据提供程序如 SQL Server、Oracle 或更通用的 OLE DB 数据提供程序而编写。因此,SqlDataReader 对象可以连接到 SQL Server 数据库,并且充当一个 firehose 游标的角色,在大量的记录间循环。SqlDataReader 也具有对查询结果的快速前向(fast-forward-only)访问功能。它从数据库的查询结果中检索到一条记录, 并保持连接为打开状态,以便成功检索下一条记录。ADO.NET 的 DataReader 由于不支持 ADO Recordset 的所有功能,因而效率 极其高。Figure 2 中的例子演示了如何在传统的 ADO 和 ADO.NET 中实现一个只前向移动的游标的例子。值得注意的是在 ADO.NET 中,DataReader 对象的 Read 方法自动移动位置到下一条记录。这就避免了开发者在使用传统的 ADO 时,由于疏忽了调用ADO Recordset 的 MoveNext 方法而导致死循环的情况的出现。 ADO 和 ADO.NET 的另外一个区别是填充前向游标的方式。ADO 中所有的行集,无论前向的还是其它的,均包含在 Recordset 对象中。而 Recordset 对象通过 Recordset.Open 方法或者 Connection 或 Command 对象的 Execute 方法而打开。ADO.NET 中, 有一个专门的方法将获取前向数据提供给 DataReader:即 Command 对象的 ExecuteReader 方法, 该方法告诉命令对象为该数据提供程序明确提出 DataReader 对象以便以优化的前向方式处理结果。如前面例子所示。该命令对象还有一个方法叫 ExecuteXmlReader, 其作用是告诉命令对象生成查询结果供 XmlReader 对象处理。XmlReader 对象可被用于转换和处理 XML 查询结果,见下面的 ASP.NET 例子: oCn.Open(); SqlCommand oCmd = new SqlCommand("SELECT * FROM Orders FOR XML AUTO",oCn); oCmd.CommandType = CommandType.Text; XmlReader oXR = oCmd.ExecuteXmlReader(); while(oXR.Read()) { Response.Write(oXR.ReadOuterXml()); }该例子演示了 XML 如何被发送到调用浏览器。不过,XML也可以整个被聚集和流化到 Response 对象。 单值命令 有时,大多数应用都需要从数据库查询中获取单个值的信息。在传统的 ADO 中标准的做法是创建一个 SQL 语句,并打开包含着查询结果的记录集。因为结果中只有一行一列,看起来似乎不必要。下列代码从查询中获取 单值:该例子获取 Orders 表中的行的数目: ''''-- ASP and ADO Set oRs = Server.CreateObject("ADODB.Recordset") oRs.ActiveConnection = oCn oRs.Open "SELECT COUNT(*) As iRowCount FROM Orders" iCount = oRs.Fields("iRowCount").Value如果你只想取得仅仅一行和一列的信息,ADO.NET 中引入了从查询中获取单个值的新的方法。使用 ADO.NET 命令对象中的 ExecuteScalar 方法, 它可以返回其相关查询的第一行和列的信息。由于不必经过创建行集,查找该值,关闭行集等过程,因而开销非常之小。ExecuteScalar 方法在检索单值时是最佳的方法。下列代码和前例完成同样的任务, 但所使用的是 ASP.NET 和 ADO.NET 中 ExecuteScalar 方法: string sSql = "SELECT COUNT(*) As iRowCount FROM Orders"; SqlCommand oCmd = new SqlCommand(sSql, oCn); oCmd.CommandType = CommandType.Text; int iCount = (int)oCmd.ExecuteScalar();另外一种获取单值的方法是使用存储过程的输出参数。该技术也需要检索大量的值。在 ADO 和 ADO.NET 中均可采用,不同的是 ADO.NET 扩充了输出参数的功能。为了在 ADO.NET 中从一个命令对象中得到输出参数的值,使用 ExecuteNonQuery 方法执行查询语句。该方法告诉 ADO.NET,该查询不返回行集,因而可以避免产生 DataSet 或 DataReader 的 开销: oCmd.ExecuteNonQuery(); oCmd.UpdatedRowSource = UpdateRowSource.OutputParameters; int iOrderID = (int)oCmd.Parameters["@OrderID"].Value; 上述代码设置 UpdatedRowSource 属性以指向输出参数,前提是输出参数已被设置。然后就可以检索到输出的值。在传统的 ADO 中 ,Connection 对象的 Execute 方法使用一个模糊的参数来完成以上任务,而 ADO.NET 是以一种直白的方式来实现的。当然,在 ADO.NET 中还有一种最佳的方法来返回一个标准的行集——即命令对象的 Execute 方法。 |
作者简介 John Papa 是个棒球迷,夏天大多数夜晚都与他的两个小女儿,妻子和忠实的狗 Kadi 一起为YanKees 队加油。他著有几本关于 ADO,XML 和 SQL Server 方面的书,常常能在 VSLive 这样的行业大会看到他演讲。 |
本文出自 MSDN Magazine 的 July 2004 期刊,可通过当地 报摊获得,或者最好是 订阅 |
从 ADO 迁移到 ADO.NET(一)转贴www.vckbase.com
最新推荐文章于 2024-05-11 19:38:32 发布