행 집합 업데이트
가장 기본적인 데이터베이스 작업은 바로 데이터 저장소를 업데이트하거나 데이터 저장소에 데이터를 작성하는 작업입니다. OLE DB에서 업데이트 메커니즘은 간단합니다. 먼저 소비자 응용 프로그램에서 바인딩되는 데이터 멤버의 값을 설정한 후 이들 값을 행 집합에 쓰고, 그런 다음 소비자가 공급자에게 데이터 저장소 업데이트를 요청하면 됩니다.
소비자는 행 내의 열 값 설정, 행 삽입 및 행 삭제와 같이 행 집합 데이터를 업데이트할 수 있습니다. 이러한 작업을 수행하기 위해, OLE DB 템플릿 클래스 CRowset은 IRowsetChange 인터페이스를 구현하여 다음 인터페이스 메서드를 재정의합니다.
SetData는 행 집합에 있는 행의 열 값을 변경합니다. 이 메서드는 SQL UPDATE 명령에 해당합니다.
Insert는 행 집합에 행을 삽입합니다. 이 메서드는 SQL INSERT 명령에 해당합니다.
Delete는 행 집합에서 행을 삭제합니다. 이 메서드는 SQL DELETE 명령에 해당합니다.
업데이트 작업 지원
ATL OLE DB 소비자 마법사로 소비자를 만들 경우 변경, 삽입 및 삭제라는 세 개의 확인란 중 하나 이상을 선택하여 업데이트 작업을 지원할 수 있습니다. 이들 확인란을 선택하면 마법사는 사용자가 선택한 변경을 지원하도록 코드를 수정합니다. 그러나 마법사를 사용하지 않은 경우에는 업데이트를 지원하기 위해서 다음 행 집합 속성을 VARIANT_TRUE로 설정해야 합니다.
DBPROPVAL_UP_CHANGE를 사용하면 행에서 데이터 값을 변경할 수 있습니다.
DBPROPVAL_UP_INSERT를 사용하면 행을 삽입할 수 있습니다.
DBPROPVAL_UP_DELETE를 사용하여 행을 삭제할 수 있습니다.
속성을 다음과 같이 설정할 수 있습니다.
CDBPropSet ps(DBPROPSET_ROWSET);
ps.AddProperty(DBPROP_IRowsetChange, true)
ps.AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE)
쓰기 가능하지 않은 열이 하나 이상일 경우에는 변경, 삽입 또는 삭제 작업이 실패할 수 있습니다. 이를 방지하려면 커서 맵을 수정하십시오.
행에서 데이터 설정
CRowset::SetData는 현재 행의 하나 이상의 열에서 데이터 값을 설정합니다. 다음 코드는 Products 테이블의 "Name"과 "Units in Stock" 열에 바인딩되는 데이터 멤버의 값을 설정한 후 SetData를 호출하여 행 집합의 100번째 행에 이 값을 씁니다.
// Instantiate a rowset based on the user record class
CTable<CAccessor<CProductAccessor> > product;
CSession session;
// Open the rowset and move to the 100th row
product.Open(session, "Product", &ps, 1); // ps is the property set
product.MoveToBookmark(&bookmark, 0); // Assume that bookmark is set to 100th row
// Change the values of columns "Name" and "Units in Stock" in the current row of the Product table
_tcscpy_s( product.m_ProductName, product.m_sizeOfProductName,
_T( "Candle" ) );
product.m_UnitsInStock = 10000;
// Set the data
HRESULT hr = product.SetData( );
행 집합에 행 삽입
CRowset::Insert는 접근자의 데이터를 사용하여 새로운 행을 만들고 초기화합니다. Insert는 현재 행 뒤에 완전히 새로운 행을 만들기 때문에, 사용자는 현재 행을 다음 행으로 증가시킬지 아니면 그대로 둘 지 지정해야 합니다. bGetRow 매개 변수를 설정하여 이를 수행할 수 있습니다.
HRESULT Insert(int nAccessor = 0, bool bGetRow = false)
false(기본값)을 설정하면 현재 행이 다음 행으로 증가됩니다. 이러한 경우, 현재 행은 삽입된 행을 가리킵니다.
true를 설정하면 현재 행이 원래 위치에 그대로 있습니다.
다음 코드는 Products 테이블의 열에 바인딩되는 데이터 멤버의 값을 설정한 후 Insert를 호출하여 행 집합의 100번째 행 다음에 이 값을 가진 새로운 행을 삽입합니다. 이는 새로운 행에 정의되지 않은 데이터가 없도록 모든 열 값을 설정하려는 경우에 유용합니다.
// Instantiate a rowset based on the user record class
CTable<CAccessor<CProductAccessor> > product;
CSession session;
// Open the rowset and move to the 100th row
product.Open(session, "Product", &ps, 1); // ps is the property set
product.MoveToBookmark(&bookmark, 0); // Assume that bookmark is set to 100th row
// Set the column values for a row of the Product table, then insert the row
product.m_ProductID = 101;
_tcscpy_s( product.m_ProductName, product.m_sizeOfProductName,
_T( "Candle" ) );
product.m_SupplierID = 27857;
product.m_CategoryID = 372;
_tcscpy_s( product.m_QuantityPerUnit, product.m_sizeOfQuantityPerUnit,
_T( "Pack of 10" ) );
product.m_UnitPrice = 20;
product.m_UnitsInStock = 10000;
product.m_UnitsOnOrder = 5201;
product.m_ReorderLevel = 5000;
product.m_Discontinued = false;
// You must also initialize the status and length fields before setting/inserting data
// Set the column status values
m_dwProductIDStatus = DBSTATUS_S_OK;
m_dwProductNameStatus = DBSTATUS_S_OK;
m_dwSupplierIDStatus = DBSTATUS_S_OK;
m_dwCategoryIDStatus = DBSTATUS_S_OK;
m_dwQuantityPerUnitStatus = DBSTATUS_S_OK;
m_dwUnitPriceStatus = DBSTATUS_S_OK;
m_dwUnitsInStockStatus = DBSTATUS_S_OK;
m_dwUnitsOnOrderStatus = DBSTATUS_S_OK;
m_dwReorderLevelStatus = DBSTATUS_S_OK;
m_dwDiscontinuedStatus = DBSTATUS_S_OK;
// Set the column length value for column data members that are not fixed-length types.
// The value should be the length of the string that you are setting.
m_dwProductNameLength = 6; // "Candle" has 6 characters
m_dwQuantityPerUnitLength = 10; // "Pack of 10" has 10 characters
// Insert the data
HRESULT hr = product.Insert( );
자세한 예제는 CRowset::Insert를 참조하십시오.
상태 및 길이 데이터 멤버 설정에 대한 자세한 내용은 마법사 생성 접근자의 필드 상태 데이터 멤버를 참조하십시오.
행 집합에서 행 삭제
CRowset::Delete는 행 집합에서 현재 행을 삭제합니다. 다음 코드는 Delete를 호출하여 행 집합에서 100번째 행을 삭제합니다.
// Instantiate a rowset based on the user record class
CTable<CAccessor<CProductAccessor> > product;
CSession session;
// Open the rowset and move to the 100th row
product.Open(session, "Product", &ps, 1); // ps is the property set
product.MoveToBookmark(&bookmark, 0); // Assume that bookmark is set to 100th row
// Delete the row
HRESULT hr = product.Delete( );
즉시 업데이트 및 지연된 업데이트
달리 지정하지 않는 이상 SetData, Insert 및 Delete 메서드를 호출하면 데이터 저장소가 즉시 업데이트됩니다. 그러나 소비자가 모든 변경 내용을 로컬 캐시에 저장한 후 다음 업데이트 메서드 중 하나를 호출할 때 이 내용을 데이터 저장소에 전송할 수 있도록 업데이트를 지연시킬 수 있습니다.
CRowset::Update는 마지막 페치 또는 Update 호출 이후에 이루어진 현재 행에 대한 보류 중인 변경 내용을 전송합니다.
CRowset::UpdateAll은 마지막 페치 또는 Update 호출 이후에 이루어진 모든 행에 대한 보류 중인 변경 내용을 전송합니다.
업데이트 메서드의 업데이트는 명령에 따라 변경한다는 특정 의미를 가지며 SQL UPDATE 명령(SetData가 SQL UPDATE 명령에 해당)과 혼동하지 말아야 합니다.
지연된 업데이트는 일련의 뱅킹 트랜잭션 같은 경우에 유용합니다. 한 트랜잭션이 취소된 경우, 마지막 변경이 커밋되기 전까지는 변경 내용을 전송하지 않으므로 사용자는 변경을 실행 취소할 수 있습니다. 또한 공급자는 변경 내용을 보다 효과적인 하나의 네트워크 호출로 묶을 수 있습니다.
지연된 업데이트를 지원하려면, "업데이트 작업 지원"에 나온 속성과 함께 DBPROP_IRowsetChange 속성을 설정해야 합니다.
pPropSet->AddProperty(DBPROP_IRowsetUpdate, true);
Update 또는 UpdateAll을 호출할 때, 메서드는 로컬 캐시의 변경 내용을 데이터 저장소로 전송한 후 로컬 캐시를 지웁니다. Update는 현재 행에 대한 변경 내용만을 전송하므로 응용 프로그램에서 업데이트되는 행과 업데이트되는 시기를 계속 추적해야 합니다. 다음 예제는 연속된 두 행을 업데이트하는 방법을 방법을 보여 줍니다.
// Instantiate a rowset based on the user record class
CTable<CAccessor<CProductAccessor> > product;
CSession session;
// Open the rowset and move to the 100th row
product.Open(session, "Product", &ps, 1); // ps is the property set
product.MoveToBookmark(&bookmark, 0); // Assume that bookmark is set to 100th row
// Change the values of columns "Name" and "Units in Stock" in the 100th row of the Product table
_tcscpy_s( product.m_ProductName, product.m_sizeOfProductName,
_T( "Wick" ) );
product.m_UnitsInStock = 10000;
HRESULT hr = product.SetData( ); // No changes made to row 100 yet
product.Update(); // Update row 100 now
// Change the values of columns "Name" and "Units in Stock" in the 101st row of the Product table
product.MoveNext( );
_tcscpy_s( product.m_ProductName, product.m_sizeOfProductName
_T( "Wax" ) );
product.m_UnitsInStock = 500;
HRESULT hr = product.SetData( ); // No changes made to row 101 yet
product.Update(); // Update row 101 now
보류 중인 변경 내용이 전송되도록 하려면, 다른 행으로 이동하기 전에 Update를 호출해야 합니다. 그러나 응용 프로그램에서 많은 행을 업데이트해야 하는 경우처럼 변경 전송이 너무 길거나 비효율적이면, UpdateAll을 사용하여 모든 행을 한 번에 업데이트할 수 있습니다.
예를 들어, 위의 코드에 첫 번째 Update 호출이 없는 경우, 행 100은 변경되지 않지만 행 101은 변경됩니다. 이 행을 업데이트하려면 이 지점 다음에서 응용 프로그램이 UpdateAll을 호출하거나 행 100으로 돌아가 Update를 호출해야 합니다.
마지막으로, 변경을 지연시키는 주요 원인 하나는 변경을 실행 취소할 수 있다는 점입니다. CRowset::Undo 호출은 로컬 변경 캐시의 상태를 보류 중인 변경이 이루어지기 전의 데이터 저장소 상태로 롤백합니다. Undo는 한 번으로 로컬 캐시의 상태를 롤백하지 않는다는 점에 주의하십시오. 즉, 가장 최근의 변경만 롤백합니다. 대신 Undo는 해당 행에 대한 로컬 캐시를 지웁니다. 또한, Undo는 현재 행에만 영향을 줍니다.