2014-04-26 1 views
-1

Visual Studio 2005에서 Microsoft ATL 및 C++을 사용하는 OLE 데이터베이스 프로그래밍을 실험하고 있습니다. 간단한 Windows 데이터베이스 프로그램과 함께 샘플 Windows 콘솔 프로그램을 만들었습니다 10 개의 문자 (ANSI 숫자) ID와 부호가있는 32 비트 길이 카운트라는 두 개의 열이 포함 된 단일 테이블이 있습니다. 표에는 두 개의 행이 있습니다. 데이터베이스, 테이블 및 행은 SQL Server 2005 Server Management Studio Express를 사용하여 만들어졌습니다.간단한 SQL 서버 테이블에서 C++의 ATL OLE 데이터베이스를 사용하여 가져온 행 데이터를 업데이트하는 방법

가져온 행의 데이터를 업데이트하기 위해 ATL에서 사용 된 방법을 알아야합니다.

가져 오기를 잘못 수행했을 수 있습니다. 문제 일 수 있습니다. 프로그램을 실행하는 동안 행을 검색하기위한 SQL 쿼리를 실행할 때 myTable.Open()에 의해 호출되는 메서드 GetInterfacePtr()에 대한 호출을 포함하는 것으로 보이는 3 개의 ASSERT가 표시됩니다. 그러나 반환 된 HRESULT 값은 S_OK이며 SQL 쿼리가 제대로 작동하는 것으로 보입니다.

myTable.SetData()에서 HRESULT

오류 반환하고 선택한 행 그러나 나는 그 의미도 어떤 변화하는 행을 갱신하는 데 필요한 모르겠어요 업데이트되지 않는 디버거에 따라 E_NOINTERFACE의 값을 갖는다.

Table_1.h 포함 파일은 Visual Studio 2005의 마법사에서 생성되지만 클래스는 CCommand 형식의 템플릿에서 파생됩니다.

class CTable_1 : public CCommand<CAccessor<CTable_1Accessor> > 

주요 프로그램 소스는 다음과 같습니다

#include "stdafx.h" 
#include <string> 
#include <iostream> 

// the VS 2005 generated include file for the table. 
#include "Table_1.h" 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    HRESULT hrResult = OleInitialize(NULL); 

    switch (hrResult) 
    { 
     case S_OK: 
      break; 
     default: 
      std::cout << "Ole Initialization Failed " << hrResult << std::endl; 
      return FALSE; 
    } 

    CTable_1 myTable; 

    HRESULT hr = myTable.OpenAll(); 

    std::string m_strQuery("select * from Table_1"); 
    hrResult = myTable.Open(myTable.m_session, m_strQuery.c_str()); 
    if (hrResult == S_OK) { 
     int nItem = 0; 
     while (myTable.MoveNext() == S_OK) 
     { 
      if (nItem < 25) 
      { 
       char szValueChar[40]; 
       for (int i = 0; i < 40; i++) szValueChar[i] = (char)myTable.m_IdNumber[i]; 
       std::string sTemp (szValueChar); 
       std::cout << nItem << " -> " << sTemp << " : " << myTable.m_Count << std::endl; 
       nItem++; 
      } 
     } 
    } else { 
     std::cout << "assessor open failed " << hrResult << " \"" << m_strQuery << "\"" << std::endl; 
    } 

    // Update a specific row in the table by incrementing its count. 
    m_strQuery = "select * from Table_1 where IdNumber='0000000001'"; 
    hrResult = myTable.Open(myTable.m_session, m_strQuery.c_str()); 
    if (hrResult == S_OK) { 
     hrResult = myTable.MoveNext(); 
     char szValueChar[40]; 
     for (int i = 0; i < 40; i++) szValueChar[i] = (char)myTable.m_IdNumber[i]; 
     std::string sTemp (szValueChar); 
     std::cout << " selected item -> " << sTemp << " : " << myTable.m_Count << std::endl; 
     myTable.m_Count++; 
      // <<<<< Following SetData() returns HRESULT of E_NOINTERFACE 
     hrResult = myTable.SetData(); 
     if (hrResult != S_OK) std::cout << "** update error. hrResult = " << hrResult << std::endl; 
    } 

    std::cout << std::endl << " after update" << std::endl; 

    m_strQuery = "select * from Table_1"; 
    hrResult = myTable.Open(myTable.m_session, m_strQuery.c_str()); 
    if (hrResult == S_OK) { 
     int nItem=0; 
     while (myTable.MoveNext() == S_OK) 
     { 
      if (nItem < 25) 
      { 
       char szValueChar[40]; 
       for (int i = 0; i < 40; i++) szValueChar[i] = (char)myTable.m_IdNumber[i]; 
       std::string sTemp (szValueChar); 
       std::cout << nItem << " -> " << sTemp << " : " << myTable.m_Count << std::endl; 
       nItem++; 
      } 
     } 
    } else { 
     std::cout << "assessor open failed " << hrResult << " \"" << m_strQuery << "\"" << std::endl; 
    } 

    myTable.CloseAll(); 

    OleUninitialize(); 
    return 0; 
} 

