Пытаюсь выполнить хранимую процедуру MSSQL и прочитать возвращаемые ею значения.
_bstr_t strCnn("Provider=sqloledb;Data Source=MSSqL; Initial Catalog=db1;User Id=user;Password=pwd;");
_ConnectionPtr pConnection = NULL;
_CommandPtr pCmdChange = NULL;
_RecordsetPtr pRs = NULL;
_ParameterPtr pprmCmdChange ;
TESTHR(pConnection.CreateInstance(__uuidof(Connection)));
pConnection->Open (strCnn, "", "", adConnectUnspecified);
TESTHR(pCmdChange.CreateInstance(__uuidof(Command)));
pCmdChange->ActiveConnection = pConnection;
pCmdChange->CommandText = "sp";
pCmdChange->CommandType=adCmdStoredProc;
TESTHR(pRs.CreateInstance(__uuidof(Recordset)));
vtCriteria.vt = VT_I2;
vtCriteria.iVal =2;
pprmCmdChange = pCmdChange->CreateParameter("brand", adInteger,adParamInput, sizeof(int), vtCriteria);
pprmCmdChange->Value = vtCriteria;
pCmdChange->Parameters->Append(pprmCmdChange);
pRs=pCmdChange->Execute(NULL, NULL, adCmdStoredProc);
А что дальше? Попытка выполнить, к примеру, pRs->MoveNext() вызывает ругань, мол, невозможно выполнить операцию на закрытом рекордсете.
В MSDN про метод Execute объекта AdoCommand пишут "Execute returns a closed Recordset." Ну никак не могу врубиться как же его открыть?!
22.08.05 17:34: Перенесено модератором из 'C/C++' — Павел Кузнецов
Здравствуйте, dilsh, Вы писали:
D>Пытаюсь выполнить хранимую процедуру MSSQL и прочитать возвращаемые ею значения.
Смотрите как у меня сделано.
Есть класс DatabaseObject. Его наследуют все классы Data Access Layer'а
#pragma once
// В ado.h просто #import
#include "../ado.h"
namespace Data
{
//
// DatabaseObject base class
class DatabaseObject
{
// Строка соединения
CString m_strConnectionString;
// Соединение
ADODB::_ConnectionPtr m_adoConnection;
protected:
//
// Защищенный конструктор. Открывает соединение
DatabaseObject(const CString &strConnectionString) :
m_strConnectionString(strConnectionString)
{
m_adoConnection.CreateInstance(__uuidof(ADODB::Connection));
m_adoConnection->Open((LPCTSTR)m_strConnectionString, L"", L"", ADODB::adOptionUnspecified);
}
//
// Деструктор. Закрывает соединение
~DatabaseObject(void)
{
m_adoConnection->Close();
}
//
// Создает новый объект Command
ADODB::_CommandPtr BuildQuery(LPCTSTR lpszStoredProcedureName)
{
//
// Creating Command object
ADODB::_CommandPtr adoCommand(__uuidof(ADODB::Command));
adoCommand->ActiveConnection = m_adoConnection;
adoCommand->CommandType = ADODB::adCmdStoredProc;
adoCommand->CommandText = lpszStoredProcedureName;
adoCommand->NamedParameters = VARIANT_TRUE;
//
// Refreshing
adoCommand->Parameters->Refresh();
return adoCommand;
}
//
// Создает объект Command. Можно использовать для постпроцессинга
ADODB::_CommandPtr BuildCommand(LPCTSTR lpszStoredProcedureName)
{
//
// Building command
return BuildQuery(lpszStoredProcedureName);
}
//
// Подготавливает команду к выполнению
ADODB::_CommandPtr PrepareCommand(LPCTSTR lpszStoredProcedureName)
{
//
// Building command
ADODB::_CommandPtr adoCommand = BuildCommand(lpszStoredProcedureName);
return adoCommand;
}
//
// Выполняет команду.
// Лучше всегоиспользовать для INSERT, UPDATE и DELETE.
// Возвращает код RETURN'а хранимой процедуры
int ExecuteCommand(ADODB::_CommandPtr adoCommand, long &lRowsAffected)
{
//
// Executing
_variant_t vtRowsAffected;
adoCommand->Execute(&vtRowsAffected, &vtMissing,
ADODB::adCmdStoredProc | ADODB::adExecuteNoRecords);
//
// Returning result
int nResult = adoCommand->Parameters->Item[L"@RETURN_VALUE"]->Value;
lRowsAffected = vtRowsAffected;
return nResult;
}
//
// Выполняет команду
// Выполняет команду и возвращает Recordset
ADODB::_RecordsetPtr ExecuteCommand(ADODB::_CommandPtr adoCommand)
{
//
// Executing
_variant_t vtRowsAffected;
ADODB::_RecordsetPtr adoRecordset = adoCommand->Execute(&vtRowsAffected, &vtMissing,
ADODB::adCmdStoredProc);
return adoRecordset;
}
//
// Выполняет команду и возвращает Record
ADODB::_RecordPtr ExecuteCommandEx(ADODB::_CommandPtr adoCommand)
{
//
// Executing
_variant_t vtRowsAffected;
ADODB::_RecordPtr adoRecord = adoCommand->Execute(&vtRowsAffected, &vtMissing,
ADODB::adCmdStoredProc | ADODB::adExecuteRecord);
return adoRecord;
}
};
} // namespace Data
А вот использующий его DAL-класс Supplier (Поставщик)
namespace Data
{
//
// Supplier class - Data Access Layer
class Supplier : public octalforty::WarehouseSystem::Classes::Data::DatabaseObject
{
public:
//
// Public constructor
Supplier(const CString &strConnectionString) :
DatabaseObject(strConnectionString)
{
}
//
// Destructor
~Supplier(void)
{
}
//
// Returns all suppliers
ADODB::_RecordsetPtr GetSuppliers()
{
//
// Executing stored procedure
return ExecuteCommand(PrepareCommand(_T("Suppliers_GetSuppliers")));
}
//
// Returns one Supplier object
ADODB::_RecordsetPtr GetSupplier(long lID)
{
//
// SQL SP parameters
ADODB::_CommandPtr adoCommand = PrepareCommand(_T("Suppliers_GetSupplier"));
adoCommand->Parameters->Item[L"@id"]->Value = lID;
//
// Executing
return ExecuteCommand(adoCommand);
}
//
// Creates one Supplier object. Returns ID of a newly created object
long CreateSupplier(long lCurrencyID, const CString &strSupplier, const CString &strAddress,
const CString &strEMail, const CString &strPhoneNumber, const CString &strSupplementalInformation)
{
//
// SQL SP parameters
ADODB::_CommandPtr adoCommand = PrepareCommand(_T("Suppliers_CreateSupplier"));
adoCommand->Parameters->Item[L"@currencyID"]->Value = lCurrencyID;
adoCommand->Parameters->Item[L"@supplier"]->Value = (LPCTSTR)strSupplier;
adoCommand->Parameters->Item[L"@address"]->Value = (LPCTSTR)strAddress;
adoCommand->Parameters->Item[L"@email"]->Value = (LPCTSTR)strEMail;
adoCommand->Parameters->Item[L"@phoneNumber"]->Value = (LPCTSTR)strPhoneNumber;
adoCommand->Parameters->Item[L"@supplementalInformation"]->Value = (LPCTSTR)strSupplementalInformation;
adoCommand->Parameters->Item[L"@id"]->Value = 0;
//
// Executing
long lRowsAffected;
ExecuteCommand(adoCommand, lRowsAffected);
return (long)adoCommand->Parameters->Item[L"@id"]->Value;
}
//
// Updates Supplier
void UpdateSupplier(long lID, long lCurrencyID, const CString &strSupplier, const CString &strAddress,
const CString &strEMail, const CString &strPhoneNumber, const CString &strSupplementalInformation)
{
//
// SQL SP parameters
ADODB::_CommandPtr adoCommand = PrepareCommand(_T("Suppliers_UpdateSupplier"));
adoCommand->Parameters->Item[L"@id"]->Value = lID;
adoCommand->Parameters->Item[L"@currencyID"]->Value = lCurrencyID;
adoCommand->Parameters->Item[L"@supplier"]->Value = (LPCTSTR)strSupplier;
adoCommand->Parameters->Item[L"@address"]->Value = (LPCTSTR)strAddress;
adoCommand->Parameters->Item[L"@email"]->Value = (LPCTSTR)strEMail;
adoCommand->Parameters->Item[L"@phoneNumber"]->Value = (LPCTSTR)strPhoneNumber;
adoCommand->Parameters->Item[L"@supplementalInformation"]->Value = (LPCTSTR)strSupplementalInformation;
//
// Executing
long lRowsAffected;
ExecuteCommand(adoCommand, lRowsAffected);
}
//
// Deletes Supplier
void DeleteSupplier(long lID)
{
//
// SQL SP parameters
ADODB::_CommandPtr adoCommand = PrepareCommand(_T("Suppliers_DeleteSupplier"));
adoCommand->Parameters->Item[L"@id"]->Value = lID;
//
// Executing
long lRowsAffected;
ExecuteCommand(adoCommand, lRowsAffected);
}
};
То есть то, что у вас записывается как
pprmCmdChange = pCmdChange->CreateParameter("brand", adInteger,adParamInput, sizeof(int), vtCriteria);
pprmCmdChange->Value = vtCriteria;
pCmdChange->Parameters->Append(pprmCmdChange);
У меня выглядит так:
pprmCmdChange->Parameters->Item[L"@brand"]->Value = vtCriteria;
Это, разумеется, при наличии хранимой процедуры с параметрами:
CREATE PROCEDURE dbo.BlogPostCategories_CreateBlogPostCategory
(
@name nvarchar(400),
@description ntext,
@id int output )
AS
-- Inserting
SET ANSI_PADDING OFF
INSERT INTO BlogPostCategories (Name, Description)
VALUES (@name, @description)
SET @id = @@IDENTITY
Вот. Пользуйтесь. А насчет закрытого рекордсета —

. Не должно так быть, ИМХО.
Здравствуйте, dilsh, Вы писали:
D>Пытаюсь выполнить хранимую процедуру MSSQL и прочитать возвращаемые ею значения.
Вы уверены, что ваша хранимая процедура возвращает рекордсет вообще?
Например, моя хранимая не возвращает
CREATE PROC tst
AS
GO
Вот мой обрезанный код, под ваш случай
void execProc(_bstr_t connStr, _bstr_t procName, _bstr_t paramName, _bstr_t paramValue)
{
ADODB::_CommandPtr pComm;
ADODB::_ConnectionPtr conn;
conn.CreateInstance(__uuidof(ADODB::Connection));
conn->Open(connStr, "", "", ADODB::adConnectUnspecified);
pComm.CreateInstance(__uuidof(ADODB::Command));
pComm->CommandText = procName;
if (paramName.length()) {
ADODB::_ParameterPtr param = pComm->CreateParameter(
paramName, ADODB::adVarWChar, ADODB::adParamInput, paramValue.length(), paramValue);
pComm->Parameters->Append(param);
}
pComm->ActiveConnection = conn;
ADODB::_RecordsetPtr res = pComm->Execute(NULL, NULL, ADODB::adCmdStoredProc);
res->MoveNext();
}
execProc(connStr, "sp_helpconstraint", "@objname", "Categories");
execProc(connStr2, "tst", "", "");
В первом случае выполняется системная хранимая, возвращающая несколько рекордсетов. Все хорошо.
Во втором — моя, указанная выше. Не возвращаем ничего. Ломаемся с той же ошибкой: закрытый рекордсет.
Здравствуйте, dilsh, Вы писали:
D>Пытаюсь выполнить хранимую процедуру MSSQL и прочитать возвращаемые ею значения.
D>D> _bstr_t strCnn("Provider=sqloledb;Data Source=MSSqL; Initial Catalog=db1;User Id=user;Password=pwd;");
D> _ConnectionPtr pConnection = NULL;
D> _CommandPtr pCmdChange = NULL;
D> _RecordsetPtr pRs = NULL;
D> _ParameterPtr pprmCmdChange ;
D> TESTHR(pConnection.CreateInstance(__uuidof(Connection)));
D> pConnection->Open (strCnn, "", "", adConnectUnspecified);
D> TESTHR(pCmdChange.CreateInstance(__uuidof(Command)));
D> pCmdChange->ActiveConnection = pConnection;
D> pCmdChange->CommandText = "sp";
D> pCmdChange->CommandType=adCmdStoredProc;
D> TESTHR(pRs.CreateInstance(__uuidof(Recordset)));
D> vtCriteria.vt = VT_I2;
D> vtCriteria.iVal =2;
D> pprmCmdChange = pCmdChange->CreateParameter("brand", adInteger,adParamInput, sizeof(int), vtCriteria);
D> pprmCmdChange->Value = vtCriteria;
D> pCmdChange->Parameters->Append(pprmCmdChange);
D> pRs=pCmdChange->Execute(NULL, NULL, adCmdStoredProc);
D>
D>А что дальше? Попытка выполнить, к примеру, pRs->MoveNext() вызывает ругань, мол, невозможно выполнить операцию на закрытом рекордсете.
D>В MSDN про метод Execute объекта AdoCommand пишут "Execute returns a closed Recordset." Ну никак не могу врубиться как же его открыть?!
Возвращаемые значения читаются так же как выходные параметры, например так
pCmdChange->CreateParameter("Return Value", adInteger,adParamReturnValue, sizeof(int));
pCmdChange->Execute(NULL, NULL, adCmdStoredProc);
COleVariant value=pCmdChange->Parameters->GetItem(COleVariant(0))->GetValue();
Если ожидается возртат Recordset, то рекомендуется все таки пользоваться методом Recordset Open