ADO.Net

出自Windows

(修订版本间差异)
跳转到: 导航, 搜索

Nothing (对话 | 贡献)
(新页面: '''ADO.NET'''是微软在.NET Framework中负责数据存取的类别库集,它是使用在COM时代奠基的OLE DB技术以及.NET Framework的类别库和程序语言...)
下一个→

在2009年1月20日 (二) 06:17所做的修订版本

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) 的计划,计划中包含了:

  • 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) 能够脱机化的能力,以及能在客户端建立一个小型数据库的概念ed data model) 的基础,而在ADO的使用情形来看,数据库联机以及资源耗用的情形较严重(像是 Server-side cursor 或是 Recordset.Open 会保持联机状态),在ADO.NET中也改良了这些对象,构成了能够减少数据库联机和资源使用量的功能。XML的使用也是这个版本的重要发展之一。

2001年,微软的Microsoft .NET计划开始成形,许多的微软产品都冠上.NET的标签,ADO+也不例外,改名为ADO.NET,并包装到.NET Framework类别库中,成为.NET平台中唯一的数据存取组件。

架构

ADO.NET 由联机数据源 (connected data source) 以及脱机数据模型 (disconnected data model) 两个部份构成,这两个部份是相辅相成的,同时依照接口的不同,分为:

  • SQL Server 原生数据源-System.Data.SqlClient (以 Sql 为前缀的类别群)。
  • OLE DB 数据源-System.Data.OleDb (以 OleDb 为前缀的类别群)。
  • Oracle 数据源-System.Data.OracleClient (以 Oracle 为前缀的类别群)。
  • ODBC 数据源-System.Data.Odbc (以 Odbc 为前缀的类别群)。

联机数据源

若没办法联机到数据库,则无法被称为数据存取组件。联机数据源便是用来连接数据库(或是具有 OLE DB 数据源提供者)的对象类别,由下列类别所构成:

  • 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():将数据填入脱机型数据对象。
    • <code>Update():将变更过的脱机型数据对象中的数据写回数据库。
  • IDataReader,建立一个只可向前读取光标 (forward-only) 的数据读取器工具,以逐列读取方式存取数据,IDbDataAdapter内部也是由它来读取数据。
    • Read():读取下一列,开发人员利用此方法移动数据集中的光标,若数据集中的数据列已读取完毕时,传回 false
  • IDataRecord,在 IDataReader 读取数据后实际装载数据列的对象,提供方法来读取数据行中的数据,以及转换成.NET Framework原生型别的工具。
    • GetOrdinal():取得指定数据行的字段索引值。
    • IsDBNull():判断指定字段的数据是否为NULL值

使用联机数据源需要由开发人员自我管理联机,并且直接操作数据存取的相关细节,但它的优点是速度快,而且可以自定义整个数据存取流程的逻辑。

脱机数据模型

脱机数据模型是微软为了改良ADO在网络应用程序中的缺陷所设计的,同时它也是COM+中,IMDB技术的设计概念的实作品,但它并没有完整的IMDB功能,像是事务处理 (transaction processing),但它仍不失为一个能在脱机状态下处理数据的好帮手,它也可以透过联机数据源对象,支持将脱机数据存回数据库的能力。脱机数据模型由下列对象组成:

  • 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()

<source lang="csharp"> // 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;

} </source>

XML的整合

XML 在 ADO.NET 中扮演了相当重要的地位,DataSet 和 DataTable 都可以转换成 XML 或和 XML 之间交换资料,在 DataTable 的内部数据的变更记录,可以被输出到一个 XML 的格式,用来识别变更的情形,这个格式称为 DiffGram,而且它可以直接读入 DataTable 之中(使用 DataTable.ReadXml() 并用 XmlReadMode.DiffGram 当参数)。一个典型的 DiffGram 如下:

<source lang="xml"> <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> </source>

DataSet与DataTable也支持直接读入XML Schema建立结构的能力,以及自行依XML的内容推断 (inference) 其结构的能力,下列程序代码为由XML推断结构的程序:

<source lang="csharp"> DataSet dataSet = new DataSet(); dataSet.InferXmlSchema("input_od.xml", new string[] "urn:schemas-microsoft-com:officedata"); </source>

DataSet和DataTable可以使用XmlDataDocument类别和XML DOM整合在一起,XmlDataDocument的角色就像一个桥接接口,并且作为DataSet和DataTable可使用XPath与 XML DOM 方式存取的方法。下列程序代码即为使用XmlDataDocument和数据库中数据转换为XSLT输出的范例:

<source lang="csharp"> // 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(); </source>

在.NET Framework中,DataSet被分为两类,一种是不会强制使用特别型态的DataSet,称为Untyped DataSet,使用上较方便,但没有强制的型别限制,另一种则是Typed DataSet,会强制型别,并且是由自定义的XML Schema所产生,Untyped DataSet则没有XML Schema,由建立时的结构来决定,Typed DataSet可以用Visual Studio,或者是 SDK 工具中的xsd.exe来产生。

<source lang="text"> xsd.exe /d /l:CS XSDSchemaFileName.xsd /eld /n:XSDSchema.Namespace </source>

产生出来的 Typed DataSet 会自动将字段设定成属性,让开发人员的存取更方便(这个功能在 TableAdapter 相当常见)。

<source lang="csharp"> 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);

</source>

指令产生器

ADO.NET 中有专门用来产生数据处理指令的指令产生器 (Command Builder),它可以利用开发人员所指定的 SELECT 指令,自动产生对应的 INSERTUPDATEDELETE 指令,但一开始它并不会自动产生,而是要靠呼叫方法来取得:

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

最常使用到的地方是和 DataAdapter 并用时,但它要求传入的 SELECT 指令必须要有键值,否则无法产生,同时自动产生的指令因为判断条件很多,对效能可能会有些伤害。

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会因为要多一层COM和.NET数据之间的转换,会让应用程序效能有少部分的损耗。

ADO.NET 的进化

随着网络应用程序的进化,ADO.NET也随之做了许多的改变,但不变的是,ADO.NET的基础提供了强固的发展支持,这些进化的技术都是植基于ADO.NET的核心组件而来。

Template:Main

长久以来,程序设计师和数据库总是保持着一种微妙的关系,在商用应用程序中,数据库一定是不可或缺的组件,这让程序设计师一定要为了连接与存取数据库而去学习 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),让数据存取的工作得以顺利与完整的进行。

Template:Main

以往在发展像是 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。

个人工具
友情链接