ADO.NET

维基百科,自由的百科全书
跳转至: 导航搜索

ADO.NET是微軟在.NET Framework中負責資料存取的類別庫集,它是使用在COM時代奠基的OLE DB技術以及.NET Framework的類別庫和程式語言來發展的,它可以讓.NET上的任何程式語言能夠連接並存取關聯式資料庫與非資料庫型資料來源(例如XML,Excel或是文字檔資料),或是獨立出來作為處理應用程式資料的類別物件,其在.NET Framework中的地位是舉足輕重,許多人將ADO.NET視為ADO的下一個版本,但其實它是一個全新的架構、產品與概念。

發展緣起[编辑]

在1997年時,微軟已經開發了許多的資料存取方式,像是ODBC架構、和Microsoft Access資料庫交互使用的DAO物件、可以跨越網路存取資料的RDO以及讓DAO元件可以存取ODBC資料來源的ODBCDirect技術等等,技術雖然多,但是卻又各自為政,而且每個技術的重疊性也很高(像是ODBC有Microsoft Access的驅動程式),RDO雖然可跨網路,但是ODBC的驅動程式中也有提供跨網路的功能(像是SQL ServerOracle驅動程式),如此琳琅滿目重疊性又高的技術群,讓企業與開發人員在選擇、學習與應用上產生了很多的困難。同時適逢 COMOLE的發展,微軟將資料存取的核心開始改寫為以COM為主的OLE DB,並且在它上面建立一個新的資料存取模型-ADO

ADO推出後順利的取代了DAO和RDO,成為在Windows NT 4.0Windows 2000作業系統上開發資料庫應用程式的首選,除了它將物件模型統一化,改由資料庫廠商發展資料提供者(data provider,這個模式在此時奠基),而ADO本身則是與資料來源無關 (data source independent) 的開發方法,讓它迅速的獲得了使用ASPVisual Basic開發人員的青睞,也是它能夠順利取代DAO與RDO等模型的主要關鍵。然而ADO本身的架構仍然有缺陷(尤其是在開發網路應用程式時,最好的例子就是Recordset無法離線),這也是微軟為何不在.NET Framework中繼續使用ADO的主要原因,在1998年時,微軟提出了一個下一代的應用程式開發框架 (Application Framework) 的計畫[1],計畫中包含了:

  • ASP+:改良與重新設計ASP技術,強化它的Web應用程式發展能力。
  • Storage+:發展新的資料庫與物件導向之檔案系統結構(用於 SQL Server 8.0(即後來的SQL Server 2000)與NTFS),以及發展新一代的資料存取元件,並改良ADO本身的缺陷,讓它更能夠成為應用程式資料存取的核心功能。
  • COM+:改良 COM 和 MTS,成為企業級應用程式開發的基礎元件。

ADO+即為Storage+的一支。

ADO.NET的前身:ADO+[编辑]

1998年起,因為Web應用程式的竄起,大大改變了許多應用程式的設計方式,傳統的資料庫連線保存設計法無法適用於此類應用程式,這讓ADO應用程式遇到了很大的瓶頸,也讓微軟開始思考讓資料集(Resultset,在ADO中稱為Recordset)能夠離線化的能力,以及能在用戶端建立一個小型資料庫的概念[2][3],這個概念就是ADO.NET中離線型資料模型 (disconnected data model) 的基礎,而在ADO的使用情形來看,資料庫連線以及資源耗用的情形較嚴重(像是 Server-side cursor 或是 Recordset.Open 會保持連線狀態),在ADO.NET中也改良了這些物件,構成了能夠減少資料庫連線和資源使用量的功能。XML的使用也是這個版本的重要發展之一。

2000年,微軟的Microsoft .NET計畫開始成形,許多的微軟產品都冠上.NET的標籤,ADO+也不例外,改名為ADO.NET,[4]並包裝到.NET Framework類別庫中,成為.NET平台中唯一的資料存取元件。

架構[编辑]

