VC中使用ADO调用存储过程实现方法

    技术2022-07-03  112

     

    本文转自:http://www.cppblog.com/Lee7/archive/2008/06/17/53775.html

     

    开发环境是VS2005  ,数据库是SQL Sever 2000

    1. 在进入正题之前,先讲点别的,如何在VC中连接Sybase数据库,

       连接字符窜为,

      _bstr_t strCnn(/"Driver={Sybase System 11};Srvr=RRRRR;Uid=RRR_Mao_bb1;Pwd=user2/");

    这里,RRRRR是数据库的名称,已经在Sybase->sdedit中设定好了

     RRR_Mao_bb1 和 user2分别是用户名和密码

     不过使用这种基于ODBC的连接使用一段时间以后,就出现问题了,出现了“Catastrophic failure”的错误,微软的解释是  http://support.microsoft.com/kb/243349/en-us

     

    2. 为了使我们的调用存储过程的例子有更多的通用性,我建了有输入参数,有输出参数,有一个返回记录集,有一个返回值的存储过程,如下

       CREATE  PROCEDURE sp_1  (                         @pin1  int ,                         @pin2  CHAR(10),                         @pout1 int OUTPUT,                         @pout2 CHAR(10)  OUTPUT                       )AS                       BEGIN  declare  @retval  int    select @pout1 = @pin1 + 100    select @pout2 =  left( ltrim(rtrim(@pin2)) + /'123/' , 10)    select Num,Name,Date     from TABLE1      select @retval =  1236    return @retvalEND

    对于这个SP来说,他这些个参数是

    @RETURN_VALUE(int ,返回值)  

    @pin1 ( int  ,输入 )  

    @pin2 ( char(10)  ,输入 ) 

    @pout1 (int ,输入/输出) 

    @pout1 ( char(10)  , 输入/输出)  

    @RETURN_VALUE是第0个参数,@pin1是第1个,依此类推

    以上信息可以在SQL 的查询分析器中看到,注意,这些参数的顺序很重要

     

    3.调用的前期准备

      这就不多说了,什么import 库阿,建立连接阿,什么的,不多说了,

     这些在 VC中使用ADO进行数据库开发的一些资料的整理 中有了阐述

    假定连接是pConn

    注意,这里要把pConn设定成adUseClient型[Page]

    pConn->CursorLocation =adUseClient;

    下面我要贴具体的代码了,为了精简所贴的代码,我把所有的捕获异常都没贴出来(try catch)

     

    4.使用Refresh的方法来调用

    先定义一些变量

     _CommandPtr     pCmd = NULL; _RecordsetPtr   pRecordset = NULL;

    初试化他们,

     pCmd.CreateInstance(__uuidof(Command));  pRecordset.CreateInstance(_uuidof(Recordset));  pCmd->ActiveConnection = pConn;  pCmd->CommandType = adCmdStoredProc;  pCmd->CommandText=_bstr_t(_T(/"sp_1/"));  //SP Name

    然后给那些input参数赋值

     pCmd->Parameters->Refresh();     pCmd->Parameters->Item[_variant_t(_bstr_t(/"@pin1/") )]->Value=_variant_t(3);  

     pCmd->Parameters->Item[_variant_t(_bstr_t(/"@pin2/") )]->Value=_variant_t(/"DD/");  

    这个refresh一定要有,

    调SP

    pRecordset =  pCmd->Execute(NULL,NULL,adCmdStoredProc);

    int   retVal = -1; _variant_t   VretVal ;

    //GetRetVal   VretVal = pCmd->Parameters->GetItem(short(0))->Value;    retVal = VretVal.lVal;     Info.Format(_T(/"The Return Value is : %d/"),retVal);  MessageBox(Info);

      //output1   VretVal = pCmd->Parameters->GetItem(short(3))->Value;   retVal = VretVal.lVal;     Info.Format(_T(/"The output1 Value is : %d/"),retVal);  MessageBox(Info);

      //@pout2   VretVal = pCmd->Parameters->GetItem(short(4))->Value;    Info= (LPCTSTR)_bstr_t(VretVal);  CString info1;  info1.Format(_T(/"The output2 Value is : %s/"),Info);    MessageBox(info1);

     //取记录集里面的内容

      if (pRecordset->adoBOF && pRecordset->adoEOF)  {   MessageBox(/"没有符合条件的记录存在!/",/"提示/");

       if(pRecordset != NULL && pRecordset->State)   {    pRecordset->Close();    pRecordset = NULL; 

    }

     

       pCmd.Detach();   return;  }     pRecordset->MoveFirst();    for(;!pRecordset->adoEOF;pRecordset->MoveNext())  {   VRectVal = pRecordset->GetCollect(_T(/"Name/"));   StrVal = (LPCTSTR)_bstr_t(VRectVal);   m_list.AddString(StrVal);  }

      if(pRecordset != NULL && pRecordset->State)  {   pRecordset->Close();   pRecordset = NULL;  [Page]  }

    最后pCmd.Detach();

     在这里,有一点要注意的是

    VretVal = pCmd->Parameters->GetItem(short(4))->Value;这里的4,就是哪个output参数的index,就是我在2中说的参数的顺序

    这里使用了Refresh,这是一个很重要的函数,我将在下面介绍一下它,我要先贴出另一种,不使用Refresh的办法,

    5 .使用非Refresh的方法来调用

    先定义变量

    _CommandPtr     pCmd = NULL; _RecordsetPtr   pRecordset = NULL;

     _ParameterPtr   retParam = NULL;       _ParameterPtr   inParam1 = NULL;   _ParameterPtr   inParam2 = NULL;   _ParameterPtr   outParam1 = NULL;  _ParameterPtr   outParam2 = NULL; 

    初试化

            pCmd.CreateInstance(__uuidof(Command));  pRecordset.CreateInstance(_uuidof(Recordset));

    retParam.CreateInstance(__uuidof(Parameter));

    //其他的ParameterPtr   也初试化  pCmd->ActiveConnection = pConn;  pCmd->CommandType = adCmdStoredProc;   pCmd->CommandText=_bstr_t(_T(/"sp_1/"));  //SP Name

     retParam = pCmd ->CreateParameter(_bstr_t(/"Return/"),                                 adInteger,            adParamReturnValue,            sizeof(int));  pCmd->Parameters->Append(retParam);

                inParam1  = pCmd ->CreateParameter(_bstr_t(/"InParam1/"),                                 adInteger,            adParamInput,            sizeof(int));

      inParam1->Value = _variant_t(3);

      pCmd->Parameters->Append(inParam1);

      inParam2  = pCmd ->CreateParameter(_bstr_t(/"InParam2/"),                                 adChar,            adParamInput,[Page]            10);   inParam2->Value = _variant_t(_T(/"DD1/"));

      pCmd->Parameters->Append(inParam2);

      outParam1 = pCmd ->CreateParameter(_bstr_t(/"OutParam1/"),                                 adInteger,            adParamOutput,            sizeof(int));  pCmd->Parameters->Append(outParam1);

      outParam2 = pCmd ->CreateParameter(_bstr_t(/"OutParam2/"),                                 adChar,            adParamOutput,            10);  pCmd->Parameters->Append(outParam2);

     

    这里不用refresh的办法,是用Parameter来,这里要注意的是,这个add的顺序要和参数的index顺序要一致

    下面就是调用了

    pRecordset =  pCmd->Execute(NULL,NULL,adCmdStoredProc);

    然后取那些return值阿,output值阿什么的

    这里有一个区别,就是用这种办法

    可以有三种办法来取这些返回值和output参数

    VretVal = pCmd->Parameters->GetItem(_bstr_t(/"Return/"))->Value;VretVal = pCmd->Parameters->GetItem(short(0))->Value; VretVal = retParam->Value;

    都是一样的

    6. 关于Refresh

    关于这个函数,作用是

    Command   对象去重新索取要操作的存储过程所有有关参数的信息,并且清空在refresh之前获取的参数信息。  

    所以一但调用它以后,就可以获取SP的那些信息,那些参数的信息,可以通过pCmd->Parameters->Item[_variant_t(_bstr_t(/"@pin1/") )]->Value=_variant_t(3);   这样的方式来设置参数

    如果要使用Parameter的办法的话,就不要用refresh了,事实上,如果先把这些参数的值设置好了,如  inParam2->Value = _variant_t(_T(/"DD1/"));,一旦refresh后,这些参数就没有意义了。

    7.关于pConn->CursorLocation =adUseClient;

     设置这个东西,如果不设置游标为adUseClient,那么我在取return和output参数的时候,必须在我把记录集关闭以后才能取,就是说,必须先取记录集,然后关闭它,最后再取return和output参数,如果我在关闭记录集之前就取return和output的值,那么就不能取到正确的值,设成adUseClient就ok了,

    另外有一点就是,Execute 方法返回的游标继承该设置。Recordset 将自动从与之关联的连接中继承该设置。我把pConn设成adUseClient,那么最后,我的记录集也是adUseClient的了[Page]

     

    //注:

    本文说明的方法:

    //此参数声明在最前 _ParameterPtr retParam = NULL; retParam = sql_command ->CreateParameter("",adInteger,adParamReturnValue,sizeof(int)); sql_command->Parameters->Append(retParam); //执行完存储过程后 int returnValue=-1; _variant_t VretVal ; VretVal=retParam->Value; returnValue=VretVal.lVal; 

    或直接用下面方法:

    int returnValue=(int)sql_command->Parameters->GetItem(long(0))->GetValue(); 

     


    最新回复(0)