当前位置 博文首页 > 启舰:VC++ ADO操作总结

    启舰:VC++ ADO操作总结

    作者:[db:作者] 时间:2021-06-12 21:43

    1、导入库文件

    #import "C:\Program Files\commonfiles\system\ado\msado15.dll" no_namespace rename("EOF","EndOfFile")rename("BOF","FirstOfFile")
    使用ADO前必须在工程的stdafx.h文件最后用直接引入符号#import引入ADO库文件,以使编译器能正确编译。代码如下:

    ADO类的定义是作为一种资源存储在ADO DLL(msado15.dll)中,在其内部称为类型库。

    类型库描述了自治接口,以及C++使用的COM vtable接口。

    当使用#import指令时,在运行时Visual C++需要从ADO DLL中读取这个类型库,

    并以此创建一组C++头文件。这些头文件具有.tli 和.tlh扩展名,#import引入ADO库文件的代码编译后,在项目的目录下生成了这两个文件。在C++程序代码中调用的ADO类要在这些文件中定义。

    no_namespace指示ADO对象不使用名称空间,在有些应用程序中,

    由于应用程序中的对象与ADO中的对象之间可能会出现命名冲突,所以有必要使用名称空间。

    如果要使用名称空间,则可把第三行程序修改为: rename_namespace("AdoNS")。

    rename("EOF","EndOfFile")表示将ADO中的EOF(文件结束)更名为adoEOF,因为文件的结尾也是以EOF结尾的,是为了避免与定义了自己的EOF的其他库冲突。 至于改为什么名字,可以根据自己的命名习惯自己确定。

    2、初始化COM环境

    OLE DB 是基于COM技术编写的,ADO是OLE DB基础之上的用户程序,

    OLE DB是一个COM组件,在访问COM组件的时候需要初始化COM库,方法如下:

    (1)??::CoInitialize(NULL); //初始化OLE/COM库环境

    释放代码:

    ::CoUninitialize();//既然初始化了环境,当然一定要记得释放他了

    (2)也可以调用MFC全局函数

    AfxOleInit();

    3、三大指针对象的定义和创建实例

    (1)

    _ConnectionPtrpConnection("ADODB.Connection");
    
    _RecordsetPtrpRecordset("ADODB.Recordset");
    
    _CommandPtrpCommand("ADODN.Command");

    (2)

    _ConnectionPtr pConnection;
    
    _RecordsetPtr pRecordset;
    
    _CommandPtr pCommand;
    
     
    
    pConnection.CreateInstance(__uuidof(Connection));
    
    pRecordset.CreateInstance(__uuidof(Recordset));
    
    pCommand.CreateInstance(__uuidof(Command));

    要产生一个智能指针对象,其实在定义的同时也可以初始化,如:

    _ConnectionPtrpConnection(__uuidof(Connection));

    _ConnectionPtr 是智能指针

    __uuidof() 用来获取Connection全局唯一标识符

    (3)

    _ConnectionPtr pConnection;
    
    _RecordsetPtr pRecordset;
    
    _CommandPtr pCommand;
    
     
    
    pConnection.CreateInstance("ADODB.Connection");
    
    pRecordset.CreateInstance("ADODB.Recordset");
    
    pCommand.CreateInstance("ADODB.Command");?

    4、打开一个连接

    pConnection->ConnectionString = "这里的字符串有下面四种写法";//对连接字符串赋值
    
    pConnection->Open(ConnectionString,"","",adModeUnknown);//连接数据库
    //第二三个参数分别为用户的ID与密码,

    因为在连接字符串ConnectionCstring中已经设置好了,这里可以为空。

    第四个参数可以取下面两个参数:

    adAsyncConnect

    异步打开数据库,在ASP中直接用16

    adConnectUnspecified

    同步打开数据库,在ASP中直接用-1

    ConnectionString根据不同的数据源,分别对应不同的写法

    (要记下来很困难,可以在VB中利用ADO控件先连接好,再将其拷贝在VC中,这样不容易出错)

    ??? 1)

    访问Access 2000

    "Provider=Microsoft.Jet.OLEDB.4.0;DataSource=databaseName;UserID=userName;Password=userPassWord"

    ???2)

    访问ODBC数据

    "Provider=MADASQL;DSN=dsnName;UID=userName;PWD=userPassword;"

    ?? 3)

    访问Oracle数据库

    “Provider=MSDAORA;DataSourse=serverName;User ID=userName;Password=userPassword;"

    ?? 4)

    访问MS SQL数据库

    "Provider=SQLOLEDB,DataSource=serverName;Initial Catalog=databaseName;UserID=userName;Password=userPassword;"

    5、执行SQL命令,得到数据

    方法1:

    pRecordset =pConnection->Execute("Select * from authors",NULL,adCmdText);

    方法2:

    pRecordset ->Open("Select * fromauthors",_
    
    variant_t((Idispacth*) pConnection), //设置活动连接
    
    adOpenDynamtic,
    
    //游标类型
    
    adLockOptimistic,
    
    //锁的类型
    
    adCmdText);
    

    方法3:

    pCommand->put_ActiveConnection(_variant_t((Idispatch*) pConn);
    
    pCommand->CommandText = "Select *from authors";
    
    pRecordset =pCmd->Execute(NULL,NULL,adCmdText);

    得到数据之后,做一个循环取得数据:

    While (!pRecordset ->adoEOF)
    
    {
    
    Str =pRecordset->GetCollect("au_lname"));
    
    pRst->MoveNext();
    
    }

    SQL命令比较多,但是不去考虑细节,这里只说出通用的方法

    CString strSQL;//定义SQL命令串,用来保存SQL语句
    strSQL.Format("SQL statement");

    然后在每个要用到SQL命令串的方法中,使用strSQL.AllocSysString()的方法进行类型转换

    6、com的专用数据类型

    variant ,bstr ,SafeArray

    ?

    variant变量的范围包括很多,它是一种变体类型,主要用于支持自动化的语言访问,

    从而在VB中非常方便地使用,但是VC中比较复杂,它使用_variant_t 进行管理

    bstr是一种字符串变量,使用_bstr_t进行管理,这个类重载了char *操作符

    7、关闭连接

    if(pConnection->State);     //不能多次关闭,否则会出现错误
    
    {
    
    pConnection->Close();   //先判断状态,然后再关闭,其它类似
    
    }
    
    pRecordset->Close();
    
    pCommand.Release();
    
    pConnection.Release();
    
    //释放引用计数
    
    pRecordset.Release();

    ?注意:调用Close()时用"->",调用Release()时要用".",为什么?

    因为智能指针,_ConnectionPtr是一个重载了->运算符的类

    _ConnectionPtr:它是一个接口指针模板。'.'是模板_com_ptr的函数。->是'接口函数'调用。

    //forexample:

    _ConnectionPtr m_Conn;
    
    m_Conn.CreateInstance(....);//Createinterfaceinstance.
    
    m_Conn->Open(...);//Openaconnectiontodatabase.

    '->'是_com_ptr重载了的运算符.目的就是为了让你调用模板参数的函数.

    8、结构化异常处理

    ADO封装了COM接口,所以需要进行错误处理

    如下例:

    HRESULT hr;
    try{
    
    hr =m_pConnection.CreateInstance("ADODB.Connection");///创建Connection对象
    
    if(SUCCEEDED(hr))
    
    {
    
    hr =m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;DataSource=test.mdb","","",adModeUnknown);///连接数据库
    
    ///上面一句中连接字串中的Provider是针对ACCESS2000环境的,对于ACCESS97,需要改为:Provider=Microsoft.Jet.OLEDB.3.51;
    
    }
    
    }catch(_com_error e)///捕捉异常
    
    {
    
    CString errormessage;
    
    errormessage.Format("连接数据库失败!\r\n错误信息:%s",e.ErrorMessage());
    
    AfxMessageBox(errormessage);///显示错误信息
    }

    ?

    ACCESS中使用日期比较

    关于access中数据类型不匹配的问题between #1993-04-26# and #1993-05-26#

    2006-10-11 16:06

    /问题:
    //基于Access
    //VC中使用sql语句查询某一日期范围内的数据
    //查询语句如下:
    m_pSet->Open(CRecordset::snapshot,_T("select * from data01 where date between '1993-04-26' and '1993-05-26'"),CRecordset::executeDirect);
    //执行出现的报错总是:标准表达式中数据类型不匹配!
    ?
    //VC+Access这个已经是老问题了:)
    //不过,同学问的这个问题,我还是头次遇到
    //昨天反复查找原因花去我2个多小时:(
    //最后还是在百度里搜到了解答

    //网络里的高手总是很多^_^
    ?
    //最后可行的解决方案如下:
    //由于数据库用的是Access,所以日期要用#1993-04-26#而不是"1993-04-26"
    m_pSet->Open(CRecordset::snapshot,_T("select * from data01 where date between #1993-04-26# and #1993-05-26#"),CRecordset::executeDirect);

    获取执行SQL函数后的返回值 EGSUM(RoundInfo.RoundLen) from RoundInfo,Main where Main.Date between 2009-1-2 and 2012-2-3"

    temp_Str=L“SUM(RoundInfo.RoundLen) from RoundInfo,Main where Main.Date between 2009-1-2 and 2012-2-3"
    
    HRESULT hr = m_ptrRecordset->Open(_bstr_t(temp_Str), _variant_t((IDispatch*)m_ptrConnection, TRUE),
    
                       adOpenStatic, adLockBatchOptimistic, adCmdUnknown);
    
    if(!m_ptrRecordset->adoEOF)  //必需首先判断数据集是否是空,否则如果直接GetCollect()的话,会报出错误
    
    {             
    
    _variant_t    varNo = (_variant_t)m_ptrRecordset->GetCollect ((long)0);
    
    if(varNo.vt!=VT_NULL)   //判断是否是空记录
    
    {
    
    AvgLen = (long)varNo;
    
    }
    
    }
    ?

    函数总结:

    m_ptrRecordset->get_RecordCount(&this->m_threeRoundEnough);

    获取查询结果的数量(即个数)

    _variant_t ?? varNo = (_variant_t)m_ptrRecordset->GetCollect ((long)0);

    这句话的意思是获取第一列当前行的值,如果是查询之后直接用这句话,则指取第一行第一列的值,取下一列,则加上

    m_ptrRecordset->MoveNext();

    hr = m_ptrRecordset->Open(_bstr_t(temp_Str), _variant_t((IDispatch*)m_ptrConnection, TRUE), adOpenStatic, adLockBatchOptimistic, adCmdUnknown);// temp_Str是查询命令
    
                  ASSERT(m_ptrRecordset);
    
                  if(hr != S_OK)
    
                  {
    
                       m_ptrConnection->Close();
    
                       AfxMessageBox(L"create recordset error!");
    
                       return false;
    
                  }
    
                  if(!m_ptrRecordset->adoEOF)
    
                  {
    
                  _variant_t    varNo = (_variant_t)m_ptrRecordset->GetCollect ((long)0);  //得到查询结果的值
    
                  if(varNo.vt!=VT_NULL)
    
                  {
    
                  MinCount = varNo;
    
                  }
    
                  }?
    下一篇:没有了