ADO.NET 由連線資料來源 (connected data source) 以及離線資料模型 (disconnected data model) 兩個部份構成[5],這兩個部份是相輔相成的,同時依照介面的不同,分為:

  • SQL Server 原生資料來源-System.Data.SqlClient(以 Sql 為字首的類別群)。
  • OLE DB 資料來源-System.Data.OleDb(以 OleDb 為字首的類別群)。
  • Oracle 資料來源-System.Data.OracleClient(以 Oracle 為字首的類別群)。
  • ODBC 資料來源-System.Data.Odbc(以 Odbc 為字首的類別群)。

連線資料來源[编辑]

若沒辦法連線到資料庫,則無法被稱為資料存取元件。連線資料來源便是用來連接資料庫(或是具有 OLE DB 資料來源提供者)的物件類別[6],由下列類別所構成:

  • IDbConnection,負責與資料庫的連線管理,包含連線字串 (connection string),連線的開關,資料庫交易的啟始與連線錯誤的處理,所有的 ADO.NET 資料提供者都要實作此介面。
    • Open()/Close():開啟與關閉資料庫連線。
    • BeginTransaction():啟動資料庫交易,並回傳一個 IDbTransaction 物件,以控制交易的結果。
  • IDbCommand,負責執行資料庫指令(在大多數的案例中都是SQL指令),並傳回由資料庫中擷取的結果集,或是執行不回傳結果集的資料庫指令。
    • ExecuteNonQuery():執行不回傳結果集的資料庫指令,像是INSERTUPDATEDELETE指令。
    • ExecuteScalar():執行指令並回傳第一列第一行中的資料。
    • ExecuteReader():執行指令並回傳 IDataReader 物件,以讀取資料集中的資料。
  • IDataParameter,負責裝載資料庫指令所需要的參數資料,在使用參數化查詢時會經常使用。
  • IDbTransaction,負責裝載資料庫交易所需的控制物件,以執行交易的認可 (commit) 或撤銷 (rollback) 的工作。
    • Commit():認可資料庫交易。
    • Rollback():撤銷資料庫交易。
  • IDbDataAdapter,負責將來自於 IDbCommand 執行取得的結果集,裝載到離線型資料集 (DataSet) 或是離線型資料表 (DataTable) 中。
    • Fill():將資料填入離線型資料物件。
    • Update():將變更過的離線型資料物件中的資料寫回資料庫。
  • IDataReader,建立一個只可向前讀取游標 (forward-only) 的資料讀取器工具,以逐列讀取方式存取資料,IDbDataAdapter內部也是由它來讀取資料。
    • Read():讀取下一列,開發人員利用此方法移動資料集中的游標,若資料集中的資料列已讀取完畢時,傳回 false
  • IDataRecord,在 IDataReader 讀取資料後實際裝載資料列的物件,提供方法來讀取資料行中的資料,以及轉換成.NET Framework原生型別的工具。
    • GetOrdinal():取得指定資料行的欄位索引值。
    • IsDBNull():判斷指定欄位的資料是否為NULL值

使用連線資料來源需要由開發人員自我管理連線,並且直接操作資料存取的相關細節,但它的優點是速度快,而且可以自訂整個資料存取流程的邏輯。

離線資料模型[编辑]

