ADO
От: dilsh  
Дата: 22.08.05 10:32
Оценка:
Пытаюсь выполнить хранимую процедуру 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++' — Павел Кузнецов
Re: ADO
От: Нахлобуч Великобритания https://hglabhq.com
Дата: 22.08.05 12:02
Оценка:
Здравствуйте, 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

Вот. Пользуйтесь. А насчет закрытого рекордсета — . Не должно так быть, ИМХО.
HgLab: Mercurial Server and Repository Management for Windows
Re: ADO
От: WPooh США  
Дата: 22.08.05 13:27
Оценка:
Здравствуйте, 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", "", "");

В первом случае выполняется системная хранимая, возвращающая несколько рекордсетов. Все хорошо.
Во втором — моя, указанная выше. Не возвращаем ничего. Ломаемся с той же ошибкой: закрытый рекордсет.
К этому моменту у меня внутри 0.5, 0.7, 0.33 (с) НС
Re: ADO
От: tarasich  
Дата: 22.08.05 13:53
Оценка:
Здравствуйте, 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
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.