ADO[转]

 
古城
@ 2007.11.24
分类:技术笔记
点击:3641  评论:0
 
 
 
微软公司的ADO (ActiveX Data Objects) 是一个用于存取数据源的COM组件。它提供了编程语言和统一数据访问方式OLE DB的一个中间层。允许开发人员编写访问数据的代码而不用关心数据库是如何实现的,而只用关心到数据库的连接。访问数据库的时候,关于SQL的知识不是必要的,但是特定数据库支持的SQL命令仍可以通过ADO中的命令对象来执行。 

ADO被设计来继承微软早期的数据访问对象层,包括RDO (Remote Data Objects) 和DAO(Data Access Objects)。ADO在1996年冬被发布。 

ADO包含一些顶层的对象: 

连接,代表到数据库的连接 
记录集,代表数据库记录的一个集合 
命令,代表一个SQL命令 
记录,代表数据的一个集合 
流,代表数据的顺序集合 
错误,代表数据库访问中产生的意外 
字段,代表一个数据库字段 
参数,代表一个SQL参数 
属性,保存对象的信息 
ADO组件的使用需要利用支持COM的高级语言,例如ASP中的VBScript或者Visual Basic,甚至Delphi,微软的竞争对手Borland的一个产品,现在也支持使用ADO来访问数据库。 

在新的编程框架.NET Framework中, 微软也提供了一个面向Internet的版本的ADO,称为ADO.NET。其对象模型和传统ADO差别很大。 ADO是一种面向对象的编程接口,微软介绍说,与其同IBM和Oracle提倡的那样,创建一个统一数据库,不如提供一个能够访问不同数据库的统一接口,这样会更加实用一些。为实现这一目标,微软在数据库和微软的OLE DB中提供了一种“桥”程序,这种程序能够提供对数据库的连接。  开发人员在使用ADO时,其实就是在使用OLE DB,不过OLE DB更加接近底层。ADO的一项属性远程数据服务,支持“数据仓库”ActiveX 组件以及高效的客户端缓存。作为ActiveX的一部分,ADO也是COM组件的一部分。ADO是由早期的微软数据接口??远程数据对象RDO演化而来的。RDO同微软的ODBC一同连接关系数据库,不过不能连接非关系数据库。 

ADO向我们提供了一个熟悉的,高层的对OLE DB的Automation封装接口。对那些熟悉RDO的程序员来说,你可以把OLE DB比作是ODBC驱动程序。如同RDO对象是ODBC驱动程序接口一样,ADO对象是OLE DB的接口;如同不同的数据库系统需要它们自己的ODBC驱动程序一样,不同的数据源要求它们自己的OLE DB提供者(OLE DB provider)。目前,虽然OLE DB提供者比较少,但微软正积极推广该技术,并打算用OLE DB取代ODBC。 

ADO向VB程序员提供了很多好处。包括易于使用,熟悉的界面,高速度以及较低的内存占用(已实现ADO2.0的Msado15.dll需要占用342K内存,比RDO的Msrdo20.dll的368K略小,大约是DAO3.5的Dao350.dll所占内存的60%)。同传统的数据对象层次(DAO和RDO)不同,ADO可以独立创建。因此你可以只创建一个"Connection"对象,但是可以有多个,独立的"Recordset"对象来使用它。ADO针对客户/服务器以及WEB应用程序作了优化。



-----------------------------------------------------------------------------------------------------------

ADO (ActiveX Data Objects,ActiveX数据对象)是Microsoft提出的应用程序接口(API)用以实现访问关系或非关系数据库中的数据。例如,如果您希望编写应用程序从DB2或Oracle数据库中向网页提供数据,可以将ADO程序包括在作为活动服务器页(ASP)的HTML文件中。当用户从网站请求网页时,返回的网页也包括了数据中的相应数据,这些是由于使用了ADO代码的结果。

象Microsoft的其它系统接口一样,ADO是面向对象的。它是Microsoft全局数据访问(UDA)的一部分,Microsoft认为与其自己创建一个数据,不如利用UDA访问已有的数据库。为达到这一目的,Microsoft和其它数据库公司在它们的数据库和Microsoft的OLE数据库之间提供了一个“桥”程序,OLE数据库已经在使用ADO技术。ADO的一个特征(称为远程数据服务)支持网页中的数据相关的ActiveX控件和有效的客户端缓冲。作为ActiveX的一部分,ADO也是Microsoft的组件对象模式(COM)的一部分,它的面向组件的框架用以将程序组装在一起。

