21. Práce s odloženými aktualizacemi

Odložené aktualizace umožňují získávat data z databáze, uložit a editovat je lokálně a potom aplikovat odložené aplikace na databázi najednou. Když odložené aktualizace jsou povoleny, pak aktualizace datové množiny (jako je odesílání změn a rušení záznamů) jsou uloženy v interní vyrovnávací paměti místo přímého zápisu do připojené tabulky datové množiny. Když změny jsou kompletní, pak naše aplikace volá metodu, která zapíše odložené aktualizace do databáze a vyprázdní vyrovnávací paměť.
Tato kapitola popisuje jak používat odložené aktualizace. Je zde také popsána komponenta TUpdateSQL, která může být použita společně s odloženými aktualizacemi k aktualizaci libovolné datové množiny, a to obzvláště datových množin, které nejsou normálně aktualizovatelné.
Kapitola se skládá z těchto sekcí:

Určení, kdy používat odložené aktualizace

Odložené aktualizace jsou hlavně určeny k omezení datového přístupu na vzdálený databázový server z důvodu: I když odložené aktualizace mohou minimalizovat čas transakcí a drasticky redukovat síťový provoz, nejsou vhodné pro všechny aplikace databázových klientů, které pracují se vzdálenými servery. Jsou tři oblasti předpokladů, které určují zda odložené aktualizace používat: Komponenty datového přístupu poskytují metody odložených aktualizací a metody řízení transakcí, které můžeme použít v kódu naší aplikace k řešení těchto situací, ale musíme pamatovat na všechny možné scénáře, které se mohou vyskytnout v našem pracovním prostředí.

Používání odložených aktualizací

Tato sekce poskytuje základní seznámení s používáním odložených aktualizací v aplikaci. Pokud jsme zatím odložené aktualizace nepoužívali, pak tento popis můžeme použít jako návod pro implementaci odložených aktualizací v naši aplikaci.
K použití odložených aktualizací, v naši aplikaci musí proběhnout toto:
  1. Povolíme odložené aktualizace. Povolením odložených aktualizací způsobíme, že transakce čtou pouze data se serveru podle potřeby pro účely zobrazení a pak končí. Lokální kopie dat jsou uloženy v paměti pro zobrazování a editaci.
  2. Zobrazujeme a editujeme lokální kopie záznamů, vkládáme nové záznamy a rušíme existující záznamy. Původní kopie každého záznamu i všechny jeho editace jsou uloženy v paměti.
  3. Získáváme další záznamy podle potřeby. Jak uživatel prochází záznamy, jsou získávány další záznamy. Každé získávání proběhne v kontextu jiné čtecí transakce. Aplikace může případně získat všechny záznamy najednou místo získávání po malých dávkách záznamů.
  4. Pokračujeme v zobrazování a editaci lokální kopie záznamů, dokud všechny požadované změny nejsou provedeny.
  5. Aplikujeme lokálně odložené změny do databáze nebo změny zrušíme. Pro každý záznam zapisovaný do databáze je generována událost OnUpdateRecord. Pokud při zápisu jistého záznamu do databáze vznikne chyba, pak je generována událost OnUpdateError, která umožňuje aplikaci chybu opravit, a pokračovat v aktualizaci. Když aktualizace jsou kompletní, pak všechny úspěšně aplikované aktualizace jsou uvolněny z lokální odkládací paměti.
Pokud místo aplikace aktualizací, aplikace aktualizace zruší, pak lokální kopie záznamů a všechny změny jsou uvolněny bez zápisu změn do databáze.
Na popis těchto operací se podívejte do:

Povolování a zakazování odložených aktualizací

Odložené aktualizace jsou povolovány a zakazovány vlastností CachedUpdates komponet TTable, TQuery a TStoredProc. Implicitně CachedUpdates je false, což znamená, že pro datovou množinu odložené aktualizace nejsou povoleny.
Poznámka: Klientské datové množiny vždy odkládají aktualizace. Tedy nemají vlastnost CachedUpdates neboť odložené aktualizace nelze pro klientskou datovou množinu zakázat.
K používání odložených aktualizací nastavíme CachedUpdates na true a to při návrhu (prostřednictvím Inspektora objektu) nebo za běhu. Pokud je nastaveno CachedUpdates na true, pak je generována událost OnUpdateRecord. Více informací o události OnUpdateRecord je uvedeno ve Vytváření obsluhy události OnUpdateRecord.
Např. následující kód povoluje za běhu odložené aktualizace pro datovou množinu:
CustomersTable->CachedUpdates = true;
Když jsou odložené aktualizace povoleny, pak kopie všech záznamů potřebných pro zobrazovací a editační účely jsou odloženy v lokální paměti. Uživatel vidí a edituje tuto lokální kopii dat. Změny, vkládání a rušení jsou také odkládány do paměti. Toto je shromažďováno v paměti, dokud lokální změny nejsou aplikovány do databáze. Pokud změněné záznamy jsou úspěšně aplikovány do databáze, pak záznamy těchto změn jsou uvolněny z odkládací paměti.
Poznámka: Aplikováním odložených aktualizací nezakážeme budoucí odložené aktualizace; jsou změny pouze zapsány do databáze a vyprázdněna odkládací paměť.
K zákazu odložených aktualizací pro datovou množinu nastavíme CachedUpdates na false. Pokud zakážeme odložené aplikace, když máme ještě nějaké neaplikované změny, pak tyto změny jsou ztraceny bez varování. Naše aplikace může testovat vlastnost UpdatePending k zjištění zda existují nevyřízené aktualizace před zákazem odložených aktualizací. Např.
if (CustomersTable->UpdatesPending)
  if (Application->MessageBox("Discard pending updates?",
                              "Unposted changes",
                              MB_YES | MB_NO) == IDYES)
    CustomersTable->CachedUpdates = false;

Získávání záznamů

Implicitně, když povolíme odložené aktualizace, pak datové množiny podporující BDE automaticky získávají data z databáze, když jsou potřeba. Datové množiny získávají potřebné záznamy k zobrazení. V průběhu zpracování můžeme mnohokrát získávat záznamy. Pokud naše aplikace má speciální požadavek, pak může všechny záznamy získat najednou. K získání všech záznamů voláme metodu FetchAll datové množiny. FetchAll vytváří v paměti lokální kopii všech záznamů z datové množiny. Pokud datová množina obsahuje mnoho záznamů nebo záznamy s velkými položkami BLOB, pak FetchAll nemůžeme použít.
Klientské datové množiny používají vlastnost PacketRecords k indikování počtu záznamů, které byly získány. Pokud nastavíme vlastnost FetchOnDemand na true, pak klientská datová množina automaticky zpracovává získávání dat v případě potřeby. Jinak, musíme volat metodu GetNextPacket k získání záznamů z datového serveru.

Aplikování odložených aktualizací