콘솔 윈도우의 출력은 다음과 같습니다

0 -> 0000000001 : 2 
1 -> 0000000002 : 3 
    selected item -> 0000000001 : 2 
** update error. hrResult = -2147467262 

after update 
0 -> 0000000001 : 2 
1 -> 0000000002 : 3 

편집 # 1 - Table_1.h (마법사가 생성 제안 변경)

// Table_1.h : Declaration of the CTable_1 

#pragma once 

// code generated on Friday, April 25, 2014, 10:25 PM 

class CTable_1Accessor 
{ 
public: 
    TCHAR m_IdNumber[11]; 
    LONG m_Count; 

    // The following wizard-generated data members contain status 
    // values for the corresponding fields in the column map. You 
    // can use these values to hold NULL values that the database 
    // returns or to hold error information when the compiler returns 
    // errors. See Field Status Data Members in Wizard-Generated 
    // Accessors in the Visual C++ documentation for more information 
    // on using these fields. 
    // NOTE: You must initialize these fields before setting/inserting data! 

    DBSTATUS m_dwIdNumberStatus; 
    DBSTATUS m_dwCountStatus; 

    // The following wizard-generated data members contain length 
    // values for the corresponding fields in the column map. 
    // NOTE: For variable-length columns, you must initialize these 
    //  fields before setting/inserting data! 

    DBLENGTH m_dwIdNumberLength; 
    DBLENGTH m_dwCountLength; 


    void GetRowsetProperties(CDBPropSet* pPropSet) 
    { 
     pPropSet->AddProperty(DBPROP_CANFETCHBACKWARDS, true, DBPROPOPTIONS_OPTIONAL); 
     pPropSet->AddProperty(DBPROP_CANSCROLLBACKWARDS, true, DBPROPOPTIONS_OPTIONAL); 
     //<< lines added from stackoverflow answer 
     pPropSet->AddProperty(DBPROP_IRowsetChange, (bool) TRUE); 
     pPropSet->AddProperty(DBPROP_IRowsetUpdate, (bool) TRUE); 
     pPropSet->AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT); 
    } 

    HRESULT OpenDataSource() 
    { 
     CDataSource _db; 
     HRESULT hr; 
     hr = _db.OpenFromInitializationString(L"Provider=SQLNCLI.1;Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=TestData;Use Procedure for Prepare=1;Auto Translate=True;Packet Size=4096;Workstation ID=CIT-31204E1FF03;Use Encryption for Data=False;Tag with column collation when possible=False;MARS Connection=False;DataTypeCompatibility=0;Trust Server Certificate=False"); 
     if (FAILED(hr)) 
     { 
#ifdef _DEBUG 
      AtlTraceErrorRecords(hr); 
#endif 
      return hr; 
     } 
     return m_session.Open(_db); 
    } 

    void CloseDataSource() 
    { 
     m_session.Close(); 
    } 

    operator const CSession&() 
    { 
     return m_session; 
    } 

    CSession m_session; 

    DEFINE_COMMAND_EX(CTable_1Accessor, L" \ 
    SELECT \ 
     IdNumber, \ 
     Count \ 
     FROM dbo.Table_1") 


    // In order to fix several issues with some providers, the code below may bind 
    // columns in a different order than reported by the provider 

    BEGIN_COLUMN_MAP(CTable_1Accessor) 
     COLUMN_ENTRY_LENGTH_STATUS(1, m_IdNumber, m_dwIdNumberLength, m_dwIdNumberStatus) 
     COLUMN_ENTRY_LENGTH_STATUS(2, m_Count, m_dwCountLength, m_dwCountStatus) 
    END_COLUMN_MAP() 
}; 

