📄 subject_47618.htm
字号:
<p>
序号:47618 发表者:大伟 发表日期:2003-07-22 15:56:46
<br>主题:关于ado的一个常识性菜问
<br>内容:_RecordsetPtr m_pRecordset; <BR><BR>m_pRecordset-〉EOF;<BR><BR>这个EOF是什么东西?方法、属性、事件?<BR>或者是个变量?当超过最后一条记录,它为真?<BR><BR>刚刚接触,手头又没书,望大侠们不吝赐教。
<br><a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p>
<hr size=1>
<blockquote><p>
回复者:风之文章 回复日期:2003-07-22 16:11:46
<br>内容:ADO一瞥<BR>翻译:GKey Chen(gkey@263.net)<BR>译者的话<BR>本人作为一名从事多年编程工作的系统分析人员,现在有兴趣将一些文章资料整理后奉献给大家。接下来我本将就VC++和RFC的英文文档翻译成为中文,希望大家喜欢。<BR>限于本人的计算机水平和英语翻译方面的能力,翻译过程中可能有不当甚至错误的地方,本人不负责由于翻译错误/失误可能给您带来的任何损失。<BR>如果您有什么建议或者意见,欢迎来信提出:gkey@263.net。<BR>绪论<BR>微软ADO(Microsoft ActiveX Data Objects)允许您通过OLEDB provider在数据库服务器中操纵和保存您的数据,因为提供了双重接口,可以在脚本语言如VBScript和JavaScript中象在C++中一样使用它。ADO具有很多优势,运行速度快捷,占用内存少,最重要的它便于使用。<BR>在这篇文章里,将要描述怎样使用ADO,比如怎样建立一个记录集,查询数据库或者运行存储过程。<BR>首先约定,本文中使用ADOTestDB.MDB作为演示数据库,开发环境为VC++6(SP3)和ADO 2.1。在数据库中构造了两个具有不同数据类型字段的简单表,Student和Dept,以及一些演示数据。还有需要在这里提及的是本文中使用了导入指令和聪明指针获得的属性。<BR>在您的stdafx.h中键入以下几行代码:<BR> #import "msado15.dll" \<BR> no_namespace \<BR> rename( "EOF", "adoEOF" )<BR>上述代码就将EOF重新命名为adoEOF,从而防止应用程序将来可能的可能冲突而浪费时间找出这些原因。<BR>这样之后,做其他事情之前需要在应用程序开始的某个地方调用CoInitialize(NULL)初始化COM,在完成所有ADO相关的工作调用CoUninitialize()。<BR>现在开始说一说怎样使用ADO:<BR>建立同数据库服务器的连接<BR>在ADO中操作数据源的第一步是连接到数据源。为了连接数据源需要使用ADO连接对象,ADO建立连接的主要方法是使用连接的Open成员函数,看看下面的代码(为了简化代码,省略了错误处理):<BR> _ConnectionPtr m_pConn;<BR> m_pConn.CreateInstance (__uuidof(Connection));<BR> m_pConn->Open ( _bstr_t ( "Provider=Microsoft.Jet.OLEDB.4.0;<BR> Data Source = ADOTestDB.MDB" ),<BR> _bstr_t ( "" ),<BR> _bstr_t ( "" ),<BR> adModeUnknown <BR> );<BR>上述代码通过Microsoft.Jet.OLEDB.4 provider建立一个同ADOTestDB.MDB的连接。首先需要定义一个_ConnectionPtr (ADO连接)对象,之后对它实例化,再调用Open函数建立连接。Open成员函数的第一个参数是连接字符串,这个参数指定使用OLEDB provider试图连接的数据源;接着的两个参数指定登录数据库的用户(UserName)和密码(Password),这里不需要指定用户所以使用了空字符串;最后一个参数事一个选择项,决定是用同步或者异步方式进行连接,如果不像使用这个属性可以使用类型adModeUnknown。<BR>也可以使用ODBC驱动程序连接数据源,下面代码演示了如何使用ODBC:<BR> m_pConn->Open ( _bstr_t ("DSN=pubs;uid=sa;pwd=;"),<BR> _bstr_t (""),<BR> _bstr_t (""),<BR> adCmdUnknown <BR> );<BR>使用SQL语句<BR>在ADO中使用SQL语句有不同的方法,最常用的方法是使用Command对象,Command是数据提供者理解的用于修改、管理和操纵数据源的用SQL语句编写的指令,下面演示查询演示数据源中数据表Student的所有数据的SQL指令:<BR> _CommandPtr pCommand;<BR> pCommand.CreateInstance (__uuidof (Command));<BR> pCommand->ActiveConnection = m_pConn; // 原来已经打开的连接指针<BR> pCommand->CommandText = "Select * From Student";<BR>如上所述,首先声明一个Command对象,再设置它的ActiveConnection属性为原来已经打开的连接对象m_pConn,CommandText属性发送给提供者描述了查询,它是一个SQL语句或者存储过程的名字,这里是一个简单的查询语句"Select * From Student"。<BR>因为命令是一个查询,执行后将返回一个记录集,为此需要定义一个Recordset对象保存返回行,另外还可以操纵这些行。<BR>现在该运行这个命令了,有两种方法在ADO中运行这个命令,第一种方法通过Command对象的Execute成员函数,另一种方法是使用Recordset的Open成员函数。下面使用Recordset的Open函数来执行:<BR> _RecordsetPtr pRecordset;<BR> pRecordset.CreateInstance (__uuidof (Recordset));<BR> pRecordset->CursorLocation = adUseClient;<BR> pRecordset->Open ( (IDispatch *) pCommand, vtMissing, adOpenStatic,<BR> adLockBatchOptimistic, adCmdUnknown);<BR>上述代码首先定义了一个Recordset类型对象再进行实例化,ADO的Recordset对象有可以实现不同目标的十几个颇有价值的属性,这里使用的CursorLocation就是其中的一个,通常用于指定在客户端和服务器端之间的游标位置,之后调用Open函数项数据源发出指令。Open成员函数的第一个参数指定一个变量,可以是一个需要计算的Command对象、一个SQL语句的变量、一个表名、一个存储过程调用或者可识别的URL;第二个参数是一个处于活动状态的连接,这是一个可选参数,就像在Command对象中指定活动的连接一样,这里不需要重新指定,可简单的忽略这个参数(在VC++,无论何时需要指定类型可变的可忽略参数,指定一个值为DISP_E_PARAMNOTFOUND的_variant_t和一个类型为VT_ERROR的_variant_t。作为选择在#import指令提供的相同的_variant_t常量vtMissing);第三个和第四个参数是游标类型和锁定类型,因为要使用批处理这里指定锁定类型为adLockBatchOptimistic ,因为这个处理需要游标服务,所以在前面指定了游标位置;最后一个参数指定除了Command对象提供者应该怎样计算源参数的值,这里源是Command对象所以简单使用adCmdUnknown 作为最后参数。现在,执行Open函数后,可以在Recordset对象中获得所有学生的信息。<BR>操纵数据<BR>本节讲一讲怎样操纵数据。在Student表中有一个字段SocialSecNo表示每个学生的社会保障号,因为政府方面的某些问题,需要改变开头为’45’的社会保障号为’77’开头。为了完成这个任务,需要过滤出社会保障号以’45’开头的当前记录集,此外,在记录集中设置StudentNo字段为索引以提高排序和过滤操作的性能。<BR>当然象下面这样可能并没有真正的有效处理某件事情,它的正确性依赖于实际的情形。但是这里最重要的目的在于介绍了ADO不同的性能,没有考虑效率和充分使用ADO的特性。<BR>操纵数据的代码如下:<BR> pRecordset->Fields->GetItem ("StudentNo")->Properties-><BR> GetItem ("Optimize")->Value = VARIANT_TRUE;<BR> pRecordset->Sort = "Name";<BR> pRecordset->Filter = "SocialSecNo LIKE '45*'";<BR> while (!pRecordset->GetadoEOF())<BR> {<BR> CString str = (char *) (_bstr_t) pRecordset->Fields-><BR> GetItem("SocialSecNo")->Value;<BR> str = "77" + str.Right(str.GetLength() - 2);<BR> pRecordset->Fields->GetItem("SocialSecNo")->Value = (_bstr_t) str;<BR> pRecordset->MoveNext();<BR> }<BR> pRecordset->Filter = (long) adFilterNone;<BR>上面代码中,首先设置了StudentNo的Optimize 属性为记录集生成一个索引,再由Name字段保存记录集,过滤出以’45’开头的SocialSecNo的记录。在循环中简单地将SocialSecNo 值改成为新值后将当前位置挪到记录集的下一条记录上。在改变SocialSecNo为新值后这条记录不再同过滤标准相匹配从而在记录集中是不可见的。为了在记录集中可见,需要在后面挪去过滤器,正如上述代码最后一行所作的那样。<BR>更新数据<BR>通常在ADO中有两种方式来更新数据。第一种方法是实时更新,因此只要执行Update函数就马上直接改变记录集合数据源;第二种方法式批处理更新,由adLockBatchOptimistic锁定类型打开的记录集,ADO以批处理的方式更新数据,批处理方式下,记录上的每个指令或者在当前记录上的Update函数调用都在拷贝缓冲里保存改变信息,在调用BatchUpdate函数时将修改发送到数据源。<BR>在下面演示代码中,使用批处理模式进行更新数据操作:<BR> pRecordset->BatchUpdate (adAffectAll );<BR>现在知道了怎样打开和查询数据,以及操纵和更新数据,但是在ADO中还有很多事需要了解,最重要的就是调用存储过程和参数化指令。<BR>运行带输入参数的存储过程<BR>调用存储过程就像前面所讲的打开一个记录集那么简单,当然还有一些配合建立输入参数和指定参数值的问题需要讨论。在ADO中有两种通用的方式传递参数,一种是通过Parameter参数对象,还有一种就是通过Refresh 方法,推荐使用地一种方法因为它比第二种方法具有更好的操作权限控制。<BR>这里首先说一说第一种方法,如下代码描述了怎样设置输入参数和演示中使用Parameter参数对象运行Query1存储过程。<BR> _CommandPtr pCommand;<BR> _ParameterPtr pParam1, pParam2;<BR> CString str("Ma%");<BR> pCommand.CreateInstance(__uuidof(Command));<BR> pCommand->ActiveConnection = m_pConn; //原来已经打开了的连接 pCommand->CommandText = "Query1";<BR> pCommand->CommandType = adCmdStoredProc;<BR> pParam1 = pCommand->CreateParameter ( _bstr_t ("DeptID"), adTinyInt, <BR> adParamInput, sizeof (BYTE), _variant_t ( long (11)));<BR> pCommand->Parameters->Append ( pParam1);<BR> pParam2 = pCommand->CreateParameter ( _bstr_t ("Name"), adVarChar, <BR> adParamInput, str.GetLength (), (_bstr_t) str);<BR> pCommand->Parameters->Append ( pParam2);<BR> _RecordsetPtr pRecordset;<BR> pRecordset.CreateInstance(__uuidof(Recordset));<BR> pRecordset = pCommand->Execute(NULL, NULL, adCmdStoredProc);<BR>开始建立一个Command对象,再设置ActiveConnection属性为一个已经打开的连接,然后指定存储过程名给CommandText属性,并且赋予adCmdStoredProc给Command对象的CommandType属性,存储过程有两个输入参数,所以生命两个Parameter对象,之后通过调用Command对象的CreateParameter方法建立它们,CreateParameter的第一个参数是一个为参数指定的可选名,第二个参数指定了参数的类型,第三个参数确定了参数的输入输出方向,第四个参数确定了变量的长度,第五个参数指定了参数的值。<BR>指定了参数之后,创建好的参数分别被传递赋值给pParam1和pParam2,之后创建好的参数被追加到Command对象的参数集中,所以为每个参数集的每个参数对象调用Append方法,现在指令可以运行了。<BR>上面提到的演示数据库的存储过程Query1 ,是一个简单的查询语句返回了一个记录集,运行命令对象后返回一个记录集,可以像上面那样方便的保存在一个Recordset对象里。<BR>错误处理机制<BR>本文中的所有代码,为了代码的简洁没有关心错误处理。现在将给出一个简单的错误处理的例子,可以使用在所有采用了ADO功能的程序中。通常,ADO构造一个COM对象,从而在运行时引发一个ADO错误的时候它总产生一个类型为_com_error的异常,将ADO函数调用放在一个可以处理产生异常的try - catch 块中,如下所示:<BR> try<BR> {<BR> HRESULT hr = m_pConn.CreateInstance(__uuidof(Connection));<BR> if (FAILED( hr ))<BR> AfxMessageBox( "Can't create an intance of ADO.Connection" );<BR> if (FAILED( m_pConn->Open( <BR> _bstr_t("Provider=Microsoft.Jet.OLEDB.4.0;Data Source = <BR> ADOTestDB.MDB"), _bstr_t( "" ), _bstr_t( "" ), <BR> adModeUnknown )))<BR> AfxMessageBox( "Can't open datasource" );<BR> ...<BR> ...<BR> ...<BR> m_pConn->Close();<BR> }<BR> catch( _com_error &e )<BR> {<BR> _bstr_t bstrSource(e.Source());<BR> _bstr_t bstrDescription(e.Description());<BR> TRACE( "Exception thrown for classes generated by #import" );<BR> TRACE( "\tCode = %08lx\n", e.Error());<BR> TRACE( "\tCode meaning = %s\n", e.ErrorMessage());<BR> TRACE( "\tSource = %s\n", (LPCTSTR) bstrSource);<BR> TRACE( "\tDescription = %s\n", (LPCTSTR) bstrDescription);<BR> }<BR> catch (...)<BR> {<BR> TRACE ( "*** Unhandled Exception ***" );<BR> }<BR>上述代码中,Open函数调用在指定的文件夹下找不到指定的mdb文件,从而产生一个异常,这个异常含有确定错误类型和错误代码以及错误的简单描述。<BR>结尾<BR>这只是关于ADO特性的简单描述,要成为这方面的专家,ADO中还需要学习大量的其它事情,这里只是试图提供一些学习ADO开发有用的应用程序的入门知识,不久的将来将向大家提供更多的这方面的文章来讨论更加有意思的ADO特性。<BR>如果您有什么建议或者问,您可以通过Email提交给我,我会非常高兴得知道您关于这篇短文的用处和缺陷,我的Email是shokuie@hotmail.com。<BR>关于M. Shokuie Nia<BR>VC++程序员,使用VC++从事果实时电话通信软件到数据库应用和基于应用的组建的不同领域的工作。 <BR>点击这里浏览M. Shokuie Nia's的在线资料。<BR><BR>
<br>
<a href="javascript:history.go(-1)">返回上页</a><br><a href=http://www.copathway.com/cndevforum/>访问论坛</a></p></blockquote>
<hr size=1>
<blockquote><p>
回复者:大伟 回复日期:2003-07-23 10:12:30
<br>内容:你这里用到了pRecordset->GetadoEOF()<BR>我看msdn的帮助中是 set->EOF,<BR>而有些文章又用 set->adoEOF==VARIANT_FALSE,<BR>能不能讲讲其中的联系和区别?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -