转换现有代码
有许多 ASP 页面使用 ADO 对象来抽取数据。让我们来讨论几种典型的情况,您在不久的将来移植和改编代码时可能会遇上这些情形。
如果您有从单个记录集生成报表的 ASP 页面,
DataReader 对象将是您最好的伙伴。
您浏览
DataReader 对象时,它会将结果输出到页面。
String strConn, strCmd;
strConn = "DATABASE=MyAgenda;SERVER=localhost;UID=sa;PWD=;";
strCmd = "Select * From Names where ID=" + contactID.Text;
SQLConnection oCN = new SQLConnection(strConn);
SQLCommand oCMD = new SQLCommand(strCmd, oCN);
oCN.Open();
SQLDataReader dr;
oCMD.Execute(out dr);
while (dr.Read())
{ // 使用 dr.GetString(index) 或
// dr["field name"] 的方法 Response.Write 来输出数据
}
您还可以用
HasMoreRows 属性快速检查
DataReader 是否为空。如果您只需要快速浏览一系列记录,没有比
DataReader 更好更快的对象了。它同样适用于查询单个记录。您不能编辑
DataReader 的内容,但您可以将其内容移入更易于管理的对象,例如
DataTable 或者一个或多个
DataRow 对象。
当您需要处理表和记录之间的复杂关系时,DataReader 就不再是合适的工具了。在 ADO 中, 最终您需要处理记录集。您的数据模型链接越多,SQL 命令就越复杂。导航模型仍然是顺序的,最后放入缓存的数据往往多于你所需要的。
DataSet 和
DataRelation 对象是这种表关系模型的基础。
为了管理父/子关系,ADO 还封装了数据形成引擎。从功能上讲,数据形成和 ADO.NET 关系是一样的。然而,从设计方面来看,它们几乎没有什么共同点。形成记录集将所有信息嵌入单个列表对象。ADO.NET 关系是您可以随时在两个数据表之间建立的动态链接。为了在执行单个 ADO 命令的过程中创建一个层次结构记录集,ADO 要依靠 Shaping OLE DB 服务提供程序,并且使用特定的类 SQL 语言。
在 ADO.NET 中,关系中涉及的每个对象总是被看成单独的个体。关系本身作为对象被公开,并且具有一定的行为规则。例如,
DataRelation 对象可以从父行到子行一层层进行更改。您可以通过将
ForeignKeyConstraint 对象添加到
DataTable 的
Constraints 集合中来进行此操作。
ForeignKeyConstraint 对象表示当删除或更新数值和行时,对通过外键关系相关联的一组列的约束。如前面提到的,一旦设置好了关系,在它按程序预设终止之前,您不能进行可能破坏该关系的更改。
另外,关系是不可传递的。您可以建立两组不同的关系,例如客户和订单、订单和产品之间的关系。然而,当在订单中导航以寻找某一位客户时,您不能从一个订单跳到与之相关的产品行。您必须另外打开订单/产品关系,定位到您需要的订单,然后才能获取相关的行。这就是为什么有时候最好不要通过原来的无格式 SQL JOIN 语句实现一对一关系的原因。
需要在 ASP Session 对象中存储记录吗?利用 ADO.NET 和
DataSet 对象,您可以相当安全的操作而不会导致在在 GIT 中存储 ADO 记录集可能会导致访问冲突(英文)中所讨论的问题,也不会有线程相似性的麻烦。
更新数据
更新数据时,Web 应用程序通常使用无格式 SQL 语句,或者使用更好的参数化存储过程。然而,当需要使用未连接的数据时,您可能想使用内置服务来更新所有需要修订的记录。ADO 提供了批更新机制来实现这个功能。
UpdateBatch 方法用于把保存在副本缓冲中的
Recordset 更改发送到服务器,以更新数据源。它采用开放式锁定,允许所有挂起的本地更改。它还在单个操作中把所有更改传送到数据源。仅当更改提交后数据源锁定要更改的记录时,才会出现开放式锁定。开放式锁定使两个用户可以同时访问同一个记录,但一个用户输入的更改很快会被另一用户所覆盖。当然,这种方式要求数据源能够检测和防止数据冲突。还要求整个数据源比较稳定,不会发生频繁的更改。否则,不难想象协调费用将很快超过替代严格锁定所带来的节约。事实上,使用
UpdateBatch 方法,在任何更改失败时都会返回一个错误。然后,您可以通过
Errors 集合和
Error 对象来访问该错误。
要理解 ADO.NET 模型为什么是更新数据的更强大的工具,理解 ADO 中开放式锁定的工作原理是非常关键的。在 ADO 代码中,您无法控制调用
UpdateBatch 之后所发生的一切。也就是说,更新是在服务器上通过滚动已更改的行,然后比较原始值和数据源中对应记录中的当前值来进行的。当所有的值都一致了,才对表执行适当的 SQL 语句(INSERT、UPDATE 或 DELETE)。
问题在于您不能控制实际应用于更改的 SQL 语句。服务器端的更新代码并不比您编写的代码好,如果您采用非 SQL 提供程序,它甚至无法运行。在本节的开头,我曾讲过 Web 应用程序通常通过参数化存储过程来更新数据。然而,如果您使用批更新就不同了。
在 ADO.NET 中,这个模型已经有所扩展。现在它采用更通用的架构,允许您自己指定基本操作命令,例如插入、删除、更新和选择等。其用意很明显:不论何种数据源,都可以从中抽取数据并提供同样的支持。在 ADO.NET 中进行批更新,您需要创建
DataSetCommand 对象即
SQLDataSetCommand 或
ADODataSetCommand。
注意:在 Beta 2 中,
DataSetCommand 对象将被称为
DataAdapter 对象。
拥有
DataSetCommand 对象之后,您便可以调用它的
Update 方法。
DataSetCommand 提供
InsertCommand、
DeleteCommand、
UpdateCommand 和
SelectCommand 等属性。它们都是
Command 对象。但是,除非默认行为无法满足需要,否则您不必设置它们。这与在 ADO 中一样。在
Update 过程中,如果没有设置任何 xxxCommand 属性,但是存在主键信息,将自动生成
Command 对象。请注意,要使上述过程正确进行,必须为所涉及的数据表设置主键。
以下代码显示了如何为 DataSet 的 EmployeesList 表设置主键:
DataColumn[] keys = new DataColumn[1];
keys[0] = m_oDS.Tables["EmployeesList"].Columns["EmployeeID"];
m_oDS.Tables["EmployeesList"].PrimaryKey = keys;
主键基本上是
DataColumn 对象的一个数组。
如果您要使用存储过程来更新表,或者采用专用非 SQL 数据提供程序,您会经常用到这些命令属性。
XML 扩展支持
在 ADO 中,XML 只不过是输入和输出格式。然而在 ADO.NET 中,XML 是一种数据格式,提供了操作、组织、共享和传递数据的手段。任何带入
DataSet 的数据,无论其来源,都能通过双面编程模型进行处理。您可以顺序交替访问信息,或者按行访问,也可以按照 XML 文档对象模型驱动的非顺序、层次结构路径进行访问。
DataSet 将数据和架构作为 XML 文档进行读写。数据和架构都可以通过 HTTP 传输,并且能在所有支持 XML 的平台上使用。相同的数据在不同的时候可以通过不同的架构来呈现,这是通过 XSLT 实现的。您可以使用
ReadXmlSchema 方法编写架构。XML 架构包括数据集中的表的说明,以及表的关系和约束。在调用
ReadXmlData 方法填充
DataSet 之前,应该先完成这个步骤。
以下代码示例是一个显示可更新数据表的最简单的 ASP.NET 页面。
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.IO" %>
<script runat="server" language="C#">
void Page_Load(Object source, EventArgs e)
{ DataSet data = new DataSet();
// 加载 XML 数据和架构
StreamReader sr;
sr = new StreamReader(Server.MapPath("data.xml"));
data.ReadXml(sr);
sr.Close();
// 添加通过 URL 传递的新记录
if (Request.QueryString.Count >0)
{
DataTable dt = data.Tables[0];
DataRow dr = dt.NewRow();
dr["FirstName"] = Request.QueryString["First"];
dr["LastName"] = Request.QueryString["Last"];
dt.Rows.Add(dr);
dt.AcceptChanges();
StreamWriter sw;
sw = new StreamWriter(Server.MapPath("data.xml"));
data.WriteXml(sw);
sw.Close();
}
// 刷新 UI(由网格组成)
grid.DataSource = data.Tables[0].DefaultView;
grid.DataBind();
}
</script>
如图 2 所示,您可以将新的行添加到表中。然而,它不涉及 SQL Server 或 Access 表。它只是一个 XML 文件,在处理它的代码中,没有使用 XML 节点或
XMLDOM 方法。您可以用相同的直观数据表接口来读取和更新 XML 记录。您的工作方式与在 ADO 中大致相同,但此处的模型更深入、更庞大,有更多的潜力供您去发掘。
/article/UploadPic/2006719105137498.gif
图 2:可更新表的示例总结
Web 应用程序的成功改变了典型分布式系统的面貌。现在大多数分布式系统都是
n 层系统,这类系统对扩展性和互操作性的要求越来越高。因此,非连接数据处理和 XML 成为最佳实践,并为业界广为接受。
ADO.NET 尝试将当今一些最好的实践统一在 .NET 下。这种用于数据访问的编程模型全面而又非常强大。但这个模型可能尚不能满足每一个人的要求,在将来的模型设计中还需要迈出一大步。然而,请记住现在 ADO.NET 还只是 Beta 版,只有有限的文档支持。
ADO 程序员从 Beta 版中获益最多,因为他们熟悉了 ADO.NET 的许多方面,包括最高层次的抽象即启发性模型。ADO.NET 代码与现有的 ADO 代码不兼容,但功能相似。要充分利用 ADO.NET,您应该花些功夫来理解概念本身,而不仅仅是找出移植代码的最快方式。无论您选择何种 .NET 编程模型,Windows 窗体、Web 窗体还是 Web 服务,ADO.NET 都会帮助您处理好数据访问的问题。
……