Atualizando conjuntos de linhas
Uma operação de banco de dados básica consiste em atualizar ou gravar dados no armazenamento de dados. No OLE DB, o mecanismo de atualização é simples: o aplicativo de consumidor define os valores dos membros de dados associados e, em seguida, grava esses valores no conjunto de linhas; o consumidor, então, solicita que o provedor atualize o armazenamento de dados.
Os consumidores podem realizar os seguintes tipos de atualizações nos dados do conjunto de linhas: definir valores de coluna dentro de uma linha, inserir uma linha e excluir uma linha. Para concluir essas operações, a classe de modelo do OLE DB CRowset implementa a interface IRowsetChange e substitui os seguintes métodos de interface:
SetData altera os valores de coluna em uma linha de um conjunto de linhas; equivale ao comando SQL UPDATE.
Insert insere uma linha em um conjunto de linhas; equivale ao comando SQL INSERT.
Delete exclui linhas de um conjunto de linhas; equivale ao comando SQL DELETE.
Suporte a operações de atualização
Observação
O Assistente de Consumidor OLE DB da ATL não está disponível no Visual Studio 2019 e posteriores. Ainda é possível adicionar a funcionalidade manualmente. Saiba mais em Criação de um consumidor sem usar um assistente.
Ao criar um consumidor com o Assistente de Consumidor OLE DB do ATL, é possível ser compatível com as operações de atualização selecionando uma ou mais das três caixas de seleção Alterar, Inserir e Excluir. Se você selecionar essas opções, o assistente modificará o código adequadamente para ser compatível com o tipo de alteração escolhido. No entanto, se você não usar o assistente, precisará definir as seguintes propriedades do conjunto de linhas como VARIANT_TRUE
para ser compatível com atualizações:
DBPROPVAL_UP_CHANGE
permite alterar os valores de dados em uma linha.DBPROPVAL_UP_INSERT
permite inserir uma linha.DBPROPVAL_UP_DELETE
permite excluir uma linha.
Defina as propriedades da seguinte maneira:
CDBPropSet ps(DBPROPSET_ROWSET);
ps.AddProperty(DBPROP_IRowsetChange, true);
ps.AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE);
Operações de exclusão, inserção ou alteração poderão falhar se uma ou mais colunas não forem graváveis. Modifique seu mapa de cursor para corrigir esse problema.
Definir dados em linhas
CRowset::SetData define valores de dados em uma ou mais colunas da linha atual. O código a seguir define os valores de membros de dados associados às colunas Name
e Units in Stock
da tabela Products
e, em seguida, chama SetData
para gravar esses valores na linha 100 do conjunto de linhas:
// 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();
Inserir linhas em conjuntos de linhas
CRowset::Insert cria e inicia uma nova linha usando os dados do acessador. Insert
cria uma linha totalmente nova após a linha atual; especifique se deseja incrementar a linha atual na próxima linha ou deixá-la inalterada. Para fazer isso, defina o parâmetro bGetRow:
HRESULT Insert(int nAccessor = 0, bool bGetRow = false)
false
(o valor padrão) especifica que a linha atual seja incrementada para a próxima linha (nesse caso, aponta para a linha inserida).true
especifica que a linha atual fique como está.
O código a seguir define os valores de membros de dados associados às colunas da tabela Products
e, em seguida, chama Insert
para inserir uma nova linha com esses valores após a linha 100 do conjunto de linhas. É recomendável definir todos os valores de coluna para evitar dados indefinidos na nova linha:
// 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();
Confira um exemplo mais detalhado em CRowset::Insert.
Saiba mais sobre como definir o status e o comprimento de membros de dados em Membros de dados de status de campo em acessadores gerados pelo assistente.
Excluir linhas dos conjuntos de linhas
CRowset::Delete exclui a linha atual do conjunto de linhas. O código a seguir chama Delete
para remover a linha 100 do conjunto de linhas:
// 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();
Atualizações imediatas e adiadas
A menos que você especifique de outra forma, as chamadas para os métodos SetData
, Insert
e Delete
atualizam o armazenamento de dados imediatamente. No entanto, você pode adiar as atualizações de forma que o consumidor armazene todas as alterações em um cache local e, em seguida, transfira-as para o armazenamento de dados ao chamar um dos seguintes métodos de atualização:
CRowset::Update transfere todas as alterações pendentes feitas na linha atual desde o último fetch ou chamada de
Update
.CRowset::UpdateAll transfere todas as alterações pendentes feitas em todas as linhas desde o último fetch ou chamada de
Update
.
Update, conforme usado pelos métodos de atualização, tem a função específica de fazer alterações no comando e não deve ser confundido com o comando UPDATE (SetData
é equivalente ao comando SQL UPDATE).
Atualizações adiadas são úteis, por exemplo, em situações como uma série de transações bancárias; se uma transação for cancelada, é possível desfazer a alteração, porque você não envia a série de alterações até que a última seja confirmada. Além disso, o provedor pode agrupar as alterações em uma chamada de rede, o que é mais eficiente.
Para ser compatível com atualizações adiadas, defina a propriedade DBPROP_IRowsetChange
com as propriedades descritas em Suporte a operações de atualização:
pPropSet->AddProperty(DBPROP_IRowsetUpdate, true);
Ao chamar Update
ou UpdateAll
, os métodos transferem as alterações do cache local para o armazenamento de dados e, em seguida, apagam o cache local. Como a atualização transfere as alterações somente para a linha atual, é importante que seu aplicativo mantenha o controle de qual linha deve ser atualizada e de quando isso deve ser feito. O exemplo a seguir mostra como atualizar duas linhas consecutivas:
// 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
Para garantir que as alterações pendentes sejam transferidas, você deve chamar Update
antes de passar para outra linha. No entanto, quando isso é entediante ou ineficiente, por exemplo, quando seu aplicativo precisa atualizar centenas de linhas, é possível usar UpdateAll
para atualizar todas as linhas ao mesmo tempo.
Por exemplo, se a primeira chamada Update
estiver ausente do código acima, a linha 100 permanecerá inalterada, enquanto a linha 101 será alterada. Depois desse ponto, seu aplicativo teria que chamar UpdateAll
ou retornar à linha 100 e chamar Update
para que essa linha fosse atualizada.
Por fim, um motivo principal para adiar as alterações é ser capaz de desfazê-las. Chamar CRowset::Undo reverte o estado do cache de alterações local para o estado em que o armazenamento de dados estava antes que todas as alterações pendentes fossem feitas. É importante observar que Undo
não reverte o estado do cache local em uma única etapa (o estado antes da alteração mais recente); em vez disso, ele limpa o cache local para aquela linha. Além disso, Undo
afeta somente a linha atual.
Confira também
Trabalhando com modelos de consumidor do OLE DB
Classe CRowset
IRowsetChange