Když datová množina je v režimu odložených aktualizací, pak změny dat nejsou zapisovány do databáze dokud naše aplikace explicitně nevolá metodu, která tyto změny aplikuje. Normálně, aplikace aplikuje aktualizace v reakci na akci uživatele, jako je stisk tlačítka nebo volba v nabídce.
Důležité: K aplikování aktualizací na množinu záznamů získaných dotazem SQL, který nevrací živou výsledkovou množinu, musíme použít objekt TUpdateSQL specifikující jak provést aktualizace. Pro aktualizaci spojení (dotazu na dvou nebo více tabulkách), musíme poskytnout jeden objekt TUpdateSQL pro každou použitou tabulku a musíme použít obsluhu události OnUpdateRecord k donucení těchto objektů provést aktualizaci.
Aplikování aktualizací je dvoufázový proces, který probíhá v kontextu řízení transakcí komponenty databáze k umožnění aplikace zotavovat se z chyb.
Když aplikujeme aktualizace pod řízením transakcí databáze, pak nastanou následující události:
  1. Je zahájena databázová transakce.
  2. Odložené aktualizace jsou zapsány do databáze (fáze 1). Obsluha události OnUpdateRecord je vyvolána (pokud existuje) pro každý záznam zapisovaný do databáze. Pokud při aplikování záznamů do databáze vznikne chyba, pak je generována událost OnUpdateError.

  3. Pokud zápis do databáze je neúspěšný: Pokud zápis do databáze je úspěšný:
Dvoufázová možnost aplikování odložených aktualizací umožňuje efektivní zotavení z chyb, a to obzvláště při aktualizování více datových množin (např. datových množin spojených do vztahu Master-detail).
Jsou dva způsoby aplikování aktualizací. Pro aplikování aktualizací pro specifikovanou množinu datových množin přiřazených ke komponentě databáze, voláme metodu ApplyUpdates komponenty databáze. K aplikování aktualizací pro jednu datovou množinu voláme metody ApplyUpdates a Commit datové množiny.
Aplikování odložených aktualizací metodou komponenty databáze
Normálně, aplikace odkládá aktualizace na úrovni datové množiny. Nicméně, někdy je důležité aplikovat aktualizace na více svázaných datových množinách v kontextu jediné transakce. Např. když pracujeme s formou Master-detail, pak můžeme požadovat zapsat změny do obou tabulek společně.
K aplikování odložených aktualizací na jednu nebo více datových množin v kontextu databázového připojení, voláme metodu ApplyUpdates komponenty databáze. Následující kód aplikuje aktualizace datové množiny CustomersQuery v reakci na stisknutí tlačítka:
void __fastcall TForm1::ApplyButtonClick(TObject *Sender)
{
  // pro lokální databáze jako jsou Paradox, dBASE a FoxPro
  // nastavíme TransIsolation na DirtyRead
  if(!Database1->IsSQLBased &&Database1->TransIsolation != tiDirtyRead)
    Database1->TransIsolation = tiDirtyRead;
  Database1->ApplyUpdates(&CustomersQuery,0);
}
Výše uvedená sekvence spouští transakci a zapisuje odložené aktualizace do databáze. V případě úspěchu transakce odložené aktualizace jsou zapsány do databáze. V případě neúspěchu, transakce je zrušena a stav odložených aktualizací se nemění. V tomto druhém případě, naše aplikace může zpracovat chyby odložených aktualizací pomocí události OnUpdateError datové množiny. Viz Zpracování chyb odložených aktualizací.
Hlavní výhodou volání metody ApplyUpdates komponenty databáze je to, že můžeme aktualizovat libovolný počet komponent datových množin, které jsou přiřazeny k databázi. Dva parametry metody ApplyUpdates pro databázi jsou pole TDBDataSet a index poslední datové množiny v poli. K aplikování aktualizací na více než jednu datovou množinu vytvoříme lokální pole ukazatelů na datové množiny. Např. následující kód aplikuje aktualizace pro dvě tabulky použité ve vztahu Master-detail:
TDBDataSet* ds[] = {MasterTable, DetailTable};
if(!Database1->IsSQLBased &&Database1->TransIsolation != tiDirtyRead)
  Database1->TransIsolation = tiDirtyRead;
Database1->ApplyUpdates(ds,1);
Více informací o aplikování tabulek Master-detail viz Aplikování aktualizací pro tabulky Master-detail.
Aplikování odložených aktualizací metodami komponenty datové množiny
Můžeme aplikovat aktualizace pro jednotlivé datové množiny přímo metodami ApplyUpdates a CommitUpdates datové množiny. Každá z těchto metod zaobaluje jednu fázi aktualizačního procesu:
  1. ApplyUpdates zapisuje odložené aktualizace do databáze (fáze 1).
  2. CommitUpdates vyprazdňuje interní odkládací paměť, když zápis do databáze byl úspěšný (faze 2).
Aplikování aktualizací na úrovni datových množin, dává řízení nad pořadím, ve kterém aktualizace jsou aplikovány na individuální datové množiny. Pořadí aktualizací je obzvláště kritické při zpracovávání vzájemných vztahů Master-detail. K zajištění správného pořadí aktualizace těchto tabulek, musíme aplikovat aktualizace na úrovni datových množin. Více informací viz Aplikování aktualizací pro tabulky Master-detail.
Následující kód ukazuje jak aplikovat aktualizace v transakci pro datovou množinu CustomerQuery, která byla výše použita v ukázce aktualizace pomocí metody databáze:
void __fastcall TForm1::ApplyButtonClick(TObject *Sender)
{
  Database1->StartTransaction();
  try
  {
    if(!Database1->IsSQLBased &&Database1->TransIsolation != tiDirtyRead)
      Database1->TransIsolation = tiDirtyRead;
    CustomerQuery->ApplyUpdates(); // pokus o zápis aktualizací do databáze
    Database1->Commit(); // úspěch, změny zapsány
  }
  catch (...)
  {
    Database1->Rollback(); // neúspěch, zrušení změn
    throw; // opětovné generování výjimky k zabránění volání CommitUpdates
  }
  CustomerQuery->CommitUpdates(); // úspěch, vyprázdnění odkládací paměti
}
Pokud během volání ApplyUpdates vznikne výjimka, pak databázová transakce je zrušena. Tím zajistíme, že databázové tabulky nejsou změněny. Příkaz throw mimo blok try ... catch opětovně generuje výjimku a zabrání volání CommitUpdates. Protože CommitUpdates není volána, interní odkládací paměť není vyprázdněna a můžeme tedy zpracovat chyby a pokusit se o aktualizaci znova.
Aplikování aktualizací pro tabulky Master-detail
Když aplikujeme aktualizace pro tabulky Master-detail, pak je důležité pořadí, ve kterém datové množiny aktualizujeme. Obecně vždy aktualizujeme tabulku Master před tabulkou Detail, mimo případu rušení záznamů. Ve složitějších vzájemných vztazích, kde detailní tabulka jednoho vztahu je tabulkou Master pro jinou detailní tabulku, používáme stejná pravidla.
Tabulky Master-detail můžeme aktualizovat na úrovni databáze nebo datových množin. Pro účely řízení, aplikujeme aktualizace na úrovni datových množin. Následující příklad ukazuje jaký kód použít k aplikování aktualizací na dvě tabulky Master a Detail, které jsou ve vzájemném vztahu Master-detail:
Database1->StartTransaction();
try
{
  Master->ApplyUpdates();
  Detail->ApplyUpdates();
  Database1->Commit();
}
catch(...)
{
  Database1->Rollback();
  throw;
}
Master->CommitUpdates();
Detail->CommitUpdates();
Pokud v průběhu aplikování aktualizací vznikne chyba, pak tento kód zachová odložené aktualizace i připojená data v databázi ve stejném stavu, jako byl před voláním ApplyUpdates.
Pokud výjimka vznikne v průběhu volání Master->ApplyUpdates, pak je zpracována podobně jako v samostatné datové množině popsané výše. Předpokládejme ale, že volání Master->ApplyUpdates je úspěšné, a následující volání Detail->ApplyUpdates chybuje. V tomto případě změny jsou již aplikovány na tabulku Master, ale nestaly se zatím trvalými, protože volání Master->Commit bylo přeskočeno. Voláním Database1->Rollback je dále (pokud nastala chyba) databáze vrácena do stavu před zahájením aktualizací.

