Aktualizowanie zestawów wierszy
Podstawową operacją bazy danych jest aktualizowanie lub zapisywanie danych w magazynie danych. W bazie danych OLE DB mechanizm aktualizacji jest prosty: aplikacja konsumenta ustawia wartości powiązanych elementów członkowskich danych, a następnie zapisuje te wartości w zestawie wierszy; następnie użytkownik żąda, aby dostawca zaktualizował magazyn danych.
Użytkownicy mogą wykonać następujące rodzaje aktualizacji danych zestawu wierszy: ustawianie wartości kolumn w wierszu, wstawianie wiersza i usuwanie wiersza. Aby wykonać te operacje, klasa szablonu OLE DB CRowset implementuje interfejs IRowsetChange i zastępuje następujące metody interfejsu:
SetData zmienia wartości kolumn w wierszu zestawu wierszy, co odpowiada poleceniu SQL UPDATE.
Wstawia wiersz do zestawu wierszy, co odpowiada poleceniu SQL INSERT.
Usunięcie usuwa wiersze z zestawu wierszy, co jest równoznaczne z poleceniem SQL DELETE.
Obsługa operacji aktualizacji
Uwaga
Kreator konsumenta OLE DB ATL nie jest dostępny w programie Visual Studio 2019 i nowszych wersjach. Nadal można dodać funkcjonalność ręcznie. Aby uzyskać więcej informacji, zobacz Tworzenie konsumenta bez korzystania z Kreatora.
Podczas tworzenia użytkownika za pomocą Kreatora konsumenta OLE DB ATL można obsługiwać operacje aktualizacji, wybierając co najmniej jedno z trzech pól wyboru Zmień, Wstaw i Usuń. W przypadku wybrania tych opcji kreator odpowiednio modyfikuje kod w celu obsługi wybranego typu zmian. Jeśli jednak nie używasz kreatora, musisz ustawić następujące właściwości zestawu wierszy, aby VARIANT_TRUE
obsługiwać aktualizacje:
DBPROPVAL_UP_CHANGE
Umożliwia zmianę wartości danych w wierszu.DBPROPVAL_UP_INSERT
umożliwia wstawienie wiersza.DBPROPVAL_UP_DELETE
umożliwia usunięcie wiersza.
Właściwości można ustawić w następujący sposób:
CDBPropSet ps(DBPROPSET_ROWSET);
ps.AddProperty(DBPROP_IRowsetChange, true);
ps.AddProperty(DBPROP_UPDATABILITY, DBPROPVAL_UP_CHANGE | DBPROPVAL_UP_INSERT | DBPROPVAL_UP_DELETE);
Operacje zmiany, wstawiania lub usuwania mogą zakończyć się niepowodzeniem, jeśli co najmniej jedna kolumna nie jest zapisywalna. Zmodyfikuj mapę kursorów, aby rozwiązać ten problem.
Ustawianie danych w wierszach
CRowset::SetData ustawia wartości danych w co najmniej jednej kolumnie bieżącego wiersza. Poniższy kod ustawia wartości elementów członkowskich danych powiązanych z kolumnami Name
i Units in Stock
tabelą Products
, a następnie wywołuje metodę SetData
zapisu tych wartości w 100 wierszu zestawu wierszy:
// 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();
Wstawianie wierszy do zestawów wierszy
CRowset::Insert tworzy i inicjuje nowy wiersz przy użyciu danych z metody dostępu. Insert
tworzy zupełnie nowy wiersz po bieżącym wierszu; Należy określić, czy należy zwiększać bieżący wiersz do następnego wiersza, czy pozostawić go bez zmian. W tym celu należy ustawić parametr bGetRow :
HRESULT Insert(int nAccessor = 0, bool bGetRow = false)
false
(wartość domyślna) określa, że bieżący wiersz zwiększa się do następnego wiersza (w takim przypadku wskazuje wstawiony wiersz).true
określa, że bieżący wiersz pozostaje tam, gdzie jest.
Poniższy kod ustawia wartości elementów członkowskich danych powiązanych z kolumnami tabeli Products
, a następnie wywołuje metodę Insert
wstawiania nowego wiersza z tymi wartościami po 100 wierszu zestawu wierszy. Zaleca się ustawienie wszystkich wartości kolumn, aby uniknąć niezdefiniowanych danych w nowym wierszu:
// 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();
Aby uzyskać bardziej szczegółowy przykład, zobacz CRowset::Insert.
Aby uzyskać więcej informacji na temat ustawiania składowych danych o stanie i długości, zobacz Elementy członkowskie danych stanu pola w metodach dostępu generowanych przez kreatora.
Usuwanie wierszy z zestawów wierszy
CRowset::D elete usuwa bieżący wiersz z zestawu wierszy. Następujące wywołania Delete
kodu w celu usunięcia 100. wiersza zestawu wierszy:
// 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();
Natychmiastowe i odroczone aktualizacje
O ile nie określisz inaczej, wywołania metod SetData
, Insert
i Delete
natychmiast aktualizują magazyn danych. Można jednak odroczyć aktualizacje tak, aby odbiorca przechowywał wszystkie zmiany w lokalnej pamięci podręcznej, a następnie przesyłał je do magazynu danych podczas wywoływania jednej z następujących metod aktualizacji:
CRowset::Aktualizacja przenosi wszelkie oczekujące zmiany wprowadzone w bieżącym wierszu od czasu ostatniego pobrania lub
Update
wywołania go.CRowset::UpdateAll przesyła wszelkie oczekujące zmiany wprowadzone we wszystkich wierszach od ostatniego pobrania lub
Update
wywołania.
Aktualizacja, używana przez metody aktualizacji, ma określone znaczenie wprowadzania zmian w poleceniu i nie jest mylona z poleceniem SQL UPDATE (SetData
jest odpowiednikiem polecenia SQL UPDATE ).
Aktualizacje odroczone są przydatne, na przykład w sytuacjach takich jak seria transakcji bankowych; Jeśli jedna transakcja zostanie anulowana, możesz cofnąć zmianę, ponieważ nie wysyłasz serii zmian do momentu zatwierdzenia ostatniego. Ponadto dostawca może powiązać zmiany w jednym wywołaniu sieciowym, co jest bardziej wydajne.
Aby obsługiwać odroczone aktualizacje, należy ustawić DBPROP_IRowsetChange
właściwość wraz z właściwościami opisanymi w temacie Obsługa operacji aktualizacji:
pPropSet->AddProperty(DBPROP_IRowsetUpdate, true);
Podczas wywoływania Update
metody lub UpdateAll
metody transferu zmieniają się z lokalnej pamięci podręcznej do magazynu danych, a następnie czyścisz lokalną pamięć podręczną. Ponieważ aktualizacja przenosi zmiany tylko dla bieżącego wiersza, ważne jest, aby aplikacja śledziła wiersz, który należy zaktualizować i kiedy go zaktualizować. W poniższym przykładzie pokazano, jak zaktualizować dwa kolejne wiersze:
// 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
Aby upewnić się, że oczekujące zmiany zostaną przeniesione, przed przejściem do innego wiersza należy wywołać metodę Update
. Jeśli jednak jest to żmudne lub nieefektywne, na przykład gdy aplikacja musi zaktualizować setki wierszy, możesz użyć UpdateAll
polecenia , aby jednocześnie zaktualizować wszystkie wiersze.
Jeśli na przykład brakuje pierwszego Update
wywołania z powyższego kodu, wiersz 100 pozostanie niezmieniony, podczas gdy wiersz 101 zostanie zmieniony. Po tym momencie aplikacja musiałaby wywołać UpdateAll
polecenie lub wrócić do wiersza 100 i wywołać Update
aktualizację tego wiersza.
Na koniec jednym z głównych powodów odroczenia zmian jest możliwość ich cofnięcia. Wywołanie funkcji CRowset::Undo przywraca stan lokalnej pamięci podręcznej zmian do stanu magazynu danych przed wprowadzeniem oczekujących zmian. Należy pamiętać, że Undo
nie przywraca stanu lokalnej pamięci podręcznej przez jeden krok (stan przed tylko najnowszą zmianą); zamiast tego czyści lokalną pamięć podręczną dla tego wiersza. Undo
Ponadto dotyczy tylko bieżącego wiersza.
Zobacz też
Praca z szablonami konsumentów OLE DB
CRowset, klasa
IRowsetChange