ADO.NET 2.0 中的新增 DataSet 功能

发布日期: 1/13/2005 | 更新日期: 1/13/2005

Jackie Goldstein
Renaissance Computer Systems

适用于:
Microsoft ADO.NET 2.0
Visual Basic 编程语言

摘要:了解有关 .NET Framework DataSet 类以及与它密切相关的类中的新增 ADO.NET 2.0 功能的知识。这些更改包括对 DataSet、DataTable 和 DataView 类的功能和性能增强。

下载与本文相关的 DataSetSamples.exe 示例代码。

*
本页内容
简介 简介
原始性能 原始性能
DataTable — 比以前更独立 DataTable — 比以前更独立
流到缓存,缓存到流 流到缓存,缓存到流
小结 小结

简介

在即将问世的 ADO.NET 版本(ADO.NET 2.0)中,有很多新增的和改进的功能,它们影响了很多不同的 .NET Framework 类和应用程序开发方案。本文讨论对核心断开模式 ADO.NET Framework 类 — DataSet 和关联的类(例如,DataSetDataTable DataView)的更改和增强。

本文实际上是有关 ADO.NET 2.0 中的 DataSet 和关联类的两篇文章中的第一篇。这里,我们将重点讨论 .NET Framework 中的类。在随后的文章中,我们将重点讨论在 Visual Studio 2005 开发环境中通过上述类和相关的类进行开发。Visual Studio 2005 提供了多个设计器和工具,它们为开发应用程序中以数据为中心的方面提供了极大的灵活性和生产率。因此,每篇文章都将给予您不同的“感受”。本文主要概述新功能,并伴以解释和代码示例。在下一篇文章中,随着我们了解如何开发有效的应用程序,将重点讨论开发过程。

正如我在前面提到的那样,本文只讨论 ADO.NET 2.0 的一小部分新功能。您可以在 ADO.NET 2.0 Feature Matrix 中找到其他一些功能的概述。下列文章中包含有关这里提到的一些主题的详细信息:

Asynchronous Command Execution in ADO.NET 2.0

Generic Coding with the ADO.NET 2.0 Base Classes and Factories

Schemas in ADO.NET 2.0

除非另行说明,否则本文的内容都是基于 Visual Studio 2005 的 Beta 1 版。代码示例使用 SQL Server 2000 随附的示例数据库 — Northwind 数据库。

返回页首返回页首

原始性能

软件开发人员总是很关心性能。有时他们会过分关心性能,并使他们的代码尽量简洁以减少一点儿执行时间,而实际上这样做根本没有什么意义 — 不过这是另一篇文章所要讨论的主题了。在涉及 ADO.NET 1.x DataSet(特别是那些包含大量数据的数据集)时,开发人员所表达的性能方面的担忧是非常正当的。大型 DataSet 的处理速度很慢 — 这体现在两个不同的上下文中。第一次感受到缓慢的速度是在加载带有大量行的 DataSet(实际上是 DataTable)时。随着 DataTable 中行数的增加,加载一个新行的时间几乎按照与 DataTable 中的行数成正比的速度增加。另一个能够感受到性能影响的时候是在序列化和远程处理大型 DataSet 时。DataSet 的一项关键功能是它能够自动了解如何序列化自身,尤其是当我们希望在应用程序层之间传递它的时候。但是,通过仔细观察可以发现,这一序列化过程很罗嗦,它需要消耗大量内存和网络带宽。上述两个性能瓶颈都在 ADO.NET 2.0 中得到了解决。

新的索引引擎

在 ADO.NET 2.0 中已经彻底重新编写了用于 DataTable 的索引引擎,并且使其能够更好地针对大型数据集进行伸缩。这会使基本的插入、更新和删除操作变得更加快速,从而使 FillMerge 操作变得更快。尽管基准和性能收益量化总是特定于应用程序,并且通常是一件有风险的事情,但上述改进无疑在加载带有一百万行的 DataTable 时提供了高于数量级的改进。但不要轻易相信我的话,请通过下面的简单示例亲自对此进行检验。请添加以下代码作为 Windows 窗体中按钮的单击事件处理程序:

Private Sub LoadButton_Click(ByVal sender As System.Object, 
ByVal e As System.EventArgs) Handles LoadButton.ClickDim ds As New DataSetDim time1 As New DateDim i As IntegerDim dr As DataRowds.Tables.Add("BigTable")ds.Tables(0).Columns.Add("ID", Type.GetType("System.Int32"))ds.Tables(0).Columns("ID").Unique = Trueds.Tables(0).Columns.Add("Value", Type.GetType("System.Int32"))' Show status labelWaitLabel.Visible = TrueMe.Cursor = Cursors.WaitCursorMe.Refresh()' catch start timetime1 = DateTime.Now()' Yes, we are loading a million rows to a DataTable!'' If you compile/run this with ADO.NET 1.1, you have time ' to make and enjoy a fresh pot of coffee...Dim rand As New RandomDim value As IntegerFor i = 1 To 1000000Tryvalue = rand.Nextdr = ds.Tables(0).NewRow()dr("ID") = valuedr("Value") = valueds.Tables(0).Rows.Add(dr)Catch ex As Exception' if there are any duplicate values, an exception' will be thrown since the ID column was specified' to be uniqueEnd TryNext' reset cursor and labelWaitLabel.Visible = FalseMe.Cursor = Me.DefaultCursor' Show elapsed time, in secondsMessageBox.Show("Elapsed Time: " & _
DateDiff(DateInterval.Second, time1, DateTime.Now))' verify number of rows in the table' This number will probably be less that the number' of loop iterations, since if the same random number' comes up, it will/can not be added to the tableMessageBox.Show("count = " & ds.Tables(0).Rows.Count)End Sub

当我通过 ADO.NET 1.1 和 Visual Studio 2003 在我的环境中运行上述代码时,执行时间大约为 30 分钟。使用 ADO.NET 2.0 和 Visual Studio 2005 时,执行时间大约为 40 到 50 !当我将行数减少到只有五十万时,1.1 版大约花费了 45 秒,而 2.0 版大约花费了 20 秒。您的数字可能有所不同,但我认为其含义是很清楚的。

实际上,该示例非常简单,因为它只包含一个针对唯一列的索引。但是,随着指定 DataTable 上的索引数的增加(例如,通过添加额外的 DataViewUniqueKeyForeignKey),性能差异将变得如此巨大。

示例代码中的 ID 值是通过随机数字生成器生成的,而不是仅仅使用循环计数器作为 ID,其原因是为了更好地表示现实世界中的方案。在实际的应用程序中,访问 DataTable 的元素以便插入、更新和删除的操作很少顺序完成。对于每个操作,必须首先找到由唯一键指定的行。在插入和删除行时,必须更新表的索引。如果我们只是将带有顺序键值的一百万行加载到一个空表中,那么结果会非常快,但是却会令人误解。

二进制序列化选择

在加载带有大量数据的 DataTable 方面的重大性能改进不要求我们对现有的 ADO.NET 1.x 代码进行任何更改。为了在序列化 DataSet 时从改进的性能中受益,我们的工作需要更加辛苦一些 — 需要添加一行代码以设置新的 RemotingFormat 属性。

在 ADO.NET 1.x 中,DataSet 序列化为 XML(甚至在使用二进制格式化程序时也是如此)。在 ADO.NET 2.0 中,除了该行为以外,我们还可以通过将 RemotingFormat 属性设置为 SerializationFormat.Binary 而不是(默认的)SerializationFormat.XML,来指定真正的二进制序列化。让我们观察一下这两个不同选择所产生的不同输出。

为了保持向后兼容性(ADO.NET 团队总是关注这一点),XML 序列化的默认值将为我们提供与 ADO.NET 1.x 中相同的行为。通过运行下面的代码,可以看到该序列化的结果:

Private Sub XMLButton_Click(ByVal sender As System.Object, 
ByVal e As System.EventArgs) Handles XMLButton.ClickDim ds As New DataSetDim da As New SqlDataAdapter("select * from [order details]", _GetConnectionString())da.Fill(ds)Dim bf As New BinaryFormatterDim fs As New FileStream("..\xml.txt", FileMode.CreateNew)bf.Serialize(fs, ds)
End Sub
Private Function GetConnectionString() As String' To avoid hard-coding the connection string in your code, ' use the application settingsReturn MySettings.Value.NorthwindConnectionEnd Function

请注意,上述代码显式使用了 BinaryFormatter 类,而文件 xml.txt 中的输出(如图 1 所示)显然是 XML。而且,在这种情况下,该文件的大小为 388 KB。

datasetenhance_01

现在,让我们通过添加行

ds.RemotingFormat = SerializationFormat.Binary

将序列化格式更改为二进制,并且通过在 FileStream 构造函数中修改文件名将数据保存到另一个文件中,现在代码将如下所示:

