ADO.NET

ADO.NET是微软在.NET Framework中负责资料存取的类别库集，它是使用在COM时代奠基的OLE DB技术以及.NET Framework的类别库和程式语言来发展的，它可以让.NET上的任何程式语言能够连接并存取关联式资料库与非资料库型资料来源（例如XML，Excel或是文字档资料），或是独立出来作为处理应用程式资料的类别物件，其在.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技术等等，技术虽然多，但是却又各自为政，而且每个技术的重叠性也很高（像是ODBC有Microsoft Access的驱动程式）；RDO虽然可跨网路，但是ODBC的驱动程式中也有提供跨网路的功能（像是SQL Server和Oracle驱动程式），如此琳琅满目重叠性又高的技术群，让企业与开发人员在选择、学习与应用上产生了很多的困难。
1996年，适逢COM的出现，微软将资料存取的核心开始改写为以COM为基础的OLE DB，并且在它上面建立一个新的统一的资料存取的高层对象模型－ADO。ADO推出后顺利的取代了DAO和RDO，成为在Windows NT 4.0和Windows 2000作业系统上开发资料库应用程式的首选。它将OLE DB的物件模型进一步简化；由资料库厂商开发满足OLE DB接口的资料提供者（data provider，这个模式在此时奠基），而ADO本身则是与资料来源无关（data source independent）的对象结构，让它迅速的获得了使用ASP、Visual Basic、COM的开发人员的青睐。它能够顺利取代DAO与RDO，要关键在于ADO的与数据库服务器端/客户端的特性无关，这使得ADO通用性极好。然而ADO本身的架构仍然有缺陷（尤其是在开发网路应用程式时，最好的例子就是Recordset无法离线），这也是微软为何不在.NET Framework中继续使用ADO的主要原因。
1998年时，微软提出了一个下一代的应用程式开发框架（Application Framework）的计划，计划中包含了：
ADO+即为Storage+的一支。
ADO.NET的前身：ADO+.
1998年起，因为Web应用程式的窜起，大大改变了许多应用程式的设计方式，传统的资料库连线保存设计法无法适用于此类应用程式，这让ADO应用程式遇到了很大的瓶颈，也让微软开始思考让资料集（Resultset，在ADO中称为Recordset）能够离线化的能力，以及能在用户端建立一个小型资料库的概念，这个概念就是ADO.NET中离线型资料模型（disconnected data model）的基础，而在ADO的使用情形来看，资料库连线以及资源耗用的情形较严重（像是Server-side cursor或是Recordset.Open会保持连线状态），在ADO.NET中也改良了这些物件，构成了能够减少资料库连线和资源使用量的功能。XML的使用也是这个版本的重要发展之一。
2000年，微软的Microsoft .NET计划开始成形，许多的微软产品都冠上.NET的标签，ADO+也不例外，改名为ADO.NET，并包装到.NET Framework类别库中，成为.NET平台中唯一的资料存取元件。
架构.
ADO.NET由连线资料来源（connected data source）以及离线资料模型（disconnected data model）两个部份构成，这两个部份是相辅相成的。
连线资料来源.
若没办法连线到资料库，则无法被称为资料存取元件。连线资料来源便是用来连接资料库（或是具有OLE DB资料来源提供者）的物件类别，由下列接口构成：
使用连线资料来源需要由开发人员自我管理连线，并且直接操作资料存取的相关细节，但它的优点是速度快，而且可以自订整个资料存取流程的逻辑。
ADO.NET资料提供者(Data Provider).
在.NET Framework中，ADO.NET预设提供了四种资料来源：
其他厂商亦为不同的资料库提供资料来源：
对每种Data Provider，ADO.NET要实现下述对象结构：
例如，对于SQL Server数据源：
<syntaxhighlight lang="C#">
strSQL = "SELECT * FROM users WHERE Name = @Name and Password = @Password";
SqlParamter[] paras = new SqlParamter[]{//参数数组
paras.value = userName;//绑定用户名
paras.value = password;//绑定用户密码
</syntaxhighlight>
离线资料模型.
离线资料模型是微软为了改良ADO在网路应用程式中的缺陷所设计的，同时它也是COM+中，IMDB技术的设计概念的实作品，但它并没有完整的IMDB功能，像是交易处理（transaction processing），但它仍不失为一个能在离线状态下处理资料的好帮手，它也可以透过连线资料来源物件，支援将离线资料存回资料库的能力。离线资料模型由下列物件组成：
DataSet和DataTable除了资料库的处理以外，也经常被用来管理应用程式中的资料，并且由于它可以储存在XML中的特性，也让它可以用来储存需要保存的应用程式资讯。DataSet中可包含DataRelation对象，用于建构表之间的约束关系。
工厂方法.
在.NET Framework 1.x的时代，ADO.NET不同的来源有不同的类别搭配（前面已述及），但是若想要在不同的资料来源间搭配，那么势必要产生很多的变数来存放不同的资料物件，因此微软在.NET Framework 2.0中提供了一个codice_45命名空间，其中有各种必要物件的共用方法（例如连线是codice_46，命令是codice_47，读取器是codice_48，资料配接器是codice_49等），以及codice_50物件，用来总管资料存取的物件。
codice_51则是电脑中所有提供者的总管，开发人员可用codice_52取得各个提供者的Invariant Name，再于呼叫codice_53时传入指定提供者的Invariant Name即可取得codice_50，再利用下列方法取得共用物件：
<syntaxhighlight lang="csharp">
// This example assumes a reference to System.Data.Common.
static DataTable GetProviderFactoryClasses()
</syntaxhighlight>
XML的整合.
XML在ADO.NET中扮演了相当重要的地位，DataSet和DataTable都可以转换成XML或和XML之间交换资料，在DataTable的内部资料的变更记录，可以被输出到一个XML的格式，用来识别变更的情形，这个格式称为DiffGram，而且它可以直接读入DataTable之中（使用DataTable.ReadXml并用XmlReadMode.DiffGram当参数）。一个典型的DiffGram如下：
<syntaxhighlight lang="xml">
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
</diffgr:diffgram>
</syntaxhighlight>
DataSet与DataTable也支援直接读入XML Schema建立结构的能力，以及自行依XML的内容推断（inference）其结构的能力，下列程式码为由XML推断结构的程式：
<syntaxhighlight lang="csharp">
DataSet dataSet = new DataSet();
dataSet.InferXmlSchema9("input_od.xml", new string[] "urn:schemas-microsoft-com:officedata");
</syntaxhighlight>
DataSet和DataTable可以使用XmlDataDocument类别和XML DOM整合在一起，XmlDataDocument的角色就像一个桥接介面，并且作为DataSet和DataTable可使用XPath与XML DOM方式存取的方法。下列程式码即为使用XmlDataDocument和资料库中资料转换为XSLT输出的范例：
<syntaxhighlight lang="csharp">
// Assumes connection is a valid SqlConnection.
connection.Open();
DataSet custDS = new DataSet("CustomerDataSet");
SqlDataAdapter customerAdapter = new SqlDataAdapter(
customerAdapter.Fill(custDS, "Customers");
SqlDataAdapter orderAdapter = new SqlDataAdapter(
orderAdapter.Fill(custDS, "Orders");
connection.Close();
custDS.Relations.Add("CustOrders",
XmlDataDocument xmlDoc = new XmlDataDocument(custDS); 
XslTransform xslTran = new XslTransform();
xslTran.Load("transform.xsl");
XmlTextWriter writer = new XmlTextWriter("xslt_output.html", 
xslTran.Transform(xmlDoc, null, writer);
writer.Close();
</syntaxhighlight>
在.NET Framework中，DataSet被分为两类，一种是不会强制使用特别型态的DataSet，称为Untyped DataSet，使用上较方便，但没有强制的型别限制，另一种则是Typed DataSet，会强制型别，并且是由自订的XML Schema所产生，Untyped DataSet则没有XML Schema，由建立时的结构来决定，Typed DataSet可以用Visual Studio，或者是SDK工具中的xsd.exe来产生。
<syntaxhighlight lang="text">
xsd.exe /d /l:CS XSDSchemaFileName.xsd /eld /n:XSDSchema.Namespace
</syntaxhighlight>
产生出来的Typed DataSet会自动将栏位设定成属性，让开发人员的存取更方便（这个功能在TableAdapter相当常见）。
<syntaxhighlight lang="csharp">
CustomerDataSet customers = new CustomerDataSet();
SqlDataAdapter adapter = new SqlDataAdapter(
adapter.Fill(customers, "Customers");
foreach(CustomerDataSet.CustomersRow customerRow in customers.Customers)
</syntaxhighlight>
指令产生器.
ADO.NET中有专门用来产生资料处理指令的指令产生器（Command Builder），它可以利用开发人员所指定的codice_59指令，自动产生对应的codice_5、codice_6与codice_7指令，但一开始它并不会自动产生，而是要靠呼叫方法来取得：
最常使用到的地方是和DataAdapter并用时，但它要求传入的codice_59语句所选择的列集合中必须要有主键或者唯一键，否则无法产生，同时自动产生的指令因为判断条件很多，对效能可能会有些影响。
Visual Studio的支援.
ADO.NET和Visual Studio开发工具几乎已经是无缝的整合了，开发人员可以利用Visual Studio来建立强型别（strong-typed）的DataSet，到了Visual Studio 2005时更能够在Windows Forms应用程式中使用TableAdapter（Typed DataSet和DataAdapter整合的产物）来开发应用程式（不会再看到DataAdapter，但使用上差不多）。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，这样的改变，让习惯使用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控件中去显示：
<syntaxhighlight lang="vbnet">
</syntaxhighlight>
ADO的RecordSet，相当于在客户机或服务器的一个逻辑上的数据表格，使用者可以通过cursor来定位/读写当前行，但不能重新对这些行重新排序，也不能对客户机上的多个RecordSet数据执行跨表的连接（join）查询。ADO.Net针对上述缺点，在客户机上实现了DataTable与DataSet，这是客户机内存中的一套（多个）数据表格，可以对其执行各种单表或多表的查询、修改、删除操作，既可以使用SQL语句，也可以使用LINQ子语言。
ADO与ADO.Net的共同点，在其内部都是使用SQL语句来对后台数据库操作。
内在实现上，ADO是基于COM技术，因此变体类型（Variant）无处不在，这是一种通用、万能类型；而ADO.Net是强类型的，并很好地支持数据库元数据与XML功能。
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完成时仍无法全部完成，因此微软将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。