class CTable_1 : public CCommand<CAccessor<CTable_1Accessor> > 
{ 
public: 
    HRESULT OpenAll() 
    { 
     HRESULT hr; 
     hr = OpenDataSource(); 
     if (FAILED(hr)) 
      return hr; 
     __if_exists(GetRowsetProperties) 
     { 
      CDBPropSet propset(DBPROPSET_ROWSET); 
      __if_exists(HasBookmark) 
      { 
       if(HasBookmark()) 
        propset.AddProperty(DBPROP_IRowsetLocate, true); 
      } 
      GetRowsetProperties(&propset); 
      return OpenRowset(&propset); 
     } 
     __if_not_exists(GetRowsetProperties) 
     { 
      __if_exists(HasBookmark) 
      { 
       if(HasBookmark()) 
       { 
        CDBPropSet propset(DBPROPSET_ROWSET); 
        propset.AddProperty(DBPROP_IRowsetLocate, true); 
        return OpenRowset(&propset); 
       } 
      } 
     } 
     return OpenRowset(); 
    } 

    HRESULT OpenRowset(DBPROPSET *pPropSet = NULL) 
    { 
     HRESULT hr = Open(m_session, NULL, pPropSet); 
#ifdef _DEBUG 
     if(FAILED(hr)) 
      AtlTraceErrorRecords(hr); 
#endif 
     return hr; 
    } 

    void CloseAll() 
    { 
     Close(); 
     ReleaseCommand(); 
     CloseDataSource(); 
    } 
}; 

답변

0

: 테이블 클래스에서 당신은 같은 (이 어딘가에 Table_1.h에 당신이 게시되지 않은 가야한다)을 가져야한다. 생성 된 출력을 가진 수정 된 버전이 아래에 제공됩니다.

첫 번째 문제점은 Open()의 등록 정보가 데이터베이스의 행 읽기를 허용하도록 설정된 Roman R.에서 식별 된 문제점이었습니다. 그는 데이터를 업데이트 할 수 있도록 추가해야 할 속성에 대해 설명합니다.

OpenAll() 메서드는 CTable_1Accessor 클래스의 GetRowsetProperties() 메서드를 사용하여 속성을 데이터베이스 열기 처리의 일부로 설정합니다. 메소드에서 디버거 중단 점을 설정하면이 점을 알 수 있습니다. 그러나 Open() 메서드에 대한 다른 호출은 GetRowsetProperties() 함수를 호출하지 않으므로 Open()에 대한 다른 호출에는 결과 행 집합의 기본 속성을 수정하기 위해 지정된 속성 집합이 있어야합니다.따라서 CTable_1Accessor 클래스의 GetRowsetProperties() 메서드가 마법사에서 포함 된 파일을 생성하는 데 필요한 변경뿐만 아니라 SetDate() 메서드를 사용하여 해당 파일을 업데이트 할 수 있도록 각 Open()에 대한 적절한 속성을 추가해야했습니다. 행 집합입니다.

게시 된 예제의 두 번째 문제점은 다양한 Open() 변형을 사용한 후에 Close() 함수가 검색된 행 집합을 닫는 데 사용되지 않는다는 것입니다. Close()이 없으면 두 번째 이후의 Open()이 호출 될 때 어설 션을 유발 한 원인이됩니다.