Private Sub BinaryButton_Click(ByVal sender As System.Object, 
ByVal e As System.EventArgs) Handles BinaryButton.ClickDim ds As New DataSetDim da As New SqlDataAdapter("select * from [order details]", _
GetConnectionString())da.Fill(ds)Dim bf As New BinaryFormatterDim fs As New FileStream("..\binary.txt", FileMode.CreateNew)ds.RemotingFormat = SerializationFormat.Binarybf.Serialize(fs, ds)
End Sub

文件 binary.txt 中的输出显示在图 2 中。在这里,我们看到它现在实际上是二进制数据,人们很难理解这些数据。此外,该文件的大小只有 59 KB — 同样,在需要传输的数据量以及处理该数据所需的 CPU、内存和带宽资源方面降低了一个数量级。应当指出的是,这一改进在使用远程处理时有重大意义,但在使用 Web 服务时没有意义,这是因为 Web 服务按照定义必须传递 XML。这意味着,只能在通信两端都基于 .NET 并且不是与非 .NET 平台进行通信时,才能利用该增强功能。

datasetenhance_02

有关 DataSet 序列化过程的详细信息,请参阅 Binary Serialization of DataSets。

返回页首返回页首

DataTable — 比以前更独立

在讨论 ADO.NET 1.x 和它的断开数据访问对象模型时,主要的对象是 DataSet。当然,它还包含其他对象,如 DataTableDataRelationDataRow 等,但是人们所关心的对象通常从 DataSet 开始并以它为中心。的确,大多数 .NET 开发人员都知道 DataTable 本身(没有封装在 DataSet 内部)极为有用,并会利用这一事实。但是,在某些情况下,我们无法通过 DataTable 完成我们希望完成的工作,除非我们首先获得它并将其强行转换为 DataSet。这方面的最突出并且通常令人痛苦的示例是在 DataTable 中读取和写入(加载和保存)XML 数据。在 ADO.NET 1.x 中,我们必须首先将 DataTable 添加到 DataSet 中,只有这样我们才能读取或写入 XML,这是因为完成该工作的方法只能在 DataSet 上使用!

ADO.NET 2.0 的目标之一是使独立的 DataTable 类比在 ADO.NET 1.x 中更为实用和有用。DataTable 现在支持用于 XML 的基本方法,就像 DataSet 一样。这包括下列方法:

ReadXML

ReadXMLSchema

WriteXML

WriteXMLSchema

DataTable 可单独序列化,并且可以在 Web 服务和远程处理方案中使用。现在,除了支持 Merge 方法以外,独立的 DataTable 还支持添加到 DataSet 中的新增 ADO.NET 2.0 功能:

RemotingFormat 属性(先前讨论过)

Load 方法(本文随后将讨论)

GetDataReader 方法(本文随后将讨论)

对于 XML 的主题,值得说明的是,在 ADO.NET 2.0 中,有大量增强的 XML 支持 — Microsoft 喜欢称之为更好的“XML 保真度”(XML Filelity)。它采取的形式是对 SQL Server 2005 XML 数据类型的支持、扩展 XSD 架构支持、改进的 XSD 架构推理引擎,以及两个通常很讨厌的限制的消除:(i) DataSet 和 DataTable 类现在可以处理多个嵌入式架构,并且 (ii) DataSet 现在完全支持命名空间,以便 DataSet 可以包含多个具有相同名称、但来自不同命名空间的 DataTable,也就是说,表具有相同的非限定名称,但具有不同的限定名称。而且,多个关系中包含的具有相同名称和命名空间的子表可以嵌套在多个父表中。

返回页首返回页首

流到缓存,缓存到流

对于 ADO.NET 2.0 中的 DataSetDataTable 类的另一个主要增强是,提供了用来消耗 DataReader(将数据加载到 DataTable 中)以及在 DataTable 的内容之上公开 DataReader 的机制。

有时,我们具有(或收到)DataReader 形式的数据,但实际上是希望具有缓存 DataTable 形式的数据。通过新增的 Load 方法,我们可以获得现有的 DataReader,并使用它的内容来填充 DataTable

有时,我们具有(或收到)缓存形式的数据 (DataTable),并且需要通过 DataReader 类型接口来访问它。通过新增的 GetTableReader 方法,我们可以获得现有的 DataTable,并通过 DataReader 接口和语义来访问它。

在下面的部分中,我们将考察一下这些新方法。

Load 方法 — 基本用法