離線資料模型是微軟為了改良ADO在網路應用程式中的缺陷所設計的,同時它也是COM+中,IMDB技術的設計概念的實作品,但它並沒有完整的IMDB功能,像是交易處理 (transaction processing),但它仍不失為一個能在離線狀態下處理資料的好幫手,它也可以透過連線資料來源物件,支援將離線資料存回資料庫的能力[7]。離線資料模型由下列物件組成:

  • DataSet,離線型資料模型的核心之一,可將它當成一個離線型的資料庫,它可以內含許多個 DataTable,並且利用關聯與限制方式來設定資料的完整性,它本身也提供了可以和 XML 交互作業的支援。
    • ReadXml()/WriteXml():以 DataSet 的結構讀寫 XML。
    • ReadXmlSchema()/WriteXmlSchema():以 DataSet 的結構讀寫XML Schema
    • GetXml()/GetXmlSchema():取得 DataSet 內容的 XML 或 XML Schema。
    • Merge():合併兩個 DataSet。
    • Load():自 IDataReader 載入資料到 DataSet。
    • AcceptChanges():將修改過的資料列的修改旗標改為 Unchanged
    • GetChanges():將修改過的資料列以 DataRow 陣列方式傳回。
    • RejectChanges():撤銷所有資料的修改。
  • DataTable,離線型資料模型的核心之一,可將它當成一個離線型的資料表,是儲存資料的收納器。
    • Copy():將 DataTable 複製出一個副本,包含結構與資料。
    • Merge():將兩個 DataTable 合併。
    • Select():以指定的特殊查詢語法,傳回符合條件的 DataRow 陣列。
    • Compute():以指定的彙總語法,傳回彙總的結果。
    • GetErrors():傳回有錯誤的 DataRow 陣列。
    • HasErrors:判斷 DataTable 中的 DataRow 有沒有含有錯誤的 DataRow。
  • DataRow,表示表格中的資料列,與資料欄組合成資料儲存的單元。
    • IsNull():判斷指定的欄位是否為 NULL 值。
    • ItemArray:將 DataRow 中的資料轉換成陣列。
  • DataColumn,表示表格中的欄位。
  • DataView,展示資料的輔助元件,類似於資料庫中的檢視表,並可設定過濾條件與排序條件。
    • Filter:設定 DataView 的過濾條件。
    • Sort:設定 DataView 的排序條件。
    • ToTable():將套用過濾與排序後的內容轉換為 DataTable 物件。
  • DataRelation,可在 DataTable 之間設定欄位間的關聯。
  • Constraint,設定欄位的條件約束,例如 ForeignKeyConstraint 為外部鍵限制,而 UniqueConstraint 則確保了欄位中的值都是唯一的。

DataSet和DataTable除了資料庫的處理以外,也經常被用來管理應用程式中的資料,並且由於它可以儲存在 XML 中的特性,也讓它可以用來儲存需要保存的應用程式資訊。

ADO.NET 資料提供者[编辑]

在 .NET Framework中,ADO.NET預設提供了四種資料來源:

  • SQL Server:由 System.Data.SqlClient 提供支援,是微軟官方建議存取SQL Server時建議使用的資料提供者。
  • OLE DB Data Source:由System.Data.OleDb提供支援,可適用於OLE DB Provider for ODBC 以外的 OLE DB 資料提供者。
  • Oracle:由System.Data.OracleClient提供支援,但使用者的電腦必須安裝 Oracle Client 8.1.7 或更新版本才行(.NET Framework 1.1 開始支援)。
  • ODBC:補OLE DB Provider for ODBC的支援,由System.Data.Odbc 提供支援(.NET Framework 1.1 開始支援)。

其他廠商亦為不同的資料庫提供資料來源:

  • DataDirect Technologies發行100%列管提供源,支援主流企業數據庫 (Oracle, Sybase, DB2, SQL Server, Progress RDBMS)
  • OpenLink Software給大量的客戶指定數據庫發行提供源,包括到其他資料存取機構的橋接提供源,並可以在視窗下微軟自己或者Mono的CLR實做下支援。
  • MySQL為本身的 MySQL Database Server 提供了 ADO.NET 的原生資料提供者。
  • Oracle自行開發的 .NET Data Provider。

工廠方法[编辑]

在.NET Framework 1.x的時代,ADO.NET不同的來源有不同的類別搭配(前面已述及),但是若想要在不同的資料來源間搭配,那麼勢必要產生很多的變數來存放不同的資料物件,因此微軟在.NET Framework 2.0中提供了一個System.Data.Common命名空間,其中有各種必要物件的共用方法(例如連線是DbConnection,命令是DbCommand,讀取器是DbDataReader,資料配接器是DbDataAdapter等),以及DbProviderFactory物件,用來總管資料存取的物件。

