ADO.NET 2.0 中的新增 DataSet 功能
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 — 比以前更獨立 | |
| 流到緩存,緩存到流 | |
| 小結 |
簡介
在即將問世的 ADO.NET 版本(ADO.NET 2.0)中,有很多新增的和改進的功能,它們影響了很多不同的 .NET Framework 類和應用程序開發方案。本文討論對核心斷開模式 ADO.NET Framework 類 — DataSet 和關聯的類(例如,DataSet、DataTable 和 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 的索引引擎,并且使其能夠更好地針對大型數據集進行伸縮。這會使基本的插入、更新和刪除操作變得更加快速,從而使 Fill 和 Merge 操作變得更快。盡管基準和性能收益量化總是特定于應用程序,并且通常是一件有風險的事情,但上述改進無疑在加載帶有一百萬行的 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 上的索引數的增加(例如,通過添加額外的 DataView、UniqueKey 和 ForeignKey),性能差異將變得如此巨大。
注 示例代碼中的 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。
現在,讓我們通過添加行
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 平臺進行通信時,才能利用該增強功能。
有關 DataSet 序列化過程的詳細信息,請參閱 Binary Serialization of DataSets。
返回頁首DataTable — 比以前更獨立
在討論 ADO.NET 1.x 和它的斷開數據訪問對象模型時,主要的對象是 DataSet。當然,它還包含其他對象,如 DataTable、DataRelation、DataRow 等,但是人們所關心的對象通常從 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 中的 DataSet 和 DataTable 類的另一個主要增強是,提供了用來消耗 DataReader(將數據加載到 DataTable 中)以及在 DataTable 的內容之上公開 DataReader 的機制。
有時,我們具有(或收到)DataReader 形式的數據,但實際上是希望具有緩存 DataTable 形式的數據。通過新增的 Load 方法,我們可以獲得現有的 DataReader,并使用它的內容來填充 DataTable。
有時,我們具有(或收到)緩存形式的數據 (DataTable),并且需要通過 DataReader 類型接口來訪問它。通過新增的 GetTableReader 方法,我們可以獲得現有的 DataTable,并通過 DataReader 接口和語義來訪問它。
在下面的部分中,我們將考察一下這些新方法。
Load 方法 — 基本用法
Load 方法是已經添加到 ADO.NET 2.0 的 DataSet 和 DataTable 中的一個新方法。它用 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 提供,它隨后被傳遞給 DataTable 的 Load 方法,以便用返回的數據填充它。用數據填充 DataTable 之后,就可以在 DataGridView 中綁定和顯示它了。下一部分將解釋(可選的)LoadOption 參數的 OverwriteRow 加載選項的重要性。
Load 方法 — 為什么要加載該數據?
如果您通過 DataSet/DataTable 和 DataAdapter 所做的所有工作就是用數據源中的數據填充 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概括了各種方案:
其中:
| ? | 主數據源 — DataTable/DataSet 只通過一個主數據源進行同步/更新。它將跟蹤更改以便可以與主數據源同步。 |
| ? | 輔助數據源 — DataTable/DataSet 從一個或多個輔助數據源接受增量數據饋送。它不負責跟蹤更改以便與輔助數據源同步。 |
圖 3 中顯示的三種情況可以總結如下:
| ? | 情況 1 — 根據主數據源初始化 DataTable。用戶希望用來自主數據源的值初始化空的 DataTable(原始值和當前值),然后,在對該數據進行更改之后,將更改傳回主數據源。 |
| ? | 情況 2 — 保留更改并且根據主數據源重新同步。用戶希望獲得修改后的 DataTable,并且在保持所作更改(當前值)的同時,將它的內容(僅限于原始值)與主數據源重新同步。 |
| ? | 情況 3 — 聚合來自一個或多個輔助數據源的增量數據饋送。用戶希望接受來自一個或多個輔助數據源的更改(當前值),然后將這些更改傳回到主數據源。 |
LoadOption 枚舉具有三個值,分別代表以下三種情況:
| ? | OverwriteRow — 用傳入的行的值更新該行的當前版本和原始版本。 |
| ? | PreserveCurrentValues(默認)— 用傳入的行的值更新該行的原始版本。 |
| ? | UpdateCurrentValues — 用傳入的行的值更新該行的當前版本。 |
注 這些名稱可能會在 Beta 1 之后更改。
下面的表 1 總結了加載語義。如果傳入的行和現有行就主鍵值達成協議,則使用該行的現有 DataRowState 來處理它,否則使用“Not Present”部分(該表的最后一行)中的內容來處理。
| 表 1. 加載語義摘要 | |||
| 現有的 DataRow 狀態 | UpdateCurrentValues | OverwriteRow | PreserveCurrentValues(默認) |
| 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. 加載之后的行狀態 | |||
| UpdateCurrentValues | OverwriteRow | PreserveCurrentValues | |
| 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 類中引入了兩個新方法:SetAdded 和 SetModified。在您詢問有關將狀態設置為 Deleted 或 Unchanged 的問題之前,讓我提醒您一下,在版本 1.x 中,我們已經具有了能夠完成該工作的 Delete 和 AcceptChanges/RejectChanges 方法。
GetTableReader 方法
GetTableReader 方法是已經添加到 ADO.NET 2.0 的 DataSet 和 DataTable 中的一個新方法。它將 DataTable 的內容作為 DataTableReader(派生自 DBDataReader)對象返回。如果在包含多個表的 DataSet 上調用該方法,則 DataReader 將包含多個結果集。
The use of the GetTableReader method is quite straight-forward:Dim dtr As DataTableReader = ds.Tables(0).GetDataReaderDataTableReader 的工作方式非常類似于您使用過的其他數據讀取器,例如,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 的行。DataView 的 ToTable 方法可以返回實際的 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。新表中的行只包含原始 DataTable 和 DataView 的兩個列。圖 4 顯示了這方面的一個示例。
返回頁首
小結
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
總結
以上是生活随笔為你收集整理的ADO.NET 2.0 中的新增 DataSet 功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python的视频分析
- 下一篇: ASP.NET下MVC设计模式的实现