目前位置: VCer资源中心 >>> VCer文章 >>> 数据库

[本帖已阅读3206次 分值110 回复2次] 张贴资源 发回信箱 控制面板

snoopy每日一译-完美的ADO

提供者:ycr40 张贴时间:2004-04-23 12:55:27.0 出处:vcer.net 作者:不祥

snoopy每日一译-完美的ADO(2004-04-23 12:55:27.0)


snoopy


 
级别: VCer排长
头衔: VCer会员

经验: 1285
作品: 28
分会: 华南分会
注册: 2004-04-15 09:22:35.0
登录: 2004-05-18 08:45:59.0

本文的目的是让你感到ADO没有什么可怕的,而不是ADO的细节。我甚至没有告诉你ADO能做什么。ADO比DAO更快、更容易使用、更强大。

完美的ADO

我们都很熟悉CDatabase和CDaoDatabase。它们相对比较容易去使用,它们很好地配合我们的应用程序,and they are easily distributed.使用CRecordset类,你很容易建立强大的数据库运用。

现在,当你刚刚感到用c++开发数据库项目有点把握的时候,微软推出一个叫UDA(Univeral Data Access数据统一访问)和一个相对简单,但缺乏文档说明的ADO(ActiveX Data Object)。非常不幸,微软的家伙们认为没有必要提供任何样子的文档Visual C开发人员。如果你试图从网上搜索,你会发现很难找倒有关ADO的好例子。

和ADO相处几个月后,我开始对ADO产生好感,可能将来我不用其它而只用ADO开发数据库。当你认识到ADO是多么容易使用、多么强大,你可能就会和我想的一样了。当我用DAO编写通用Recordset时,有一简单的方法使用数据动态绑定,那就是在查询(query)而不是表(table)上建立recordset。而对于ADO,缺省使用的就是数据动态绑定,这正是我喜欢ADO的原因之一。

开始

在你使用ADO之前,你必须让你的应用程序知道你将使用它。在stdfx.h文件中,你必须加入以下代码:

这行代码的基本意思是使用ADO,但不使用命名空间,并且将EOF改成adoEOF。你必须重命名EOF,是因为常量冲突。加入上述代码后,你不需要在#include,不需要连接别的什么到你的应用程序中了。

先看看ADO的部件(pieces):_ConnectionPtr, _CommandPtr, and _RecordsetPtr (本文不涉及_CommandPtr)

像相应的DAO和CDatabase一样,ADO也有几个部件。和DAO、CDatabase不同,ADO是基于COM的。一个令人不那么愉快的事情是学习ADO,你被迫学习一些COM知识(这也是好事,因为作为windows开发人员,你迟早会走上这条不归路)。ADO的三个部件是Connection、Command、Recordset。

Connection返回recordset或者NULL。一般来说,你使用它连接数据库,并(或)执行SQL语句,而不返回任何东西。当Connection对象返回一个recordset,那不是一个最好的方法。像CDaoDatabase一样,你(大多数情况)使用Connection对象连接数据库,而用其它对象访问数据。

Command返回一个recordset,并允许你运行返回一个recordset的存储程序(stored procedures)或任何SQL语句。你可以使用全局的Connetcion连接数据库,或者你可以在打开command的时候告诉它连接语句。当你进行一次性连接时,这是一个好特性。但如果你需要建立大量recordset,你会用Connection对象去连接数据库,而用Command对象运行存储程序。

而Recordset是...噢,就是recordset。它提供多一些对于recordset的控制(例如锁定、光标等...)。有了Command你不需要一个打开的connection。如果包含一个connection语句,而不是指向connection对象的指针,你的Recordset就可以使用了。如果你使用多个recordset,最好的方法是Connection对象连接数据库,用recordset对象处理recordset。

我在本文要说的两个部件是Connection和Recordset。

_ConnectionPtr,是Connection接口。类似于CDatabaseCDaoDatabase。它们的使用方法基本上一样。你先建立_ConnectionPtr的一个实例,通过ODBC或数据提供者指向数据库,然后打开它。看看它和CDaoDatabase有多类似:

现在看看ado:

_RecordsetPtr,是recordset接口。和CDaoRecordset类似。一旦你发现_RecordsetPtr和CDaoRecordset是这么类似,你会后悔不早点使用ADO。让我们看看它们如何工作(我们将用前面代码的数据库和connection)

    ADO是相对辣手一点,但使用ADO的优点(不在本文讨论范围之内)值得你去使用它。

现在我们有了一个connection和一个recordset,让我们读取一些数据吧。我们使用recordset中的数据去填充列表筐(假设我们已经有一个名为m_list的列表筐)。

DAO:

   

ADO:

   

需要特别注意的是:没有文档提到GetCollect方法,我搜索了任何地方,没有人提到它。另外一个返回数据的方法是:

 

我更喜欢GetCollect。

动态绑定 vs DFX:

动态绑定允许你使用任何合法的SQL语句建立一个记录集并返回一些东西。例如,想象一下用DFX建立一个允许你求几个域的和记录集:

SELECT (SUM(field_1) + SUM(field_2)) AS answer FROM some_table

这不是一个容易的任务,这正是动态绑定的优点。另外一个优点是代码的精简。动态绑定使你的应用程序更小并容易维护。最后,根据微软所说,动态绑定是推荐的从数据源获取数据的方法。既然动态绑定更具弹性、更快、更容易维护,我们还要求什么?

大部分的应用,你可以使用单一(全局)的connetction连接数据库,然后建立多个recordset。如果你已经用大量recordset写了一些应用程序,那么你知道DFX在你的应用程序中加入了大量的代码。全部这些代码的结果是动态绑定。