수정 된 출처는 다음과 같습니다. 이 작업은 Visual Studio 2005에서 ATL로 새 Windows 콘솔 프로젝트를 시작한 다음 클래스 마법사를 사용하여 ATL 기반 테이블 액세스 클래스를 만드는 방법으로 작성되었습니다. 마법사를 사용하여 삽입, 삭제 및 업데이트가 가능하도록 마법사 대화 상자의 확인란을 선택하고 CTable1 클래스 (class CTable_1 : public CCommand<CAccessor<CTable_1Accessor> >)가 사용하는 접근 자에 대해 Roman R.이 설명한대로 적절한 GetRowsetProperties() 메서드를 생성했습니다.

수정 된 예제 프로그램은 다음과 같습니다.

#include "stdafx.h" 
#include <string> 
#include <iostream> 

#include "Table_1.h" 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    HRESULT hrResult = OleInitialize(NULL); 
    switch (hrResult) 
    { 
     case S_OK: 
      break; 
     default: 
      std::cout << "Ole Initialization Failed " << hrResult << std::endl; 
      return 1; 
    } 

    // Our standard property set used in various Open() where we specify an SQL query. 
    CDBPropSet pPropSet(DBPROPSET_ROWSET); 
    pPropSet.AddProperty(DBPROP_CANFETCHBACKWARDS, true, DBPROPOPTIONS_OPTIONAL); 
    pPropSet.AddProperty(DBPROP_CANSCROLLBACKWARDS, true, DBPROPOPTIONS_OPTIONAL); 
    pPropSet.AddProperty(DBPROP_IGetRow, true, DBPROPOPTIONS_OPTIONAL); 
    pPropSet.AddProperty(DBPROP_IRowsetChange, true, DBPROPOPTIONS_OPTIONAL); 
    pPropSet.AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE); 

    CTable_1 myTable;  // our table access object we will use for all our operations. 
    int  nItem = 0; 
    HRESULT hr; 

    // First example, OpenAll() which uses the default SQL query retrieving all records 
    hr = myTable.OpenAll(); 
    for (nItem = 0, hr = myTable.MoveFirst(); hr == S_OK; hr = myTable.MoveNext()) 
    { 
     char szValueChar[12] = {0}; 
     for (int i = 0; i < 10; i++) szValueChar[i] = (char)myTable.m_IdNumber[i]; 
     std::string sTemp (szValueChar); 
     std::cout << nItem << " -> " << sTemp << " : " << myTable.m_Count << std::endl; 
     nItem++; 
    } 
    std::cout << " -- Update the first record then redisplay rows" << std::endl; 
    hr = myTable.MoveFirst(); // move to the first row of the row set 
    myTable.m_Count++;   // increment the count of the first row 
    hr = myTable.SetData();  // update the database with the modified count 
    // redisplay all rows including the updated row. 
    for (nItem = 0, hr = myTable.MoveFirst(); hr == S_OK; hr = myTable.MoveNext()) 
    { 
     char szValueChar[12] = {0}; 
     for (int i = 0; i < 10; i++) szValueChar[i] = (char)myTable.m_IdNumber[i]; 
     std::string sTemp (szValueChar); 
     std::cout << nItem << " -> " << sTemp << " : " << myTable.m_Count << std::endl; 
     nItem++; 
    } 
    myTable.Close(); // close the OpenAll() so that we can now do Open() with SQL query. 

    std::cout << " -- update record specific row" << std::endl; 

    TCHAR *tsSqlQuery = _T("select * from dbo.Table_1 where IdNumber='0000000002'"); 
    hr = myTable.Open (myTable.m_session, tsSqlQuery, &pPropSet); 
    if ((hr = myTable.MoveFirst()) == S_OK) 
    { 
     char szValueChar[12] = {0}; 
     for (int i = 0; i < 10; i++) szValueChar[i] = (char)myTable.m_IdNumber[i]; 
     std::string sTemp (szValueChar); 
     LONG countTemp = myTable.m_Count; 
     myTable.m_Count++; 
     std::cout << " incrementing " << sTemp << " " << countTemp << " to " << myTable.m_Count << std::endl; 
     hr = myTable.SetData(); 
    } 
    myTable.Close(); // close this row set. 

    // select all rows and output the values after the various changes 
    // do an Open() with our new query using our standard property set. 
    tsSqlQuery = _T("select * from dbo.Table_1"); 
    hr = myTable.Open (myTable.m_session, tsSqlQuery, &pPropSet); 
    nItem = 0; 
    for (nItem = 0, hr = myTable.MoveFirst(); hr == S_OK; hr = myTable.MoveNext()) 
    { 
     char szValueChar[12] = {0}; 
     for (int i = 0; i < 10; i++) szValueChar[i] = (char)myTable.m_IdNumber[i]; 
     std::string sTemp (szValueChar); 
     std::cout << nItem << " -> " << sTemp << " : " << myTable.m_Count << std::endl; 
     nItem++; 
    } 
    myTable.Close(); // close this row set. 

    OleUninitialize(); 
    return 0; 
} 