Zrušení nevyřízených odložených aktualizací

Nevyřízené odložené aktualizace jsou aktualizační záznamy, které jsou odeslány do odkládací paměti, ale nejsou aplikovány na databázi. Jsou tři způsoby zrušení nevyřízených odložených aktualizací:
Zrušení nevyřízených aktualizací a zákaz dalších odložených aktualizací
K zrušení dalšího odkládání aktualizací a zrušení všech nevyřízených aktualizací bez jejich aplikování, nastavíme vlastnost CachedUpdates na false. Když CachedUpdates je nastaveno na false, pak je automaticky vyvolána metoda CancelUpdates.
Z odložených aktualizací, zrušené záznamy jsou obnoveny, modifikované záznamy jsou vráceny na původní hodnoty a nově vložené záznamy jsou zrušeny.
Poznámka: Tato možnost není dostupná pro klientské datové množiny.
Zrušení nevyřízených odložených aktualizací
CancelUpdates vyprazdňuje odkládací paměť všech nevyřízených aktualizací a obnovuje datovou množinu do stavu ve kterém byla při otevření, v době kdy odložené aktualizace byly povoleny nebo aktualizace naposled úspěšně aktualizovány. Např. následující příkaz ruší aktualizace pro CustomersTable:
CustomersTable->CancelUpdates();
Z odložených aktualizací, zrušené záznamy jsou obnoveny, modifikované záznamy jsou vráceny na původní hodnoty a nově vložené záznamy jsou zrušeny.
Poznámka: Volání CancelUpdates nezakazuje odložené aktualizace. Jsou pouze zrušeny nevyřízené aktualizace.
Zrušení aktualizací pro současný záznam
RevertRecord obnovuje současný záznam v datové množině na stav ve kterém byl při otevření, v době kdy odložené aktualizace byly povoleny nebo aktualizace naposled úspěšně aktualizovány. Většinou je používána v obsluze události OnUpdateError k opravě chybových situací. Např.
CustomersTable->RevertRecord();
Odvolání odložených změn na jednom záznamu neovlivňuje ostatní záznamy. Pouze pokud jsou odloženy aktualizace jediného záznamu a změny jsou odvolány pomocí RevertRecord, pak vlastnost UpdatesPending pro komponentu datové množiny je automaticky změněna z true na false.
Pokud záznam není modifikován, pak toto volání nemá žádný efekt. Více informací o vytváření obsluhy OnUpdateError, viz Vytváření obsluhy událostí OnUpdateError.

Odvolání odložených zrušení záznamů

Odvolání zrušení odložených záznamů vyžaduje jiné kódování, protože zrušený záznam je odeslán do odkládací paměti a nemůže se již státi současným záznamem a není dále v datové množině. V některých situacích jej ale můžeme chtít obnovit. Pomocí vlastnosti UpdateRecordTypes uděláme zrušené záznamy viditelnými a potom voláme RevertRecord. Následuje kód obnovující všechny zrušené záznamy v tabulce:
void __fastcall UndeleteAll(TBDEDataSet *DataSet)
{
  DataSet->UpdateRecordTypes.Clear();
  DataSet->UpdateRecordTypes<<rtDeleted; //zobrazení pouze zrušených záznamů
  try
  {
    DataSet->First();  //přechod na první zrušený záznam
    while (!DataSet->Eof)
       DataSet->RevertRecord();  //obnovování až do posledního záznamu
  }
  catch(...)
  { //obnovení zobrazování pouze modifikovaných, vložených a nemodifikovaných záznamů
    DataSet->UpdateRecordTypes.Clear();
    DataSet->UpdateRecordTypes << rtModified << rtInserted << rtUnmodified;
    throw;
  }
  DataSet->UpdateRecordTypes.Clear();
  DataSet->UpdateRecordTypes << rtModified << rtInserted << rtUnmodified;
}

Specifikování viditelných záznamů v odkládací paměti

Vlastnost UpdateRecordTypes určuje, které typy záznamů odložených v paměti jsou viditelné, když jsou povoleny odložené aktualizace. UpdateRecordTypes pracuje na odložených záznamech stejným způsobem jako filtr pracuje na tabulkách. Vlastnost UpdateRecordTypes je množina a může obsahovat libovolnou kombinaci následujících hodnot:
 
Hodnota Význam
rtModified Modifikované záznamy
rtInserted Vložené záznamy
rtDeleted Zrušené záznamy
rtUnmodified Nemodifikované záznamy

Implicitní hodnota pro UpdateRecordTypes zahrnuje pouze rtModified, rtInserted a rtUnmodified (zrušené záznamy - rtDeleted - nejsou zobrazovány).
Vlastnost UpdateRecordTypes je hlavně užitečná v obsluze události OnUpdateError pro zpřístupnění zrušených záznamů. Tato vlastnost je také užitečná, když chceme pro uživatele zobrazit pouze podmnožinu odložených záznamů (např. nově vložených záznamů).
Např. můžeme mít čtyři voliče (RadioButton1 RadioButton4) s texty Všechny, Modifikované, Vložené a Zrušené. Těmto voličům přiřadíme stejnou obsluhu události OnClick ve které změnou vlastnosti UpdateRecordTypes zajistíme zobrazení pouze požadovaného typu záznamu.
Více informací o vytváření obsluhy OnUpdateError, viz Vytváření obsluhy událostí OnUpdateError.

Testování stavu aktualizace

Když jsou pro naši aplikaci povoleny odložené aktualizace, pak můžeme testovat zda jsou nevyřešené odložené aktualizace, testováním vlastnosti UpdateStatus pro záznam. Testování stavu aktualizace se často používá v obsluhách událostí OnUpdateRecord a OnUpdateError. Více informací o vytváření obsluhy OnUpdateError, viz Vytváření obsluhy událostí OnUpdateError. Více informací o vytváření a používání události OnUpdateRecord viz Vytváření obsluhy události OnUpdateRecord.
Jak procházíme množinou nevyřízených změn, UpdateStatus se mění k určení stavu aktualizace současného záznamu. UpdateStatus vrací pro současný záznam jednu z následujících hodnot:
 
Hodnota Význam
usUnmodified Záznam je nezměněn
usModified Záznam je změněn
usInserted Záznam je nový záznam
usDeleted Záznam je zrušen

Když datová množina je otevřena, pak všechny záznamy mají aktualizační stav usUnmodified. Jak záznamy jsou vkládány, rušeny nebo modifikovány, pak jejich stav se mění. Zde je příklad vlastnosti UpdateStatus použité v obsluze události OnScroll pro datovou množinu. Obsluha události zobrazuje aktualizační stav všech záznamů na stavovém řádku.
void __fastcall TForm::CalcFields(TDataSet *DataSet)
{
  if (DataSet->UpdateStatus != usUnmodified)
    Table1ModifiedRow->Value = "*";
  else
    Table1ModifiedRow->Value = NULL;
}
Poznámka: Pokud UpdateStatus záznamu je usModified, pak můžeme testovat vlastnost OldValue pro každou položku v datové množině k zjištění její předchozí hodnoty.