Load 方法是已经添加到 ADO.NET 2.0 的 DataSetDataTable 中的一个新方法。它用 DataReader 对象的内容加载 DataTable。如果 DataReader 包含多个结果集,则它实际上可以一次加载多个表。

Load 方法的基本用法非常简单:

MyDataTable.Load (MyDataReader)

下面的示例代码较为完整地说明了它的用法:

Private Sub LoadButton_Click(ByVal sender As System.Object, 
ByVal e As System.EventArgs) Handles LoadButton.ClickTryUsing connection As New SqlConnection(GetConnectionString())Using command As New SqlCommand("SELECT * from customers", connection)connection.Open()Using dr As SqlDataReader = command.ExecuteReader()'Fill table with data from DataReaderDim dt As New DataTabledt.Load(dr, LoadOption.OverwriteRow)' Display the dataDataGridView1.DataSource = dtEnd UsingEnd UsingEnd UsingCatch ex As SqlExceptionMessageBox.Show(ex.Message)Catch ex As InvalidOperationExceptionMessageBox.Show(ex.Message)Catch ex As Exception' You might want to pass these errors' back out to the caller.MessageBox.Show(ex.Message)End TryEnd Sub

上述代码初始化连接和命令对象,然后执行 ExecuteReader 方法以便从数据库中获取数据。查询的结果作为 DataReader 提供,它随后被传递给 DataTableLoad 方法,以便用返回的数据填充它。用数据填充 DataTable 之后,就可以在 DataGridView 中绑定和显示它了。下一部分将解释(可选的)LoadOption 参数的 OverwriteRow 加载选项的重要性。

Load 方法 — 为什么要加载该数据?

如果您通过 DataSet/DataTableDataAdapter 所做的所有工作就是用数据源中的数据填充 DataSet,修改该数据,然后在随后的某个时刻将该数据推送到数据源中,则这些工作会非常平稳地进行。如果您要利用开放式并发并且检测到并发冲突(其他某个人已经更改了您要尝试更改的某一行),则会发生第一个问题。在这种情况下,为了解决冲突而通常需要完成的工作是将 DataSet 与数据源重新进行同步,以便这些行的原始值与当前数据库值相匹配。这可以通过将 DataTable 与新值合并到原始表中来完成(在 ADO.NET 1.x 中,合并方法仅在 DataSet 上可用):

OriginalTable.Merge(NewTable, True)

通过匹配带有相同主键的行,可以将新表中的记录与原始表中的记录合并。这里,具有关键意义的是第二个参数 — PreserveChanges。该参数指定合并操作只应当更新每个行的原始值,而不应当影响这些行的当前值。这使开发人员随后可以执行 DataAdapter.Update,它现在将成功地用更改(当前值)更新数据源,这是因为原始值现在与当前数据源值相匹配。如果 PreserveChanges 保留它的默认值 false,则合并操作会重写原始 DataTable 中的行的原始值和当前值,并且所作的所有更改都将丢失。

但是,有时我们希望更新数据源中的数据,在数据源中,新值不是通过以编程方式修改值而得到的。或者我们从其他数据库或 XML 源获得更新的值。在这种情况下,我们希望更新 DataTable 中的行的当前值,但是不希望影响这些行的原始值。在 ADO.NET 1.x 中没有提供实现这一点的简单方式。正是因为这个原因,ADO.NET 2.0 Load 方法接受参数 LoadOption,该参数指示如何将传入的新行与 DataTable 中已经存在的相同(主键)行组合在一起。

LoadOption 使我们可以显式指定我们在加载数据时的意图(同步或聚合),以及我们因此希望如何合并新行和现有行。图 3概括了各种方案:

datasetenhance_03

其中:

主数据源DataTable/DataSet 只通过一个主数据源进行同步/更新。它将跟踪更改以便可以与主数据源同步。

辅助数据源DataTable/DataSet 从一个或多个辅助数据源接受增量数据馈送。它不负责跟踪更改以便与辅助数据源同步。

图 3 中显示的三种情况可以总结如下:

情况 1根据主数据源初始化 DataTable。用户希望用来自主数据源的值初始化空的 DataTable(原始值和当前值),然后,在对该数据进行更改之后,将更改传回主数据源。

情况 2保留更改并且根据主数据源重新同步。用户希望获得修改后的 DataTable,并且在保持所作更改(当前值)的同时,将它的内容(仅限于原始值)与主数据源重新同步。

