我已经开始维护一个使用经典 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 对象模型似乎已经成功了。如果测试验证一切正常,我会将其作为答案发布