Používání objektů aktualizace k aktualizování datových množin

TUpdateSQL je aktualizační komponenta, která používá příkazy SQL k aktualizaci datové množiny. Musíme poskytnout jednu komponentu TUpdateSQL pro každou zpřístupněnou tabulku v dotazu, který chceme aktualizovat.
Poznámka: Pokud používáme více než jednu aktualizační komponentu k provádění aktualizační operace, pak musíme vytvořit obsluhu OnUpdateRecord k provedení všech aktualizačních komponent.
Aktualizační komponenta obvykle zaobaluje tři komponenty TQuery. Každá z těchto komponent dotazu provádí jednu aktualizační úlohu. Jedna z komponent dotazu poskytuje příkaz SQL UPDATE pro modifikaci existujících záznamů; druhá komponenta dotazu poskytuje příkaz INSERT k přidávání nových záznamů k tabulce a třetí komponenta poskytuje příkaz DELETE k odstraňování záznamů z tabulky.
Když umístíme aktualizační komponentu do datového modulu, pak nevidíme komponenty dotazu, které zaobaluje. Aktualizační komponenty jsou vytvářeny za běhu na základě třech aktualizačních vlastností, pro které předáme příkazy SQL: Za běhu, když aktualizační komponenta je použita k aplikování aktualizací, pak:
  1. Vybereme příkaz SQL k provedení na základě automaticky generovaného parametru UpdateKind pro aktualizační událost záznamu. UpdateKind specifikuje, zda současný záznam je modifikován, vložen nebo zrušen.
  2. Poskytneme hodnoty parametrů příkazu SQL.
  3. Připravíme a spustíme příkaz SQL k provedení specifikované aktualizace.
V této sekci jsou ještě popsány tyto body:

Specifikování vlastnosti UpdateObject pro datovou množinu

Jeden nebo více aktualizačních objektů může být přiřazeno k aktualizované datové množině. Přiřazení aktualizačních objektů s aktualizovanou datovou množinou provedeme nastavením vlastnosti UpdateObject komponenty datové množiny na aktualizační objekt nebo nastavíme vlastnost DataSet aktualizačního objektu na aktualizovanou datovou množinu. Která metoda je použita závisí na tom, zda v aktualizované datové množině je použita pouze jedna základní tabulka nebo více tabulek.
Musíme použít jednu z těchto dvou možností přiřazování aktualizované datové množiny s aktualizačním objektům. Bez správného přiřazení, dynamické plnění parametrů příkazu SQL v aktualizačních objektech nemůže nastat. Použijeme jednu přiřazovací metodu nebo druhou, ale nikdy obě najednou.
Způsob přiřazení aktualizačního objektu k datové množině také určuje, jak aktualizační objekt je prováděn. Aktualizační objekt může být prováděn automaticky, bez explicitní intervence aplikace nebo můžeme explicitně požádat o jeho provedení. Pokud přiřazení je provedeno pomocí vlastnosti UpdateObject komponenty datové množiny, pak aktualizační objekt bude automaticky prováděn. Když přiřazení je provedeno vlastností DataSet aktualizačního objektu, pak aktualizační objekt musíme provést programově.
Následující body popisují proces přiřazování aktualizačních objektů ke komponentám datových množin podrobněji a informují o tom, kdy každá metoda má být použita a jejím efektu na provedení aktualizace.
Používání jednoho aktualizačního objektu
Když v aktualizované datové množině je zapotřebí aktualizovat pouze jednu základní tabulku, pak přiřadíme aktualizační objekt k datové množině nastavením vlastnosti UpdateObject komponenty datové množiny na jméno aktualizačního objektu.
Aktualizační příkazy SQL v aktualizačním objektu jsou provedeny automaticky, když je volána metoda ApplyUpdates aktualizované datové množiny. Aktualizační objekt je vyvolán pro každý záznam vyžadující aktualizaci. Nevolejte metodu ExecSQL aktualizačního objektu v obsluze události OnUpdateRecord, neboť výsledkem by byl druhý pokus o aplikování každého aktualizovaného záznamu.
Pokud dodáme obsluhu pro událost OnUpdateRecord datové množiny, pak minimální akce, kterou musíme provést v obsluze je nastavení parametru UpdateAction obsluhy na uaApplied. Můžeme případně také provést ověření přípustnosti dat, modifikaci dat nebo operace podobající se nastavováním hodnot parametrů.
Používání více aktualizačních objektů
Když v aktualizované datové množině potřebujeme aktualizovat více než jednu základní tabulku, pak musíme použít více aktualizačních objektů a to vždy jeden pro každou aktualizovanou základní tabulku. Protože UpdateObject komponenty datové množiny povoluje přiřadit pouze jeden aktualizační objekt k datové množině, musíme každý aktualizační objekt přiřadit k datové množině nastavením vlastnosti DataSet objektu na jméno datové množiny. Vlastnost DataSet aktualizačních objektů není dostupná při návrhu v Inspektoru objektů. Tuto vlastnost můžeme nastavit pouze za běhu.
Aktualizační příkazy SQL v aktualizačním objektu nejsou automaticky prováděny, když je volána metoda ApplyUpdates aktualizované datové množiny. K aktualizaci záznamů musíme dodat obsluhu události OnUpdateRecord pro komponentu datové množiny a volat v ní metodu ExecSQL nebo Apply aktualizačního objektu. Tím vyvoláme aktualizační objekt pro každý záznam vyžadující aktualizaci.
V obsluze pro událost OnUpdateRecord datové množiny musíme provést minimálně tyto akce: Můžeme případně také provést ověření přípustnosti dat, modifikaci dat nebo jiné operace závisející na každém aktualizovaném záznamu.
Poznámka: Je také možné mít jeden aktualizační objekt přiřazen k datové množině pomocí vlastnosti UpdateObject komponenty datové množiny a druhý a další aktualizační objekty přiřazené pomocí jejich vlastností DataSet. První aktualizační objekt je prováděn automaticky při volání metody ApplyUpdates komponenty datové množiny. Zbývající jsou prováděny manuálně.

Vytváření příkazů SQL pro aktualizační komponenty

K aktualizování záznamů v přiřazené datové množině, aktualizační objekt používá tři příkazy SQL. Tři příkazy SQL ruší, vkládají a modifikují odložené záznamy při aktualizaci. Příkazy jsou obsaženy ve vlastnostech (typu seznamu řetězců) DeleteSQL, InsertSQL a ModifySQL aktualizačního objektu. Jelikož každý aktualizační objekt je použit k aktualizaci jediné tabulky, příkazy aktualizačního objektu se odkazují na stejnou základní tabulku.
Jak jsou aplikovány aktualizace pro jednotlivé záznamy, jeden ze tří příkazů SQL je proveden k aktualizaci základní tabulky. Který z příkazů SQL je proveden závisí na automaticky generovaném parametru UpdateKind pro každý aktualizovaný záznam.
SQL příkazy pro aktualizační objekty můžeme vytvářet při návrhu nebo za běhu. Následující body popisují vytvářecí proces příkazů SQL podrobněji.
Vytváření SQL příkazů při návrhu
K vytvoření příkazů SQL pro aktualizační komponentu:
  1. Vybereme komponentu TUpdateSQL.
  2. Vybereme jméno aktualizační komponenty z rozbalovacího seznamu vlastnosti UpdateObject komponenty datové množiny v Inspektoru objektů. Tím zajistíme, že v následujícím kroku bude vyvolán Editor UpdateSQL k určení hodnot pro generační volby SQL.
  3. V místní nabídce aktualizační komponenty zvolíme UpdateSQL Editor k vyvolání Editoru UpdateSQL. Editor vytváří příkazy SQL pro vlastnosti ModifySQL, InsertSQL a DeleteSQL aktualizační komponenty na základě připojené množiny dat a jí předávaných hodnotách.