情况 3聚合来自一个或多个辅助数据源的增量数据馈送。用户希望接受来自一个或多个辅助数据源的更改(当前值),然后将这些更改传回到主数据源。

LoadOption 枚举具有三个值,分别代表以下三种情况:

OverwriteRow — 用传入的行的值更新该行的当前版本和原始版本。

PreserveCurrentValues默认)— 用传入的行的值更新该行的原始版本。

UpdateCurrentValues — 用传入的行的值更新该行的当前版本。

这些名称可能会在 Beta 1 之后更改。

下面的表 1 总结了加载语义。如果传入的行和现有行就主键值达成协议,则使用该行的现有 DataRowState 来处理它,否则使用“Not Present”部分(该表的最后一行)中的内容来处理。

表 1. 加载语义摘要
现有的 DataRow 状态UpdateCurrentValuesOverwriteRowPreserveCurrentValues(默认)

Added

Current = <Incoming>

Original = - --

State = <Added>

Current = <Incoming>

Original = <Incoming>

State = <Unchanged>

Current = <Existing>

Original = <Incoming>

State = <Modified>

Modified

Current = <Incoming>

Original = <Existing>

State = <Modified>

Current = <Incoming>

Original = <Incoming>

State = <Unchanged>

Current = <Existing>

Original = <Incoming>

State = <Modified>

Deleted

(Undo Delete) 和

Current = <Incoming>

Original = <Existing>

State = < Modified >

(Undo Delete) 和

Current = <Incoming>

Original = <Incoming>

State = <Unchanged>

Current = <Existing>

Original = <Incoming>

State = <Deleted>

Unchanged

Current = <Incoming>

Original = <Existing>

如果新值与现有值相同,则

State = <Unchanged>

Else

State = <Modified>

Current = <Incoming>

Original = <Incoming>

State = <Unchanged>

Current = <Incoming>

Original = <Incoming>

State = <Unchanged>

Not Present

Current = <Incoming>

Original = ---

State = < Added >

Current = <Incoming>

Original = <Incoming>

State = <Unchanged>

Current = <Incoming>

Original = <Incoming>

State = <Unchanged>

示例

为了说明表 1 中指定的行为,我提供了一个简单示例。

假设现有的 DataRow 和传入的行都具有 2 个带有匹配名称的列。第一列是主键,第二列包含一个数值。下面的表显示了数据行中第二列的内容。

表 2 表示行在调用 Load 之前处于所有 4 种状态时的内容。传入的行的第二列值为 3。表 3 显示了它在加载后的内容。

表 2. 加载之前的行状态
现有的行状态版本已添加已修改已删除未更改

当前

2

2

-

4

原始

-

4

4

4

传入的行
传入的行

3

表 3. 加载之后的行状态
UpdateCurrentValuesOverwriteRowPreserveCurrentValues

Added

Current = <3>

Original = ---

State = <Added>

Current = <3>

Original = <3>

State = <Unchanged>

Current = <2>

Original = <3>

State = <Changed>

Modified

Current = <3>

Original = <4>

State = <Modified>

Current = <3>

Original = <3>

State = <Unchanged>

Current = <2>

Original = <3>

State = <Changed>

Deleted

Current = <3>

Original = <4>

State = <Modified>

Current = <3>

Original = <3>

State = <Unchanged>

Current = <2>

Original = <3>

State = <Changed>

Unchanged

Current = <3>

Original = <4>

State = <Modified>

Current = <3>

Original = <3>

State = <Unchanged>

Current = <3>

Original = <3>

State = <Unchanged>

Not Present

Current = <3>

Original = ---

State = <Added>

Current = <3>

Original = <3>

State = <Unchanged>

Current = <3>

Original = <3>

State = <Unchanged>

您可以看到此概念的萌芽已经存在于 ADO.NET 1.x 之中了。在将数据加载到 DataTable 中时,DataAdapter 的 Fill 方法的默认行为是将所有行标记为“未更改”(这可以通过将 AcceptChangesOnFill 属性设置为 False 来重写)。但是,在使用 ReadXML 将数据加载到 DataSet 中时,行被标记为“已添加”。这一机制(它是基于客户反馈实现的)的基本原理是:这将允许将新数据从 XML 源加载到 DataSet 中,然后使用关联的 DataAdapter 来更新主数据源。如果行在从 ReadXML 加载时被标记为“未更改”,则 DataAdapter.Update 不会检测到任何更改,并且不会针对数据源执行任何命令。

