ADO.NET

ADO.NET是微軟在.NET Framework中負責資料存取的類別庫集，它是使用在COM時代奠基的OLE DB技術以及.NET Framework的類別庫和程式語言來發展的，它可以讓.NET上的任何程式語言能夠連線並存取關聯式資料庫與非資料庫型資料或是獨立出來作為處理應用程式資料的類別物件，其在.NET Framework中的地位是舉足輕重，許多人將ADO.NET視為 ActiveX Data Objects (ADO) 的下一個版本，但其實它是一個全新的架構、產品與概念。ADO.NET類封裝在System.Data.dll中，並且與System.Xml.dll中的XML類整合。歷史.發展緣起.在1990年代初期，微軟已經開發了許多的資料存取方式，像是ODBC架構、和Microsoft Access資料庫互動使用的DAO物件、可以跨越網路存取資料的以及讓DAO元件可以存取ODBC資料ODBCDirect技術等等，技術雖然多，但是卻又各自為政，而且每個技術的重疊性也很高，如此琳琅滿目重疊性又高的技術群，讓企業與開發人員在選擇、學習與應用上產生了很多的困難。1996年，適逢COM的出現，微軟將資料存取的核心開始改寫為以COM為基礎的OLE DB，並且在它上面建立一個新的統一的資料存取的高層物件模型－ADO。ADO推出後順利的取代了DAO和RDO，成為在Windows NT 4.0和Windows 2000作業系統上開發資料庫應用程式的首選。它將OLE DB的物件模型進一步簡化；由資料庫廠商開發滿足OLE DB介面的資料提供者，這也是微軟為何不在.NET Framework中繼續使用ADO的主要原因。1998年時，微軟提出了一個下一代的應用程式開發框架的計畫，計畫中包含了：ADO+即為Storage+的一支。ADO.NET的前身：ADO+.1998年起，因為Web應用程式的竄起，大大改變了許多應用程式的設計方式，傳統的資料庫連線儲存設計法無法適用於此類應用程式，這讓ADO應用程式遇到了很大的瓶頸，也讓微軟開始思考讓資料集，在ADO.NET中也改良了這些物件，構成了能夠減少資料庫連線和資源使用量的功能。XML的使用也是這個版本的重要發展之一。2000年，微軟的Microsoft .NET計畫開始成形，許多的微軟產品都冠上.NET的標籤，ADO+也不例外，改名為ADO.NET，並包裝到.NET Framework類別庫中，成為.NET平臺中唯一的資料存取元件。架構.ADO.NET由連線資料個部份構成，這兩個部份是相輔相成的。連線資料若沒辦法連線到資料庫，則無法被稱為資料存取元件。連線資料是用來連線資料庫的物件類別，由下列介面構成：使用連線資料要由開發人員自我管理連線，並且直接操作資料存取的相關細節，但它的優點是速度快，而且可以自訂整個資料存取流程的邏輯。ADO.NET資料提供者(Data Provider).在.NET Framework中，ADO.NET預設提供了四種資料其他廠商亦為不同的資料庫提供資料對每種Data Provider，ADO.NET要實現下述物件結構：例如，對於SQL Server資料strSQL = "SELECT * FROM users WHERE Name = @Name and Password = @Password";SqlParamter[] paras = new SqlParamter[]{//引數陣列new SqlParamter("@Name",SqlDBType.Varchar,50)new SqlParamter("@Password",SqlDBType.Varchar,50)};paras[0].value = userName;//繫結使用者名稱paras[1].value = password;//繫結使用者密碼離線資料模型.離線資料模型是微軟為了改良ADO在網路應用程式中的缺陷所設計的，同時它也是COM+中，IMDB技術的設計概念的實作品，但它並沒有完整的IMDB功能，像是交易處理，但它仍不失為一個能在離線狀態下處理資料的好幫手，它也可以透過連線資料件，支援將離線資料存回資料庫的能力。離線資料模型由下列物件組成：DataSet和DataTable除了資料庫的處理以外，也經常被用來管理應用程式中的資料，並且由於它可以儲存在XML中的特性，也讓它可以用來儲存需要儲存的應用程式資訊。DataSet中可包含DataRelation物件，用於建構表之間的約束關係。工廠方法.在.NET Framework 1.x的時代，ADO.NET不同的不同的類別搭配，以及codice_50物件，用來總管資料存取的物件。codice_51則是電腦中所有提供者的總管，開發人員可用codice_52取得各個提供者的Invariant Name，再於呼叫codice_53時傳入指定提供者的Invariant Name即可取得codice_50，再利用下列方法取得共用物件：// 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之中。一個典型的DiffGram如下：DataSet與DataTable也支援直接讀入XML Schema建立結構的能力，以及自行依XML的內容推斷其結構的能力，下列程式碼為由XML推斷結構的程式：DataSet dataSet = new DataSet();dataSet.InferXmlSchema9("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會自動將欄位設定成屬性，讓開發人員的存取更方便。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中有專門用來產生資料處理指令的指令產生器，它可以利用開發人員所指定的codice_59指令，自動產生對應的codice_5、codice_6與codice_7指令，但一開始它並不會自動產生，而是要靠呼叫方法來取得：最常使用到的地方是和DataAdapter並用時，但它要求傳入的codice_59語句所選擇的列集合中必須要有主鍵或者唯一鍵，否則無法產生，同時自動產生的指令因為判斷條件很多，對效能可能會有些影響。Visual Studio的支援.ADO.NET和Visual Studio開發工具幾乎已經是無縫的整合了，開發人員可以利用Visual Studio來建立強型別來讓開發人員以簡單的設定方式來建立DataSet，部分開發人員也將TableAdapter和ASP.NET應用程式的ObjectDataSource控制項並用，亦得到不錯的效果。在.NET Framework 3.5中，微軟特別為了DataSet和DataTable建立了LINQ Provider得以繼續使用並享有LINQ的便利性。ADO.NET和ADO的差異.對於ADO的開發人員來說，最明顯的變化在於以往ADO中的Recordset消失了，並且明確的分開為連線型的DataReader以及離線型的DataSet與DataTable，並且發展支援離線型資料瀏覽工具DataView，這樣的改變，讓習慣使用ADO的VB/ASP開發人員會有某種程度的不習慣，同時讓ADO.NET的學習會較ADO有較些許的複雜性，因此有部分新入門或是VB 6.0/ASP開發人員會在學習.NET Framework或是使用VB.NET開發應用程式時，在.NET Framework中使用ADO來連線資料但在.NET Framework應用程式使用ADO的話，.NET Framework會因為要多一層ADO的COM與VB.NET使用的.NET之間的資料轉換，會讓應用程式效能有少部分的損耗。下述示例，用ADO讀取一個數據庫中的表格，然後轉為ADO.Net的資料，最後繫結到DataGridView控制元件中去顯示：Dim cn As ADODB.ConnectionDim rs As ADODB.Recordsetcn = New ADODB.Connectionrs = New ADODB.Recordsetcn.Provider = "Microsoft.ACE.OLEDB.12.0;"cn.ConnectionString = "D:\\budget2016.accdb;"cn.Open()'check whether the serial num exists in table cutterDim sSQL As String = "SELECT * FROM tPassword"rs.CursorLocation = ADODB.CursorLocationEnum.adUseClientrs.Open(sSQL, cn, ADODB.CursorTypeEnum.adOpenKeyset, ADODB.LockTypeEnum.adLockReadOnly,_ADODB.CommandTypeEnum.adCmdText)Dim da As New System.Data.OleDb.OleDbDataAdapter()Dim ds As New DataSet()da.Fill(ds, rs, "tPassword")'rs.Close() 'Cannot closers.ActiveConnection = Nothingcn.Close()rs = Nothingcn = NothingDataGridView1.DataSource = (ds.Tables("tPassword"))ADO的RecordSet，相當於在客戶機或伺服器的一個邏輯上的資料表格，使用者可以透過cursor來定位/讀寫當前行，但不能重新對這些行重新排序，也不能對客戶機上的多個RecordSet資料執行跨表的連線資料表格，可以對其執行各種單表或多表的查詢、修改、刪除操作，既可以使用SQL語句，也可以使用LINQ子語言。ADO與ADO.Net的共同點，在其內部都是使用SQL語句來對後臺資料庫操作。內在實現上，ADO是基於COM技術，因此變體型別無處不在，這是一種通用、萬能型別；而ADO.Net是強型別的，並很好地支援資料庫元資料與XML功能。ADO.NET的進化.隨著網路應用程式的進化，ADO.NET也隨之做了許多的改變，但不變的是，ADO.NET的基礎提供了強固的發展支援，這些進化的技術都是植基於ADO.NET的核心元件而來。長久以來，程式設計師和資料庫總是保持著一種微妙的關係，在商用應用程式中，資料庫一定是不可或缺的元件，這讓程式設計師一定要為了連線與存取資料庫而去學習SQL指令，因此在資訊業中有很多人都在研究如何將程式設計模型和資料庫整合在一起，物件關聯對應，構成了現在的ADO.NET Entity Framework。Entity Framework利用了抽象化資料結構的方式，將每個資料庫物件都轉換成應用程式物件，讓資料存取的工作得以順利與完整的進行。以往在發展像是AJAX應用程式時，伺服端總是需要設計一個HTTP介面埠資料撰寫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。