Editor UpdateSQL má dvě stránky. Při vyvolání editoru je viditelná stránka Options. Kombinovaný ovladač Table Name použijeme k výběru aktualizované tabulky. Po specifikaci jména tabulky, seznamy Key Fields a Update Fields jsou zaplněny dostupnými sloupci.
Seznam Update Fields obsahuje sloupce, které mohou být aktualizovány. Když specifikujeme tabulku, pak všechny sloupce v seznamu Update Fields jsou vybrány. Můžeme podle potřeby vybírat i více položek.
Seznam Key Fields je používán pro specifikaci sloupců používaných v průběhu aktualizace jako klíčů. Pro Paradox, dBASE a FoxPro, specifikované sloupce musí odpovídat existujícímu indexu, ale toto není požadováno pro SQL databáze. Místo nastavování Key Fields můžeme stisknout tlačítko Primary Keys k volbě klíčových položek pro aktualizaci na základě primárního indexu tabulky. Stiskem Dataset Defaults se vrátíme k původnímu stavu výběru: všechny položky vybrané jako klíče a všechny vybrané pro aktualizaci.
Označíme značku Quote Field Names pokud náš server požaduje uzavírat jména položek do uvozovek.
Po specifikaci tabulky, vybereme sloupce klíče a vybereme aktualizační sloupce a stiskem Generate SQL zahájíme generování příkazů SQL pro vlastnosti ModifySQL, InsertSQL a DeleteSQL pro aktualizační komponentu. V mnoha případech nám postačí automaticky generované příkazy SQL.
K zobrazení a modifikaci příkazů SQL, přejdeme na stránku SQL. Pokud máme vygenerované příkazy SQL, pak při přechodu na tuto stránku, příkaz pro vlastnost ModifySQL je zobrazen v ovladači Memo nazvaném SQL Text. Příkaz zde můžeme podle potřeby editovat.
Důležité: Vygenerované příkazy jsou počátkem pro vytváření aktualizačních příkazů. Tyto příkazy můžeme modifikovat. Např. když pracujeme s daty které obsahují hodnoty NULL, pak můžeme požadovat modifikovat klauzuli WHERE na
WHERE field IS NULL
namísto použití generovaných proměnných položek. Sami každý příkaz přímo otestujeme.
Pomocí voličů Statement Type se přepneme na další generované příkazy a podle potřeby je editujeme. K akceptování příkazů a k jejich přiřazení vlastnostem SQL aktualizační komponenty stiskneme OK.
Seznámení se substitucí parametrů v aktualizačním příkazu SQL
Aktualizační příkazy SQL používají speciální formu substituce parametrů, která umožňuje nahradit staré nebo nové hodnoty položek v aktualizovaných záznamech. Když Editor UpdateSQL generuje své příkazy, je určeno, které hodnoty položek použije. Když zapisujeme aktualizační SQL, pak specifikujeme hodnoty položek k použití.
Když jméno parametru se shoduje se jménem sloupce v tabulce, pak nová hodnota v položce v odložených aktualizacích pro záznam je automaticky použita jako hodnota pro parametr. Když jméno parametru odpovídá jménu sloupce předcházené řetězcem OLD_, pak pro položku je použita stará hodnota. Např. v následujícím aktualizačním příkazu SQL, parametr :LastName je automaticky plněn novou hodnotou položky z odložených aktualizacích pro vkládaný záznam.
INSERT INTO Names
(LastName, FirstName, Address, City, State, Zip)
VALUES (:LastName, :FirstName, :Address, :City, :State, :Zip)
Nové hodnoty položek jsou obvykle používány v příkazech InsertSQL a ModifySQL. V aktualizaci pro modifikovaný záznam, nové hodnoty položky z aktualizační odkládací paměti jsou použity příkazem UPDATE k nahrazení staré hodnoty položky v aktualizované základní tabulce.
V případě rušení záznamů, nejsou nové hodnoty a tak vlastnost DeleteSQL používá syntaxi :OLD_FieldName. Staré hodnoty položek jsou také normálně použity v klauzuli příkazu SQL pro modifikování nebo rušení aktualizací k určení který záznam aktualizovat nebo zrušit.
V klauzuli WHERE aktualizačních příkazů SQL UPDATE nebo DELETE předáváme minimální počet parametrů k jednoznačné identifikaci záznamu v základní tabulce, která je aktualizována odloženými daty. Např. v seznamu zákazníků, použití pouze příjmení zákazníka nepostačuje k jednoznačné identifikaci opravovaného záznamu v základní tabulce, neboť může existovat několik zákazníků stejného jména. Ale použití parametrů pro příjmení a telefonní číslo může být již postačující kombinace. Je ale mnohem vhodnější použít položku typu číslo zákazníka.
Skládání aktualizačních příkazů SQL
Komponenta TUpdateSQL má tři vlastnosti pro aktualizační příkazy SQL: DeleteSQL, InsertSQL a MofifySQL. Jak nám již napovídají jejich jména, tyto SQL příkazy ruší, vkládají a modifikují záznamy v základní tabulce.
Vlastnost DeleteSQL obsahuje pouze SQL příkaz DELETE. Aktualizovaná základní tabulka musí být uvedena v klauzuli FROM. A tak příkaz SQL pouze zruší v základní tabulce záznam, jehož odpovídající záznam byl zrušen v aktualizační odkládací paměti, pomocí klauzule WHERE. V klauzuli WHERE použijeme parametr pro jednu nebo více položek k jednoznačné identifikaci záznamu v základní tabulce, který odpovídá záznamu z odložených aktualizací. Pokud parametr má stejné jméno jako položka s předponou OLD_, pak parametr automaticky získá hodnotu z odpovídající položky ze záznamu odložených aktualizací. Když parametr je pojmenován jinak, pak hodnotu parametru musíme dodat.
DELETE FROM Inventory I
WHERE (I.ItemNo = :OLD_ItemNo)
Některé typy tabulek nemusí být schopny nalézt záznam v základní tabulce, když položky používají k identifikaci záznamu obsahující hodnoty NULL. V těchto případech aktualizace rušení pro tyto záznamy chybuje. K zabránění tomu, přidáme podmínku pro tyto položky s predikátem IS NULL. Např. když FirstName může obsahovat NULL:
DELETE FROM Names
WHERE (LastName = :OLD_LastName) AND
  ((FirstName = :OLD_FirstName) OR (FirstName IS NULL))