为了提供类似的功能,已经将 FillLoadOptions 属性添加到 DataAdapter 中,以便提供与这里描述的 Load 方法相同的语义和行为,同时仍然保留 Fill 方法的相同(默认情况下)现有行为。

开发人员总是针对 ADO.NET 1.x 询问的另一个功能(它并不存在)是手动修改 DataRow 状态的能力。尽管 Load 方法提供的选项可以满足大多数情况的需要,但您仍然可能希望对行状态进行较细粒度的控制 — 您可能需要修改单个行的状态。有鉴于此,ADO.NET 2.0 在 DataRow 类中引入了两个新方法:SetAddedSetModified。在您询问有关将状态设置为 DeletedUnchanged 的问题之前,让我提醒您一下,在版本 1.x 中,我们已经具有了能够完成该工作的 DeleteAcceptChanges/RejectChanges 方法。

GetTableReader 方法

GetTableReader 方法是已经添加到 ADO.NET 2.0 的 DataSetDataTable 中的一个新方法。它将 DataTable 的内容作为 DataTableReader(派生自 DBDataReader)对象返回。如果在包含多个表的 DataSet 上调用该方法,则 DataReader 将包含多个结果集。

The use of the GetTableReader method is quite straight-forward:Dim dtr As DataTableReader = ds.Tables(0).GetDataReader

DataTableReader 的工作方式非常类似于您使用过的其他数据读取器,例如,SqlDataReader OleDbDataReader。但是,区别在于 DataTableReader 提供了对断开连接的 DataTable 的行的迭代,而不是从活动数据库连接流式传输数据。

DataTableReader 提供了智能且稳定的迭代器。缓存的数据可以在 DataTableReader 处于活动状态时进行修改,而读取器可以自动适当地维护它的位置 — 即使在迭代时有一个或多个行被删除或插入。

通过对 DataTable 调用 GetDataReader 而创建的 DataTableReader 所包含的结果集具有与创建它时所依据的 DataTable 相同的数据。该结果集只包含每个 DataRow 的当前列值,而被标记为删除的行将被跳过。通过对包含多个表的 DataSet 调用 GetDataReader 而创建的 DataTableReader 将包含多个结果集。该结果集将具有与 DataSet 对象的 DataTableCollection 中的 DataTable 对象相同的顺序。

除了上面概述的功能以外,GetDataReader 方法的另一个美妙用途是将数据从一个 DataTable 快速复制到另一个 DataTable 中:

Dim dt2 as new DataTable
dt2.Load(ds.Tables(0).GetDataReader) 

DataView.ToTable 方法

与上述方法有点关系(因为它为现有数据提供了新的 DataTable 缓存)并且值得一提的另一个新方法是 DataView 类的 ToTable 方法。作为提示,DataView 类提供了 DataTable 中的行的逻辑视图。该视图可以按行、行状态进行筛选,并且可以排序。但是,在 ADO.NET 1.1 中,不存在保存或传递该视图的行的简单方式,这是因为 DataView 没有它自己的行副本 — 它只是按照筛选器和排序参数的指示来访问基础 DataTable 的行。DataViewToTable 方法可以返回实际的 DataTable 对象(该对象是用当前视图所公开的行填充的)。

ToTable 方法的重载版本提供了用于指定要在所创建的表中包含的列的列表的选项。生成的表将按照指定的顺序(可能不同于原始的表/视图)包含列出的列。ADO.NET 1.x 中缺少这种限制视图中的列数量的功能,这一点已经使很多 .NET 程序员感到失望。您还可以指定所创建的表的名称,并指定它是应当包含所有行还是只包含独特的行。

下面是一些示例代码,它说明了如何使用 ToTable 方法:

   Private Sub ToTableButton_Click(ByVal sender As System.Object, 
ByVal e As System.EventArgs) Handles ToTableButton.Click' Show only 2 columns in second gridDim columns As String() = {"CustomerID", "ContactName"}Dim dt As DataTable = _
ds.Tables("customers").DefaultView.ToTable( _
"SmallCustomers", False, columns)DataGridView2.DataSource = dt
End Sub

假定 DataSet 中的“customers”表的内容显示在第一个网格中,则该例程会显示刚刚创建的、只包含那些由 DefaultView(由它的筛选器参数所指定)公开的行的 DataTable。新表中的行只包含原始 DataTableDataView 的两个列。图 4 显示了这方面的一个示例。

datasetenhance_04
返回页首返回页首

小结

