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:
-
Minimalizace času transakcí
-
Minimalizací provozu v síti
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:
-
Odložená data jsou lokální v naší aplikaci a nejsou pod řízením
transakcí. V rušném prostředí Klient/server to má pro naši aplikaci dva
důsledky:
-
Ostatní aplikace mohou zpřístupňovat a měnit aktuální data
na serveru zatímco náš uživatel edituje lokální kopii dat.
-
Ostatní aplikace nemohou vidět žádné datové změny provedené
naší aplikací, dokud neaplikujeme všechny změny.
-
Ve vzájemných vztazích Master-detail, správa odložených aktualizací
může být choulostivá.
-
K aplikování odložených aktualizací na datových množinách
založených na dotazech určených pouze pro čtení použijeme aktualizační
objekty.
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:
-
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.
-
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.
-
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ů.
-
Pokračujeme v zobrazování a editaci lokální kopie záznamů,
dokud všechny požadované změny nejsou provedeny.
-
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:
-
Je zahájena databázová transakce.
-
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.
Pokud zápis do databáze je neúspěšný:
-
Databázové změny jsou zrušeny a transakce je ukončena.
-
Odložené aktualizace nejsou zapsány, zůstávají v interní
odkládací paměti.
Pokud zápis do databáze je úspěšný:
-
Databázové změny jsou zapsány a transakce je ukončena.
-
Odložené aktualizace jsou zapsány a interní odkládací paměť
je vyprázdněna (fáze 2).
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:
-
ApplyUpdates zapisuje odložené aktualizace do databáze
(fáze 1).
-
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 až
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:
-
ModifySQL specifikuje příkaz UPDATE
-
InsertSQL specifikuje příkaz INSERT
-
DeleteSQL specifikuje příkaz DELETE
Za běhu, když aktualizační komponenta je použita k aplikování
aktualizací, pak:
-
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.
-
Poskytneme hodnoty parametrů příkazu SQL.
-
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:
-
Volat metodu SetParams aktualizačního objektu (pokud
později voláme
ExecSQL).
-
Provést aktualizační objekt pro současný záznam pomocí ExecSQL
nebo
Apply.
-
Nastavit parametr UpdateAction obsluhy události na
uaApplied.
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:
-
Vybereme komponentu TUpdateSQL.
-
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.
-
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:
-
Hodnoty záznamu jsou spojeny s parametry v příslušném aktualizačním
SQL příkazu.
-
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:
-
Hodnoty pro záznam jsou spojeny s parametry v odpovídajícím
aktualizačním příkazu SQL.
-
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:
-
Přidáme komponentu TUpdateSQL k datovému modulu v
naši aplikaci.
-
Nastavíme vlastnost UpdateObject komponenty datové
množiny na jméno komponenty TUpdateSQL v datovém modulu.
-
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.
-
Uzavřeme datovou množinu.
-
Nastavíme vlastnost CachedUpdates komponenty datové
množiny na true.
-
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:
-
Vybereme komponentu datové množiny.
-
Přejdeme na stránku událostí Inspektora objektů.
-
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.
-
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
|