Příkaz InsertSQL může obsahovat pouze SQL příkaz INSERT. Základní tabulka pro aktualizaci musí být uvedena v klauzuli INTO. V klauzuli VALUES předáváme čárkami oddělený seznam parametrů. Pokud parametr je pojmenován stejně jako položka, pak parametr automaticky získá danou hodnotu ze záznamu odložené aktualizace. Je-li pojmenován jinak, pak hodnoty parametru musíme dodat. Seznam parametrů předává hodnoty pro položky v nově vytvářeném záznamu. Musí to být všechny hodnoty parametrů jako jsou položky uvedeny v příkazu.
INSERT INTO Inventory
(ItemNo, Amount)
VALUES (:ItemNo, 0)
Příkaz ModifySQL může obsahovat pouze SQL příkaz UPDATE. Základní tabulka k aktualizaci musí být uvedena v klauzuli FROM. Obsahuje jedno nebo více přiřazení hodnot v klauzuli SET. Pokud přiřazované hodnoty v klauzuli SET jsou parametry pojmenované stejně jako položky, pak parametrům jsou automaticky dány hodnoty z položek stejného jména v odloženém aktualizovaném záznamu. Při použití jiných jmen parametrů, musíme hodnoty parametru předat manuálně. Jako u příkazu DeleteSQL, předáme klauzuli WHERE k jednoznačné identifikaci záznamů v základní tabulce (jména položek předcházená OLD_). V následujícím příkazu, parametr :ItemNo získá automaticky hodnotu a :Price ne.
UPDATE Inventory I
SET I.ItemNo = :ItemNo, Amount = :Price
WHERE (I.ItemNo = :OLD_ItemNo)
Předpokládejme předchozí příkaz SQL v případě kdy koncový uživatel modifikuje existující záznam. Původní hodnota položky ItemNo je 999. V připojené mřížce uživatel změní položku ItemNo na 123 a Amount na 20. Když je vyvolána metoda ApplyUpdates, pak tento SQL příkaz ovlivňuje všechny záznamy v základní tabulce u kterých položka ItemNo je 999, pomocí staré hodnoty položky v parametru :OLD_ItemNo. U těchto záznamů je změněna hodnota položky ItemNo na 123 (pomocí parametru :ItemNo, hodnotu získáme z mřížky) a Amount na 20.
Zpřístupnění vlastnosti Query aktualizační komponenty
Pomocí vlastnosti Query aktualizační komponenty přistupujeme k jedné aktualizační vlastnosti SQL DeleteSQL, InsertSQL nebo ModifySQL a to pro nastavování nebo změnu příkazu SQL. Použijeme hodnotu konstanty UpdateKind jako index v poli komponent dotazů. Vlastnost Query je dostupná pouze za běhu.
Následující příkaz používá konstantu ukDelete UpdateKind s vlastností Query pro zpřístupnění vlastnosti DeleteSQL. Normálně vlastnosti indexované vlastností Query jsou nastavovány při návrhu pomocí Editoru UpdateSQL. Můžeme k ním ale přistupovat za běhu, pokud nepoužívají sestavování parametrů. Následující příklad generuje unikátní vlastnosti Query pro každý aktualizovaný řádek:
void __fastcallTForm1::EmpAuditUpdateRecord(TDataSet *DataSet,
           TUpdateKind UpdateKind, TUpdateAction &UpdateAction)
{
  TUpdateSQL *pUpdate = (TUpdateSQL *)((TBDEDataSet *)DataSet)->UpdateObject;
  switch (UpdateKind)
  {
    case ukModify:
      pUpdate->SQL[UpdateKind]->Text =
              Format("UPDATE EMPTAB SET SALARY = %d WHERE EMPNO = %d",
                     ARRAYOFCONST((EmpAuditSalary->NewValue->AsInteger,
                                   EmpAuditEmpNo->OldValue->AsInteger)));
      break;
    case ukInsert:
      ...
      break;
    case ukDelete:
      ...
      break;
  }
  pUpdate->ExecSQL(UpdateKind);
  UpdateAction = uaApplied;
}
Poznámka: Query vrací hodnotu typu TDataSetUpdateObject. K chápání této vrácené hodnoty jako komponenty TUpdateSQL použijeme přetypování. Např.
((TUpdateSQL *)Query1->UpdateObject)->Query[UpdateKind];
Používání vlastností DeleteSQL, InserSQL a ModifySQL
Vlastnosti DeleteSQL, InsertSQL a ModifySQL používáme k nastavování aktualizačních příkazů SQL. Tyto vlastnosti jsou všechny seznamy řetězců. K zadávání příkazů používáme metody seznamu řetězců. Tyto vlastnosti jsou přístupné při návrhu i za běhu.

Provádění aktualizačních příkazů

Je několik metod určených k aktualizování individuálních záznamů. Tato volání metod se obvykle používají v obsluze události OnUpdateRecord aktualizačního objektu pro spouštění aktualizačního SQL k aplikování současného záznamu odložených aktualizací. V různých situacích používáme různé metody. V následujících bodech jsou popsány tyto metody podrobněji:
Volání metody Apply
Metoda Apply aplikační komponenty manuálně aplikuje aktualizace současného záznamu. Jsou dva kroky vyvolávající tento proces:
  1. Hodnoty záznamu jsou spojeny s parametry v příslušném aktualizačním SQL příkazu.
  2. Příkaz SQL je proveden.
K aplikování aktualizací pro současný záznam v aktualizační odkládací paměti voláme metodu Apply. Apply můžeme použít když aktualizační objekt není přiřazen k datové množině pomocí vlastnosti UpdateObject komponenty datové množiny, kdy aktualizační objekt není automaticky prováděn. Apply automaticky volá metodu SetParams ke spojení starých a nových hodnot položek ke speciálně pojmenovaným parametrům v aktualizačním příkazu SQL. SetParams při používání Apply nevoláme sami. Metoda Apply je často volána v obsluze události OnUpdateRecord datové množiny.
Pokud použijeme vlastnost UpdateObject komponenty datové množiny k přiřazení datové množiny a aktualizačního objektu, pak tato metoda je volána automaticky. V obsluze události OnUpdateRecord komponenty datové množiny nevoláme Apply, protože výsledkem by byl druhý pokus o aplikování aktualizací současného záznamu.
V obsluze události OnUpdateRecord, parametr UpdateKind je použit k určení, který aktualizační příkaz použít. Při vyvolávání připojenou datovou množinou, UpdateKind je nastavován automaticky. Pokud vyvoláme metodu v obsluze OnUpdateRecord, pak předáme konstantu UpdateKind jako parametr Apply.
Pokud v průběhu provádění aktualizace je generována výjimka, pak provádění pokračuje událostí OnUpdateError, pokud její obsluha je definována.
Poznámka: Operace prováděné Apply jsou analogické k metodám SetParams a ExecSQL popsaným v následujících bodech.
Volání metody SetParams
Metoda SetParams pro aktualizační komponentu používá speciální pravidla substituce prarametrů k vložení staré a nové hodnoty položky do aktualizačního příkazu SQL. Normálně, SetParams je voláno automaticky metodou Apply aktualizační komponenty. Pokud Apply voláme přímo v události OnUpdateRecord, pak sami nevoláme SetParams. Pokud provádíme aktualizační objekt pomocí jeho metody ExecSQL, pak volání SetParams připojuje hodnoty k parametrům aktualizačního příkazu.
SetParams nastavuje parametry SQL příkazu určeného parametrem UpdateKind. Pouze ty parametry, které používají speciální pojmenovací konvence automaticky mají přiřazenou hodnotu. Pokud parametr má stejné jméno jako položka nebo jako jméno položky předcházené OLD_, pak parametr získá automaticky hodnotu. Pro jinak pojmenované parametry, musíme hodnotu přiřadit manuálně.
Provádění aktualizačních příkazů
Metoda ExecSQL aktualizační komponenty manuálně aplikuje aktualizace pro současný zánam. Při vyvolání tohoto procesu jsou dva kroky:
  1. Hodnoty pro záznam jsou spojeny s parametry v odpovídajícím aktualizačním příkazu SQL.
  2. Je proveden příkaz SQL.