DataSet(和 DataTable)的 ADO.Net 2.0 版本引入了大量新增功能以及对现有功能的增强。本文所讨论的主要功能包括:由于新的索引引擎和二进制序列化格式选项而显著改进的性能、可用于独立 DataTable 的大量功能,以及用于将缓存数据公开为流 (DataReader) 和将流数据加载到 DataTable 缓存的机制。ADO.NET 2.0 还提供了对 DataTable 中行状态的更强控制,以便更好地满足更多实际情况的需要。

感谢 Microsoft 的 Kawarjit S. Bedi、Pablo Castro、Alan Griver、Steve Lasker 和 Paul Yuknewicz 帮助我准备本文。

Jackie Goldstein 是 Renaissance Computer Systems 的负责人,该公司专门从事咨询、培训以及使用 Microsoft 工具和技术进行开发。Jackie 是 Microsoft 地区主管、Israel VB User Group 的创始人以及国际开发人员活动(包括 TechEd、VSLive!、Developer Days 和 Microsoft PDC)的主要演讲人。它还是 Database Access with Visual Basic .NET (Addison-Wesley, ISBN 0-67232-3435) 一书的作者以及 INETA Speakers Bureau 的成员。在 2003 年 12 月,Microsoft 将 Jackie 指定为 .NET 软件传奇人物!

转到原英文页面

转载于:https://www.cnblogs.com/login/archive/2005/01/26/97397.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/301138.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为WPF播放GIF伤神不?

为WPF播放GIF伤神不&#xff1f;WpfAnimatedGif仓库地址&#xff1a;https://github.com/XamlAnimatedGif/WpfAnimatedGifNuget 包&#xff1a;WpfAnimatedGif[1]。今天介绍一个用于在 WPF 中显示动态 GIF 图片的库&#xff0c;可在 XAML 或代码中使用&#xff1a;WpfAnimatedG…

每日一笑 | 最真实的商业模式

全世界只有3.14 % 的人关注了数据与算法之美&#xff08;图源网络&#xff0c;侵权删&#xff09;

java执行更新sql_sql server执行更新需要更多时间

我有两个表(UserTable和UserProfile)和结构&#xff1a;create table userTable(id_user int identity(1,1) primary key ,Name varchar(300) not null ,Email varchar(500) not null ,PasswordUser varchar(700) not null,userType int ,constraint usertype_fk foreign key(u…

昨天订了一台FSC Lifebook S6220

准备出差用 转载于:https://www.cnblogs.com/rexhost/archive/2005/03/24/124683.html

如何绕过 TPM 2.0 安装 Windows 11 操作系统?

方法一&#xff1a;删除 appraiserres.dll 文件1.下载 Windows 11 原版系统 ISO 镜像文件并解压到单独文件夹。&#xff08;一条不成熟的建议&#xff1a;现在请直接拔掉网线或关闭 WiFi&#xff09;2.打开已解压的文件&#xff0c;点击【source】文件夹。3.选择【appraiserres…

《悦趣式连锁反应》玩转STEM教育!529块积木元件,N+1款炫酷模型

▲数据汪特别推荐点击上图进入玩酷屋之前推荐的“小小机械师”成了孩子最受欢迎的玩具&#xff0c;玩了的孩子几乎没有不喜欢的。还有家长买多套送给朋友的孩子作为生日礼物。有家长来问&#xff0c;还有没有这种类型的新产品。和厂家咨询后&#xff0c;小木找到了一款“小小机…

域名的MX设置及校验方法

国内私募机构九鼎控股打造APP&#xff0c;来就送 20元现金领取地址&#xff1a;http://jdb.jiudingcapital.com/phone.html内部邀请码&#xff1a;C8E245J &#xff08;不写邀请码&#xff0c;没有现金送&#xff09;国内私募机构九鼎控股打造&#xff0c;九鼎投资是在全国股份…

昨天去驾校桩考

我通过了&#xff0c;当然。 封闭的电子考场&#xff0c;在场外待考的人们不惜屈尊偷看场内的“考题”&#xff0c;不过想来也没有什么看的&#xff0c;不还是平常一样的正反手进出库和移库嘛。 8:30正式开考之前&#xff0c;可以买票&#xffe5;10练习一次&#xff0c;有一位…

java前补零工具类_java生成编码工具类,不足补0

~~~~~ 小小工具类&#xff01;你值得拥有简单粗暴&#xff0c;直接上代码import java.text.NumberFormat;/*** author: Abner* description: 编码工具类* date: Created on 2018/5/24*/public class SnUtils {/*** 生成 0000000000001 格式* param value 传入的数值* param min…

