ADO.NET是.Net FrameWork SDK中用以操作數(shù)據(jù)庫的類庫的總稱。而DataSet類則是ADO.NET中最核心的成員之一,也是各種開發(fā)基于.Net平臺程序語言開發(fā)數(shù)據(jù)庫應(yīng)用程序最常接觸的類。之所以DataSet類在ADO.NET中具有特殊的地位,是因為DataSet在ADO.NET實現(xiàn)從數(shù)據(jù)庫抽取數(shù)據(jù)中起到關(guān)鍵作用,在從數(shù)據(jù)庫完成數(shù)據(jù)抽取后,DataSet就是數(shù)據(jù)的存放地,它是各種數(shù)據(jù)源中的數(shù)據(jù)在計算機內(nèi)存中映射成的緩存,所以有時說DataSet可以看成是一個數(shù)據(jù)容器。同時它在客戶端實現(xiàn)讀取、更新數(shù)據(jù)庫等過程中起到了中間部件的作用(DataReader只能檢索數(shù)據(jù)庫中的數(shù)據(jù))。
  各種.Net平臺開發(fā)語言開發(fā)數(shù)據(jù)庫應(yīng)用程序,一般并不直接對數(shù)據(jù)庫操作(直接在程序中調(diào)用存儲過程等除外),而是先完成數(shù)據(jù)連接和通過數(shù)據(jù)適配器填充DataSet對象,然后客戶端再通過讀取DataSet來獲得需要的數(shù)據(jù),同樣更新數(shù)據(jù)庫中數(shù)據(jù),也是首先更新DataSet,然后再通過DataSet來更新數(shù)據(jù)庫中對應(yīng)的數(shù)據(jù)的。可見了解、掌握ADO.NET,首先必須了解、掌握DataSet。DataSet主要有三個特性:
  1. 獨立性。DataSet獨立于各種數(shù)據(jù)源。微軟公司在推出DataSet時就考慮到各種數(shù)據(jù)源的多樣性、復(fù)雜性。在.Net中,無論什么類型數(shù)據(jù)源,它都會提供一致的關(guān)系編程模型,而這就是DataSet。
  2. 離線(斷開)和連接。DataSet既可以以離線方式,也可以以實時連接來操作數(shù)據(jù)庫中的數(shù)據(jù)。這一點有點像ADO中的RecordSet。
  3. DataSet對象是一個可以用XML形式表示的數(shù)據(jù)視圖,是一種數(shù)據(jù)關(guān)系視圖。
一.DataSet對象的結(jié)構(gòu)模型及和RecordSet的比較
  雖說ADO.NET是 ADO在.Net平臺下得后繼版本,但二者的區(qū)別是很大的。突出表現(xiàn)在ADO中的RecordSet對象和ADO.NET中的DataSet對象。RecordSet其實也是非常靈活的一個對象,微軟公司推出它也是煞費苦心,如:RecordSet可以離線操作數(shù)據(jù)庫,性能優(yōu)良,效率較高等等這些都讓當時的程序員為之一振。RecordSet雖然已經(jīng)很復(fù)雜,但DataSet卻比RecordSet復(fù)雜的多,我們知道每一DataSet往往是一個或多個DataTable 對象的集合,這些對象由數(shù)據(jù)行和數(shù)據(jù)列以及主鍵、外鍵、約束和有關(guān)DataTable對象中數(shù)據(jù)的關(guān)系信息組成。而RecordSet只能存放單張數(shù)據(jù)表,雖然這張數(shù)據(jù)表可以由幾張數(shù)據(jù)表JOIN生成。所以有些時候說,RecordSet更類似于DataSet中的DataTable。DataSet對象的結(jié)構(gòu)模型如圖01所示:

圖01:DataSet對象的結(jié)構(gòu)模型圖

  通過圖01可見在DataSet對象結(jié)構(gòu)還是非常復(fù)雜的,在DataSet對象的下一層中是DataTableCollection對象、DataRelationCollection對象和ExtendedProperties對象。上文已經(jīng)說過,每一個DataSet對象是由若干個DataTable對象組成。DataTableCollection就是管理DataSet中的所有DataTable對象。表示DataSet中兩個DataTable對象之間的父/子關(guān)系是DataRelation對象。它使一個DataTable 中的行與另一個DataTable中的行相關(guān)聯(lián)。這種關(guān)聯(lián)類似于關(guān)系數(shù)據(jù)庫中數(shù)據(jù)表之間的主鍵列和外鍵列之間的關(guān)聯(lián)。DataRelationCollection對象就是管理DataSet中所有DataTable之間的DataRelation關(guān)系的。在DataSet中DataSet、DataTable和DataColumn都具有ExtendedProperties屬性。ExtendedProperties其實是一個屬性集(PropertyCollection),用以存放各種自定義數(shù)據(jù),如生成數(shù)據(jù)集的SELECT語句等。
二.使用DataSet:
  DataSet其實就是數(shù)據(jù)集,上文已經(jīng)說過DataSet是把數(shù)據(jù)庫中的數(shù)據(jù)映射到內(nèi)存緩存中的所構(gòu)成的數(shù)據(jù)容器,對于任何數(shù)據(jù)源,它都提供一致的關(guān)系編程模型。在DataSet中既定義了數(shù)據(jù)表的約束關(guān)系以及數(shù)據(jù)表之間的關(guān)系,還可以對數(shù)據(jù)表中的數(shù)據(jù)進行排序等。DataSet使用方法一般有三種:
  1. 把數(shù)據(jù)庫中的數(shù)據(jù)通過DataAdapter對象填充DataSet。
  2. 通過DataAdapter對象操作DataSet實現(xiàn)更新數(shù)據(jù)庫。
  3. 把XML數(shù)據(jù)流或文本加載到DataSet。
  下面就來詳細探討以上DataSet使用方法的具體實現(xiàn),使用語言是C#。
  1. 把數(shù)據(jù)庫中的數(shù)據(jù)通過DataAdapter對象填充DataSet:
  掌握DataSet使用方法必須掌握ADO.NET另外一個核心常用成員--數(shù)據(jù)提供者(Data Provider)。數(shù)據(jù)提供者(也稱為托管提供者Managed Provider)是一個類集合,在.Net FrameWork SDK 1.0中數(shù)據(jù)提供者分為二種:The SQL Server .NET Data Provider和The OLE DB .NET Data Provider。而到了.Net FrameWork SDK 1.1時,ADO.NET中又增加了The ODBC .NET Data Provider和 The Oracle .NET Data Provider二個數(shù)據(jù)提供者。The SQL Server .NET Data Provider的操作數(shù)據(jù)庫對象只限于Sql Server 7.0及以上版本,Oracle .NET Data Provider的操作數(shù)據(jù)庫對象只限于Oracle 8.1.7及以上版本。而The OLE DB .NET Data Provider和The ODBC .NET Data Provider可操作的數(shù)據(jù)庫類型就相對多了許多,只要它們在本地分別提供Ole Db提供程序和ODBC提供程序。
  在這些數(shù)據(jù)提供者中都有一個DataAdapter類,如:OLE DB .NET Framework 數(shù)據(jù)提供者中是 OleDbDataAdapter類,The SQL Server .NET Framework 數(shù)據(jù)提供者中是SqlDataAdapter類,The ODBC .NET Framework 數(shù)據(jù)提供者中是OdbcDataAdapter類。通過這些DataAdapter就能夠?qū)崿F(xiàn)從數(shù)據(jù)庫中檢索數(shù)據(jù)并填充 DataSet 中的表。
  DataAdapter填充DataSet的過程分為二步:首先通過DataAdapter的SelectCommand屬性從數(shù)據(jù)庫中檢索出需要的數(shù)據(jù)。SelectCommand其實是一個Command對象。然后再通過DataAdapter的Fill方法把檢索來的數(shù)據(jù)填充 DataSet。代碼清單01就是以Microsoft SQL Server 中的Northwind數(shù)據(jù)庫為對象,C#使用The SQL Server .NET Data Provider中的SqlDataAdapter填充DataSet的具體實現(xiàn)方法:
  代碼清單01:

SqlConnection sqlConnection1 = new SqlConnection ( "Data Source=localhost ;Integrated Security=SSPI ;Initial Catalog=Northwind" ) ;
//創(chuàng)建數(shù)據(jù)連接
SqlCommand selectCMD = new SqlCommand ( "SELECT CustomerID , CompanyName FROM Customers" , sqlConnection1 ) ;
//創(chuàng)建并初始化SqlCommand對象
SqlDataAdapter sqlDataAdapter1 = new SqlDataAdapter ( ) ;
custDA.SelectCommand = selectCMD ;
sqlConnection.Open ( ) ;
//創(chuàng)建SqlDataAdapter對象,并根據(jù)SelectCommand屬性檢索數(shù)據(jù)
DataSet dsDataSet1 = new DataSet ( ) ;
sqlDataAdapter1.Fill ( dsDataSet1 , "Customers" ) ;
//使用SqlDataAdapter的Fill方法填充DataSet
sqlConnection.Close ( ) ;
//關(guān)閉數(shù)據(jù)連接

  對于其他數(shù)據(jù)提供者的DataAdapter,具體的實現(xiàn)檢索數(shù)據(jù)庫中的數(shù)據(jù)并填充DataSet的實現(xiàn)方法類似于以上方法。
  2. 通過DataAdapter對象操作DataSet實現(xiàn)更新數(shù)據(jù)庫:
  DataAdapter是通過其Update方法實現(xiàn)以DataSet中數(shù)據(jù)來更新數(shù)據(jù)庫的。當DataSet實例中包含數(shù)據(jù)發(fā)生更改后,此時調(diào)用Update方法,DataAdapter 將分析已作出的更改并執(zhí)行相應(yīng)的命令(INSERT、UPDATE 或 DELETE),并以此命令來更新數(shù)據(jù)庫中的數(shù)據(jù)。如果DataSet中的DataTable是映射到單個數(shù)據(jù)庫表或從單個數(shù)據(jù)庫表生成,則可以利用 CommandBuilder 對象自動生成 DataAdapter 的 DeleteCommand、InsertCommand 和 UpdateCommand。使用DataAdapter對象操作DataSet實現(xiàn)更新數(shù)據(jù)庫具體的實現(xiàn)方法,只需把下面的代碼清單02添加到代碼清單01之后,二者合并即可實現(xiàn)刪除Customers數(shù)據(jù)表中第一行數(shù)據(jù):
  代碼清單02: 

SqlCommandBuilder sqlCommandBuilder1 = new SqlCommandBuilder ( sqlDataAdapter1 ) ;
//以sqlDataAdapter1為參數(shù)來初始化SqlCommandBuilder實例
dsDataSet1.Tables["Customers"].Rows[0].Delete ( ) ;
//刪除DataSet中刪除數(shù)據(jù)表Customers中第一行數(shù)據(jù)
sqlDataAdapter1.Update ( dsDataSet1 ,"Customers" ) ;
//調(diào)用Update方法,以DataSet中的數(shù)據(jù)更新從數(shù)據(jù)庫
dsDataSet1.Tables["Customers"].AcceptChanges ( ) ;

  由于不了解DataSet結(jié)構(gòu)和與數(shù)據(jù)庫關(guān)系,很多初學者往往只是更新了DataSet中的數(shù)據(jù),就認為數(shù)據(jù)庫中的數(shù)據(jù)也隨之更新,所以當打開數(shù)據(jù)庫瀏覽時發(fā)現(xiàn)并沒有更新數(shù)據(jù),都會比較疑惑,通過上面的介紹,疑惑應(yīng)當能夠消除了。
  3. XML和DataSet:
  DataSet中的數(shù)據(jù)可以從XML數(shù)據(jù)流或文檔創(chuàng)建。并且.Net Framework可以控制加載XML數(shù)據(jù)流或文檔中那些數(shù)據(jù)以及如何創(chuàng)建DataSet的關(guān)系結(jié)構(gòu)。加載XML數(shù)據(jù)流和文檔到DataSet中是可使用DataSet對象的ReadXml方法(注意:ReadXml來加載非常大的文件,則性能會有所下降)。ReadXml 方法將從文件、流或 XmlReader 中進行讀取,并將 XML 的源以及可選的 XmlReadMode 參數(shù)用作參數(shù)。該ReadXml方法讀取 XML 流或文檔的內(nèi)容并將數(shù)據(jù)加載到 DataSet 中。根據(jù)所指定的XmlReadMode和關(guān)系架構(gòu)是否已存在,它還將創(chuàng)建DataSet的關(guān)系架構(gòu)。