위의 프로그램에 의해 생성 된 출력은 다음과 같습니다. 이 출력에는 원래 행 값과 일부 행 값에 대한 여러 가지 변경 결과가 표시됩니다.

0 -> 0000000001 : 22 
1 -> 0000000002 : 12 
2 -> 0000000004 : 23 
3 -> 0000000006 : 34 
-- Update the first record then redisplay rows 
0 -> 0000000001 : 23 
1 -> 0000000002 : 12 
2 -> 0000000004 : 23 
3 -> 0000000006 : 34 
-- update record specific row 
incrementing 0000000002 12 to 13 
0 -> 0000000001 : 23 
1 -> 0000000002 : 13 
2 -> 0000000004 : 23 
3 -> 0000000006 : 34 
+0

SQL Server Compact Edition에 대한 다음 예제도 참조하십시오. http://stackoverflow.com/questions/23459657/sql-server-ce-3-5-update-row-error-db-e-errorsoccurred-column-error-is- dbstatus –

1

데이터를 변경/업데이트 할 수있는 기능을 요청하지 않고 테이블을 열었을 수 있습니다. 이것을 요청하지 않고는 SetData 호출에 사용 된 인터페이스가 없으므로 오류가 발생합니다. 게시 된 문제의 원래 프로그램 몇 가지 문제가 있습니다

VOID GetRowsetProperties(CDBPropSet* pSet) throw() 
    { 
     ATLVERIFY(pSet->AddProperty(DBPROP_IRowsetChange, (bool) TRUE)); 
     ATLVERIFY(pSet->AddProperty(DBPROP_IRowsetUpdate, (bool) TRUE)); 
     ATLVERIFY(pSet->AddProperty(DBPROP_UPDATABILITY, 
      DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_DELETE | DBPROPVAL_UP_INSERT)); 
    } 
+0

답장을 보내 주셔서 감사합니다. 질문에 추가 할 Table_1.h에는 SetData()에서 동일한 HRESULT를 얻지 만 제안한 소스 행을 추가 한 접근 자의 GetRowsetProperties() 함수가 있습니다. 나는'_W'이 무엇을하고 있는지에 대해 더 많은 정보를 원합니다. 그것을 사용하면 컴파일 오류가 발생하고 Google은 아무 도움이되지 않습니다. –

+0

나는이 내부의 단계로 가서이'E_NOINTERFACE'의 소스에 도달하여 정확히 어떤 인터페이스를 찾을 수 없는지 알아낼 것을 제안합니다. '_W'는'ATLVERIFY' 결과 검사 매크로의 줄임말입니다. –

+0

내가 발견 한 것을 살펴보면'CRomSet' 클래스의 변수는 유효한 값을 가지기보다는 NULL이라는'CComPtr m_spRowsetChange;'입니다. 이 포인터는'SetData()'에서 실제 행을 업데이트하는 데 사용됩니다. 이것은 내가하고있는 일을해야한다는 조작이 있음을 나타냅니다. 어떤 아이디어? –