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 Server和Oracle驱动程序),如此琳琅满目重叠性又高的技术群,让企业与开发人员在选择、学习与应用上产生了很多的困难。同时适逢 COM与OLE的发展,微软将数据访问的内核开始改写为以COM为主的OLE DB,并且在它上面创建一个新的数据访问模型-ADO。
ADO推出后顺利的取代了DAO和RDO,成为在Windows NT 4.0和Windows 2000操作系统上开发数据库应用程序的首选,除了它将对象模型统一化,改由数据库厂商发展数据提供者(data provider,这个模式在此时奠基),而ADO本身则是与数据来源无关 (data source independent) 的开发方法,让它迅速的获得了使用ASP与Visual Basic开发人员的青睐,也是它能够顺利取代DAO与RDO等模型的主要关键。然而ADO本身的架构仍然有缺陷(尤其是在开发网络应用程序时,最好的例子就是Recordset无法脱机),这也是微软为何不在.NET Framework中继续使用ADO的主要原因,在1998年时,微软提出了一个下一代的应用程序开发幀架 (Application Framework) 的计划[1],计划中包含了:
ADO+即为Storage+的一支。
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],这两个部分是相辅相成的,同时依照接口的不同,分为:
若没办法连接到数据库,则无法被称为数据访问组件。连接数据来源便是用来连接数据库(或是具有 OLE DB 数据来源提供者)的对象类[6],由下列类所构成:
Open()/Close():打开与关闭数据库连接。BeginTransaction():激活数据库交易,并回传一个 IDbTransaction 对象,以控制交易的结果。ExecuteNonQuery():运行不回传结果集的数据库指令,像是INSERT、UPDATE与DELETE指令。ExecuteScalar():运行指令并回传第一列第一行中的数据。ExecuteReader():运行指令并回传 IDataReader 对象,以读取数据集中的数据。Commit():认可数据库交易。Rollback():撤销数据库交易。Fill():將資料填入離線型資料物件。Update():将变更过的脱机型数据对象中的数据写回数据库。IDbDataAdapter内部也是由它来读取数据。
Read():读取下一列,开发人员利用此方法移动数据集中的光标,若数据集中的数据列已读取完毕时,传回 false。IDataReader 读取数据后实际装载数据列的对象,提供方法来读取数据行中的数据,以及转换成.NET Framework本地型别的工具。
GetOrdinal():取得指定数据行的字段索引值。IsDBNull():判断指定字段的数据是否为NULL值。使用连接数据来源需要由开发人员自我管理连接,并且直接操作数据访问的相关细节,但它的优点是速度快,而且可以自定义整个数据访问流程的逻辑。
脱机数据模型是微软为了改良ADO在网络应用程序中的缺陷所设计的,同时它也是COM+中,IMDB技术的设计概念的实现品,但它并没有完整的IMDB功能,像是交易处理 (transaction processing),但它仍不失为一个能在脱机状态下处理数据的好帮手,它也可以通过连接数据来源对象,支持将脱机数据存回数据库的能力[7]。脱机数据模型由下列对象组成:
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():撤销所有数据的修改。Copy():将 DataTable 复制出一个副本,包含结构与数据。Merge():将两个 DataTable 合并。Select():以指定的特殊查询语法,传回符合条件的 DataRow 数组。Compute():以指定的汇总语法,传回汇总的结果。GetErrors():传回有错误的 DataRow 数组。HasErrors:判断 DataTable 中的 DataRow 有没有含有错误的 DataRow。IsNull():判断指定的字段是否为 NULL 值。ItemArray:将 DataRow 中的数据转换成数组。Filter:设置 DataView 的过滤条件。Sort:设置 DataView 的排序条件。ToTable():将套用过滤与排序后的属性转换为 DataTable 对象。ForeignKeyConstraint 为外部键限制,而 UniqueConstraint 则确保了字段中的值都是唯一的。DataSet和DataTable除了数据库的处理以外,也经常被用来管理应用程序中的数据,并且由于它可以存储在 XML 中的特性,也让它可以用来存储需要保存的应用程序信息。
在 .NET Framework中,ADO.NET默认提供了四种数据来源:
其他厂商亦为不同的数据库提供数据来源:
在.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 在 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 指令,自动产生对应的 INSERT、UPDATE 与 DELETE 指令,但一开始它并不会自动产生,而是要靠调用方法来取得:
DbCommandBuilder.GetInsertCommand()DbCommandBuilder.GetUpdateCommand()DbCommandBuilder.GetDeleteCommand()最常使用到的地方是和 DataAdapter 并用时,但它要求传入的 SELECT 语句所选择的列集合中必须要有主键或者唯一键[8],否则无法产生,同时自动产生的指令因为判断条件很多,对性能可能会有些影响。
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 的开发人员来说,最明显的变化在于以往 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的内核组件而来。
长久以来,程序设计师和数据库总是保持着一种微妙的关系,在商用应用程序中,数据库一定是不可或缺的组件,这让程序设计师一定要为了连接与访问数据库而去学习 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 端点数据服务的数据供应层,即为 ADO.NET Data Services。
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
stock | retire | vm
Why are we here?
All text is available under the terms of the GNU Free Documentation License
This page is cache of Wikipedia. History