ADO从原来的Microsoft数据接口远程数据对象(RDO)而来。RDO与ODBC一起工作访问关系数据库,但不能访问如ISAM和VSAM的非关系数据库。

  ADO 是对当前微软所支持的数据库进行操作的最有效和最简单直接的方法,它是一种功能强大的数据访问编程模式,从而使得大部分数据源可编程的属性得以直接扩展到你的Active Server 页面上。可以使用ADO 去编写紧凑简明的脚本以便连接到 Open Database Connectivity (ODBC) 兼容的数据库和 OLE DB 兼容的数据源,这样 ASP 程序员就可以访问任何与 ODBC 兼容的数据库,包括 MS SQL SERVER、Access、 Oracle 等等。

  比如,如果网站开发人员需要让用户通过访问网页来获得存在于IBM DB2或者Oracle数据库中的数据,那么就可以在ASP页面中包含ADO程序,用来连接数据库。于是,当用户在网站上浏览网页时,返回的网页将会包含从数据库中获取的数据。而这些数据都是由ADO代码做到的。

  ADO是一种面向对象的编程接口,微软介绍说,与其同IBM和Oracle提倡的那样,创建一个统一数据库,不如提供一个能够访问不同数据库的统一接口,这样会更加实用一些。为实现这一目标,微软在数据库和微软的OLE DB中提供了一种“桥”程序,这种程序能够提供对数据库的连接。  开发人员在使用ADO时,其实就是在使用OLE DB,不过OLE DB更加接近底层。ADO的一项属性??远程数据服务,支持“数据仓库”ActiveX 组件以及高效的客户端缓存。作为ActiveX的一部分,ADO也是COM组件的一部分。ADO是由早期的微软数据接口??远程数据对象RDO演化而来的。RDO同微软的ODBC一同连接关系数据库,不过不能连接非关系数据库。

ADO向我们提供了一个熟悉的,高层的对OLE DB的Automation封装接口。对那些熟悉RDO的程序员来说,你可以把OLE DB比作是ODBC驱动程序。如同RDO对象是ODBC驱动程序接口一样,ADO对象是OLE DB的接口;如同不同的数据库系统需要它们自己的ODBC驱动程序一样,不同的数据源要求它们自己的OLE DB提供者(OLE DB provider)。目前,虽然OLE DB提供者比较少,但微软正积极推广该技术,并打算用OLE DB取代ODBC。

ADO向VB程序员提供了很多好处。包括易于使用,熟悉的界面,高速度以及较低的内存占用(已实现ADO2.0的Msado15.dll需要占用342K内存,比RDO的Msrdo20.dll的368K略小,大约是DAO3.5 的Dao350.dll所占内存的60%)。同传统的数据对象层次(DAO和RDO)不同,ADO可以独立创建。因此你可以只创建一个 "Connection"对象,但是可以有多个,独立的"Recordset"对象来使用它。ADO针对客户/服务器以及WEB应用程序作了优化。



一、ADO 对象总结


二、ADO 事件


三、在哪里能得到ADO?


目前ADO1.5版已经可以从微软网站免费下载。到目前为止,微软网站仍是你获取有关ADO最新信息的最佳场所。ADO1.5是作为OLE DB SDK的一部分提供的。你可以从下面这个网址下载:
http://www.microsoft.com/data/oledb/download.htm
在下载之前请先确认OLE DB SDK提供的各项特性。下载文件大约有15M,如果完全安装的话要占用80M的硬盘空间。如果你只对ADO感举趣,就选择最小安装,这样只会占用你15M的硬盘空间。关于ADO的网页在:

http://www.microsoft.com/data/ado/adoinfo.htm.
在这里你可以找到许多关于ADO的示例代码和文章,尤其是在"Workshop"系列的文章中。你也可以从本站下载ADO2.5的帮助文件。

尽管OLE DB SDK提供自己的ADO帮助文件,你会发现ADO1.0的帮助文件更易于使用。同时它还向你提供ADO对象模型的图示


四、ADO是如何组织起来的?