Metodu ExecSQL voláme k aplikování aktualizací pro současný záznam v aktualizační odkládací paměti. ExecSQL použijeme pouze, když aktualizační objekt není přiřazen k datové množině pomocí vlastnosti UpdateObject komponenty datové množiny, kdy aktualizační objekt není prováděn automaticky. ExecSQL nevolá automaticky metodu SetParams ke spojení hodnot k parametrům aktualizačního příkazu SQL; SetParams voláme sami před vyvoláním ExecSQL. Metoda ExecSQL je často volána v obsluze události OnUpdateRecord.
Pokud použijeme vlastnost UpdateObject komponenty datové množiny k přiřazení datové množiny a aktualizačnho objektu, pak tato metoda je volána automaticky. Nevoláme ExecSQL v obsluze události OnUpdateRecord komponenty datové množiny, neboť výsledkem by byl druhý pokus o aplikování aktualizací současného záznamu.
V obsluze události OnUpdateRecord, parametr UpdateKind je použit k určení který aktualizační příkaz SQL použít. Při vyvolání přiřazenou datovou množinou, UpdateKind je nastavován automaticky. Jestliže vyvoláme metodu v události OnUpdateRecord, pak předáme konstantu UpdateKind jako parametr ExecSQL.
Pokud v průběhu provádění aktualizace je generována výjimka, pak provádění pokračuje událostí OnUpdateError, pokud její obsluha je definována.

Používání komponent datových množin k aktualizaci datové množiny

Aplikování odložených aktualizací obvykle vyžaduje použití jednoho nebo více aktualizačních objektů. Aktualizační příkazy SQL pro tyto objekty aplikují datové změny na základní tabulku. Použití aktualizační komponenty je nejsnadnější způsob aktualizování datové množiny, ale není požadován. Můžeme případně použít komponenty datových množin jako TTable a TQuery k aplikování odložených aktualizací.
V obsluze události OnUpdateRecord komponenty datové množiny, použijeme vlastnosti a metody jiné komponenty datové množiny k aplikování odložených aktualizací pro každý záznam.

Aktualizování výsledkové množiny určené pouze pro čtení

I když BDE se pokouší poskytnout aktualizovatelný nebo "živý" výsledek dotazu, když vlastnost RequestLive komponenty dotazu je true, jsou některé situace, kdy to provést nelze. V těchto situacích, můžeme manuálně aktualizovat datovou množinu takto:
  1. Přidáme komponentu TUpdateSQL k datovému modulu v naši aplikaci.
  2. Nastavíme vlastnost UpdateObject komponenty datové množiny na jméno komponenty TUpdateSQL v datovém modulu.
  3. Zadáme aktualizační příkazy SQL pro výsledkovou množinu do vlastností ModifySQL, InsertSQL nebo DeleteSQL aktualizační komponenty nebo použijeme Editor UpdateSQL.
  4. Uzavřeme datovou množinu.
  5. Nastavíme vlastnost CachedUpdates komponenty datové množiny na true.
  6. Datovou množinu opět otevřeme.
Poznámka: V mnoha situacích můžeme také chtít pro datovou množinu zapsat obsluhu události OnUpdateRecord.

Řízení procesu aktualizace

Když je volána metoda ApplyUpdates komponenty datové množiny, pak je učiněn pokus o aktualizaci pro všechny záznamy v aktualizační odkladací paměti na odpovídající záznamy v základní tabulce. Jak aktualizace pro každé rušení, vložení nebo modifikaci jsou aplikovány, je generována událost OnUpdateRecord komponenty datové množiny.
Poskytnutím obsluhy pro událost OnUpdateRecord umožníme provádět akce práve před provedením aktualizace současného záznamu. Tyto akce mohou obsahovat kontrolu přípustnosti dat, aktualizaci ostatních tabulek nebo spouštění více aktualizačních objektů. Obsluha události OnUpdateRecord zvyšuje možnost řízení procesu aktualizace.
V této sekci nalezneme ještě tyto body:

Určení, zda potřebujeme řídit aktualizační proces

Někdy, když používáme odložené aktualizace, vše co potřebujeme dělat je volat ApplyUpdates k aplikování odložených změn do základních tabulek v databázi (např. když máme výlučný přístup k lokálním tabulkám Paradoxu nebo dBASE prostřednictvím komponenty TTable). V některých jiných případech můžeme požadovat nebo musíme požadovat další proces k zajištění, že aktualizace budou správně aplikovány. K poskytnutí tohoto dalšího procesu použijeme obsluhu události OnUpdateRecord aktualizované komponenty datové množiny.
Např. můžeme použít událost OnUpdateRecord k ověření přípustnosti dat před jejich aplikováním na tabulku nebo můžeme chtít použít událost OnUpdateRecord k poskytnutí dalšího zpracování pro záznamy v tabulkách Master-detail před jejich zápisem do základních tabulek.
V mnoha případech musíme poskytnout další zpracování. Např. pokud přistupujeme k více tabulkám pomocí spojeného dotazu, pak musíme poskytnout jeden objekt TUpdateSQL pro každou tabulku v dotazu a musíme použít OnUpdateRecord k zajištění, že každý aktualizační objekt bude proveden k zápisu změn do tabulek.

Vytváření obsluhy události OnUpdateRecord

Událost OnUpdateRecord zpracovává případy kdy jedna aktualizační komponenta nemůže být použita k provedení požadovaných aktualizací nebo když naše aplikace potřebuje více řízení nad substitucí speciálních parametrů. Událost OnUpdateRecord je generována jednou při aplikování změn pro každý modifikovaný záznam v aktualizační odkládací paměti.
K vytvoření obsluhy události OnUpdateRecord pro datovou množinu:
  1. Vybereme komponentu datové množiny.
  2. Přejdeme na stránku událostí Inspektora objektů.
  3. Dvojitě klikneme na hodnotu vlastnosti OnUpdateRecord k vyvolání editoru kódu.
Následuje kostra kódu obsluhy události OnUpdateRecord:
void __fastcallTForm1::DataSetUpdateRecord(TDataSet *DataSet,
          TUpdateKind UpdateKind, TUpdateAction &UpdateAction)
{
  // Zde provádíme aktulizace...
}
Parametr DateSet specifikuje odloženou datovou množinu s aktualizacemi.
Parametr UpdateKind indikuje typ prováděné aktualizace. Hodnoty pro UpdateKind jsou ukModify, ukInsert a ukDelete. Když používáme aktualizační komponentu, pak musíme předat tento parametr při jejím provádění a parametr spojit s metodou. Např. použitím ukModify a metodou Apply provádíme příkaz ModifySQL aktualizačního objektu. Můžeme také potřebovat zkoumat tento parametr pokud obsluha provádí nějaké speciální zpracování na základě typu prováděné aktualizace.
Parametr UpdateAction indikuje zda aktualizace je aplikována nebo ne. Hodnoty pro UpdateAction jsou uaFail (implicitně), uaAbort, uaSkip, uaRetry a uaApplied. Pokud během aktualizace nenastane žádný problém, pak naše obsluha by měla před ukončením nastavit tento parametr na uaApplied. Pokud jistý záznam nechceme aplikovat, pak nastavíme hodnotu na uaSkip k ochránění neaplikovaných změn v odkládací paměti.
Pokud nezměníme hodnotu pro UpdateAction, pak celá aktualizační operace pro datovou množinu je zrušena.
Mimo těchto parametrů, obvykle používáme vlastnosti OldValue a NewValue položkových komponent přiřazených k současnému záznamu.
Důležité: Událost OnUpdateRecord, podobně jako obsluhy událostí OnUpdateError a OnCalcFields, nikdy nesmí volat žádnou metodu, která mění (přesouvá) současný záznam v datové množině.

Zpracování chyb odložených aktualizací

Protože mezi časem odložení aktualizace záznamu a jeho aplikováním uplynul nějaký čas, je možné, že jiné aplikace tento záznam mohly změnit v databázi dříve než jej aplikace aplikuje. Nemusí to být vždy konflik mezi aktualizacemi uživatelů, ale při aplikování aktualizovaného záznamu vznikne chyba. BDE speciálně testuje konflikty aktualizací a další podmínky a oznamuje chybu.
Událost OnUpdateError komponenty datové množiny umožňuje chyby zachytit a reagovat na ně. Můžeme vytvořit pro tuto událost, pokud používáme odložené aktualizace. Pokud ji nevytvoříme a vznikne chyba, pak celá aktualizační operace je neúspěšná.
Pozor: Nevoláme žádnou metodu datové množiny, která mění současný zázmam (jako je Next nebo Prior) v obsluze události OnUpdateError. Pokud to provedeme, pak obsluha události přejde do nikdy nekončícího cyklu.
Následuje kostra kódu obsluhy události OnUpdateError:
void __fastcallTForm1::DataSetUpdateError(TDataSet *DataSet,
         EDatabaseError *E, TUpdateKind UpdateKind, TUpdateAction &UpdateAction)
{
  // Zde reagujeme na chybu...
}
V této sekci jsou uvedeny ještě tyto body:

Odkazování na datovou množinu na kterou aplikujeme aktualizace

DataSet ukazuje na datovou množinu na které jsou aplikovány aktualizace. Ke zpracování hodnot nového a starého záznamu v průběhu zpracování chyb tento odkaz musíme předat.

Indikování typu aktualizace, která generovala chybu

Událost OnUpdateError získává parametr UpdateKind, který je typu TUpdateKind. Popisuje typ aktualizace, která generovala chybu. Dokud naše obsluha chyb nebude provádět speciální akci na základě typu aktualizace, pak náš kód pravděpodobně tento parametr nebudeme používat.
Následující tabulka uvádí možné hodnoty pro UpdateKind:
 
Hodnota Význam
ukModify Editace existujícího záznamu způsobyla chybu.
ukInsert Vložení nového záznamu způsobylo chybu.
ukDelete Zrušení existujícího záznamu způsobylo chybu.

Specifikace akce k provedení

UpdateAction je parametr typu TUpdateAction. Když naše aktualizační chybová obsluha je poprvé volána, pak hodnota pro tento parametr je vždy nastavena na uaFail. Na základě chybové podmínky pro záznam způsobující chybu jej můžeme nastavit na jinou hodnotu před ukončením obsluhy. UpdateAction můžeme nastavit na jednu z následujících hodnot:
 
Hodnota Význam
uaAbort Zrušení aktualizační operace bez zobrazení chybové zprávy.
uaFail Zrušení aktualizační operace a zobrazení chybové zprávy. Je to implicitní hodnota pro UpdateAction.
uaSkip Přeskočení aktualizování řádku, ale aktualizace pro záznam zůstává v odkládací paměti.
uaRetry Opakuje aktualizační operaci. Před nastavením na tuto hodnotu opravíme chybovou podmínku.
uaApplied Nepoužíváme ve funkcích zpracování chyb.

Jestliže naše obsluha chyby může opravit chybovou podmínku, která způsobila vyvolání obsluhy, pak nastavíme UpdateAction na příslušnou akci a obsluhu ukončíme. Pro opravenou chybovou podmínku, nastavíme SetAction na uaRetry k opakovanému aplikování aktualizace na záznam. Když nastavíme SetAction na uaSkip, pak aktualizace pro řádek způsobující chybu je přeskočen a aktualizace zůstane v odkládací paměti po dokončení všech ostatních aktualizací.
uaFail i uaAbort ukončují celou aktualizační operaci. uaFail generuje výjimku a zobrazuje chybovou zprávu. uaAbort generuje pouze výjimku, ale zprávu nezobrazuje.
Poznámka: Pokud chyba vznikne v průběhu aplikování odložených aktualizací, pak je generována výjimka a zobrazena chybová zpráva. Když ApplyUpdates není volána z konstrukce try...catch, pak chybová zpráva pro uživatele je zobrazena v obsluze události OnUpdateError, může být zobrazena dvakrát. K zabránění duplikace chybové zprávy nastavíme UpdateAction na uaAbort.
Hodnota uaApplied může být používána pouze v události OnUpdateRecrd. Tuto hodnotu nenastavujeme v aktualizační obsluze chyby.

Práce s textem chybové zprávy

Parametr E je obvykle typu EDBEngineError. Z tohoto typu výjimky, můžeme získat chybovou zprávu, kterou můžeme zobrazit pro uživatele v naší obsluze chyby. Např. následující kód zobrazuje chybovou zprávu v komponetě Label:
ErrorLabel->Caption = E->Message;
Tento parametr je také užitečný k zjištění aktualní příčiny chyby. Z EDBEngineError můžeme extrahovat chybový kód a na základě jeho hodnoty provést příslušnou akci. Např. následující kód testuje, zda chyba aktualizace je spojena s integritou klíče a pokud ano, pak parametr UpdateAction je nastaven na uaSkip.
// vložíme BDE.hpp do naší jednotky pro tento příklad
void __fastcallTForm1::DataSetUpdateError(TDataSet *DataSet,
    EDatabaseError *E, TUpdateKind UpdateKind, TUpdateAction &UpdateAction)
{
  UpdateAction = uaFail
  if (E->ClassNameIs("EDBEngineError"))
  {
    EDBEngineError *pDBE = (EDBEngineError *)E;
    if (pDBE->Errors[pDBE->ErrorCount - 1]->ErrorCode == DBIERR_KEYVIOL)
      UpdateAction = uaSkip;
  }
}

Zpřístupňování vlastností OldValue, NewValue a CurValue položek

Když jsou povoleny odložené aktualizace, pak původní hodnoty pro položky v každém záznamu jsou uloženy ve vlastnostech OldValue určených pouze pro čtení položkových komponent. Nové hodnoty jsou analogicky uloženy ve vlastnosti NewValue. V klientských datových množinách, další vlastnost CurValue, ukládá hodnoty položek současně zobrazené v datové množině. CurValue může být stejná jako OldValue dokud jiný uživatel needituje záznam. Pokud jiný uživatel edituje záznam, pak CurValue získá současnou hodnotu položek které byly odeslány tímto uživatelem.

  1. Nyní se podíváme na další již hotový program. Nalezneme jej v adresáři Program files\Borland\CBuilder\Examples\DBTask\CachesUp. Jedná se o aplikaci používající odložené aktualizace. Aplikaci si prohlédněte a vyzkoušejte ji.
21. Práce s odloženými aktualizacemi