簡介:本文主要討論了作為實現基本數據庫操作方法之一的ADO.NET,以及ADO.Net與ADO的基本比較
ADO.NET將成為構建數據感知 .NET應用程序的基礎. 不同於ADO 的是,ADO.NET更具有通用性,不是那麼專門針對數據庫而進行的設計. ADO.NET聚集了所有可以進行數據處理的類.這些類呈現了具有典型數據庫功能的data container objects,比如:索引,排序,浏覽.盡管ADO.NET是作為重要的.Net數據庫應用程序的解決方案,它更多的顯示了涵蓋全面的設計,而不僅是作為和ADO模型一樣的以數據庫為中心。.
ADO .NET與ADO有很大的不同.它是一個全新的訪問編程模型.當你開始使用ADO.Net時,你會發現你所掌握的任何關於ADO的技能在搭建有效的程序以及解決難題方面對你都會有很大幫助,能夠幫你在解決問題上朝更靈活更穩妥的方向發展.
ADO.NET不是ADO為適應.NET基礎構造而進行改進的版本.當你慢慢了解了ADO.Net的語法,代碼設計以及移植後,你就會清楚了.
1.Net中的數據訪問
訪問ADO.NET中的數據源是由托管提供程序所控制. 雖然托管提供程序與OLE DB有兩處重大的不同,但是二者是極為類似的.首先, 托管提供程序在.NET環境下運行,通過 DataReader 和DataTable .NET類來檢索和展示數據.第二,它們的體系結構都比較簡單,是因為為了適應.Net而進行了優化.
此時,ADO.Net分成兩種不同類型的托管提供程序:一種用於SQL Server? 7.0 或更高版本,另一種適用於所有你可能已經安裝的OLE DB 提供程序.雖然運用在兩種托管提供程序中的類是不同的,但它們卻都遵循相類似的命名方式.除開前綴之外,其它名稱都是相同的.前一種情況前綴為SQL, 後一種則是ADO.
你需要利用SQL類來訪問SQL Server 表,因為SQL類會跳過由OLE DB 提供程序呈現的中間層, 而直接進入數據庫服務器內部API. ADO類是位於OLE DB 提供程序頂端的.Net接口,利用COM Interop 橋來進行工作.
關於ADO.Net的入門知識,你可以讀讀Omri Gazitt's的文章,文章裡主要介紹了ADO+:
關於微軟..NET 框架的數據庫訪問服務(Data Access Services),而我的文章裡關於ADO+的論述主要指出了數據種類的進化.前者更純技術化,並提供了更高水平的關於ADO.NET編程模型的概述。後者主要是解釋ADO.NetR的目標,以及它與XML,腳本及其它技術的聯系.
2.讀取數據
ADO.NET應用程序要從數據源裡讀取數據,首先得創建一個連接對象.這個連接對象可以是SQLConnection 或是 ADOConnection,這取決於所采用的目標提供程序. 需要記住的是,雖然在這裡不做推薦,但你也可以利用ADO .Net 類來連接到SQL Server數據庫. 這種方法唯一不足是,代碼需要通過一個不必要的額外代碼層. 首先它會調入ADO的托管提供程序, 然後ADO的托管提供程序再調用SQL Server OLE DB 提供程序. 如同OLE DB 提供程序做的一樣,SQL Server 托管提供程序會直接操作數據,
關於ADO 和ADO.NET在連接對象上最大的差別在於ADO.NET連接不支持CursorLocation屬性.與其說這是一個文檔BUG,還不如認為這是一個備具爭議的設計問題.為強制執行它的以數據為中心的基准,ADO.Net沒有游標的顯示實現.
在ADO中,你已習慣於利用游標將記錄從數據庫或其它OLE DB兼容的數據源中抽取, 你可以選擇客戶端或是服務器端游標,每種游標都有幾個預先設定的游標類型. 而在ADO.Net中更多的是從數據源中抽取數據,並且為讀取和分析數據提供新的編程接口
在ADO中,通過規定連接和命令文本,你可以創建一個Recordset 對象.對於游標的位置和類型Recordset有一些規定.你可以按下面的方法來讀取數據.
在內存中創建選定記錄的靜態副本,然後在斷開與數據源的連接時對副本進行處理,ADO稱之為靜態游標.
通過快速的, 僅向前的, 只讀游標來滾動數據,,ADO稱之為僅向前游標.
通過服務器端游標來訪問數據,需要良好的連接,但您可以在不同層面上檢測由其它連線用戶輸入的信息,ADO稱之為: 動態游標.
頭兩種都是在斷開的recordsets上進行操作,並從客戶端緩存中讀取信息,另外,前兩種方式也常被用於面向WEB的環境中以及全新的 n-tIEr 系統當中.
在ADO中,以上所有這些方式與不同類型的游標相對應 .在文中,你將會發現,ADO.Net雖然與ADO不同,但它具備了ADO的所有功能.相對照來說,你的代碼將從實際的數據源及其物理存儲媒介和格式中抽取數據.
ADO.NET能夠使DataSet 和 DataReader 將數據從數據源中抽取出來.前者是記錄在內存中的緩存,你可以從任意方向訪問並隨意作出修改. 後者是高度優化的對象,在只讀紀錄集中以僅向前方式向前移動。注: DataSet 看起來象是靜態游標,但實際上,在.Net中,與ADO只讀游標相對應的是DataReader 對象.
在ADO.NET中,雖然對於服務器端的游標不提供任何支持,但這不意味著你就不能使用游標.實際上,你所需要做的步驟是在.Net中輸入ADO庫.你只需在references node上單擊右鍵,就可以在你自己的程序裡運行本地ADO 對象.
但是我個人認為,在你想轉向.NET時,請慎重考慮. 首先,請務必完全輸入ADO, 這不會花費太多時間和精力,這是向.NET邁出的第一步,.但是,這僅僅是萬裡長征的第一步而且也是通向.NET必須的一步. .Net的真正附加值是基於一個均勻的,持續穩定的接口以及本地classes的廣為應用之上的.關於COM librarIEs是可以被支持的,合理的,但不被鼓勵的,因為它僅僅是個短期解決方案,或者是一個過渡步驟.
當你要開始使用ADO.NET時,請考慮這樣一個事實:ADO.Net統一了數據容器類編程接口,.因此,不管是何種類型的程序: Windows Form, Web Form, 或者 Web Service也好,你都得在同一組類中集中處理有關數據. 不管處於後端的數據源是SQL Server database,或是OLE DB 提供程序,, XML文件,又或是數組,你都可以使用一樣的方法和屬性來進行處理.
Figure 1. Solution Explorer menu
如果你堅持在.Net世界中使用ADO,那麼請准備好面對一些其它的影響,例如你需要額外的代碼才能夠從數據綁定控件中使用recordset.
3.DataSet, DataTable, and Recordset
關於Recordset object.,ADO.Net並沒有與其直接相對應的對象.最接近的是DataTable 對象.雖然它們二者幾乎具有相同的功能,但它們在各自的框架裡發揮著不同的作用.
Recordset是一個相當大的對象,具備ADO的大多數功能,但在某些方面仍有欠缺. Recordset在一些方面性能優良,如:它具可創造性,它可以離線操作,功能眾多,但在一些方面仍需改進,如:基於其固有的COM特性, Recordset很難在網絡上連載; Recordset是一個二進制的對象,因此不同平台之間的模塊很難共享它;還有就是蛇不能夠穿過防火牆.另外,它表現的是記錄的單個表.如果該table作為一個或幾個JOIN的結果,那麼它很難更新原始代碼源.當你試圖將脫線的recordset與原始代碼源統一起來時,數據源必須能夠識別SQL.不管如何,你的recordset可以由非SQL 提供程序創建.
在ADO.Net中,ADO Recordset的所有功能被分拆成幾塊更簡單的對象:其中一個便是DataReader. DataReader模擬了快速,只讀,僅向前的只讀游標的操作.
DataTable,表現了數據源,是個簡單的對象. 你可以手動構造一個DataTable,或者也可使用DataSet命令自動生成. DataSet對於它所包含的數據知之不多.通過它,你可以在內存中處理數據,或者是其它比如排序,編輯,篩選,創建浏覽等工作.
DataSet對象是一個數據容器類,是實現ADO.Net數據抽取的關鍵對象. DataSet集合了一個或幾個DataTable 對象. DataTable 通過如行,列這樣的通用集合,公開自身的內容.當你嘗試從數據表讀取數據時,你也許正穿過了兩個不同的層面: DataTableMapping 和 DataVIEw.
DataTableMapping 對象包含了數據源中的數據列,以及DataTable object之間的映射關系.
當填充 DataSet 時,DataSetCommand 對象要使用這個類。它維護數據集中的抽象列和數據源中的物理列之間的鏈接。
表的視圖通過 DataView 對象實現。它表示 DataTable 的自定義視圖,可以綁定到特定控件(如 Windows 窗體和 Web 窗體中的數據網格)中。該對象相當於 SQL CREATE VIEW 語句在內存中的實現。
DataSet中所有的表,通過一個公共的域,相互之間能產生關聯.它們之間的聯系是由DataRelation 對象來進行管理.這樣說起來挺象ADO的數據形成,但還是有一個最大的不同.
在DataRelation裡,你不需要使用數據形成語言,而且還可以獲得非常靈活的組織架構. 通過ADO .Net 導航模型,你可以很容易的從某一張表中的主行移動到它的所有子行裡.
DataRelation object是關於JOIN 語句在內存中的實現,可用於建立數據類型相同的的parent/child關系,. 一旦關系確立,任何破壞這種關系的修改都被禁止. Views和 relations是完成master/detail 架構的兩個方法.請記住vIEw僅是加載於記錄之上的掩碼, 但是relation
是位於幾個列之間的動態鏈接,在relation下,你無法更改順序或是設置條件.
如果你的代碼需要1對1的外鍵關系,而且更改數據,最好不用JOIN命令.如果你需要額外的篩選功能,你可以尋求ADO .Net自定義視圖的支持.
4.轉換現有代碼
大量的ASP頁面使用ADO對象來抽取數據.讓我們一起來回顧下幾例典型的案例,對你在以後處理移植或者改寫代碼時也許會有幫助。
如果你有從單個recordset生成報表的ASP頁面,那麼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()) {
// Use dr.GetString(index) or
// dr["fIEld name"] to Response.Write data
}
你可以利用HasMoreRows屬性來快速檢查是否DataReader為空.如果你僅僅只簡單處理一系列記錄,沒有什麼比DataReader.更快,更好的對象了,它同樣適用於查詢單個記錄。
DataReader.的內容是不可編輯的,但你可以將內容移動到更具管理功能的對象裡,如:
DataTable或是一個或多個DataRow 對象.
當你需要處理表與記錄二者之間的復雜關系時,DataReader就不是合適的工具了。數據模型鏈接越多,SQL命令則會越復雜。導航模塊保有連續性,最後放入緩存的數據往往多於你所需要的,. DataSet 和 DataRelation objects是這種表關系模型的基礎.
為管理parent/child 關系,ADO同樣也對data-shaping engine進行封裝. 總的說來, data shaping 和 ADO .NET 關系是一回事.就設計方面來說,二者幾乎沒有共同點. Shaped recordsetsct嵌入列表對象中包括了所有數據表信息。ADO.Net關系是動態鏈接,你可以在兩個數據表間隨時建立. ADO依靠於Shaping OLE DB service 提供程序,並使用專門的SQL類語言特征以在執行單個ADO命令的過程中生成一個分層的recordset.
在 ADO.Net 中,關系中涉及的每個對象總是被看成單獨的個體。關系本身作為對象被公開,並且具有一定的行為規則。例如,DataRelation 對象可以從父行到子行一層層進行更改。您可以通過將 ForeignKeyConstraint 對象添加到 DataTable 的 Constraints 集合中來進行此操作。ForeignKeyConstraint 對象表示當刪除或更新數值和行時,對通過外鍵關系相關聯的一組列的約束。如前面提到的,一旦設置好了關系,在它按程序預設終止之前,您不能進行可能破壞該關系的更改。
正如早先提到的一樣,一旦設置了relationship,除非它是程序性的終止,你不能夠對它進行修改,那樣會使它突然中斷.
另外, relations沒有遞延性.你可以在Customers 和Orders之間,Orders 和 Products之間設置兩個不同的關系.但是,當為了某個customer而對orders導航時,你不能夠從一個order跳到相關的products行.解決方法是,你必須另外打開Orders/Products 關系,鎖定你需要的order,然後獲取相關的行.
程序員需要在ASP Session 對中存儲記錄嗎?通過ADO .Net 和 DataSet 對象,你可以非常安全的進行工作,而不會引起在"Storing an ADO Recordset in GIT Might Cause An Access Violation"中所論及的麻煩.
5.更新數據
Web程序通常利用無程式語句或者通過參數代存儲過程來更新數據.但是,當遇見脫線的數據時,你也許希望利用內置服務來更新所有需要修訂的記錄.為完成這一工作.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, and SelectCommand.它們都是Command對象,但你不能夠對它們進行設置,除非缺省設置沒有按你的要求完成.這與ADO中一樣.在Update過程中,如果沒有設置xxxCommand屬性,但是主關鍵字已經存在內,則會自動生成Command對象.
以下代碼展示了如何為EmployeesList table設置主關鍵字,
DataColumn[] keys = new DataColumn[1];
keys[0] = m_oDS.Tables["EmployeesList"].Columns["EmployeeID"];
m_oDS.Tables["EmployeesList"].PrimaryKey = keys;
主關鍵字基本上是是DataColumn對象的一個數組.
如果你想利用存儲過程來更新表單,或者你利用專用非SQL 數據提供程序進行操作,那麼你將會常常用到這 些命令屬性.
6.XML的延展支持功能
在ADO中,XML僅僅只是作為輸入和輸出格式.但是,在ADO.Net中,XML作為數據記錄格式為你提供了一系列的方法,如: manipulating, reorganizing, sharing, and transferring. 任何你輸入進到DataSet中的數據,不管是不是原創,都能夠通過雙面編程模型進行處理.
如同XML文檔一樣,DataSet 讀取/書寫數據和模式。數據和模式在HTTP中是可轉移的,也可以在任一支持XML的平台上運行。相同的數據在不同的時間段通過不同的模式可以被執行。你利用ReadXmlSchema來書寫模式。 XML模式包含了data set中tables 的名稱,如同data set 中的relations 和 constraints一樣。在調用ReadXMLData之前你應該完成這個步驟
以下代碼示例是一個顯示可更新數據表的最簡單的 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();
// Loads XML data and schema
StreamReader sr;
sr = new StreamReader(Server.MapPath("data.XML"));
data.ReadXML(sr);
sr.Close();
// Add a new record passed through the 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();
}
// Refreshes the UI (made of a grid)
grid.DataSource = data.Tables[0].DefaultVIEw;
grid.DataBind();
}
</script>
如圖 2 所示,您可以將新的行添加到表中。然而,它不涉及 SQL Server 或 Access 表。它只是一個 XML 文件,在處理它的代碼中,沒有使用 XML 節點或 XMLDOM 方法。您可以用相同的直觀數據表接口來讀取和更新 XML 記錄。您的工作方式與在 ADO 中大致相同,但此處的模型更深入、更龐大,有更多的潛力供您去發掘。
Figure 2. Example of an updateable table
7.結論
Web 應用程序的成功改變了典型分布式系統的面貌。現在大多數分布式系統都是 n 層系統,這類系統對擴展性和互操作性的要求越來越高。因此,非連接數據處理和 XML 成為最佳實踐,並為業界廣為接受。
ADO.NET試圖將一些現有的在.NET旗下最好的精華都統成為一體.對於數據訪問的所有的編程模式就綜合性的,並是非常強大的.也許該模式不能一一滿足你的每個要求,但它朝模式設計方向跨出了一大步,不管如何,請記住ADO.Net只是一個測試版,而且只有有限的文檔支持.
ADO程序員從該測試版中將會受益非淺,因為他們已經熟悉了關於ADO.NET的方方面面,包括關於abstraction的最高層次-- inspiring 模型. ADO.NET代碼與現有的ADO代碼並不兼容,但是功能卻近似. 為完全發揮ADO.NET 的優勢,與其只是簡單的計算出最快的方式來放置代碼,還不如實實在在的弄清楚ADO.NET它本身的要領.不管如何,.你所選擇的NET編程模式-- Windows Forms, Web Forms, or Web Services,ADO.Net都會在數據存取方面幫你一把.