掌握神经网络,入门深度学习

从无人驾驶汽车到AlphaGo战胜人类&#xff0c;机器学习成为了当下最热门的技术。而机器学习中一种重要的方法就是深度学习。人工智能、机器学习与深度学习的关系深度学习的动机在于建立、模拟人脑进行分析学习的神经网络&#xff0c;整个过程就是使用多个处理层对数据进行高层抽…

[旧博客]Python 第一次

决定学习Python&#xff0c;发现其需要安装的东西很小&#xff0c;只需要在官方网站下载和15MB左右的安装包&#xff0c;Python for windows。安装完毕就双击IDE快捷方式就打开IDE了。 你很发现IDE好像很面熟&#xff0c;对啊&#xff0c;Python原生的IDE就和一个windows笔记本…

人造流星这种生日礼物,你有过吗?现在国外有了

全世界只有3.14 % 的人关注了数据与算法之美数据汪列举了不同“级别”的富豪是如何庆生的&#xff0c;大家看看自己处于什么水平。三流土豪的孩子过生日&#xff0c;看的是蜡烛...二流土豪的孩子过生日&#xff0c;看的是烟花...那么一流土豪的孩子看的又是什么呢&#xff1f;现…

Concurrent connection limit

这几天在做IIS 6上Web Service (WSE 2.0)的性能测试。在这个过程中陆续发现和解决了一些问题。 其中有一个问题比较有意思。我和项目组的同事发现&#xff0c;不论我们用C#写的模拟客户端用多少并发量来连接Web Service&#xff0c;服务器端监测到的并发连接数&#xff08;性能…

用啥Selenium?! .NET程序员就用自家的Playwright for .NET

提到用于Web应用程序自动化测试的工具&#xff0c;大家肯定第一个想到的就是Selenium。可以说&#xff0c;Selenium已经成为以编程方式自动化浏览器的事实标准。但是&#xff0c;Selenium作为老牌工具&#xff0c;也存在一些缺点&#xff0c;比如不支持Shadow DOM &#xff0c;…

每日一笑 | 一些关于集合的知识

全世界只有3.14 % 的人关注了数据与算法之美&#xff08;图源网络&#xff0c;侵权删&#xff09;

java调用js查询mongo_mongodb操作之使用javaScript实现多表关联查询

一、数据控制mongodb操作数据量控制&#xff0c;千万控制好&#xff0c;不要因为操作的数据量过多而导致失败。演示一下发生此类错误的错误提示&#xff1a;二、多表关联查询实现/*声明变量bridge,用来记录两个集合所连接的桥梁。相当于sql语句中的Join on语句&#xff0c;on后…

ABP Framework 研习社经验总结(6.28-7.2)

ABP Framework 研习社经验总结&#xff08;6.28-7.2&#xff09;研习社初衷在翻译 《实现领域驱动设计》—— 基于 ABP Framework 实现领域驱动设计实用指南 时&#xff0c;因为DDD理论和实践的宽泛性&#xff0c;不同公司、不同行业、不同项目实现程度不同&#xff0c;觉得有必…

一篇万字长文读懂微软PDB、SourceLink——.net core之nuget 包调试

序言在大前年&#xff0c;为了说服框架组采用Nuget包的形式分发框架类库&#xff0c;我费了老鼻子的劲也没有取得成功&#xff0c;其中最致命的一个问题是&#xff0c;nuget包不能获得源码调试级的支持&#xff0c;在分发和包的管理形式上其比其他方案都优秀。最后折中的选择是…

放弃winform的窗体吧,改用html作界面,桌面应用程序UI的新的开发方式。

做过很多winform项目&#xff0c;都为winform控件头疼不已。想实现一些漂亮的样子总是很难。我这里列举几个缺点&#xff1a; 1.winform控件大多是 绝对布局 &#xff0c;你需要给出准确的坐标。那么在实现居中效果就会很难。 2.学习成本&#xff0c;也了解各个控件的结构&…

数学建模必备算法模型,全新升级!

转眼间2019年已经过去了四分之一&#xff0c;近日&#xff0c;2019年数学建模国赛的时间也已经出来啦&#xff0c;确定为9月12日&#xff08;周四&#xff09;18时至9月15日&#xff08;周日&#xff09;20时。随着各种各样的数模比赛源源不断地开展&#xff0c;时不时有小伙伴…