词条 | ActiveX Data Objects |
释义 | 一种程序对象,用于表示用户数据库中的数据结构和所包含的数据。在Microsoft Visual Basic编辑器中,可以使用ADO对象以及ADO的附加组件(称为Microsoft ADO Extensions for DLL and Security(ADOX))来创建或修改表和查询、检验数据库、或者访问外部数据源。还可在代码中使用ADO来操作数据库中的数据。 ADO编程应用(1.显式定义对象类型 2.绑定列到具体的字段对象 3.用SQL语句和存储过程进行数据更新 4.使用集合操作单条的SELECT语句 5.只查询所需要的数据 6.正确选择游标的位置、类型和锁方式 7.调整记录集对象的CacheSize属性 8.定义Command对象的参数 9.使用原始的OLE DB提供者 10.断开Connection连接 11.使用adExecuteNoRecords选项 12.使用session/connection缓冲池) 简介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 对象总结对象 说明 Command Command 对象定义了将对数据源执行的指定命令。 Connection 代表打开的、与数据源的连接。 DataControl (RDS) 将数据查询 Recordset 绑定到一个或多个控件上(例如,文本框、网格控件或组合框),以便在 Web 页上显示 ADOR.Recordset 数据。 DataFactory (RDS Server) 实现对客户端应用程序的指定数据源进行读/写数据访问的方法。 DataSpace (RDS) 创建客户端代理以便自定义位于中间层的业务对象。 Error 包含与单个操作(涉及提供者)有关的数据访问错误的详细信息。 Field 代表使用普通数据类型的数据的列。 Parameter 代表与基于参数化查询或存储过程的 Command 对象相关联的参数或自变量。 Property 代表由提供者定义的 ADO 对象的动态特性。 RecordSet 代表来自基本表或命令执行结果的记录的全集。任何时候,Recordset 对象所指的当前记录均为集合内的单个记录。 ADO 事件ActiveX 数据对象 (ADO) 是添加到 Microsoft Active Server Pages (ASP) 的一套高级别接口,有利于服务器端与数据库的连接。ADO 与低级别接口 (OLE DB) 一起使用则有利于 Microsoft Universal Data Access 策略。ADO 2.0 版可生成 Visual Studio Analyzer 事件。可使用这些事件跟踪分布式应用程序中的 ADO 交互。 ADO 生成的 Visual Studio Analyzer 事件 事件 事件描述 事件数据 ConnectionClose 指示 ADO 要与 OLE DB 数据源断开连接。 无。 ConnectionOpen 指示 ADO 正在连接到 OLE DB 数据源。 如果客户端提供,则为连接到数据源所用的连接字符串。 Find 指示 ADO 客户端已调用 ADO Recordset.Find 函数。 “查找”操作的判据;根据该判据匹配记录。 GetRows 指示 ADO 客户端已调用 ADO Recordset.GetRows 函数。 提取的行数。 QueryResult 指示数据库已返回响应查询的结果集。 无。 QuerySend 指示 ADO 正在执行命令。该事件可由下列函数触发: Connection.Execute Command.Execute Connection.<存储过程名> Recordset.Open 构成查询的 SQL 语句。 RecordsetOpen 指示 ADO 正在打开远程服务器上的记录集。仅适用于三层方案。 打开记录集的源(通常为行返回的命令文本)。 Sort 指示 ADO 准备筛选或对数据排序。 排序或筛选应用于记录集数据的判据。 Transaction Rollback 指示 ADO 要中止当前本地事务。 返回真或假。如果为真,则保持中止,即该事务中止后紧跟着开始另一事务。如果为假,则不保持中止。 TransactionCommit 指示 ADO 正在提交 OLE DB 提供程序上的本地事务。 返回真或假。如果为真,则保留提交,即该事务提交后紧跟着开始另一事务。如果为假,则不保留提交。 TransactionStart 指示 ADO 正在开始 OLE DB 提供程序上的本地事务。 ADO 开始事务所基于的隔离级别。隔离级别指示可看到其他事务所做更改的哪一级别。 UpdateBatch 指示 ADO 正在向提供程序发送更新批处理。仅适用于三层方案。 如果有,为 ADO 将更新发送到的远程服务器名。 在哪里能得到ADO目前ADO1.5版已经可以从微软网站免费下载。到目前为止,微软网站仍是你获取有关ADO最新信息的最佳场所。ADO1.5是作为OLE DB SDK的一部分提供的。 在下载之前请先确认OLE DB SDK提供的各项特性。下载文件大约有15M,如果完全安装的话要占用80M的硬盘空间。如果你只对ADO感兴趣,就选择最小安装,这样只会占用你15M的硬盘空间。 在这里你可以找到许多关于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的版本来说,从功着你可以通过这两种方法解决同样的问题;它不是指存在重命名的或者优化的功能相同的对象.因此,移植到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” \o_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(); } 2.用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!”); 3.用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(); } //释放对象 |
随便看 |
百科全书收录4421916条中文百科知识,基本涵盖了大多数领域的百科知识,是一部内容开放、自由的电子版百科全书。