DbProviderFactories則是電腦中所有提供者的總管,開發人員可用DbProviderFactories.GetFactoryClasses()取得各個提供者的Invariant Name,再於呼叫DbProviderFactories.GetFactory()時傳入指定提供者的Invariant Name即可取得DbProviderFactory,再利用下列方法取得共用物件:

  • DbProviderFactory.CreateConnection()
  • DbProviderFactory.CreateCommand()
  • DbProviderFactory.CreateParameter()
  • DbProviderFactory.CreateDataAdapter()
// This example assumes a reference to System.Data.Common.
static DataTable GetProviderFactoryClasses()
{
    // Retrieve the installed providers and factories.
    DataTable table = DbProviderFactories.GetFactoryClasses();
 
    // Display each row and column value.
    foreach (DataRow row in table.Rows)
    {
        foreach (DataColumn column in table.Columns)
        {
            Console.WriteLine(row[column];
        }
    }
    return table;
}

XML的整合[编辑]

XML 在 ADO.NET 中扮演了相當重要的地位,DataSet 和 DataTable 都可以轉換成 XML 或和 XML 之間交換資料,在 DataTable 的內部資料的變更記錄,可以被輸出到一個 XML 的格式,用來識別變更的情形,這個格式稱為 DiffGram,而且它可以直接讀入 DataTable 之中(使用 DataTable.ReadXml() 並用 XmlReadMode.DiffGram 當參數)。一個典型的 DiffGram 如下:

<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
  <CustomerDataSet>
    <Customers diffgr:id="Customers1" msdata:rowOrder="0" diffgr:hasChanges="modified">
      <CustomerID>ALFKI</CustomerID>
      <CompanyName>New Company</CompanyName>
    </Customers>
    <Customers diffgr:id="Customers2" msdata:rowOrder="1" diffgram:hasErrors="true">
      <CustomerID>ANATR</CustomerID>
      <CompanyName>Ana Trujillo Emparedados y Helados</CompanyName>
    </Customers>
    <Customers diffgr:id="Customers3" msdata:rowOrder="2">
      <CustomerID>ANTON</CustomerID>
      <CompanyName>Antonio Moreno Taquera</CompanyName>
    </Customers>
    <Customers diffgr:id="Customers4" msdata:rowOrder="3">
      <CustomerID>AROUT</CustomerID>
      <CompanyName>Around the Horn</CompanyName>
    </Customers>
  </CustomerDataSet>
  <diffgr:before>
    <Customers diffgr:id="Customers1" msdata:rowOrder="0">
      <CustomerID>ALFKI</CustomerID>
      <CompanyName>Alfreds Futterkiste</CompanyName>
    </Customers>
  </diffgr:before>
  <diffgr:errors>
    <Customers diffgr:id="Customers2" diffgr:Error="An optimistic concurrency violation has occurred for this row."/>
  </diffgr:errors>
</diffgr:diffgram>

DataSet與DataTable也支援直接讀入XML Schema建立結構的能力,以及自行依XML的內容推斷 (inference) 其結構的能力,下列程式碼為由XML推斷結構的程式:

DataSet dataSet = new DataSet();
dataSet.InferXmlSchema("input_od.xml", new string[] "urn:schemas-microsoft-com:officedata");

DataSet和DataTable可以使用XmlDataDocument類別和XML DOM整合在一起,XmlDataDocument的角色就像一個橋接介面,並且作為DataSet和DataTable可使用XPath與 XML DOM 方式存取的方法。下列程式碼即為使用XmlDataDocument和資料庫中資料轉換為XSLT輸出的範例:

// Assumes connection is a valid SqlConnection.
connection.Open();
 
DataSet custDS = new DataSet("CustomerDataSet");
 
SqlDataAdapter customerAdapter = new SqlDataAdapter(
  "SELECT * FROM Customers", connection);
customerAdapter.Fill(custDS, "Customers");
 
SqlDataAdapter orderAdapter = new SqlDataAdapter(
  "SELECT * FROM Orders", connection);
orderAdapter.Fill(custDS, "Orders");
 
connection.Close();
 
custDS.Relations.Add"CustOrders",
  custDS.Tables["Customers"].Columns["CustomerID"],
                     custDS.Tables["Orders"].Columns["CustomerID"].Nested = true;
 
XmlDataDocument xmlDoc = new XmlDataDocument(custDS); 
 
XslTransform xslTran = new XslTransform();
xslTran.Load("transform.xsl");
 
XmlTextWriter writer = new XmlTextWriter("xslt_output.html", 
  System.Text.Encoding.UTF8);
 
xslTran.Transform(xmlDoc, null, writer);
writer.Close();

在.NET Framework中,DataSet被分為兩類,一種是不會強制使用特別型態的DataSet,稱為Untyped DataSet,使用上較方便,但沒有強制的型別限制,另一種則是Typed DataSet,會強制型別,並且是由自訂的XML Schema所產生,Untyped DataSet則沒有XML Schema,由建立時的結構來決定,Typed DataSet可以用Visual Studio,或者是 SDK 工具中的xsd.exe來產生。

xsd.exe /d /l:CS XSDSchemaFileName.xsd /eld /n:XSDSchema.Namespace

產生出來的 Typed DataSet 會自動將欄位設定成屬性,讓開發人員的存取更方便(這個功能在 TableAdapter 相當常見)。

CustomerDataSet customers = new CustomerDataSet();
SqlDataAdapter adapter = new SqlDataAdapter(
  "SELECT * FROM dbo.Customers;",
  "Data Source=(local);Integrated " +
  "Security=SSPI;Initial Catalog=Northwind");
 
adapter.Fill(customers, "Customers");
 
foreach(CustomerDataSet.CustomersRow customerRow in customers.Customers)
  Console.WriteLine(customerRow.CustomerID);

指令產生器[编辑]

ADO.NET 中有專門用來產生資料處理指令的指令產生器 (Command Builder),它可以利用開發人員所指定的 SELECT 指令,自動產生對應的 INSERTUPDATEDELETE 指令,但一開始它並不會自動產生,而是要靠呼叫方法來取得:

  • DbCommandBuilder.GetInsertCommand()
  • DbCommandBuilder.GetUpdateCommand()
  • DbCommandBuilder.GetDeleteCommand()

最常使用到的地方是和 DataAdapter 並用時,但它要求傳入的 SELECT 语句所选择的列集合中必須要有主键或者唯一键[8],否則無法產生,同時自動產生的指令因為判斷條件很多,對效能可能會有些影响。

Visual Studio的支援[编辑]

ADO.NET和Visual Studio開發工具幾乎已經是無縫的整合了,開發人員可以利用Visual Studio來建立強型別(strong-typed)的DataSet,到了Visual Studio 2005時更能夠在Windows Forms應用程式中使用TableAdapter(Typed DataSet 和 DataAdapter 整合的產物)來開發應用程式(不會再看到 DataAdapter,但使用上差不多)[9]。Visual Studio 在建立 Typed DataSet 時有提供視覺化介面的支援,以及資料庫組態精靈 (Database Configuration Wizard) 來讓開發人員以簡單的設定方式來建立 DataSet,部分開發人員也將 TableAdapter 和 ASP.NET 應用程式的 ObjectDataSource 控制項並用,亦得到不錯的效果。

在.NET Framework 3.5中,微軟特別為了DataSet和DataTable建立了LINQ Provider(稱為 LINQ to DataSet 或 LINQ to ADO.NET),讓 LINQ 可以在DataSet或DataTable上使用,可以讓原本在DataSet上的投資(程式碼)得以繼續使用並享有LINQ的便利性。

ADO.NET和ADO的差異[编辑]

對於 ADO 的開發人員來說,最明顯的變化在於以往 ADO 中的 Recordset 消失了,並且明確的分開為連線型的 DataReader 以及離線型的 DataSet 與 DataTable,並且發展支援離線型資料來源的瀏覽工具 DataView[10],這樣的改變,讓習慣使用 ADO 的 VB/ASP 開發人員會有某種程度的不習慣,同時讓 ADO.NET 的學習會較 ADO 有較些許的複雜性,因此有部分新入門或是VB 6.0/ASP開發人員會在學習.NET Framework或是使用VB.NET開發應用程式時,在 .NET Framework 中使用 ADO 來連接資料來源。但在 .NET Framework 應用程式使用 ADO 的話,.NET Framework會因為要多一層COM和.NET資料之間的轉換,會讓應用程式效能有少部分的損耗[11]

ADO.NET 的進化[编辑]

隨著網路應用程式的進化,ADO.NET也隨之做了許多的改變,但不變的是,ADO.NET的基礎提供了強固的發展支援,這些進化的技術都是植基於ADO.NET的核心元件而來。

長久以來,程式設計師和資料庫總是保持著一種微妙的關係,在商用應用程式中,資料庫一定是不可或缺的元件,這讓程式設計師一定要為了連接與存取資料庫而去學習 SQL 指令,因此在資訊業中有很多人都在研究如何將程式設計模型和資料庫整合在一起,物件關聯對應 (Object-Relational Mapping) 的技術就是由此而生,像Hibernate或NHibernate都是這個技術下的產物,而微軟雖然有了ADO.NET這個資料存取的利器,但卻沒有像NHibernate這樣的物件對應工具,因此微軟在.NET Framework 2.0發展時期,就提出了一個ObjectSpace的概念,ObjectSpace可以讓應用程式可以用完全物件化的方法連接與存取資料庫,其技術概念與NHibernate相當類似,然而ObjectSpace專案相當大,在.NET Framework 2.0完成時仍無法全部完成[12],因此微軟將ObjectSpace納入下一版本的.NET Framework中,並且再加上一個設計的工具(Designer),構成了現在的 ADO.NET Entity Framework。

Entity Framework 利用了抽象化資料結構的方式,將每個資料庫物件都轉換成應用程式物件 (entity),而資料欄位都轉換為屬性 (property),關聯則轉換為結合屬性 (association),讓資料庫的 E/R 模型完全的轉成物件模型,如此讓程式設計師能用最熟悉的程式語言來呼叫存取。而在抽象化的結構之下,則是高度整合與對應結構的概念層、對應層和儲存層,以及支援 Entity Framework 的資料提供者 (provider),讓資料存取的工作得以順利與完整的進行。

以往在發展像是 AJAX 應用程式時,伺服端總是需要設計一個 HTTP 介面埠 (end point),通常都會使用 Web Service 來實作,但是隨著 Mashup 應用程式的成長,若每次都要為一份(或一組)資料撰寫 Web Service 或 HTTP end point 的話,對開發人員也是不小的負擔,而且 Web Service 只支援 XML/SOAP 的資料格式,無法相容於 Mashup 應用程式常用的 JSON 資料格式,微軟也發現未來的 Silverlight 應用程式也是會面臨到相同問題。

當時剛好微軟的 ADO.NET Entity Framework 也正在開發中,它的 EDM 能力剛好可以提供給 WCF 資料存取的能力,因此微軟特別以 ADO.NET Entity Framework 為基礎,開發一個專門提供 HTTP 端點資料服務的資料供應層,即為 WCF Data Services。

參考與注釋[编辑]

  1. ^ COM+, A Windows 2000 technology showcase
  2. ^ ADO+
  3. ^ 此概念的原型為 In-Memory Database,又稱IMDB,可在記憶體中運行的資料庫,然而以當時的環境(2000年初,記憶體尚未跌到目前的價格水準),以及技術不成熟的情況下,這項技術在 Windows 2000 RC2 時被抽離。
  4. ^ 有著和它相同遭遇的還有ASP+(改名為ASP.NET)。
  5. ^ ADO.NET 架構
  6. ^ 擷取和修改 ADO.NET 中的資料
  7. ^ DataSet、DataTable 及 DataView (ADO.NET)
  8. ^ .NET Framework 开发人员指南 - 使用CommandBuilder生成命令(ADO.NET)
  9. ^ TableAdapter
  10. ^ ADO.NET ─ ADO 開發人員指引
  11. ^ Revisiting the Use of ADO in .NET Applications
  12. ^ A First Look at ObjectSpaces in Visual Studio 2005

相關條目[编辑]