以前的对象模型,如DAO和RDO是层次型的。也就是说一个较低的数据对象如Recordset是几个较高层次的对象,如Environment和QueryDef,的子对象。在创建一个QueryDef对象的实例之前,你不能创建DAO Recordset对象的实例。但ADO却不同,它定义了一组平面型顶级对象.
最重要的三个ADO对象是Connection, Recordset和Command. 本文将主要介绍Connection和Recordset这两个对象。每个Connection的属性定义了与数据源的连接。Recordset对象接收来自数据源的数据。Recordset可以与Connection一起起使用,先建立一个连接,然后获取数据。尽管如此,Recordset也可以被单独创建,其Connection参数可以在Open属性定义。


五、ADO 2.0有什么新特点?


对于ADO1.5以前包括1.5的版本来说,从功能的角度来看RDO和ADO不是完全相等的.等同就意味着你可以通过这两种方法解决同样的问题;它不是指存在重命名的或者优化的功能相同的对象.因此,移植到ADO 不是一个简单的事情.从另一方面来说,一旦你熟练掌握了RDO或DAO技术的话,学习ADO是件相当容易的事情.

ADO 2.0的新特性包括事件处理,记录集的延续,分层目录结构指针和数据成形,分布式事务处理,多维数据,远程数据服务(RDS),以及对C++和Java的支持的增强.在钻研一些Visual Basic代码的时候将会见到所有的这些特性.当使用Visual J++时,我将举例说明新的Windows Foundation Classes(WFC)是如何支持ADO的.ADO的最让人激动的是在Visual Studio 6.0中的任何开发工具中你都可以找到对它的充分的支持.


六、ADO 对象编程模型

连接数据源 (Connection),可选择开始事务。
可选择创建表示 SQL 命令的对象 (Command)。
可选择指定列、表以及 SQL 命令中的值作为变量参数 (Parameter)。
执行命令(Command、Connection 或 Recordset)。
如果命令以行返回,将行存储在存储对象中 (Recordset)。
可选择创建存储对象的视图以便进行排序、筛选和定位数据 (Recordset)。
编辑数据。可以添加、删除或更改行、列 (Recordset)。
在适当情况下,可以使用存储对象中的变更对数据源进行更新 (Recordset)。
在使用事务之后,可以接受或拒绝在事务中所做的更改。结束事务 (Connection)。


七、如何使用ADO?


一旦安装了ADO,在VB的工程->引用对话框中你就可以看到象下图所示的东西了:


选择 "ActiveX Data Objects 1.5 Library" (ADODB).在其下的 "ADO Recordset 1.5 Library"是一个客户端的版本(ADOR),它定义了有聚的数据访问对象。ADOR 对于客户端的数据访问来说是足够的了,因为你不需要Connection对象来建立与远程数据源的联系。

如果你想要访问更多的外部数据源,你需要安装这些外部数据源自己的OLE DB Provider,就象你需要为新的数据库系统安装新的ODBC驱动程序一样。如果该外部数据源没有自己的OLE DB Provider,你就得使用OLE DB SDK来自己为这个外部数据源创建一个OLE DB Provider了。这已不是本文讨论的范围了。

示例

下面的示例代码以Northwinds数据库作为远程数据源,然后用ADO来访问它。首先在控制面板中打开“32位数据源”,单击“添加”按钮。在弹出的对话框中选择 "Microsoft Access Driver (*.mdb)" 作为数据源驱动程序。

然后按下图所示,在对话框中填写下面的内容


选择数据库Northwinds所在路径。单击完成,退出ODBC设备管理器。

启动一个新的VB工程,在窗体的Load事件中输入下面的代码:

Private Sub Form_Load()

Dim cn As ADODB.Connection
Set cn = New ADODB.Connection

'Set Connection properties
cn.ConnectionString = "DSN=RDC Nwind;UID=;PWD=;"
cn.ConnectionTimeout = 30
cn.Open

If cn.State = adStateOpen Then _
MsgBox "Connection to NorthWind Successful!"

cn.Close

End Sub
按F5运行程序,看看,一个消息框弹出来告诉你连接成功了。请注意,这里我特别注明了是ADODB.Connection,而不是ADOR.Connection,这样做是为了将二者区分开(如果你引用了ADODB和ADOR的话,这样做很有必要)。连接字符串看上去同RDO的连接字符串差不多。事实上,二者确实差不多。
如果我们要访问一个SQL server数据库,你的Connection代码看上去应象下面所示:

'设置连接属性cn.Provider = "MSDASQL"
cn.ConnectionString = "driver={SQL Server};" & "server=prod1;uid=bg;pwd=;database=main"
cn.Open

"Provider"属性指向SQL Server的OLE DB Provider.
回到我们的示例程序,让我们创建一个Recordset对象来访问“Orders”表,并从该表的"ShipCountry"字段中产生头十个不重复的国家名。修改窗体Load事件中的代码,让它看上去象下面这样。

Private Sub Form_Load()

Dim cn As ADODB.Connection
Dim rs As ADODB.Recordset

Dim sSQL As String
Dim sOut As String
Dim Count As Integer

Set cn = New ADODB.Connection
Set rs = New ADODB.Recordset

' Set properties of the Connection.
cn.ConnectionString = "DSN=RDC Nwind;UID=;PWD=;"
cn.ConnectionTimeout = 30
cn.Open

If cn.State = adStateOpen Then _
MsgBox "Connection to NorthWind Successful!"

sSQL = "SELECT DISTINCT Orders.ShipCountry FROM Orders"
Set rs = cn.Execute(sSQL)

'Enumerate the recordset
sOut = ""
For Count = 1 To 10
sOut = sOut & rs("ShipCountry") & vbCrLf
rs.MoveNext
Next Count

MsgBox sOut, vbExclamation, "ADO Results"
cn.Close

End Sub
运行程序后,你会看到如下图所示的消息框。


不幸的是,目前这个Recrodset对象是只读的和forward cursor。如果你想要获取更多的功能,你需要创建一个独立的Recordset对象,该对象拥有自己的Connection属性,就象下面的代码所示:

Private Sub Form_Load()

Dim rs As ADODB.Recordset

Dim sSQL As String
Dim sOut As String
Dim Count As Integer

Set rs = New ADODB.Recordset

sSQL = "SELECT DISTINCT Orders.ShipCountry FROM Orders"

rs.Open sSQL, "DSN=RDC Nwind;UID=;PWD=;", adOpenDynamic

'Report Recordset Connection information
MsgBox rs.ActiveConnection, , "Connection Info"

'Enumerate the recordset
sOut = ""
For Count = 1 To 10
sOut = sOut & rs("ShipCountry") & vbCrLf
rs.MoveNext
Next Count

MsgBox sOut, vbExclamation, "ADO Results"

rs.Close

End Sub
上面代码返回的结果同前例一样,但是本代码中的Recordset是独立的。这一点是DAO和RDO做不到的。Recordset对象的Open方法打开一个代表从SQL查询返回的记录的游标。虽然你可以用Connection对象同远程数据源建立连接,但请记住,在这种情况下,Connection对象和Recordset对象是平行的关系。
总结
本文仅向你介绍了ADO强大的功能的冰山一角。微软承诺,在将来ADO将会取代DAO和RDO。所以现在你应该考虑如何将你的数据访问代码投向ADO的怀抱。这种转变不会很痛苦,因为ADO的语法同现有的语法差不多。也许微软或第三方会在将来开发出转换向导来简化这一转换过程。从现在起,你就应开发纯ADO代码的程序。你也可以继续使用DAO或RDO代码来开发你的程序,但落伍的感觉总是不好的。

八、ADO编程应用
 

  ADO(ActiveX Data Objects)是基于组件的数据库编程接口,它是一个和编程语言无关的COM组件系统。本文主要介绍用ADO编程所需要注意的技巧和在VC下进行ADO 编程的模式,并对C++Extensions进行了简单的讨论,希望对ADO开发人员有一定的帮助作用。因为ADO是一个和编程语言无关的COM组件系统,所以这里讨论的要点适用于所有的编程语言和编程环境,比如:VB、VBScript、VC、Java等等。


编程技巧


1.显式定义对象类型

实际上,这条准则不仅适用于ADO编程,也适用于其他的与COM对象相关的编程。因为如果一开始就定义变量类型,则编译器在编译的时候就可以知道变量的类型,此时编译器实际上是采用vtable偏移的方式来得到具体的COM对象包含的方法的地址(这一点和 C++中虚函数的地址获取方式类似);但如果一开始不指定变量类型的话,比如简单地采用如下的语句:

DIM myCon as Object

或者是:

DIM myCon

这样,编译器在编译的时候就不能得到变量的类型,而只能在运行的时候动态地得到方法的信息(通过使用接口IDispatch的Invoke方法来实现),如此为了得到方法的地址和相关的变量情况就需要在内部进行两次调用,无疑会降低程序的运行速度。

2.绑定列到具体的字段对象

在程序开始时就建立对字段对象的引用,可以避免在每次得到记录后,再在Recordset::Fields中进行查找而增加系统的开销。

例如,可以采用如下所示的代码:

Private Sub TblBrowse_Click()

Dim fld1 As ADODB.Field

Dim fld2 As ADODB.Field

Dim rs As ADODB.Recordset

set rs=g_cn.execute(...)

'g_cn为全局对象adodb.connection

Set fld1 = rs.Fields(“id”) '数据表的字段

Set fld2 = rs.Fields(“name”) ’数据表的字段

If rs.BOF = False Then

While rs.BOF = False

Debug.Print fld1.Value

Debug.Print fld2.Value

rs.MoveNext

Wend

End If

rs.Close

End Sub

3.用SQL语句和存储过程进行数据更新

尽管采用Recordset对象来更新数据是非常方便的,但是它的开销也大,通过数据源对象返回的查询集不仅包含了数据,而且也包含了元数据(metadata), 在有些时候元数据可能比数据本身还要大,所以最好采用SQL语句来更新数据。还有要使用存储过程而不是单一的SQL语句来获取信息。因为存储过程是在服务器端执行的,只把结果返回到客户端,这样一方面可以降低网络进行数据交互的开销,另一方面使系统更加容易维护,并且能保持数据的一致性。

4.使用集合操作单条的SELECT语句

在使用游标时,最好使用集合的方法对单条的SELECT语句进行操作。Recordset:: get_Collect方法和Recordset::put_Collect方法是Recordset 对象的快捷方式,可以快速地得到一个字段的值而不需要获得关于一个字段的引用。例如,可以采用如下代码:

Sub Collect()

Dim rs As New Recordset

rs.ActiveConnection = “...”

rs.Source=“一条SQL查询语句”

rs.Open

Debug.Print rs.Collect(0),rs.Collect(1),rs.Collect(2)

Debug.Print rs!au_id, rs!au_fname, rs!au_lname

End Sub

5.只查询所需要的数据

尽管很多开发人员都习惯采用“SELECT * FROM TBL”的模式进行查询,但是为了提高系统的效率,如果只需要其中某几个字段的值,最好把这几个字段直接写出来,同时需要限定返回记录集的范围(通过WHERE子句进行限定)。

6.正确选择游标的位置、类型和锁方式

如果只需要按顺序读取记录并且不需要滚动和更新记录,最好使用服务器端游标(adUseServer)、仅向前游标(adOpenForwardOnly)和读加锁(adLockReadOnly),这样可以获得最好的性能。如果需要滚动记录,采用客户端游标(adUseServer)会比采用服务器端游标所得到的性能要好,因为ADO系统默认是采用服务器端游标类型。当然如果数据集合相当大,采用服务器端游标的性能会好一些。同时需要注意:如果采用客户端游标,最好只采用读加锁(adLockReadOnly)的锁类型,因为如果需要更新数据,客户端游标引擎需要得到额外的信息(元数据),而获取这个信息的代价是非常昂贵的。

7.调整记录集对象的CacheSize属性

ADO使用记录集对象的CacheSize属性来决定提取和缓存的记录的数目,当在缓存的范围内浏览数据时,ADO就只从缓存中提取数据。当要浏览的数据超出缓存范围的时候,ADO就释放当前缓存,提取下一些记录(提取的数目为CacheSize所指定的大小),所以必须根据具体的应用程序的情况,来设定CacheSize的大小,保证得到最佳的性能。

8.定义Command对象的参数

在许多数据源中,得到参数信息和执行命令的代价几乎是一样的,所以最好自己在程序中定义好Command参数(也就是说要定义好参数的名称、类型和方向信息),避免一些从数据提供者(Provider)那里获取信息的操作。

