단순 소비자 구현
다음 항목에서는 MFC 응용 프로그램 마법사 및 ATL OLE DB 소비자 마법사가 만든 파일을 편집하여 간단한 소비자를 만드는 방법을 보여 줍니다.이 예제는 다음과 같은 부분으로 이루어집니다.
"소비자로 데이터 검색"에서는 데이터베이스 테이블에서 행 단위로 모든 데이터를 읽는 소비자에서 코드를 구현하는 방법을 보여 줍니다.
"책갈피 지원을 소비자에 추가"에서는 책갈피 지원을 소비자에 추가하는 방법을 설명합니다.
"XML 지원을 소비자에 추가"에서는 소비자 코드를 수정하여 조회한 행 집합을 XML 데이터로 출력하는 방법을 설명합니다.
[!참고]
이 단원에서 설명하는 소비자 응용 프로그램을 사용하여 MyProv 및 Provider 샘플 공급자를 테스트할 수 있습니다.
[!참고]
단순한 읽기 전용 공급자의 기능 향상에 설명된 것과 동일한 공급자인 MyProv를 테스트하기 위해 소비자 응용 프로그램을 작성하려면, "책갈피 지원을 소비자에 추가"에 설명된 것과 같이 책갈피 지원을 포함해야 합니다.
[!참고]
공급자를 테스트하는 소비자 응용 프로그램을 작성하려면 "책갈피 지원을 소비자에 추가"에 설명된 책갈피 지원은 건너뛰고 "XML 지원을 소비자에 추가"로 가십시오.
소비자로 데이터 검색
OLE DB 소비자를 사용하여 콘솔 응용 프로그램을 수정하려면
MyCons.cpp에서 다음과 같이 굵은 텍스트를 삽입하여 main 코드를 변경합니다.
// MyCons.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "Products.h" ... int main(int argc, char* argv[]) { HRESULT hr = CoInitialize(NULL); // Instantiate rowset CProducts rs; hr = rs.OpenAll(); ATLASSERT( SUCCEEDED( hr ) ); hr = rs.MoveFirst(); // Iterate through the rowset while( SUCCEEDED(hr) && hr != DB_S_ENDOFROWSET ) { // Print out the column information for each row printf("Product ID: %d, Name: %s, Unit Price: %d, Quantity per Unit: %d, Units in Stock %d, Reorder Level %d\n", rs.m_ProductID, rs.m_ProductName, rs.m_UnitPrice, rs.m_QuantityPerUnit, rs.m_UnitsInStock, rs.m_ReorderLevel ); hr = rs.MoveNext(); } rs.Close(); rs.ReleaseCommand(); CoUninitialize(); return 0; }
책갈피 지원을 소비자에 추가
책갈피는 테이블의 행을 고유하게 구별하는 열입니다.일반적으로 키 열이 책갈피가 되지만 항상 그런 것은 아니고 공급자에 따라 다릅니다.이 단원에서는 책갈피 지원을 추가하는 방법을 보여 줍니다.이를 위해 사용자 레코드 클래스에서 다음 작업을 수행해야 합니다.
책갈피를 인스턴스화합니다.CBookmark 형식의 개체입니다.
DBPROP_IRowsetLocate 속성을 설정하여 공급자에서 책갈피 열을 요청합니다.
BOOKMARK_ENTRY 매크로를 사용하여 열 맵에 책갈피 엔트리를 추가합니다.
위의 단계는 작업할 책갈피 개체 및 책갈피 지원을 제공합니다.이 코드 예제는 다음과 같이 책갈피를 설명합니다.
쓰기 위해 파일을 엽니다.
행 단위로 행 집합 데이터를 파일에 출력합니다.
MoveToBookmark를 호출하여 행 집합 커서를 책갈피로 이동합니다.
책갈피가 있는 행을 파일의 끝에 추가하면서 출력합니다.
[!참고]
이 소비자 응용 프로그램을 사용하여 Provider 샘플 공급자 응용 프로그램을 테스트하려면 이 단원에서 설명한 책갈피 지원을 건너뛰십시오.
책갈피를 인스턴스화하려면
접근자는 CBookmark 형식의 개체를 포함해야 합니다.nSize 매개 변수는 책갈피 버퍼의 크기를 바이트 단위로 지정합니다. 일반적으로 32비트 플랫폼에서는 4바이트이고, 64비트 플랫폼에서는 8바이트입니다.다음 선언을 사용자 레코드 클래스의 열 데이터 멤버에 추가합니다.
////////////////////////////////////////////////////////////////////// // Products.h class CProductsAccessor { public: CBookmark<4> m_bookmark; // Add bookmark declaration LONG m_ProductID; ...
공급자에게 책갈피 열을 요청하려면
다음 코드를 사용자 레코드 클래스의 GetRowsetProperties 메서드에 추가합니다.
// Set the DBPROP_IRowsetLocate property. void GetRowsetProperties(CDBPropSet* pPropSet) { pPropSet->AddProperty(DBPROP_CANFETCHBACKWARDS, true, DBPROPOPTIONS_OPTIONAL); pPropSet->AddProperty(DBPROP_CANSCROLLBACKWARDS, true, DBPROPOPTIONS_OPTIONAL); // Add DBPROP_IRowsetLocate property to support bookmarks pPropSet->AddProperty(DBPROP_IRowsetLocate, true); }
책갈피 엔트리를 열 맵에 추가하려면
다음 엔트리를 사용자 레코드 클래스의 열 맵에 추가합니다.
// Set a bookmark entry in the column map. BEGIN_COLUMN_MAP(CProductsAccessor) BOOKMARK_ENTRY(m_bookmark) // Add bookmark entry COLUMN_ENTRY_LENGTH_STATUS(1, m_ProductID, m_dwProductIDLength, m_dwProductIDStatus) COLUMN_ENTRY_LENGTH_STATUS(2, m_ProductName, m_dwProductNameLength, m_dwProductNameStatus) ... END_COLUMN_MAP()
main 코드에서 책갈피를 사용하려면
앞에서 만든 콘솔 응용 프로그램의 mycons.cpp 파일에서 다음과 같이 main 코드를 변경합니다.책갈피를 사용하려면 main 코드에서 해당 책갈피 개체(myBookmark)를 인스턴스화해야 합니다. 이 개체는 접근자에 있는 책갈피 개체(m_bookmark)와는 다릅니다.
/////////////////////////////////////////////////////////////////////// // MyCons.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "Products.h" #include <iostream> #include <fstream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { HRESULT hr = CoInitialize(NULL); // Instantiate rowset CProducts rs; hr = rs.OpenAll(); hr = rs.MoveFirst(); // Cast CURRENCY m_UnitPrice to a long value LONGLONG lPrice = rs.m_UnitPrice.int64; // Open file output.txt for writing in overwrite mode ofstream outfile( "C:\\output.txt", ios::out ); if (!outfile) // Test for invalid file return -1; // Instantiate a bookmark object myBookmark for the main code CBookmark<4> myBookmark; int nCounter = 0; // Iterate through the rowset and output column data to output.txt row by row // In the file, mark the beginning of this set of data: outfile << "initial row dump" << endl; while( SUCCEEDED(hr) && hr != DB_S_ENDOFROWSET ) { nCounter++; if( nCounter == 5 ) myBookmark = rs.bookmark; // Output the column information for each row: outfile << rs.m_ProductID << rs.m_ProductName << lPrice << rs.m_QuantityPerUnit << rs.m_UnitsInStock << rs.m_ReorderLevel << endl; hr = rs.MoveNext(); } // Move cursor to bookmark hr = rs.MoveToBookmark(myBookmark); // Iterate through the rowset and output column data to output.txt row by row // In the file, mark the beginning of this set of data: outfile << "row dump starting from bookmarked row" << endl; while( SUCCEEDED(hr) && hr != DB_S_ENDOFROWSET ) { // Output the column information for each row outfile << rs.m_ProductID << rs.m_ProductName << lPrice << rs.m_QuantityPerUnit << rs.m_UnitsInStock << rs.m_ReorderLevel << endl; hr = rs.MoveNext(); } rs.CloseAll(); CoUninitialize(); return 0; }
책갈피에 대한 자세한 내용은 책갈피 사용을 참조하십시오.책갈피에 대한 다른 예제를 보려면 행 집합 업데이트를 참고하십시오.
XML 지원을 소비자에 추가
XML 데이터 액세스에서 설명한 것처럼 데이터 소스에서 XML 데이터를 검색하는 방법에는 두 가지가 있습니다. CStreamRowset을 사용하거나 CXMLAccessor를 사용하는 것입니다.이 예제에서는 CStreamRowset을 사용하는데, 이 방법이 더 효율적이지만 이 샘플 응용 프로그램을 실행할 컴퓨터에 SQL Server 2000이 실행되고 있어야 합니다.
CStreamRowset에서 상속된 명령 클래스를 수정하려면
이전에 만든 소비자 응용 프로그램에서 CCommand 선언 부분을 변경하여 CStreamRowset을 다음과 같이 행 집합 클래스로 지정합니다.
class CProducts : public CCommand<CAccessor<CProductsAccessor>, CStreamRowset >
XML 데이터를 검색하고 출력하도록 main 코드를 수정하려면
앞에서 만든 콘솔 응용 프로그램의 MyCons.cpp 파일에서 다음과 같이 main 코드를 변경합니다.
/////////////////////////////////////////////////////////////////////// // MyCons.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "Products.h" #include <iostream> #include <fstream> using namespace std; int _tmain(int argc, _TCHAR* argv[]) { HRESULT hr = CoInitialize(NULL); // Instantiate rowset CProducts rs; // Add variable declarations for the Read method to handle sequential stream data CHAR buffer[1001]; // Pointer to buffer into which data stream is read ULONG cbRead; // Actual number of bytes read from the data stream hr = rs.OpenAll(); // Open file output.txt for writing in overwrite mode ofstream outfile( "C:\\output.txt", ios::out ); if (!outfile) // Test for invalid file return -1; // The following loop reads 1000 bytes of the data stream at a time // until it reaches the end of the data stream for (;;) { // Read sequential stream data into buffer HRESULT hr = rs.m_spStream->Read(buffer, 1000, &cbRead); if (FAILED (hr)) break; // Output buffer to file buffer[cbRead] = 0; outfile << buffer; // Test for end of data stream if (cbRead < 1000) break; } rs.CloseAll(); CoUninitialize(); return 0; }