Aggiornamento dei rowset

Una delle operazioni di database più elementari è l'aggiornamento o la scrittura dei dati nell'archivio dati. In OLE DB il meccanismo di aggiornamento è semplice: l'applicazione consumer imposta i valori dei membri dati associati e quindi scrive tali valori nel rowset. A questo punto, il consumer richiede al provider di aggiornare l'archivio dati.

I consumer possono eseguire i seguenti tipi di aggiornamento sui dati dei rowset: impostare i valori delle colonne all'interno di una riga, inserire una riga ed eliminare una riga. Per eseguire queste operazioni, la classe modello OLE DB CRowset implementa l'interfaccia IRowsetChange ed esegue l'override dei seguenti metodi dell'interfaccia:

  • SetData, che modifica i valori delle colonne in una riga di un rowset ed equivale al comando SQL UPDATE.

  • Insert, che inserisce una riga in un rowset ed equivale al comando SQL INSERT.

  • Delete, che elimina una riga da un rowset ed equivale al comando SQL DELETE.

Supporto delle operazioni di aggiornamento

Quando si crea un consumer con la Creazione guidata consumer OLE DB ATL, è possibile supportare le operazioni di aggiornamento selezionando una o più delle tre caselle di controllo Cambia, Inserisci ed Elimina. Se si selezionano queste opzioni, il codice verrà modificato di conseguenza per garantire il supporto del tipo di aggiornamento impostato. Se invece non si utilizza la procedura guidata, per supportare gli aggiornamenti sarà necessario impostare le seguenti proprietà del rowset su VARIANT_TRUE:

  • DBPROPVAL_UP_CHANGE, che consente di modificare i valori dei dati di una riga.

  • DBPROPVAL_UP_INSERT, che consente di inserire una riga.

  • DBPROPVAL_UP_DELETE, che consente di eliminare una riga.

Le proprietà devono essere impostate come indicato di seguito:

CDBPropSet ps(DBPROPSET_ROWSET);
ps.AddProperty(DBPROP_IRowsetChange, true)
ps.AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE)

Le operazioni di modifica, inserimento o eliminazione potrebbero non essere eseguite correttamente nel caso in cui una o più colonne non siano modificabili. Modificare la mappa dei cursori per risolvere questo problema.

Impostazione dei dati nelle righe

CRowset::SetData imposta i valori dei dati in una o più colonne della riga corrente. Mediante il codice riportato di seguito vengono impostati i valori dei membri dati associati alle colonne "Name" e "Units in Stock" della tabella Products e quindi viene chiamato SetData per scrivere tali valori nella centesima riga del rowset.

// 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( );

Inserimento di righe in un rowset

CRowset::Insert crea e inizializza una nuova riga utilizzando i dati forniti dalla funzione di accesso. Insert crea una riga completamente nuova dopo la riga corrente. È necessario specificare se incrementare la riga corrente nella riga successiva o lasciarla invariata. Questa operazione richiede l'impostazione del parametro bGetRow:

HRESULT Insert(int nAccessor = 0, bool bGetRow = false)
  • False è il valore predefinito e specifica che la riga corrente viene portata alla riga successiva, nel qual caso punta alla riga inserita.

  • True specifica che la riga corrente rimane invariata.

Il codice riportato di seguito imposta i valori dei membri dati associati alle colonne della tabella Products e quindi chiama Insert per inserire una nuova riga con tali valori dopo la centesima riga del rowset. Si consiglia di impostare i valori di tutte le colonne per evitare di avere dati non definiti nella nuova riga:

// 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( );

Per un esempio più dettagliato, vedere CRowset::Insert.

Per ulteriori informazioni sull'impostazione dei membri dati di stato e di lunghezza, vedere Membri dati di stato dei campi in funzioni di accesso generate dalla creazione guidata.

Eliminazione di righe da un rowset

CRowset::Delete elimina la riga corrente dal rowset. Mediante il codice seguente viene chiamato Delete per rimuovere la centesima riga del rowset:

// 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( );

Aggiornamenti immediati e posticipati

Se non altrimenti specificato, le chiamate ai metodi SetData, Insert e Delete aggiornano immediatamente l'archivio dati. È tuttavia possibile posticipare gli aggiornamenti in modo che il consumer memorizzi tutte le modifiche in una cache locale e quindi trasferisca tali modifiche all'archivio dati quando viene chiamato uno dei metodi di aggiornamento seguenti:

  • CRowset::Update, che trasferisce le modifiche in sospeso apportate alla riga corrente a partire dall'ultimo recupero o dall'ultima chiamata a Update su questa.

  • CRowset::UpdateAll, che trasferisce le modifiche in sospeso apportate a tutte le righe a partire dall'ultimo recupero o dall'ultima chiamata a Update su queste.

Si tenga presente che il termine aggiornamento riferito ai metodi di aggiornamento si riferisce in modo specifico all'apporto delle modifiche in base a un comando e non deve essere confuso con la funzione svolta dal comando SQL UPDATE, che equivale invece a SetData.

Gli aggiornamenti posticipati sono utili, ad esempio, in situazioni in cui si utilizza una serie di transazioni bancarie. Se una transazione viene annullata, è possibile annullare la modifica, in quanto la serie di modifiche non viene inviata fino a quando non viene eseguito il commit dell'ultima transazione. Il provider può inoltre raggruppare le modifiche in un'unica chiamata di rete, per ottenere una maggiore efficienza.

Per supportare gli aggiornamenti posticipati, è necessario impostare la proprietà DBPROP_IRowsetChange oltre alle proprietà descritte in "Supporto delle operazioni di aggiornamento":

   pPropSet->AddProperty(DBPROP_IRowsetUpdate, true);

Quando si chiama Update o UpdateAll, i metodi trasferiscono le modifiche dalla cache locale all'archivio dati e quindi cancellano la cache locale. Dal momento che Update trasferisce le modifiche solo per la riga corrente, è importante che l'applicazione tenga traccia della riga da aggiornare e di quando aggiornarla. Nell'esempio che segue viene mostrato come aggiornare due righe consecutive:

// 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

Per garantire il trasferimento delle modifiche in sospeso, è necessario chiamare Update prima di spostarsi su un'altra riga. Tuttavia, se questa operazione risulta impegnativa e poco efficiente, ad esempio quando l'applicazione deve aggiornare centinaia di righe, è possibile utilizzare UpdateAll per aggiornare tutte le righe in un'unica operazione.

Se, ad esempio, la prima chiamata a Update non fosse stata specificata nel codice sopra riportato, la riga 100 sarebbe rimasta invariata, mentre sarebbe stata modificata la riga 101. Da quel punto in poi, l'applicazione avrebbe dovuto chiamare UpdateAll oppure tornare alla riga 100 e chiamare Update per poter aggiornare tale riga.

Infine, una ragione importante per posticipare le modifiche è che, in tal modo, è sempre possibile annullarle. Se si chiama CRowset::Undo, nella cache locale delle modifiche viene ripristinato lo stato dell'archivio precedente alle modifiche in sospeso. È importante notare che Undo non ripristina lo stato della cache precedente all'ultima operazione, ovvero non annulla solo l'ultima modifica apportata, ma cancella la cache locale relativa alla riga corrente. Inoltre, Undo ha effetto solo sulla riga corrente.

Vedere anche

Riferimenti

Utilizzo dei modelli consumer OLE DB

CRowset Class

IRowsetChange