9.使用原始的OLE DB提供者

MDAC对许多数据源提供了原始的数据提供者,比如SQL Server、Oracle和Access数据库,这样就不需要再通过ODBC来获取数据(也就是说不需要再通过ODBC驱动这一层),这样的好处是能更快地得到数据,并且能降低磁盘和内存的开销。

10.断开Connection连接

如果使用客户端游标,就要断开Connection连接。ADO有一个特征是当使用客户端游标操作 Recordset记录集的时候,不需要和服务器保持联系。所以可以充分利用这个特性降低服务器端的开销(服务器就不需要维护这些连接了)。当操作完记录集需要更新时,可以重新和数据库进行连接来更新数据。为了创建一个可以断开连接的记录集,同时需要使用静态游标(adOpenStatic)和批处理的加锁模式(adLockBatchOptimistic)。下面是有关处理的VC代码:

pRs.CreateInstance(__uuid(Recordset));

pRs->CursorLoction=adUseClient;

pRs->Open(strCmdText,strConnection,adOpenStatic,adLockBatchOptimistic,adCmdText);

pRs->PutRefActiveConnection(NULL);

//对记录集对象pRs进行操作

//重新和数据库建立连接

pRs->PutRefActiveConnectio(pCon);

//批量更新数据

pRs->UpdateBatch(adAffectAll);

需要注意的是:当执行批量更新时,必须自己处理数据冲突问题,因为更新数据时,其他用户也可能同时正在对该数据进行操作。

11.使用adExecuteNoRecords选项

如果不需要返回记录,要使用adExecuteNoRecords选项。ADO 2.0包括一个新的执行选项称为adExecuteNoRecords。当使用该选项的时候,ADO就不会创建记录集对象,不设置任何游标属性。数据提供者因为不需要认证集合的属性而使性能得到优化。具体的例子如下:

con.Execute “insert into tbl values(fv1, fv2) ”, , adExecuteNoRecords

对仅有一条的执行语句采用Connection::Execute方法比使用Recordset::Open方法或者是Command::Execute方法的效果要好,因为ADO不保留任何命令状态的信息,因此执行性能就有所改进。

12.使用session/connection缓冲池

因为数据库的打开和关闭非常消耗系统资源,因此,使用连接池对基于多层的应用的性能会有很大的提高。当使用MDAC的时候,开发人员本身并不需要考虑对数据库连接的缓存,MDAC会自动处理它。连接池在两个层次上提供支持:OLE DB sessions和ODBC连接。如果使用ADO,数据库连接会自动被OLE DB session缓冲池所缓存;如果使用ODBC,可以利用在ODBC数据源管理中新的连接缓冲池选项对ODBC缓冲进行设置。

实现方法

我们知道,在VB下进行基于ADO的编程相对比较简单,只要通过reference加载了适当的类型库后,就可以正常地调用ADO对象。但是对于VC下的基于ADO的数据库开发就稍微复杂一些。VC中实现对ADO操作通常有三种方法:

#import方法;

利用MFC OLE的ClassWizard;

通过Windows API中COM相关的函数。

在这三种方法中,#import是最方便的方法,它允许产生一个类似VB的类结构,使程序开发变得很方便。下面分别介绍这三种方法。

1.#import方法

在#import方法中,需要提供所要包含的类型库的路径和名称,VC能够自动产生一个对GUIDs的定义,以及自动生成对ADO对象的封装。对任何引用的类型库,VC会在编译的时候自动生成两个文件:

头文件(.tlh):包含了所列举的类型和对类型库中对象的定义;

实现文件(.tli):对类型库对象模型中的方法产生封装。

例如,在stdafx.h文件中增加对msado15.dd的

#import之后,VC会产生msado15.tlh和msado15.tli两个文件。

#import能够使用一个新的类_com_ptr_t,它也被称为智能指针。智能指针能够自动执行QuyerInterface、AddRef和Release函数。

下面的代码演示了如何使用#import在应用中实现对ADO的操作:

#import “c:\program files\common files\system\ado\msado15.dll” \no_namespace

rename ( “EOF”, “adoEOF” )

重命名EOF是必要的,因为典型的VC应用都已经定义了EOF作为常数-1。

