Я начал обслуживать настольное приложение MFC, которое использует классический ADO.Существует библиотека доступа к базе данных, которая оборачивает импортированный ADO, который используется во всем приложении.Используются хранимые процедуры, но также есть много текстовых запросов, ни один из которых не параметризован.Меня попросили преобразовать их в параметризованные запросы.Первые 2 запроса, которые я изменил, столкнулись с проблемой.Я дважды вызываю функцию, которая получает строковое значение из таблицы с именем «Параметры» (без отношения), индексируемой уникальным целым числом.Я создаю параметр 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 Command & Recordset создаются в конструкторе DBRecordSet.
EDIT 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, значение передается как long, а не как вариант).в примере с MSDN значение параметра снова устанавливается после создания (хотя не уверен, что это важно, зачем устанавливать его дважды? если это не известная «причуда»).Приведение типов в соответствие с объектной моделью ADO, похоже, добилось цели.Я опубликую это как ответ, если тестирование подтвердит, что все работает правильно