日期:2012-03-12  浏览次数:20602 次

导 读:.NET 在数据存取方面做了很大的调整。在.NET 框架下,数据存取是由ADO.NET来完成的,这是一个ADO的改进和完善版本。它最显著的变化是其完全基于XML。而对于从事ADO开发的人员来说,Recordset对象的消失也令他们感到惊奇。
--------------------------------------------------------------------------------

翻译整理:.net技术网(www.51dotnet.com)slash
原文出处:http://www.dnjonline.com/articles/essentials/iss22_essentials.html

表4显示了DataSet 中现有的数据。可以发现现在有两种数据类型,同时SCHEMA 也做了相应的调整来描述这两种数据类型。

请注意我们现在并没有做创建一个内连接或外连接,而是类似于用SHAPE 语言用两个单独的表创建了一个分级的Recordset对象。当然你也可以创建连接,这在DataSet中表现为一个表。

ADO开发者在操作Recordset 对象的时候,需要知道他们到底需要一个客户端还是服务器端的光标。MoveFirst 或是 AbsolutePosition之类的操作,在服务器端光标的情况下将消耗很大的服务器资源,但在客户端光标的情况下,确是高效和有力的工具。两类光标存在着巨大的差异。一个客户端光标的Recordset 对象事实上更类似于一个高性能的数组,而不是一一种序列化的存取结构。

与之相对,DataSet 始终是'客户端的',并且可以发挥'高性能数组'存取模型的最高效率。在Recordset 中有字段集合,但对于一个Recordset 对象,却没有相应的集合。而DataSet中的所有表都有一个列和一个行的集合,你可以使用简单的随机存取技术来操作它们,表5显示了在ADO.NET 中操作DataSet的对象模型。

通过循环的方式你可以对DataTable中的每一行进行操作,然而我在下一个例子中采用了另一种方法:DataTable 的 Select 方法。这是一个重载方法,从本质上来说,它相当于结合了Recordset的FILTER 和 SORT 属性。SELECT 方法返回一个以DataRow对象为元素的数组--能够利用标准的数组的方法对它处理。需要注意的是所有这些过程是在你程序的缓存中进行的,DataSet 已经和数据源完全的断开了。

下面的示例代码向DataSet中填充两个数据表(第二个表没有使用 WHERE 子句)然后用SELECT 方法从'Authors'返回一个数组,并利用该结果创建一个动态的下拉列表。

Dim dc As New ADODataSetCommand( _
"select au_id, au_fname," & _
" au_lname from authors", strConnect)
Dim ds As New DataSet()

' Declare an array of DataRows
Dim dr() As DataRow
Dim i As Integer

dc.FillDataSet(ds, "Authors")
dc = New ADODataSetCommand( _
"select * from titleauthor", strConnect)
dc.FillDataSet(ds, "Titles")

dr = ds.Tables("Authors").Select( _
"au_lname >= 'R'", "au_lname ASC")

For i = 0 To UBound(dr)
listbox1.Items.Add( _
CStr(dr(i)("au_fname")) & " " _
& CStr(dr(i)("au_lname")))
Next

在这里,SELECT 语句返回所有的行,其中的 last name 的打头字母在 'R'之前,并且对这些行进行了分类,'Titles'表在这里被忽略了

表之间的联系

如果你没有利用SHAPE LANGUAGE 进行过工作,你很可能只是创建一个拥有一个数据表的 DataSet 并对其进行操作,就象Recordset 对象一样。当你一旦向DataSet 中加入了多个表,你会希望在它们之间建立关联以便于操作。在下面的代码中,假定以与上例完全相同的方法创建了一个名为DS的DataSet 对象:

Dim dr() As DataRow
Dim drChildren() As DataRow
Dim dl As DataRelation
Dim i, j As Integer

dl = New DataRelation("AuthorTitles", _
ds.Tables("Authors").Columns("au_id"), _
ds.Tables("Titles").Columns("au_id"))
ds.Relations.Add(dl)

dr = ds.Tables("Authors").Select( _
"au_lname >= 'R'", "au_lname ASC")

For i = 0 To UBound(dr)
listbox1.Items.Add( _
CStr(dr(i)("au_fname")) & " " _
& CStr(dr(i)("au_lname")))
drChildren = dr(i).GetChildRows(dl)
For j = 0 To UBound(drChildren)
listbox1.Items.Add(" " & _
CStr(drChildren(j)("title_id")))
Next
Next

DataSetCommands


表 6:
使用list box显示两个表的一多关系

这段代码在'Authors' 表和 'Titles'表之间建立了一个父子关系的关联,这是通过创建一个DataRelation对象(命名为dl)并将它加入DataSet实现的。关联指定 au_id 为关键字段,通过对子表('Titles')中 au_id 的匹配来得到父表中每一行的子行。在ADO 数据筛选的SHAPE 语言中是,这是通过 RELATE 语句来实现的。

当你指定了父表中的行时,你可以利用这种关联。你可以通过GetChildRows方法得到所有子表中所有相关的行,当然这里的关联关系是由你来决定的。DataRelations 使得创建一个master-detail程序变的非常简单。上面的代码的显示结果见表6。

下面我们来了解一下ADODataSetCommand对象以及与它功能相似的SQLDataSetCommand对象。我们已经了解了它们三个主要功能中的一个,就是通过使用命令字符串和一个连接号向DataSet 对象中加入数据。下面对另外两个主要功能进行讨论,首先是更新(updating)。

在传统的ADO中,一个客户端的 Recordset 对象通过SQL 语句来进行更新。在这里SQL 模拟开放式锁定,因此更新得以被返回到数据库。这是一个灵活的机制,但有两个缺点:一、自动生成的SQL语句不易更改,因此假如你写一些高效率的存储过程,将会比直接使用SQL 语句迅速的多。二、这是第一个问题的延续。当需要更新的数据源无法理解ANSI-SQL的时候,你就无法使用客户端的Recordset了。象Active Directory, Exchange 2000以及 Indexing Services这些兼容ADO 的数据源,它们不兼容ANSI 的标准。因此你如果想通过ADO对它们进行更新,你就只能使用服务器端的光标了。

在ADO.NET 中这些问题被解决了。第一种方法,DataSet 与数据源完全断开,ADODataSetCommand作为一个独立的实