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();
}
};
SQL Server Compact Edition에 대한 다음 예제도 참조하십시오. http://stackoverflow.com/questions/23459657/sql-server-ce-3-5-update-row-error-db-e-errorsoccurred-column-error-is- dbstatus –