1

我已经开始维护一个使用经典 ADO 的 MFC 桌面应用程序。有一个数据库访问 dll 包装了整个应用程序中使用的导入的 ADO。使用了存储过程,但也有很多文本查询,没有一个是参数化的。我被要求将它们转换为参数化查询。我更改的前 2 个查询遇到了问题。我调用了一个函数两次,它从一个名为“Parameters”(无关系)的表中获取一个字符串值,该表由一个唯一的整数索引。我创建了一个 ADO 参数来保存整数并执行查询。第二次调用此参数时,未设置参数并返回 -1(在 SQL 分析器中看到,第一次是正确的),导致记录集为空。我无法解释这一点,(尽管根据过去的经验,我'

m_spGlobal->LoginType = CSTR GetParam(19006);   //Calls function below          
BOOL bPrompt = (GetParam(19007) == "1") ? TRUE:FALSE;  //Second call

CString CMainFrame::GetParam(int nPram )
{
    DBSWIFTLib::IDBRecordsetPtr pDB(__uuidof(DBSWIFTLib::DBRecordset));//Declare smart pointer to dB access dll
    CString sSQL;
    pDB->ClearParameters();// loops through parameters collection, deleting any that exist(but shouldn't be any)
    pDB->ParameterInt( "pPram",nPram,   ADODB::adParamInput);   
    pDB->LockType = ADODB::adLockReadOnly;
    pDB->CursorLocation = ADODB::adUseClient;
    pDB->CursorType = ADODB::adOpenForwardOnly;
    sSQL.Format("SELECT sValue FROM Parameters WITH (NOLOCK) WHERE Id= ?");
    pDB->ExecuteSQL(CSTR sSQL);
    CString sReturn = "";
    if (!pDB->Empty())
    {
        sReturn = pDB->strval["sValue"];
    }
    return sReturn.Trim();
}
// ExecuteSQL from above function(in different COM dll)
STDMETHODIMP CDBRecordset::ExecuteSQL(LPSTR pszCommand)
{
    try
    {
        if (m_pRs->State != adStateClosed )
            m_pRs->Close( );
        m_pCmd->CommandText = pszCommand;
        m_pCmd->CommandType = adCmdText;
        m_pCmd->PutActiveConnection(_variant_t((IDispatch* )m_pRsConn ) );
        m_pRs = m_pCmd->Execute(&vtMissing, &vtMissing, adCmdText );
     }
    catch (_com_error &e)
    {
        m_strFunction  = _T("ExecuteSQL");
        m_strExtraInfo = pszCommand;
        DisplayADOError(e ); 
    }
    return S_OK;
}

//In same dll as previous function
STDMETHODIMP CDBRecordset::ParameterInt(LPSTR pszName, int nValue, int nDirection )
{
    try
    {
        m_pParam = m_pCmd->CreateParameter(pszName, 
                                       adInteger, 
                                       (ParameterDirectionEnum )nDirection,
                                       sizeof(nValue ), 
                                       (long )nValue );
        m_pCmd->Parameters->Append(m_pParam );
    }

    catch (_com_error &e ) 
    { 
        m_strFunction  = _T("ParameterInt");
        m_strExtraInfo = pszName;
        DisplayADOError(e ); 
    }
    return S_OK;
}

STDMETHODIMP CDBRecordset::ClearParameters( )
{
    try
   {
        long cParams = (m_pCmd->Parameters->Count - 1 );
        for (long m_nParams = cParams; m_nParams >= 0; m_nParams-- )
            m_pCmd->Parameters->Delete(variant_t(m_nParams ) );
    }

    catch (_com_error &e ) 
    { 
         m_strFunction  = _T("ClearParameters");
         DisplayADOError(e ); 
    }
    return S_OK;
}
  • 进一步(奇怪)信息:我现在注意到,对“GetParams”的两个函数调用的存在或执行会导致数据访问 dll 中的其他一些方法在被调用时抛出 _com_errors(它们涉及复制记录集)一个不相关的dll。如果我注释掉 2 个函数调用,错误就会消失,而引发错误的方法没有改变。

  • 编辑 21:31 4/11/11 我应该给出 ClearParameters 的实现 - 见上面代码的底部 至于没有设置参数,我的意思是查询中替换的值是“-1”而不是“ 19007”根据 SQL Server Profiler 记录。我认为 -1 是一个虚假值,它来自于参数在创建时未成功分配值。我应该补充一点,ADO 命令和记录集对象是在 DBRecordSet 构造函数中创建的。

    • 编辑21:32 5/11/11 我可能已经解决了这个问题。我正在使用 ADO 的“backcompat”版本,我不确定自从应用程序是用 VS6 编写以来方法参数类型是否发生了变化,但 CreateParameter 的签名现在是:

      _bstr_t Name, enum DataTypeEnum Type, enum ParameterDirectionEnum Direction, ADO_LONGPTR Size, const _variant_t & Value
      

这与示例代码中的参数不同(名称是 LPSTR,MSDN 中整数参数的大小例如是 -1,值作为长整数传递,而不是变体) 同样在 MSDN 示例中,设置了参数值在创建之后再次(虽然不确定这是否相关,为什么要设置两次?除非这是一个已知的“怪癖”)。使类型符合 ADO 对象模型似乎已经成功了。如果测试验证一切正常,我会将其作为答案发布

4

1 回答 1

0

正如我在上面的编辑中所写,我发现虽然应用程序在引入参数化查询之前工作(即所有存储过程数据访问调用都工作,隐式转换对于 SP 来说似乎没问题),但 ADO 中使用的类型“CreateParameter”的方法参数不正确(长而不是variant_t等)导致“未定义”行为。一旦我更正了方法参数类型,上面详述的参数化查询(和其他)工作正常,其他看似不相关的错误也消失了。起初我错过了这一点,因为该应用程序已经运行了 10 年以上而没有参数化查询 - 它通过添加它们来暴露问题。(我会等一会儿再接受这个作为答案,以防有人对此有更好的解释)

编辑- 当我让他们为只读记录集工作时,我发现在使用创建连接和从连接对象打开事务的技术以及使用此连接时出现“提供程序不支持更新”错误打开几个后续记录集,更改各种值,发出“更新”命令并提交事务。一旦我尝试修改字段的值,我就会收到错误消息。这永远不会发生在打开的记录集(从记录集对象而不是命令)或创建记录集的存储过程中。连接的位置是“客户端”,我没有理由期望它不起作用。我在 SQL Profiler 中观察到了它,直到它不起作用为止,一切看起来都是正确的(我认为)。

于 2011-11-07T21:11:16.983 回答