通常来说,操作一个自动化对象需要定义和初始化一个用来操作的变量。可以通过使用智能指针

(_com_ptr_t)的构造函数传递一个有效的CLSID或者是PROGID,也可以通过_com_ptr_t::CreateInstance()方法来定义对象。具体代码如下所示:

_ConnectionPtr Conn1( __uuidof( Connection ) );

也可以采用下面的代码实现同样的功能:

_ConnectionPtr Conn1 = NULL; //定义对象

HRESULT hr = S_OK;

//创建实例

hr =Conn1.CreateInstance( __uuidof( Connection ) );

推荐采用第二种方式,因为用第一种方式不能返回一个失败的HRESULT,所以也就不能判断ADO连接对象是成功还是失败,以及失败的原因。注意这里的__uuidof( Connection)中的Connection是在.tlh文件中定义的。通过把它传递给方法CreateInstance,就可以创建一个有效的 ADOConnection对象。

需要注意的是#import的no_namespace属性,它告诉编译器该类在不在一个单独的名字空间中。使用no_namespace意味着不需要在初始化变量时引用名字空间。当然如果在应用中需要导入多个类型库时,最好不要使用 no_namespace,以免引起名字冲突。

下面是一个简单的采用了#import方法的基于ADO应用的示例代码:

#include

#import rename(“EOF”, “adoEOF”)

void main()

{

HRESULT hr = S_OK;

//因为没有在#import中指定no_namespace,所以必须采用ADODB::这样的形式来定义变量类型

ADODB::_RecordsetPtr Rs1 = NULL;

//通过ODBC建立ADO连接

_bstr_t Connect( “DSN=AdoDemo;UID=sa;PWD=;” );

_bstr_t Source ( “SELECT * FROM Authors” );

CoInitialize();

//初始化Rs1对象

hr = Rs1.CreateInstance( __uuidof( ADODB::Recordset ) );

//省略对返回值hr的判断

Rs1->Open( Source,

Aonnect,

ADODB::adOpenForwardOnly,

ADODB::adLockReadOnly,

-1 );

//此处可以添加对记录集Rs1进行操作的代码

Rs1->Close();

Rs1 = NULL;

::MessageBox( NULL,“Success!”,“”,MB_OK );

CoUninitialize();

}


用MFC OLE创建ADO应用


MFC OLE同样能够封装(wrapper)一个类型库,但是与#import不同,它不能从类型库中产生枚举类型。MFC类CString和 COleVariant隐藏了BSTRS和Variants的细节。由MFC OLE产生的类都继承了类ColeDispatchDriver,由ADO产生的失败的HRESULTS被封装在类 ColeDispatchException中。

用MFC OLE ClassWizard创建ADO应用的步骤如下:

从Tools菜单中,选择Options选项中的Directories tab条目,在Show Directories中的Library Files中增加路径C:\program files\common files\system\ado,设置包含ADO类型库的路径。

从View菜单中,激活ClassWizard,点击Add Class按钮并选择“From A Type Library...”选项,然后在Type Library dialog box对话框中,从C:\program files\common files\system\ado中选择文件msado15.dll,在Confirm Classes对话框中,选择所有列出的类并按OK按钮退出ClassWizard。这样,ClassWizard便生成了两个文件msado15.h和 msado15.cpp。

下面是实现ADO应用的示例代码:

//初始化COM对象

AfxOleInit();

...

//定义数据集对象

_Recordset Rs1;

COleException e;

COleVariant Connect( “DSN=AdoDemo;UID=sa;PWD=;” );

COleVariant Source ( “SELECT * FROM Authors” );

//创建数据集对象

Rs1.CreateDispatch(“ADODB.Recordset.2.0”,&e );

Rs1.Open( (VARIANT) Source,

(VARIANT) Connect,

0, 1, -1 );

//此处可以添加对结果集Rs1进行处理的代码

Rs1.Close();

Rs1.ReleaseDispatch();

AfxMessageBox(“Success!”);


用COM API创建ADO工程


#import和MFC OLE都围绕着一个给定的自动化对象产生了一个封装类,它们分别继承自_com_ptr_t和ColeDispatchDriver。其实也可以通过使用 Windows API函数直接初始化ADO对象。为了直接使用ADO和COM对象,需要添加两个头文件adoid.h和adoint.h,这两个头文件定义了 CLSIDs、接口定义和操作ADO类型库所需要的枚举类型。此外,还需要增加头文件INITGUID.H。