_variant和_bstr_t不好么?

不幸的是,CString变成了COM所需要的类型(叹气,CStringEx也是)。因为COM是跨开发平台的,它需要一个更通用的方法去处理字符串和另外的数据。这个通用的方法是什么?答案是VARIANT类型和BSTR类型。VARIANT基本上是你能想到的所有数据类型(除了char*)的联合。BSTR基本上是一个字符串和串长的变量(代替char*)。

处理它们真的会令屁股非常的痛。因此键入_variant_t和_bstr_t。基本上(非常基本),_variant_t类封装了VARIANT类型并允许我们简单地使用类型转换。这简化了使用VARIANT。_bstr_t做BSTR同样的事情。在例子中,你可以看到我怎样从GetCollect方法中取得VARIANT,然后将它放入_bstr_t,接着转换成char*类型,或者我将_variant_t转换成long、double或任何东西。

   

对比不使用_variant和_bstr_t:

相当不同。

修改、插入和删除:

进行修改、插入和删除操作的时候,通常我喜欢使用Connection对象或Command对象。原因是这样似乎就是简单地用CString建立SQL语句,然后执行它们。但是你可以使用Recordset对象的三个方法:

Update方法可以在使用下面三种方法之一的基础上修改记录:

1、给Field对象的Value属性赋值,然后调用Update方法;

2、调用Update方法时,传输域名和值作为参数;

3、调用Update方法时,传输一个域名数组和一个值数组作为参数。

AddNew方法使用一个域数组和相对应的值数组作为参数。

Delete方法删除当前记录或者当前过滤器过滤的记录。

在三个方法中,你必须使用Requery方法刷新记录。

简单的代码:

本文包含的简单代码是一个MFC简单应用程序。在CWinApp中,我声明了_connectionPtr、_CommandPtr和_RecordsetPtr接口。

有趣的是,(在vc6.0中),当键入"m_pConnection.",你将得到一个函数和成员的下拉列表;但是你键入"m_pConnection->"时,你会得到另外一个完全不同的函数和成员列表。这是因为你实际上指向两个不同的东西。当键入"."时,你看到的是一个智能指针;而"->"是你建立的东西的指针(_ConnetctionPtr等)。这就是为什么你看到两行代码的原因,一行使用".",另外一行使用"->"。

   

回到例子代码。在应用程序初始化实例时,我打开了连接。它指向我的系统中的一个数据库。你可能必须修改它指向你的数据库(ODBC)或者使用UDA提供者提供一个数据库。

如果你打开about对话框,你会看到一个列表框。你会看到一个叫button1的按纽,这个按纽正是ADO这块肥肉的落脚点。我先建立recordset接口的实例,然后在我想要的查询中我打开recordset,然后遍历记录集。

记得使用try和catch,否则ADO会粉碎你的应用程序。你应该catch _com_error 和...,在任何时候。

我必须尝试让它简单些。我省略了大量的细节,忽略了一些好的编程习惯(例如,检查大部分COM方法都返回的HRESULT)。本文的目的是让你感到ADO没有什么可怕的,而不是ADO的细节。我甚至没有告诉你ADO能做什么。ADO比DAO更快、更容易使用、更强大。

有两本好书帮助你开始使用ADO。一本是免费的(免费的噢),在http://www.mcp.com/;另外一本你得掏钱。(两本我都要,除非你在浴室和床上有一台电脑)。

这是WROC出版社的"ADO 2.0"。这本书,像其它书一样,很少c++例子。但是它是所有的方法和属性的好参考。你使用ADO之后,将例子代码转化成c++代码十分简单。另外一本,是"Learning Programming with Visual C++ in 21 days"。是的,我知道那些"in 21 days"的书很臭,当另外的程序开发人员在你身边的时候,你买这样的书是很尴尬的,你会将书藏到书架中。但这本书不是这样的,它里面的信息很好。或者你可以在http://www.mcp.com/读这本书。两本都很好。"21 Days"让你明白怎样去使用ADO(好东西),另外一本告诉你怎样设计数据库等等(也很好,基本资料)。

注:转载文章需注明来源:VCer.net 文章地址:http://vcer.net/1076417661402.html

  如果你觉得VCer.net不错,而且你愿意为VCer.net捐赠一元钱,那么点击后面的捐赠按钮吧:) vcer.net捐赠

[回复该贴] [加入个人书签]
[连载系列]

[1] snoopy每日一译-完美的ADO
[2] snoopy每日一译-完美的ADO[2](上)
[3] snoopy每日一译-完美的ADO[2](中)
[4] snoopy每日一译-完美的ADO[2](下)

[投票结果]

A: 评分 10 100% (3 票)
B: 评分 5 0% (0 票)
C: 评分 0 0% (0 票)
D: 评分 -5 0% (0 票)
E: 评分 -10 0% (0 票)

 


re:snoopy每日一译-完美的ADO
不好意思: theApp.m_pRecordset..CreateInstance(__uuidof(Recordset));//多了一个点"." 请改成: theApp.m_pRecordset.CreateInstance(__uuidof(Recordset)); 另外: 1、注意stdafx.h中的#import语句的路径。 2、注意去掉解压后文件夹的只读属性。

ycr40 于 2004-04-27 08:09:59.0 编辑 [回复该贴]

re:snoopy每日一译-完美的ADO
源程序无法编译的说

zzhe79 于 2004-04-26 17:53:58.0 编辑 [回复该贴]