为了能够编译用COM API创建的ADO工程文件,还需要在机器中安装OLE DB SDK或者是MSDASDK工具。下面是利用API创建ADO的简单的示例代码:

#include

#include

#include “adoid.h” // ADO的GUID's

#include “adoint.h” // ADO的类、枚举等等

void main()

{

HRESULT hr = S_OK;

// ADORecordset 是在adoint.h中定义的

ADORecordset*Rs1 = NULL;

VARIANT Source;

VARIANT Connect;

VariantInit( &Source );

VariantInit( &Connect );

Source.vt = VT_BSTR;

Source.bstrVal = ::SysAllocString( L“SELECT * FROM Authors”);

Connect.vt = VT_BSTR;

Connect.bstrVal = ::SysAllocString( L“DSN=AdoDemo;UID=sa;PWD=;” );

hr = CoCreateInstance( CLSID_CADORecordset,

NULL,

CLSCTX_INPROC_SERVER,

IID_IADORecordset,

(LPVOID *) &Rs1 );

if( SUCCEEDED( hr ) ) hr = Rs1->Open

(Source,

Connect,

adOpenForwardOnly,

adLockReadOnly,

-1 );

//对记录集Rs1进行处理

if( SUCCEEDED( hr ) ) hr = Rs1->Close();

if( SUCCEEDED( hr ) ) { Rs1->Release(); Rs1 = NULL; }

if( SUCCEEDED( hr ) ) ::MessageBox( NULL, “Success!”, “”, MB_OK );

}

C++ Extensions

如果用C++进行ADO应用程序开发,应该使用ADO C++ Extensions。我们知道,用VB或者VBScript来操作ADO是非常方便的,但是如果使用C++或者是Java,就必须要处理类似 Variants这样的数据结构以实现和C++数据结构的转换,而这种处理无疑是所有C++开发人员都很头疼的事情。但如果使用C++ Extensions的话,ADO就不需要从数据提供者处得到列信息,而是在设计时刻使用开发人员提供的列信息。以下是一个简单的示例:

//创建和具体记录相对应的类

class CAuthor : public CADORecordBinding

{

BEGIN_ADO_BINDING(CCustomRs1)

ADO_VARIABLE_LENGTH_ENTRY4(1,

adVarChar, m_szau_id, sizeof(m_szau_id), FALSE)

ADO_VARIABLE_LENGTH_ENTRY4(2,

adVarChar,m_szau_fname,sizeof(m_szau_fname), FALSE)

ADO_VARIABLE_LENGTH_ENTRY4(3,

adVarChar,m_szau_lname,sizeof(m_szau_lname), FALSE)

END_ADO_BINDING()

protected:

char m_szau_id[12];

char m_szau_fname[21];

char m_szau_lname[41];

};

void FetchAuthorData()

{

CAuthor author;

//记录集对象

_RecordsetPtr pRs;

IADORecordBinding *piAdoRecordBinding;

//获取COM对象接口指针

pRs.CreateInstance(__uuidof(Recordset));

//得到需要的记录集

pRs->Open(“select au_id,au_fname,au_lname from Employees”,“Provider=SQLOLEDB;Data Source=sureshk1;Database=pubs;User Id=sa;Password=;”,

adOpenForwardOnly,

adLockReadOnly,

adCmdText);

//查询接口IADORecordBinding

pRs->QueryInterface(__uuidof(IADORecordBinding),(LPVOID*)&piAdoRecordBinding);

//绑定对象

piAdoRecordBinding->BindToRecordset(&author);

//得到记录中的相关内容

while (VARIANT_FALSE == pRs->EOF) {

printf(“%s %s %s”, author.m_szau_id,

author.m_szau_fname, author.m_szau_lname);

pRs->MoveNext();

}

//释放对象
 
 
 
 
 

本文评论

 
 

发表评论

你的评论
← 填你的昵称
以下内容非必填,可根据需要填写
← 可以展示在你的评论上方
← 不会在页面展示
← 不会在页面展示
← 只给我看?勾选上
这是一个别人称之为角落的世界
幸而,它的确是我的世界