Použití tříd pro přístup k datům

Tato kapitola popisuje využití vlastností a prostředků Delphi pro vytváření databázových aplikací. Je uveden základní přehled a krátký popis tříd pro práci s databázovými soubory. Bližší informace týkající se databázových prvků a jejich metod a vlastností lze najít v on-line helpu.

Hierarchie tříd pro práci s databázemi

Hierarchie tříd pro práci s databázemi je podstatná pro pochopení vlastností, metod a událostí, které jednotlivé třídy dědí od svých předků. Nejdůležitější třídy pro práci s databázemi jsou:

Použití třídy TSession

Prvky třídy TSession jsou používány zřídka, ale v některých speciálních případech mohou být užitečné. Delphi vytváří instanci třídy TSession se jménem Session při každém běhu databázové aplikace. Tento prvek není explicitně zobrazen a nemůže být explicitně vytvořen, lze však použít jeho metody a vlastnosti, které ovlivňují globální chování aplikace.

Ovládání databázových sezení

Třída TSession umožňuje globální řízení databázových sezení dané aplikace. Vlastnost Databases třídy TSession obsahuje seznam všech aktivních databázových sezení. Vlastnost DatabaseCount obsahuje počet aktivních databází (tj. počet použitých instancí třídy TDatabase).

Logická vlastnost KeepConnections udává, zda mají být uchována neaktivní databázová sezení - databázové sezení přestane být aktivní, když prvek třídy TDatabase nemá žádné aktivní prvky třídy TDataSet. Implicitní hodnota vlastnosti KeepConnections je true a aplikace uchovává databázová sezení, i když nejsou aktivní. To je obecně vhodnější v případě, že aplikace opakovaně otevírá a uzavírá tabulky databáze. Má-li KeepConnections hodnotu false, databázové sezení je ukončeno okamžitě, jakmile přestane být aktivní. Metoda DropConnections ukončí všechna neaktivní databázová sezení.

Vlastnost NetFileDir obsahuje cestu k pracovnímu adresáři BDE. Vlastnost PrivateDir udává adresář pro uchování dočasných souborů (např. souborů vytvářených při zpracování SQL příkazů). Tato vlastnost by se měla nastavovat jen v případě, že může aplikace běžet v každém okamžiku pouze jednou. V opačném případě dochází ke kolizi takto vytvářených dočasných souborů.

Získávání informací o databázi

Třída TSession má několik metod, které umožňují aplikaci získat informace týkající se zpracovávané databáze. Všechny metody používají parametr typu TStrings, vrací v tomto parametru požadované informace a jejich přehled je v následující tabulce.

Metody třídy TSession
MetodaVrací
GetAliasNames Alias jméno v BDE
GetAliasParams Parametry daného BDE aliasu
GetDatabaseNames Použitá jména databází a BDE aliasů
GetDriverNames Jména instalovaných BDE driverů
GetDriverParams Parametry zadaného BDE driveru
GetTableNames Jména všech tabulek zadané databáze

Práce s datovými množinami

Třídy TTable a TQuery jsou odvozeny od třídy TDataSet. Obě tyto třídy sdílí řadu společných vlastností, metod i událostí. Z tohoto důvodu používáme společný termín datové množiny a budeme se s nimi zabývat nejprve společně.

Poznámka: Mezi datové množiny řadíme i instance třídy TStoredProc, protože i ta je odvozena od třídy TDataSet. Většina údajů v této části se vztahuje i na třídu TStoredProc v případě, že příslušná procedura vrací výsledkovou množinu (a ne např. jednu hodnotu).

Stavy datových množin

Datové množiny se mohou vyskytovat v některém ze stavů uvedených v následující tabulce.

Stavy datových množin
StavPopis
Neaktivní (Inactive) Datová množina není otevřena.
Prohlížení (Browse) Implicitní stav po otevření datové množiny. Záznamy lze prohlížet, nelze je měnit ani vkládat.
Editace (Edit) Umožňuje editaci aktuálního záznamu.
Vkládání (Insert) Umožňuje vložení nového záznamu.
Nastavení klíče (SetKey) Tento stav se týká pouze třídy TTable a umožňuje hledání v tabulkách databáze pomocí metod FindKey, GoToKey a GoToNearest. Třída TQuery využívá k hledání prostředků jazyka SQL.
Výpočet položek (CalcFields) Aplikace nastavuje tento stav při provádění události OnCalcFields, explicitně se používá zřídka.

Aplikace převádí datovou množinu do požadovaného stavu většinou voláním metody, jejíž jméno odpovídá anglickému názvu stavu. Například tabulku Table1 převedeme do stavu "Vkládání" voláním metody Table1.Insert nebo do stavu "Editace" voláním Table1.Edit. Řada dalších metod vrací prvky do základního stavu "Prohlížení", v závislosti na výsledku volané metody. Volání metody Cancel má vždy za následek přechod do stavu "Prohlížení".

Speciálním případem je stav "Výpočet položek". Z programu tento stav explicitně nenastavujeme, ale datová množina do tohoto stavu přechází automaticky při provádění události OnCalcFields, která slouží k definici hodnot "vypočítávaných" položek. V tomto stavu je generována výjimka, pokud se aplikace pokusí přiřadit hodnotu jiné než vypočítávané položce. Po ukončení události OnCalcFields se datová množina vrátí do původního stavu.

Základní stavy datových množin a přechod mezi těmito stavy při volání jednotlivých metod obsahuje následující diagram.

Vlastnost State uchovává aktuální stav datové množiny. Možné hodnoty této vlastnosti odpovídají výše uvedeným stavům: dsInactive, dsEdit, dsInsert, dsSetKey a dsCalcFields.

Při změně stavu připojeného prvku třídy TDataSource je provedena událost OnStateChange. Bližší informace jsou v části Použití událostí třídy TDataSource.

Otevření a uzavření datových množin

Dříve než může aplikace přistupovat pomocí datových množin ke zpracovávaným datům, je třeba datovou množinu otevřít. To lze provést dvěma způsoby:

Oba výše uvedené příkazy otevírají datovou množinu a převádí ji do režimu "Prohlížení".

Podobně existují dva způsoby, jak datovou množinu uzavřít:

Oba výše uvedené příkazy uzavírají datovou množinu a převádí jí do režimu "Neaktivní".

Pohyb v tabulce databáze

Pro pochopení toho, jak Delphi pracuje s datovými množinami, je důležitý pojem kurzor. Každá aktivní datová množina má kurzor, což je v podstatě ukazatel na aktuální záznam v příslušné datové množině. Kurzor můžeme chápat také jako lokální kopii tohoto pracovního záznamu, jako prostor do něhož se například ukládají změny položek provedené v režimu "Editace" před tím, než jsou voláním metody Post fyzicky zapsány do databáze.

Skupinu datových záznamů před a za kurzorem umísťuje Delphi do lokální vyrovnávací paměti pro urychlení práce s datovou množinou při pohybu v datech směrem nahoru nebo dolů.

Metody umožňující pohyb v datové množině jsou uvedeny v následující tabulce:

Navigační metody a vlastnosti
Metoda nebo vlastnostPopis
metoda First Nastavuje kurzor na první záznam datové množiny.
metoda Last Nastavuje kurzor na poslední záznam datové množiny.
metoda Next Nastavuje kurzor na následující záznam.
metoda Prior Nastavuje kurzor na předcházející záznam.
vlastnost BOF Má hodnotu true, pokud je známo, že je kurzor na prvním záznamu datové množiny; jinak má hodnotu false.
vlastnost EOF Má hodnotu true, pokud je známo, že je kurzor na posledním záznam datové množiny; jinak má hodnotu false.
metoda MoveBy(n) Přesunuje kurzor o n záznamů dopředu; n je kladné nebo záporné celé číslo.

Většina těchto metod je dostupná i přes ovládací prvek třídy TDBNavigator. Bližší informace o této třídě je v části "Použití databázových ovládacích prvků".

Metody a Prior:

Metoda Next přesunuje kurzor na další záznam:

Table1.Next;

Podobně metoda Prior přesunuje kurzor na předcházející záznam příslušné datové množiny. Přesun na předcházející záznam v tabulce tedy vypadá následovně:

Table1.Prior;

Metody First a Last:

Jak vyplývá z anglických názvů těchto metod, nastavují kurzor na první, resp. na poslední záznam datové množiny. Následující příkaz nastavuje kurzor na první záznam tabulky zpřístupněné datovou množinou Table1:

Table1.First;

Podobně metoda Last nastavuje kurzor na poslední záznam datové množiny:

Table1.Last;

Vlastnosti BOF a EOF:

BOFje logická vlastnost určená pouze pro čtení, která udává, zda je o datové množině známo, že je nastavena na první záznam. Vlastnost BOF obsahuje hodnotu true pouze v následujících případech:

Databáze jsou dynamické; zatímco jedna aplikace zprostředkovává prohlížení dat, jiná může vkládat řádek před záznam, který první aplikace považuje za první. Z tohoto důvodu se nelze vždy spolehnout na předpokládanou hodnotu vlastnosti BOF.

Vezměme jako příklad následující kód:

Table1.Open;  {BOF  = true}
Table1.Next;  {BOF  = false}
Table1.Prior; {BOF  = false}

Po provedení tohoto zlomku programu má vlastnost BOF hodnotu false, a to i v případě, kdy před aktuálním záznamem žádné další záznamy nejsou. U otevřené datové množiny může Delphi nastavit BOF na hodnotu true pouze tehdy, když aplikace explicitně vyvolá First nebo když selže volání Prior. Podobně může Delphi nastavit EOF na hodnotu true pouze v případě, když aplikace explicitně vyvolá metodu Last nebo když selže volání Next.

Následující zlomek programu ukazuje standardní postup využívající vlastnost BOF:

while not Table1.BOF do begin
      UdelejNeco; Table1.Prior
end;

V tomto příkladu je volána hypotetická funkce UdelejNeco pro aktuální záznam a potom pro všechny záznamy mezi aktuálním záznamem a začátkem datové množiny. Cyklus pokračuje až do doby, kdy se nepodaří voláním Prior přesunout aktuální záznam. Tím získá vlastnost BOF hodnotu true a programový cyklus se ukončí.

Před iteračním zpracováním datové množiny je vhodné vyvolat metodu DisableControls. Tím zabráníme databázovým ovládacím prvkům zobrazovat hodnoty jednotlivých záznamů a jednak značně urychlíme provádění cyklu, jednak zamezíme pro uživatele nepříjemným rychlým změnám obsahu obrazovky. Po dokončení cyklu vyvoláme metodu EnableControls. Je žádoucí použít příkaz try...finally...end s voláním metody EnableControls ve frázi finally. V opačném případě zůstanou po výskytu chyby databázové ovládací prvky neaktivní.

Obdobné zásady platí i pro vlastnost EOF, která nabývá hodnoty true v následujících případech:

Následující ukázka programu představuje jednoduchý cyklus přes všechny záznamy datové množiny využívající metodu Next a vlastnost EOF :

Table1.DisableControls;
try Table1.First;
    while not Table1.EOF do begin
          UdelejNeco;
          Table1.Next;
    end;
finally Table1.EnableControls;
end;
Pozor! Typickou chybou při použití těchto metod pro pohyb v datové množině je použití cyklu repeat...until se zapomenutým voláním metody Next tak, jak ukazuje následující příklad:

Table1.First;
repeat UdelejNeco until Table1.EOF;

Při provedení tohoto nebo obdobného kódu aplikace "zamrzne", protože tatáž akce bude donekonečna prováděna pro první záznam datové množiny a vlastnost EOF nikdy nenabude hodnoty true.

Pro prázdnou tabulku nabývají obě vlastnosti BOF i EOF po otevření datové množiny nebo po volání kterékoliv z navigačních metod hodnotu true.

Funkce MoveBy:

Funkce MoveBy umožňuje pohyb v datové množině dopředu i dozadu o zadaný počet záznamů. Tato funkce má jediný parametr, kterým je požadovaný počet záznamů. Kladné číslo znamená pohyb dopředu, záporné číslo pohyb dozadu.

Například pro posun o dva záznamy dopředu v tabulce Table1 použijeme příkaz:

Table1.MoveBy(2);

Při použití této funkce je třeba mít na paměti, že ve víceuživatelském prostředí jsou datové množiny proměnlivé entity a že záznam, který byl nedávno o pět záznamů zpátky, může být nyní zpět o čtyři záznamy, nebo o šest záznamů, nebo o nějaký jiný počet záznamů, protože s databází může pracovat a databázi modifikovat současně větší počet uživatelů.

Poznámka: Funkčně není rozdíl mezi voláním Table1.Next a voláním Table1.MoveBy(1), stejně jako není rozdíl mezi voláním Table1.Prior a Table1.MoveBy(-1).

Modifikace dat v datové množině

Pro vkládání, modifikaci a rušení dat v datových množinách může aplikace použít metody z následující tabulky.

Metody pro vkládání, modifikaci a rušení dat
MetodaPopis
Edit Převádí datovou množinu do stavu "Editace". Je-li datová množina již ve stavu "Editace" nebo "Vkládání", volání metody Edit nemá žádný efekt.
Append Předává připravená data, nastavuje kurzor na konec datové množiny a převádí datovou množinu do stavu "Vkládání".
Insert Předává připravená data a převádí datovou množinu do stavu "Vkládání".
Post Předává nový nebo modifikovaný záznam do databáze. Při úspěšném předání převádí datovou množinu do stavu "Prohlížení"; při neúspěšném předání se stav nemění.
Cancel Ukončuje předčasně rozpracovanou operaci a převádí datovou množinu do stavu "Prohlížení".
Delete Ruší aktuální záznam a převádí datovou množinu do stavu "Prohlížení"

Vlastnost CanModify:

CanModify je vlastnost datové množiny pouze pro čtení, která udává, zda může aplikace data v této datové množině měnit. Má-li CanModify hodnotu false, datovou množinu lze pouze číst a nelze změnit její stav na "Editace" nebo "Vkládání". Má-li CanModify hodnotu true, stav datové množiny může být změněn na "Editace" nebo "Vkládání". Ani v případě, že tento atribut má hodnotu true, není garantována uživateli možnost vkládat nebo modifikovat data v databázi. Mezi faktory, které tomu mohou zabránit, jsou například chybějící přístupová práva na úrovni databáze.

Třída TTable má vlastnost ReadOnly, která při nastavení na hodnotu false umožňuje zápis, má-li uživatel příslušná přístupová práva. Má-li ReadOnly hodnotu true, je vlastnost CanModify automaticky nastavena na hodnotu false. Bližší informace viz část Použití třídy TTable.

Předání dat do databáze

Metoda Post má klíčovou roli při interakci aplikace v Delphi s databázovou tabulkou. Činnost metody Post závisí na stavu datové množiny.

Předání dat může být explicitní nebo může být implicitní součástí jiné metody. Při opuštění aktuálního záznamu volá Delphi metodu Post implicitně. Pokud je datová množina ve stavu "Editace" nebo "Vkládání", vede volání metod First, Next, Prior a Last k volání Post. Metody Append a Insert rovněž volají pro připravená data metodu Post.

Poznámka: Metoda Post není implicitně volána při provedení Close. Pro explicitní předání připravených dat lze použít událost BeforeClose.

Editace záznamů

Předtím, než může aplikace modifikovat záznamy ve zpracovávané tabulce, musí být datová množina ve stavu "Editace". Do tohoto stavu přejde datová množina voláním své metody Edit. Ve stavu "Editace" změníme voláním Post hodnotu aktuálního záznamu. Pokud datová množina již ve stavu "Editace" je, volání Edit nemá žádný efekt.

Metody Edit a Post používáme většinou společně. Příklad:

Table1.Edit;
Table1.FieldByName('CISLO_ZAK').AsString := '1234';
Table1.Post;

První řádek tohoto příkladu převádí datovou množinu do stavu "Editace". Další řádek přiřazuje položce CISLO_ZAK řetězec '1234'. Poslední řádek potom předává, nebo zapisuje, právě modifikovaná data do databáze.

Přidávání záznamů

Pro přidání nového záznamu k datové množině volá aplikace buď metodu Insert nebo metodu Append. Obě metody převádí datovou množinu do stavu "Vkládání". Metoda Insert otevírá nový prázdný záznam bezprostředně za aktuálním záznamem. Metoda Append nastavuje kurzor na konec datové množiny a tam otevírá nový prázdný záznam.

Při následném volání metody Post je nový záznam vložen do databáze na pozici podle aktuálního indexu, je-li nějaký definován. Pro indexované tabulky se tedy Insert i Append chovají stejně. Není-li pro danou tabulku definován index, pozice záznamu zůstane zachována -- Append proto přidá záznam na konec tabulky a Insert ho přidá za záznam, který byl aktuální v okamžiku volání metody Insert. V obou případech může při zápisu do mřížky dojít ke změně všech zobrazených záznamů, pokud datová množina přejde na pozici danou indexem nově vytvořeného záznamu a načte data zobrazená v okolních záznamech mřížky.

Rušení záznamů

Metoda Delete ruší aktuální záznam a ponechává datovou množinu ve stavu "Prohlížení". Kurzor se přesune na následující záznam.

Zrušení provedených změn

Změny provedené v aktuálním záznamu může aplikace kdykoliv vrátit zpět až do doby, kdy jsou explicitně nebo implicitně zapsány do databáze metodou Post. Pokud je například datová množina ve stavu "Editace" a uživatel změnil data v jedné nebo více položkách, aplikace může obnovit původní stav záznamu voláním metody Cancel příslušné datové možiny. Volání metody Cancel vždy způsobí přechod do stavu "Prohlížení".

Práce s celým záznamem

V následující tabulce jsou uvedeny metody, které umožňují pracovat jedním příkazem současně s celým záznamem. Každá z těchto metod má jako parametr pole hodnot oddělených čárkami, kde každá hodnota odpovídá sloupci příslušné tabulky. Hodnotami mohou být konstanty, proměnné a hodnota Null nebo nil. Je-li počet hodnot menší než počet sloupců datové množiny, zbývající hodnoty jsou pokládány za prázdné.

Metody pro práci s celými záznamy
MetodaPopis
AppendRecord([pole hodnot]) Připojuje na konec datové množiny záznam se zadanými hodnotami položek analogicky jako metoda Append. Provádí implicitní volání metody Post.
InsertRecord([pole hodnot]) Vkládá záznam vytvořený ze zadaných hodnot položek za aktuální pozici kurzoru analogicky jako metoda Insert. Provádí implicitní volání metody Post.
SetFields([pole hodnot]) Nastavuje hodnoty v daném záznamu. Aplikace musí sama provést volání metody Post.

U neindexovaných tabulek přidává metoda AppendRecord záznam na konec tabulky a metoda InsertRecord vkládá záznam za aktuální kurzor. U indexovaných tabulek vkládají obě metody záznam na místo odpovídající hodnotě indexu pro daný záznam. V obou případech je kurzor nastaven na nový záznam.

Metoda SetFields přiřazuje hodnoty zadané v poli hodnot položkám datové množiny. Aplikace musí nejprve provést volání Edit pro převedení datové množiny do stavu "Editace" a po modifikaci záznamu provést volání Post.

Protože všechny tyto metody závisí na struktuře příslušných tabulek, měly by být v aplikaci použity pouze v případě, že se struktura tabulky nebude měnit (a to je dost silný požadavek).

Vezměme jako příklad tabulku STAT s položkami NAZEV, HLAVNI_MESTO, SVETADIL, PLOCHA a OBYVATEL. Je-li datová množina Table1 navázána na tabulku STAT, následující příkaz vloží do tabulky STAT nový záznam:

Table1.InsertRecord(['Japonsko','Tokio','Asie']);

V příkazu nejsou zadány hodnoty pro plochu a počet obyvatel, proto bude do těchto položek vložena hodnota Null. Pokud je tabulka indexována podle položky NAZEV, záznam bude vložen na základě abecedního pořadí názvu "Japonsko".

K doplnění záznamu mohou být použity následující příkazy:

Table1.Edit;
Table1.SetFields(nil, nil, nil, 344567, 164700000);
Table1.Post;

Tyto příkazy předpokládají, že kurzor bude umístěn na právě vložený záznam týkající se Japonska. Přiřazuje hodnoty pro plochu a počet obyvatel a předává je do databáze. První tři hodnoty nil tedy slouží jako specifikace místa pro první tři položky, jejichž hodnota se nemění.

Nastavení modifikačního režimu

Vlastnost UpdateMode datové množiny udává, jak bude aplikace hledat záznamy pro modifikaci v SQL databázi. Tato vlastnost je podstatná ve víceuživatelském prostředí, kdy mohou uživatelé vybírat stejné záznamy a provádět v nich konfliktní úpravy.

Když uživatel předá do databáze změnu, Delphi používá k nalezení záznamu v databázi původní hodnoty záznamu. Tento přístup odpovídá optimistickému uzamykacímu schématu. Vlastnost UpdateMode udává, které položky k nalezení záznamu má Delphi použít. V pojmech jazyka SQL UpdateMode udává, které položky jsou obsaženy ve frázi WHERE příkazu UPDATE. Pokud Delphi nedokáže najít záznam s původními hodnotami zadaných položek (protože je jiný uživatel v databázi změnil), Delphi změnu neprovede a generuje výjimku.

Vlastnost UpdateMode může nabývat následujících hodnot:

Jako příklad vezměme tabulku STAT s položkami NAZEV (jako klíč), HLAVNI_MESTO a SVETADIL. Předpokládejme, že si já a ještě jeden uživatel prohlížíme záznam s následujícími hodnotami:

NAZEV = "Filipíny"
HLAVNI_MESTO =  "Nairobi"
SVETADIL = "Afrika"

Oba si všimneme, že zobrazená informace je nesprávná a je třeba jí opravit. Nechť druhý uživatel změní SVETADIL na "Asie" a HLAVNI_MESTO na "Manila" a předá data do databáze. O několik sekund později změním já NAZEV na "Keňa" a předám do databáze i svojí změnu.

Má-li aplikace nastaven UpdateMode pro datovou množinu na hodnotu WhereKeyOnly, Delphi porovná původní hodnotu klíče (NAZEV = "Filipíny") s aktuální hodnotou v databázi. Protože druhý uživatel nezměnil sloupec NAZEV, moje modifikace proběhne. Já předpokládám, že záznam je nyní ["Keňa", "Nairobi", "Afrika"] a druhý uživatel předpokládá, že záznam je ["Filipíny", "Manila", "Asie"]. Bohužel skutečný záznam je ["Keňa", "Manila", "Asie"], což je i nadále chybně, přestože si oba uživatelé myslí, že chybu opravili. Problém vznikl proto, že atribut UpdateMode byl nastaven na nejméně omezující hodnotu, která proti těmto případům nechrání.

Pokud má datová množina nastaveno UpdateMode na hodnotu WhereAll, Delphi zkontroluje všechny sloupce předtím, než se pokusí provést modifikaci. Protože druhý uživatel změnil sloupce HLAVNI_MESTO a SVETADIL, Delphi nedovolí další změnu provést. Získám-li záznam znovu, uvidím nové hodnoty vložené druhým uživatelem a poznám, že chyba již byla opravena.

Označování dat

Často je užitečné si označit konkrétní pozici v tabulce tak, aby bylo možno se tam v případě potřeby rychle vrátit. Pro tento účel dává Delphi k dispozici značkovací metody (bookmarking methods). Tyto metody umožňují umístit do datové množiny značku a později se k ní rychle vrátit.

Značkovací metody jsou tři:

Tyto metody se používají společně. Funkce GetBookMark vrací proměnnou typu TBookMark. Tato proměnná obsahuje ukazatel na konkrétní pozici v datové množině. Předáme-li tuto značku metodě GoToBookMark, tato metoda nastaví kurzor datové množiny na tuto označenou pozici.

Metoda FreeBookMark uvolňuje paměť přidělenou dané značce. Volání metody GetBookMark přidělí pro značku paměť, proto by aplikace měla přidělenou paměť po použití značky voláním metody FreeBookMark opět vrátit.

Následující příkazy ilustrují typické použití značky:

procedure UdelejNeco;
var BookMark:TBookMark;
begin
BookMark:=Table1.GetBookMark;        {označení pozice}
Table1.DisableControls;
try Table1.First;
    while not Table1.EOF  do begin
          {požadovaná činnost}
          Table1.Next;
    end;
finally
    Table1.GoToBookMark;             {použití značky}
    Table1.EnableControls;
    Table1.FreeBookMark(BookMark);   {uvolnění značky}
end;
end;

Zablokování, odblokování a obnovení databázových ovládacích prvků

Metoda DisableControls blokuje všechny databázové ovládací prvky připojené k datové množině. Tuto metodu je možno s určitou opatrností použít k zamezení "blikání" obrazovky při pohybu v datech - například když programově procházíme nebo prohledáváme datovou množinu. Jakmile je kurzor znovu nastaven, aplikace by měla vyvolat EnableControls a tak databázové ovládací prvky znovu odblokovat. Je důležité ovládací prvky metodou EnableControls odblokovat ihned, jakmile aplikace dokončí iteraci nebo prohledávání, aby byla zaručena aktuálnost informací zobrazovaných těmito ovládacími prvky. Způsob použití příkazu try...finally ukazuje předcházející příklad.

Metoda Refresh vyprazdňuje všechny lokální vyrovnávací paměti a znovu obnovuje data z příslušné datové množiny. Tuto funkci lze použít k obnovení tabulky, pokud předpokládáme, že mohlo dojít ke změně zobrazovaných dat. Obnovení datové množiny někdy může vést k neočekávaným výsledkům. Pokud si například uživatel prohlíží záznam, který byl mezitím zrušen, tento záznam v okamžiku volání metody Refresh neočekávaně zmizí. Podobně se mohou změnit data, pokud je některý jiný uživatel změnil v době mezi původním natažením dat a voláním metody Refresh.

Události vázané k datovým množinám

K datovým množinám patří řada událostí, které umožňují aplikaci provádět validaci dat, počítat součty nebo provádět další akce v závislosti na volané metodě. Seznam těchto událostí je v následující tabulce.

Události vázané k datovým množinám
UdálostPopis
BeforeOpen, AfterOpen Je provedena před/po otevření datové množiny.
BeforeClose, AfterClose Je provedena před/po uzavření datové množiny.
BeforeInsert, AfterInsert Je provedena před/po změně stavu datové množiny na "Vkládání".
BeforeEdit, AfterEdit Je provedena před/po změně stavu datové množiny na "Editace".
BeforePost, AfterPost Je provedena před/po předání změn do databáze.
BeforeCancel, AfterCancel Je provedena před/po zrušení operace.
BeforeDelete, AfterDelete Je provedena před/po zrušení záznamu.
OnNewRecord Je provedena po vytvoření nového záznamu; používá se k zadání implicitních hodnot.
OnCalcFields Je provedena při výpočtu hodnot vypočítávaných položek.

Zrušení akce

Pro zrušení metod jako je Open nebo Insert je možno generovat výjimku nebo volat proceduru Abort v kterékoliv z metod Before.... Následující příklad vyžaduje potvrzení zrušení záznamu:

procedure TForm1.TableBeforeDelete (DataSet: TDataSet);
begin
if MessageDlg('Mohu zrušit  tento záznam?', mtConfirmation,
   mbYesNoCancel, 0) <> mrYes then Abort;
end;

Použití události OnCalcFields

Událost OnCalcFields se používá k nastavení hodnot vypočítávaných položek. Okamžik volání metody OnCalcFields je řízen vlastností AutoCalcFields. Má-li AutoCalcFields hodnotu true, je událost OnCalcFields volána:

Metoda OnCalcFields je také volána při každé změně skutečné (nevypočítávané) položky, bez ohledu na hodnotu vlastnosti AutoCalcFields.

Událost OnCalcFields je typicky volána mnohokrát a měla by být tudíž krátká. Pokud má AutoCalcFields hodnotu true, událost OnCalcFields by neměla dělat nic, co vede ke změně datové množiny (nebo jiné datové množiny svázané relací), protože to může vést k rekurzivnímu volání události. Pokud by například událost OnCalcFields volala metodu Post a vlastnost AutoCalcFields by měla hodnotu true, byla by metoda OnCalcFields vyvolána znovu, znovu by vyvolala Post atd.

Má-li AutoCalcFields hodnotu false, je událost OnCalcFields provedena při volání metody Post příslušné datové množiny (nebo jiné metody, která volá Post implicitně, jako je Insert nebo Append).

Při provádění události OnCalcFields je datová množina ve stavu "Výpočet položek". Ve stavu "Výpočet položek" nelze změnit hodnotu jiné než vypočítávané položky. Po dokončení události OnCalcFields je datová množina vrácena do původního stavu.

Použití třídy TTable

Třída TTable je jednou z nejdůležitějších tříd databázových prvků. Spolu s další databázovou třídou TQuery umožňuje aplikaci přístup k databázovým tabulkám. Tato část popisuje nejdůležitější vlastnosti specifické pro prvky třídy TTable.

Vazba na databázovou tabulku

Vlastnost TableName obsahuje jméno tabulky, na kterou je datová množina třídy TTable navázána. Tuto vlastnost většinou nastavujeme při vytváření programu v Editoru objektů.

Vlastnost DatabaseName udává, kde má Delphi zadanou databázovou tabulku hledat. Může to být BDE alias, explicitní určení adresáře nebo hodnota vlastnosti DatabaseName některé z instancí třídy TDatabase v dané aplikaci. Pro Paradox nebo Dbase tabulky je explicitním určením jméno adresáře včetně cesty; pro SQL tabulky to může být úplné jméno souboru obsahujícího databázi.

Poznámka: Tyto vlastnosti nelze měnit, je-li tabulka otevřená -- tj. když má vlastnost Active dané datové množiny hodnotu true.

Vlastnosti třídy TTable

Vlasnost TableType udává typ použité databázové tabulky. Pro SQL tabulky se tato vlastnost nepoužívá. Je-li vlastnost TableType nastavena na hodnotu Default, je typ tabulky určen extenzí zadaného souboru:

Nemá-li TableType hodnotu Default, tabulka je považována za tabulku zadaného typu bez ohledu na extenzi souboru.

Prohledávání tabulky

Třída TTable má několik metod, které umožňují vyhledávat v databázových tabulkách zadané hodnoty:

Novější verze Delphi doporučují používání obecnějších metod Locate a Lookup, použití starších metod "GoTo" a "Find" může být někdy jednodušší a efektivnější.

Nejjednodušší je vyhledání hodnot pomocí vyhledávacích ("Find") funkcí FindKey a FindNearest. Tyto dvě funkce kombinují možnosti základních funkcí "GoTo", které popíšeme napřed.

V tabulkách typu Paradox a Dbase lze hledat pouze podle položek, pro něž byl vytvořen index. V SQL tabulkách lze hledat podle libovolných položek, pokud je uvedeme ve vlastnosti IndexFieldNames příslušné datové množiny třídy TTable. Bližší informace viz část Indexy.

Potřebujeme-li hledat v tabulkách typu Paradox nebo Dbase hodnotu položky, pro níž není vytvořen index, použijeme datovou mnopžinu třídy TQuery a vhodný SQL příkaz SELECT. Bližší informace o použití SQL datových množin třídy TQuery viz "Použití jazyka SQL".

Použití funkcí "GoTo"

Metody GoToKey a GoToNearest umožňují vyhledávat v tabulkách klíčové položky. Metoda SetKey převádí datovou množinu do stavu "Nastavení klíče". V tomto stavu zadáme do položek tvořících index hodnoty, které mají být vyhledány. Metoda GotoKey nastavuje kurzor na první záznam tabulky, který obsahuje zadané hodnoty položek.

Následující příklad může být použit jako obsluha události OnClick tlačítka "Hledej":

procedure PrikladVyhledani.SearchClick(Sender: TObject);
begin
Table1.SetKey;
Table1.Fields[0].AsString := Edit1.Text;
Table1.GoToKey;
end;

První řádek příkladu za klíčovým slovem begin převádí datovou množinu do stavu "Nastavení klíče". Následující přiřazení hodnoty vlastnosti Fields je tedy zadáním hledané hodnoty - předpokládáme že je nastaven index podle první položky tabulky. V tomto příkladu hledáme text, který uživatel zapsal do editačního pole Edit1. Nakonec provedeme voláním metody GoToKey vlastní vyhledání a nastavení kurzor na nalezený záznam (pokud existuje).

Metoda GoToKey je logická funkce, která nastaví kurzor a vrací true, bylo-li hledání úspěšné. Je-li hledání neúspěšné, nastavení kurzoru se nemění a metoda vrací hodnotu false. Příklad:

Table1.SetKey;
Table1.Fields[0].AsString := 'Smith';
if not Table1.GoToKey then
   ShowMessage('Záznam nenalezen');

Pokud není nalezen záznam, ve kterém je v první položce hodnota "Smith", standardní funkce ShowMessage zobrazí dialog se zprávou "Záznam nenalezen".

Je-li primární klíč tabulky tvořen více položkami a chceme-li hledat jen podle části klíče, nastavíme vlastnost KeyFieldCount na počet položek, podle kterých chceme hledat. Pokud je například primární klíč tabulky tvořen třemi položkami a chceme hledat hodnotu pouze první z nich, nastavíme KeyFieldCount na hodnotu 1. U tabulek se složenými klíči lze hledat pouze podle začátku klíče. Můžeme tedy hledat podle první položky, nebo podle první a druhé, případně podle první, druhé a třetí, ale nikoliv třeba podle první a třetí.

Podobná je procedura GoToNearest, s tím, že hledá částečnou shodu. Lze ji použít pouze pro položky obsahující řetězce. Například:

Table1.SetKey;
Table1.Fields[0].AsString := 'Sm';
Table1.GoToNearest;

Pokud existuje záznam obsahující v prvních dvou znacích první položky znaky "Sm", kurzor bude nastaven na nalezený záznam. V opačném případě se nastavení kurzoru nezmění.

Pokud se nejedná o vyhledávání podle primárního indexu lokální tabulky, musí aplikace buď specifikovat jména použitých položek ve vlastnosti IndexFieldNames nebo specifikovat index pomocí vlastnosti IndexName příslušné datové množiny. Pokud má například tabulka ZAKAZNIK sekundární index se jménem MestoIdx a chceme podle něj vyhledávat, je třeba nastavit hodnotu vlastnosti IndexName dané datové množiny na hodnotu "MestoIdx". Prohledání tabulky potom probíhá následujícím způsobem:

Table1.IndexName := 'MestoIdx';
Table1.Open;
Table1.SetKey;
Table1.FieldByName('Mesto').AsString := Edit1.Text;
Table1.GoToNearest;

Protože jména indexů často nebývají příliš intuitivní, lze alternativně použít vlastnost IndexFieldNames pro zadání jmen indexovaných položek.

Po každém volání SetKey musí aplikace nastavit hodnoty všech položek, podle kterých má hledání proběhnout. Jinými slovy, volání SetKey maže všechny existující hodnoty položek z předchozích volání. Tyto hodnoty lze použít voláním metody EditKey.

Pokud chceme například pokračovat v předcházejícím hledání doplněním jména města o jméno státu, lze použít následující příkazy:

Table1.EditKey;
Table1.FieldByName('STAT').AsString :=  Edit2.Text;

Použití funkcí "Find"

Funkce FindKey a FindNearest kombinují v jednom příkaze funkci metody SetKey, přiřazení hledané hodnoty a volání funkce "GoTo".

Obě tyto funkce mají jako parametr seznam hodnot oddělených čárkami, přičemž každá hodnota odpovídá jedné položce příslušné tabulky. Hodnotami mohou být konstanty, proměnné, hodnota Null nebo nil. Pokud je počet hodnot uvedených v parametru menší než počet položek indexu, zbývající hodnoty jsou považovány za prázdné. Obě funkce provedou hledání zadaných hodnot podle aktuálního indexu.

Metoda FindKey je rozšířením metody GoToKey:

Pokud je například Table1 indexována podle první položky, potom příkaz

Table1.FindKey([Edit1.Text]);

provede tutéž činnost jako tři příkazy

Table1.SetKey;
Table1.Fields[0].AsString := Edit1.Text;
Table1.GoToKey;

Metoda FindNearest je rozšířením funkce GoToNearest a přesune kurzor na záznam s nejblíže odpovídající hodnotou. Může být použita pouze pro sloupce položky textového typu.

Implicitně pracují obě metody s primárním indexem. Pro hledání podle jiného indexu je třeba nastavit jméno položky ve vlastnosti IndexFieldNames příslušné datové množiny nebo jméno indexu ve vlastnosti IndexNames.

Poznámka: Pro tabulky typu Paradox nebo Dbase lze takto pracovat pouze s položkami, pro které je definován index. U SQL databází lze pracovat s libovolnými položkami uvedenými v atributu IndexFieldNames.

Vlastnost KeyExclusive

Vlastnost KeyExclusive udává, zda má hledání nastavit kurzor na nebo za záznam, který je hledán. Má-li KeyExclusive hodnotu false (což je implicitní hodnota), potom metody GoToNearest a FindNearest přesunou kurzor na záznam, který odpovídá zadaným hodnotám. Má-li hodnotu true, dojde k nastavení na záznam bezprostředně za záznamem s případně nalezenou hodnotou klíče.

Omezení množiny záznamů získané z tabulky

V reálném světě mohou být tabulky hodně velké, proto často potřebujeme omezit množinu záznamů, se kterou se bude pracovat. Možnost tohoto omezení (nastavení filtru) je velkou výhodou třídy TTable.

Nastavení podmnožiny se provádí následujícími metodami třídy TTable:

Metoda SetRangeStart udává, že následující přiřazení hodnotám položek definuje začátek intervalu záznamů, s nimiž bude aplikace pracovat. Metoda SetRangeEnd udává, že následující přiřazení definuje konec požadovaného intervalu záznamů. Nespecifikované hodnoty položek nemají vliv. Odpovídající metody EditRangeStart a EditRangeEnd zachovávají stávající hodnoty hranic intervalu, s tím, že následujícím přiřazením se provádí jejich modifikace.

Metoda ApplyRange nastavuje připravený interval. Pokud nebyla před voláním ApplyRange volána metoda SetRangeStart, interval začíná na začátku tabulky; podobně, pokud nebyla volána metoda SetRangeEnd, interval končí na konci tabulky. Metoda CancelRange ruší nastavení filtru a nadále se pracuje s celou tabulkou.

Funkce SetRange kombinuje metody SetRangeStart, SetRangeEnd a následující přiřazení do jednoho příkazu, který má jako parametr seznamy hodnot.

Poznámka: Pro tabulky typu Paradox a Dbase lze tyto metody použít pouze pro položky, pro něž byl definován index. U SQL databází lze pracovat s libovolnými položkami uvedenými ve vlastnosti IndexFieldNames.

Předpokládejme například, že máme formulář s datovou množinou třídy TTable se jménem Zakaznik, připojeným k tabulce ZAKAZNIK. Tabulka ZAKAZNIK je indexována podle první položky (CISLO_ZAK). Nechť má formulář také dvě editační pole pojmenované Prvni_hod a Posledni_hod a nechť byla pro položku CISLO_ZAK vytvořena instance třídy TField. Potom omezíme interval zobrazených záznamů použitím následujících příkazů:

Zakaznik.SetRangeStart;
ZakaznikCislo_Zak.AsString := Prvni_hod.Text;
Zakaznik.SetRangeEnd;
if Posledni_hod <> '' then
   ZakaznikCislo_Zak.AsString := Posledni_hod.Text;
Zakaznik.ApplyRange;

Za zmínku stojí to, že program před přiřazením koncové hodnoty intervalu testuje, zda text zadaný do editačního pole Posledni_hod není prázdný. Pokud je prázdný text v Prvni_hod, jsou zahrnuty všechny záznamy od začátku tabulky, protože všechny hodnoty jsou větší než Null. Pokud je však prázdný text v Posledni_hod, není zahrnut žádný záznam, protože žádná hodnota není menší než Null.

Tento program lze také přepsat pomocí funkce SetRange:

if Posledni_hod.Text <> '' then
   Zakaznik.SetRange([Prvni_hod.Text], [Posledni_hod.Text]);
Zakaznik.ApplyRange;

Použití parciálních klíčů

Je-li klíč složen z jedné nebo více textových položek, lze použít hledání podle parciálních klíčů. Existuje-li například složený index pro položky PRIJMENI a JMENO, lze použít následující specifikaci intervalu:

Table1.SetRangeStart;
Table1.FieldByName('PRIJMENI').AsString := 'Novák';
Table1.SetRangeEnd;
Table1.ApplyRange;

Tím zahrneme všechny záznamy, kde je příjmení "Novák" nebo abecedně větší. Zadání hodnoty může být i částečné:

Table1.FieldByName('PRIJMENI').AsString := 'No';

Tím zahrneme všechny záznamy, kde je příjmení rovno nebo abecedně větší než "No". Další příklad zahrnuje záznamy s příjmením rovným nebo větším než "Novák" a křestním jménem rovným nebo větším než "J":

Table1.FieldByName('PRIJMENI').AsString := 'Novák';
Table1.FieldByName('JMENO').AsString := 'J';

Vlastnost KeyExclusive

Vlastnost KeyExclusive udává, zda filtrovaný interval vylučuje hranice intervalu. Implicitní hodnota je false, což znamená, že záznamy budou zahrnuty, pokud je hodnota klíče rovna nebo větší než zadaný začátek intervalu a rovna nebo menší než zadaný konec intervalu. Má-li atribut KeyExclusive hodnotu true, interval nebude obsahovat hraniční hodnoty.

Indexy

Index určuje, jak budou data při zobrazení setříděna. Delphi implicitně zobrazuje data vzestupně na základě hodnot primárního klíče tabulky.

Delphi podporuje SQL indexy, udržované indexy pro tabulky typu Paradox a .MDX indexy pro tabulky typu Dbase. Delphi nepodporuje:

Metoda GetIndexNames vrací seznam jmen indexů použitelných pro zpracovávanou tabulku. Pro tabulky typu Paradox je primární index bezejmenný a není tedy v seznamu metody GetIndexNames zahrnut. Potřebujeme-li použít u tabulek typu Paradox primární index, přiřadíme atributu IndexName příslušné datové množiny třídy TTable prázdný řetězec.

IndexFields obsahuje seznam jmen položek, pro něž je vytvořen index. IndexFieldCount obsahuje počet položek v indexu. IndexFieldCount a IndexFields jsou vlastnosti použitelné pouze ke čtení při běhu programu.

Vlastnost IndexName používáme pro setřídění tabulky nebo pro hledání v tabulce podle jiného indexu než podle primárního klíče. Jinými slovy, při použití pouze primárního indexu tabulky nemusíme s vlastností IndexName pracovat. Při použití sekundárního indexu je však třeba IndexName zadat.

Pro tabulky v SQL databázi udává atribut IndexFieldNames položky, které lze při vybírání dat uvést ve frázi ORDER BY. Do tohoto atributu zadáváme seznam jmen položek oddělených středníky. Záznamy jsou potom tříděny podle hodnot zadaných položek. Třídění může být pouze vzestupné. Rozlišování velkých a malých písmen závisí na použitém SQL serveru.

Pokud chceme setřídit záznamy o zákaznících uložené v SQL tabulce podle poštovního směrovacího čísla a o úroveň níž podle čísla zákazníka, zadáme do atributu IndexFieldName hodnotu

"PSC ; CISLO_ZAK"

Pro tabulky typu Paradox a Dbase vybere Delphi index podle položek zadaných v IndexFieldName. Je-li zadána položka nebo položky, pro něž není definován index, dojde k chybě.

Vlastnosti IndexName a IndexFieldName se vzájemně vylučují. Nastavení jedné z nich maže hodnotu obsaženou v druhé z nich.

Vlastnost Exclusive

Vlastnost Exclusive udává, zda se tabulky otevírají s výhradním právem přístupu. Má-li hodnotu true, nemůže s tabulkou pracovat další uživatel. Pokud s tabulkou pracuje nějaký jiný uživatel, nelze tabulku v režimu Exclusive otevřít.

Pracujeme-li s tabulkou v SQL databázi, exklusivní zámek umožňuje ostatním uživatelům data číst, ale neumožňuje jim je modifikovat. Některé SQL servery nepodporují exklusivní zamykání tabulek. Bližší informace viz dokumentace příslušného SQL serveru.

Další vlastnosti a metody

Kromě vlastností sdílených s třídou TQuery má třída TTable některé specifické vlastnosti a metody. Některé z nich jsou například:

V této části je uvedeno několik důležitějších metod. Kompletní popis je v on-line helpu.

Vlastnosti ReadOnly a CanModify

Před otevřením datové množiny třídy TTable nastavíme vlastnost ReadOnly na hodnotu false, pokud požadujeme právo číst i zapisovat, a na hodnotu true, pokud požadujeme přístup pouze pro čtení. V závislosti na charakteristikách zpracovávané tabulky může být právo zapisovat do tabulky databází poskytnuto nebo odmítnuto.

CanModify je vlastnost datové množiny, kterou můžeme pouze číst při běhu programu a která odráží faktická práva k dané datové množině. Má-li ReadOnly hodnotu true, CanModify je automaticky nastaveno na false. Má-li ReadOnly hodnotu false, CanModify bude mít hodnotu true, pokud databáze povoluje čtecí i zápisová práva pro danou datovou množinu a příslušnou tabulku.

Má-li CanModify hodnotu false, tabulku lze pouze číst a datovou množinu nelze převést do stavu "Editace" ani "Vkládání". I v případě, že má CanModify hodnotu true, není zaručeno, že bude uživatel moci vkládat nebo modifikovat záznamy v tabulce. Závisí to i na dalších vlivech, například přístupových právech k dané tabulce v SQL databázi.

Metoda GoToCurrent

Metoda GoToCurrent synchronizuje dvě instance třídy TTable připojené k téže databázové tabulce a používající tentýž index. Tato metoda má jako parametr instanci třídy TTable a nastavuje kurzor na aktuální záznam této datové množiny předané jako parametr. Například:

Table1(GoToCurrent(Table2));

Vytváření formulářů s vazbou 1:n

Vlastnosti MasterSource a MasterFields slouží k definici vazby 1:n mezi dvěma tabulkami. Vlastnost MasterSource odkazuje na instanci třídy TDataSource, přes kterou jsou získávána data pro hlavní tabulku. Pokud tedy svážeme dvě tabulky vazbou 1:n, potom může podřízená tabulka na základě tohoto odkazu reagovat na události v hlavní tabulce.

Pro spojení tabulek na základě více položek zadáváme seznam jmen položek oddělený středníky:

Table1.MasterFields := 'Cislo_Obj;Cislo_Pol';

Dialog pro spojování tabulek

Při vytváření aplikace lze dvojitým kliknutím na vlastnost MasterFields v Editoru objektů (nebo jednoduchým kliknutím na tři tečky tamtéž) vyvolat Dialog pro spojování tabulek. Ten umožňuje interaktivně provést propojení hlavní a podřízené tabulky. Rozbalovací seznam označený "Available Indexes" ("indexy k použití") ukazuje aktuálně existující indexy použitelné pro spojení tabulek. Pro tabulky typu Paradox je implicitně zvoleno "Primary", což znamená použití primárního klíče pro podřízenou tabulku. V seznamu jsou i ostatní indexy definované pro danou tabulku.

V seznamu "Detail Fields" ("položky podřízené tabulky") vybereme položku, kterou použijeme pro spojení na straně podřízené tabulky, dále v seznamu "Master Fields" ("položky hlavní tabulky") vybereme položku odkazovanou z podřízené tabulky a nakonec odešleme tlačítko označené "Add" ("přidej"). Vybrané položky jsou zobrazeny v seznamu "Joined Fields" ("spojené položky"), například

Cislo_Obj -> Cislo_Obj

Pro spojování tabulek na SQL serveru není zobrazován rozbalovací seznam "Available Indexes" a je třeba ručně vybrat spojovací položky v obou seznamech "Master Fields" a "Detail Fields".

Použití třídy TDataSource

Prvky třídy TDataSource slouží jako spojky mezi datovými množinami a databázovými ovládacími prvky. Většinou je jedinou akcí prováděnou s prvky třídy TDataSource nastavení jejich vlastnosti DataSet na odpovídající datovou množinu. Potom nastavíme vlastnost DataSource příslušného databázového ovládacího prvku tak, aby odkazovala na příslušnou instanci třídy TDataSource. Třída TDataSource se používá i pro spojení datových množin vazbou 1:n.

Vlastnostni třídy TDataSource

Třída TDataSource má kromě standardních vlastností Name a Tag pouze několik málo dostupných vlastností.

Vlastnost DataSet

Vlastnost DataSet obsahuje jméno datové množiny, která je pro daný prvek třídy TDataSource zdrojem dat. Vlastnost DataSet lze nastavit i na datovou množinu z jiného formuláře a synchronizovat tak databázové ovládací prvky v obou formulářích. Příklad:

procedure TForm2.FormCreate (Sender:TObject);
begin
DataSource1.DataSet := Form1.Table1;
end;

Vlastnost Enabled

Vlastnost Enabled umožňuje dočasně odpojit TDataSource od příslušné datové množiny. Nastavíme-li tuto vlastnost na false, všechny připojené databázové ovládací prvky zůstanou neaktivní až do doby, kdy nastavíme tuto vlastnost opět na hodnotu true.

Obecně bývá vhodnější použít pro tuto funkci metody DisableControls a EnableControls datové množiny, protože ovlivňují všechny připojené objekty třídy TDataSource.

Vlastnost AutoEdit

Vlastnost AutoEdit udává, zda datová množina připojené k tomuto prvku třídy TDataSource automaticky přechází do stavu "Editace", když uživatel začne psát do připojených databázových ovládacích prvků. Má-li vlastnost nastavenu (implicitní) hodnotu true, Delphi automaticky převádí datovou množinu do stavu "Editace", pokud uživatel zahájí vstup do některého z připojených databázových ovládacích prvků. V opačném případě přechází datová množina do stavu "Editace" pouze v případě, když aplikace explicitně vyvolá její metodu Edit. Bližší informace o stavech datových množin viz část Stavy datových množin.

Události třídy TDataSource

Třída TDataSource pracuje se třemi událostmi:

Událost OnDataChange

Událost OnDataChange je provedena, pokud dojde ke změně aktuálního záznamu. Jinými slovy, pokud aplikace volá metody Next, Previous, Insert nebo jinou metodu, která má za následek změnu pozice kurzoru, je provedena i událost OnDataChange.

Tato událost se používá pro programovanou synchronizaci databázových ovládacích prvků.

Událost OnUpdateData

Událost OnUpdateData je provedena před modifikací dat v aktuálním záznamu. Přesněji, událost OnUpdateData je provedena po volání Post, ale před tím než jsou fakticky data do databáze předána.

Tato událost se používá, pokud aplikace pracuje se standardními (tedy nikoliv databázovými) ovládacími prvky a je třeba je synchronizovat s datovou množinou.

Událost OnStateChange

Událost OnStateChange je provedena, když se mění stav datové množiny uložený v její vlastnosti State . Tato událost se používá pro provedení požadovaných akcí při změně stavu datové množiny, jak ukazuje třeba následující příklad.

V průběhu běžné práce s databází se stav datových množin neustále mění. Ke sledování těchto změn lze využít programového kódu zapsaného do události OnStateChange. Příkladem je následující ukázka, která zajišťuje zobrazení aktuálního režimu pomocí textového prvku Label:

procedure TForm1.DataSource1.StateChange(Sender:TObject);
var S:String;
begin
case Table1.State of
dsInactive: S:='Není aktivní';
dsBrowse:   S:='Prohlížení';
dsEdit:     S:='Editace';
dsInsert:   S:='Vkládání';
dsSetKey:   S:='Nastavení klíče';
end;
Label.Text := S;
end;

Událost OnStateChange se často používá i k blokování tlačítek nebo položek v menu na základě aktuálního stavu:

procedure TForm1.DataSource1.StateChange(Sender:TObject);
begin
InsertBtn.Enabled := (Table1.State = dsBrowse);
CancelBtn.Enabled := Table1.State in
      [dsInsert, dsEdit, dsSetKey];
...
end;

Použití třídy TField a Editoru položek

Prvky třídy TField odpovídají sloupcům databázové tabulky. Jsou vytvořeny:

Z třídy TField se odvozují specializované třídy pro všechny datové typy, včetně TStringField, TSmallintField, TIntegerField, TWordField, TBooleanField, TFloatField, TCurrencyField, TBCDField, TDateField, TTimeField a TDateTimeField. Tato část se zabývá třídou TField obecně a týká se tedy i všech tříd odvozených. Informace o vlastnostech jednotlivých konkrétních odvozených tříd jsou v on-line helpu.

K čemu je třída TField?

Všechny databázové ovládací prvky Delphi spoléhají na činnost přiřazeného prvku třídy TField. Ačkoliv tyto prvky nejsou na formuláři zobrazeny, jsou důležité z toho důvodu, že poskytují přímou vazbu aplikace na příslušný sloupec tabulky v databázi. Třída TField má vlastnosti udávající datový typ sloupce, aktuální hodnotu, zobrazovaný formát, editační formát a další údaje. Třída TField má také připraveny události (např. OnValidate), které lze použít k implementaci validačních pravidel pro jednotlivé položky.

Každá položka zpracovávané databázové tabulky má odpovídající prvek třídy TField. Implicitně jsou prvky třídy TField generovány dynamicky v okamžiku, kdy je vlastnost Active datové množiny nastavena na hodnotu true, což platí jak při vytváření, tak i při běhu programu. Dynamickým generováním je myšleno to, že Delphi vytvoří na základě struktury databázové tabulky tyto prvky pokaždé, když je aktivováno připojení na databázovou tabulku. Dynamicky generované prvky třídy TField tedy vždy odpovídají položkám příslušné tabulky.

Pro vytvoření trvalého seznamu prvků třídy TField slouží Editor položek. Vytvoření trvalého seznamu prvků třídy TField má určité výhody --- poskytuje efektivní, srozumitelný a typově bezpečný přístup k uloženým datům. Garantuje při každém běhu aplikace použití a zobrazení týchž sloupců, vždy ve stejném pořadí, dokonce i tehdy, pokud se změní struktura příslušné tabulky. Vytvoření prvků třídy TField při tvorbě aplikace zaručuje správnou a očekávanou funkci všech databázových ovládacích prvků i programového kódu, které spoléhají na existenci a typ určité položky databázové tabulky. Pokud je položka modifikována nebo zrušena, Delphi generuje výjimku a nedojde tedy k běhu aplikace nad neexistující položkou nebo neodpovídajícími daty.

Použití Editoru položek

Pokud je datové možina TTable nebo TQuery připojena k databázi a jejich vlastnost Active má hodnotu true, pro každou položku tabulky je dynamicky generován prvek třídy TField. Každý takový prvek uchovává o položce informace týkající se jejího zobrazení. Tyto informace jsou potom využity databázovými ovládacími prvky tříd jako je TDBEdit nebo TDBGrid pro formátování dat zobrazených ve formuláři. Vyvoláním Editoru položek lze vytvořit tyto prvky jako trvalé a zobrazení pak modifikovat.

Editor položek umožňuje:

Spuštění Editoru položek

Editor položek pro konkrétní datovou množinu vyvoláme dvojitým kliknutím na daný prvek nebo z menu zobrazovaného pro příslušný prvek pravým tlačítkem myši.

Tím zahájíme dialog, ve kterém jsou jména trvale vytvořených prvků třídy TField vytvořených pro danou datovou množinu. Když poprvé otevřeme Editor položek pro danou datovou množinu, je tento seznam prázdný, protože implicitně se všechny tyto prvky vytvářejí dynamicky. Pokud tento seznam není prázdný, pak databázové ovládací prvky mohou zobrazovat data pouze ze zde vyjmenovaných položek. Přemísťováním položek v seznamu lze měnit pořadí, ve kterém jsou tyto položky zobrazovány v ovládacích prvcích zobrazujících více sloupců jako je např. mřížka.

Navigátor ve spodní části dialogu umožňuje pohyb v zobrazované tabulce (pokud je datová množina aktivní).

Tlačítko "Add" ("přidej") umožňuje zobrazit seznam jmen všech sloupců existujících v dané databázové tabulce a aktuálně nezahrnutých do seznamu položek Editoru položek a přidávat tak další prvky třídy TField.

Tlačítko "Define" umožňuje definovat vypočítávané položky. Tyto položky jsou definovány pouze pro zobrazování. Skutečná struktura databázových tabulek se nemění.

Tlačítko "Remove" ("odstraň") ruší označenou položku. Tlačítko "Clear All" ruší všechny prvky třídy TField zobrazené v seznamu.

Přidání prvku třídy TField

Tlačítko "Add" v Editoru položek zobrazí všechny nepoužité položky dané datové množiny, pro které nejsou vytvořeny trvalé prvky třídy TField. Odesláním tlačítka "OK" přesuneme položku do seznamu "Fields" v hlavním dialogu Editoru položek.

Položky přesunuté do seznamu Fields se stávají trvalými. Vždy při otevření datové množiny zkontroluje Delphi existenci všech nevypočítávaných položek. Pokud tato kontrola neprojde, je generována výjimka, oznamující, že databázová položka není platná, a datová množina není otevřena.

Zrušení prvku třídy TField

Tlačítko "Remove" v Editoru položek ruší označený prvek třídy TField. Položky odstraněné ze seznamu Fields nejsou nadále součástí datové množiny a nejsou pro databázové ovládací prvky přístupné. Prvky třídy TField odstraňujeme, pokud chceme pracovat jen s podmnožinou položek tabulky nebo pokud chceme definovat novou položku nahrazující některou z existujících.

Zrušený prvek třídy TField lze pomocí tlačítka "Add" znovu obnovit, vlastnosti a události přiřazené zrušenému prvku jsou však ztraceny.

Definice nového prvku třídy TField

Tlačítko "Define" v Editoru položek umožňuje vytvářet nové prvky třídy TField. Tento prvek lze vytvořit i pro položky příslušné databázové tabulky (například pro změnu datového typu), hlavním smyslem je však vytvoření prvků třídy TField, jejichž hodnoty jsou vypočítávány programově.

Definice vypočítávaných položek

Vypočítávaná položka slouží k zobrazení hodnot, které jsou získávány až při běhu programu v popisu události OnCalcFields. Příkladem je třeba vytvoření textového pole zobrazující zřetězené texty ze dvou položek.

Pro vytvoření vypočítávané položky:

Modifikaci vlastností nebo událostí nového prvku třídy TField lze provést výběrem jména položky ze seznamu Fields a úpravou vlastností nebo událostí pomocí Editoru objektů.

Stanovení hodnoty vypočítávané položky

Vypočítáváné položky mají po definici prázdnou hodnotu až do doby, kdy připravíme programový kód pro výpočet hodnoty položky. Tento programový kód je součástí popisu události OnCalcFields pro danou datovou množinu a může modifikovat pouze položky, jejichž vlastnost Calculated má hodnotu true.

Příprava programu pro stanovení hodnoty vypočítávané položky je následující:

Úprava prvků třídy TFields

Při tvorbě programu lze definovat vlastnosti a události trvalého prvku třídy TField, a to tak, že ho vybereme buď ze seznamu Fields Editoru položek nebo ze seznamu prvků v Editoru objektů. Tyto vlastnosi řídí především zobrazení položky připojenými databázovými ovládacími prvky, například to, zda se objeví jako sloupec v mřížce nebo zda lze modifikovat jeho hodnotu. Události řídí činnost při získání nebo přiřazení hodnoty položky, při její změně nebo při její validaci.

Úprava atributů zobrazení

Pro úpravu atributů zobrazení vybraného prvku třídy TField zvolíme v Editoru objektů skupinu "Properties". Následující tabulka obsahuje vlstnosti, které můžeme zadat. Některé vlastnosti mohou u konkrétního potomka třídy TField chybět. Například prvek třídy TStringField nemá vlastnosti Currency, MaxValue nebo DisplayFormat. Prvky třídy TFloatField nemají vlastnost Size.

Vlastnosti třídy TField
VlastnostVýznam
Alignement Zobrazení obsahu položky v databázových ovládacích prvcích se zarovnáním doleva, doprava nebo centrovaně.
Calculated Při hodnotě true je hodnota vypočítávána při běhu programu metodou CalcFields. Při hodnotě false je hodnota převzata z aktuálního záznamu.
Currency Hodnota true je určena pro peněžní údaje.
DisplayFormat Udává formát, v němž je hodnota databázovými ovládacími prvky zobrazována.
DisplayLabel Udává jméno sloupce použité v mřížce.
DisplayWidth Udává šířku sloupce v mřížce tabulce (v počtu znaků).
EditFormat Udává editační formát používaný databázovými ovládacími prvky při vstupu dat.
EditMask Omezuje množinu vstupních znaků v editovatelné položce na zadaný typ a interval znaků a specifikuje dodatečné, needitovatelné znaky zobrazované v položce (pomlčky, závorky, apod.).
FieldName Udává aktuální jméno položky fyzické tabulky, z něhož odvozuje prvek třídy TField svou hodnotu a datový typ.
Index Udává pořadí položek v datové množině.
MaxValue Udává maximální numerickou hodnotu, kterou lze do dané editovatelné numerické položky zadat.
MinValue Udává minimální numerickou hodnotu, kterou lze do dané editovatelné numerické položky zadat.
Name Udává jméno položky z hlediska programového kódu Delphi.
ReadOnly Při hodnotě true je položka zobrazena, ale nelze ji měnit. Při hodnotě false to možné je.
Size Udává maximální počet znaků, který lze zobrazit nebo zapsat do textové položky, nebo velikost položek typu byte nebo var byte.
Tag Položka typu longint k volnému použití programátorem.
Visible Při hodnotě true je položka v mřížce. Prvky definované uživatelem mohou tuto položku použít k rozhodování o zobrazení nebo nezobrazení položky. Při hodnotě false není položka mřížkou zobrazována.

Hodnotu logických vlastností (s možnou hodnotou true nebo false) lze změnit dvojitým kliknutím na danou vlastnost v Editoru objektů. Ostatní vlastnosti vyžadují zápis příslušné hodnoty nebo výběr z rozbalovacího seznamu. Všechny vlastnosti prvků třídy TField lze rovněž měnit programově.

Smysl většiny výše uvedených vlastností je zřejmý, některé vlastnosti jako např. Calculated však vyžadují při použití ještě další programátorské obraty. Některé další vlastnosti jako je DisplayFormat, EditFormat a EditMask jsou na sobě závislé a jejich nastavení musí být koordinováno. Bližší informace o použití vlastnosti Calculated obsahuje část Stanovení hodnoty vypočítávané položky. Bližší informace k vlastnostem DisplayFormat, EditFormat a EditMask obsahuje část Formátování položek.

Použití Editoru vstupní masky

Atribut EditMask umožňuje omezit vstup zadávaný uživatelem do databázového ovládacího prvku připojenému k položce. Konkrétní editační masku lze buď přímo zapsat nebo ji lze vytvořit pomocí Editoru vstupní masky.

Editor vstupní masky otevřeme po výběru prvku třídy TField dvojitým kliknutím na vlastnost EditMask v Editoru objektů nebo kliknutím na tři tečky ve sloupci Values.

V seznamu "Sample Masks" lze vybrat některý ze zobrazených vzorů vstupních masek. Ten je potom možno upravit editací v textovém editačním poli "Input Mask". Povolený vstup je možno otestovat v editačním poli "Test Input". Bližší informace viz on-line help.

Poznámka: U třídy TStringField je vlastnost EditMask použita také jako zobrazovací formát.

Formátování položek

Delphi obsahuje vestavěné zobrazovací a editační formátovací procedury a inteligentní implicitní formátování prvků třídy TField. Použití těchto procedur a formátů nevyžaduje žádnou akci ze strany programátora. Implicitní formátování je odvozeno z implicitního nastavení v Ovládacím panelu Windows. Například při použití implicitních nastavení pro USA u sloupce třídy TFloatField a při vlastnosti Currency nastaveném na hodnotu true je hodnota 1234.56 zobrazována jako $1234.56, zatímco editační formátování zůstává 1234.56. Pro daný prvek jsou použitelné pouze vlastnosti odpovídající datovému typu prvku.

Formátování prvků třídy TField provádí procedury uvedené v tabulce:

Formátovací procedury třídy TField
ProceduraPoužívaná pro třídy ...
FormatFloat TFloatField, TCurrencyField
FormatDateTime TDateField, TTimeField, TDateTimeField
FormatInteger TIntegerField, TSmallintField, TWordField

Formátovací procedury používají lokální nastavení z Ovládacího panelu Windows k rozhodnutí, jak zobrazit datum, čas, peněžní hodnoty a numerické hodnoty. Toto implicitní nastavení je možné změnit buď úpravou DisplayFormat a EditFormat nebo lze použít událost OnGetText a OnSetText prvku třídy TField k vlastnímu programovému formátování.

Použití událostí třídy TField

Pro úpravu událostí u vybraného prvku třídy TField vybereme v Editoru objektů skupinu "Events". Zveřejněné události shrnuje následující tabulka:

Zveřejněné události třídy TField
UdálostVýznam
OnChange Je provedena při změně hodnoty prvku.
OnGetText Je provedena při získání hodnoty prvku pro zobrazení nebo editaci.
OnSetText Je provedena při zápisu hodnoty prvku.
OnValidate Je volána pro provedení validace při změně nebo vložení hodnoty.

Události OnGetText a OnSetText jsou určeny především pro vlastní formátování přesahující možnosti vestavěných funkcí Delphi jako jsou FormatFloat nebo FormatDate.

Třída TField obsahuje metodu FocusControl, která umožňuje, aby událost aktivovala první databázový ovládací prvek přiřazený danému prvku této třídy. To je podstatné hlavně pro validaci záznamu (např. při provádění události BeforePost třídy TTable), protože validaci prvku TField lze provádět bez ohledu na to, zda je přiřazený databázový ovládací prvek právě aktivován.

Použití konverzních funkcí třídy TField

Třída TField obsahuje funkce pro konverzi mezi datovými typy. V závislosti na typu prvku třídy TField jsou dostupné různé konverzní funkce a tyto konverzní funkce se jinak chovají. Konverzní funkce sumarizuje následující tabulka:

Konverzní funkce třídy TField
Typ AsString AsInteger AsFloat AsDateTimeAsBoolean
TStringField -- Konverze na integer (lze-li) Konverze na float (lze-li) Konverze na datum (lze-li) Konverze na boolean (lze-li)
TIntegerField
TSmallintField
TWordField
Konverze na řetězec -- Konverze na float Nelze Nelze
TFloatField
TCurrencyField
TBCDField
Konverze na řetězec Zaokrouhlení -- Nelze Nelze
TDateTimeField
TDateField
TTimeField
Konverze na řetězec (závisí na DisplayFormat) Konverze data na počet dnů od 1.1.0001 Konverze času na zlomek dne -- Nelze
TBytesField
TVarBytesField
TBlobField
TMemoField
TGraphicField
Konverze na řetězec (obecně má smysl pouze pro TMemoField) Nelze Nelze Nelze Nelze

Konverzní funkce k danému prvku třídy TField lze použít na obou stranách přiřazovacího příkazu. Následující příkaz například transformuje hodnotu prvku třídy TField pojmenovaného MojePolozka na řetězec a přiřazuje ho do editačního pole Edit1:

Edit1.Text := MojePolozka.AsString;

Další příkaz naopak přiřazuje text z editačního pole Edit1 prvku třídy TField:

MojePolozka.AsString := Edit1.Text;

Pokud by měla být při běhu programu provedena nepodporovaná nebo chybná konverze, je generována výjimka.

Programový přístup k vlastnostem třídy TField

Přístup aplikace k hodnotě položky databázové tabulky je realizován prostřednictvím vlastnosti Value daného prvku třídy TField. Následující příkaz například přiřazuje hodnotu prvku třídy TField se jménem Zakaznik_Stat do editačního ovládacího prvku Edit3:

Edit3.Text := Zakaznik_Stat.Value;

Všechny vlastnosti třídy TField dostupné z Editoru objektů jsou rovněž dostupné a nastavitelné programově. Následující příkaz například mění pořadí položek nastavením vlastnosti Index prvku Zakaznik_Stat na hodnotu 3:

Zakaznik_Stat.Index := 3;

Zobrazení dat pomocí standardních ovládacích prvků

Hodnoty z databáze lze při běhu programu zobrazovat jak pomocí standardních ovládacích prvků, tak i pomocí databázových ovládacích prvků. Kromě práce s prvky třídy TField vytvořenými Editorem položek lze při běhu programu pracovat s hodnotami uloženými v databázi ještě dalšími dvěma způsoby: pomocí vlastnosti Fields a metody FieldByName. V obou případech se jedná o přístup k hodnotám zadané položky aktuálního záznamu připojené databázové tabulky a v obou případech je vyžadována existence datové množiny, ale nikoliv prvku třídy TDataSource.

Obecně je nejvhodnější používat v databázových aplikacích databázové ovládací prvky, které jsou součástí Delphi. Tyto prvky již mají vlastnosti a metody umožňující jim napojit se na databázové položky, zobrazovat aktuální hodnotu dané položky a provádět její modifikaci. Použijeme-li standardní ovládací prvky, musíme k nim analogický programový kód doplnit sami.

Použití vlastnosti Fields

K hodnotám položek lze přistupovat i prostřednictvím vlastnosti Fields datových množin udáním pořadového čísla položky v tabulce (počínaje číslem 0). Pro přístup nebo změnu hodnoty je třeba použít odpovídající konverzní funkce jako je AsString nebo AsInteger.

Tato metoda vyžaduje znalost pořadí položek v tabulce a jejich datových typů. Tuto metodu používáme, pokud chceme realizovat cyklus přes několik položek nebo pokud pracujeme s tabulkami, jejichž struktura není při vytváření programu známa.

Následující příkaz například přiřazuje aktuální hodnotu sedmé položky tabulky ZAKAZNIK editačnímu prvku Edit1:

Edit1.Text := ZAKAZNIK.Fields[6].AsString;

Naopak lze položce datové množiny (která je ve stavu "Editace") přiřadit hodnotu tak, že ji přiřadíme vlastnosti Fields této množiny:

ZAKAZNIK.Fields[6].AsString := Edit1.Text;

Použití metody FieldByName

K hodnotě položky lze přistupovat rovněž pomocí metody FieldByName, kde pro určitou datovou množinu voláme tuto metodu FieldByName a předáme jí jako parametr jméno požadované položky. Pro přístup nebo změnu hodnoty je třeba použít odpovídající konverzní funkce jako je AsString nebo AsInteger.

Tento postup vyžaduje znalost jména položky, se kterým potřebujeme pracovat. Rovněž lze použít pro práci s databázovými tabulkami, jejichž struktura není při vytváření aplikace známa.

Následující příkaz například předává hodnotu položky STAT tabulky ZAKAZNIK do editačního pole Edit2:

Edit2.Text := ZAKAZNIK.FieldByName('STAT').AsString;

Naopak lze přiřadit hodnotu do položky datové množiny (která je ve stavu "Editace"), tak, že přiřadíme tuto hodnotu vlatnosti FieldByName:

ZAKAZNIK.FieldByName('STAT').AsString := Edit2.Text;

Použití třídy TBatchMove

Prvky třídy TBatchMove umožňují provádět operace pro skupiny záznamů nebo pro celou tabulku. Hlavní použití této třídy je pro přenesení dat ze serveru do lokální aplikace (pro analýzu apod.) nebo pro přenesení databáze z osobního počítače na server ("upsizing").

TBatchMove je mocná třída, neboť umožňuje vytvářet nové tabulky na základě existujících a automaticky při tom mapovat jména sloupců a jejich datové typy.

Dvě vlastnosti třídy TBatchMove specifikují odkud a kam se budou data přesouvat -- Source udává zdrojovou datovou množinu (prvek třídy TTable nebo TQuery) odpovídající existující databázové tabulce a Destination udává prvek třídy TTable odpovídající cílové databázové tabulce. Cílová tabulka může a nemusí existovat.

Režimy práce třídy TBatchMove

Vlastnost Mode udává režim činnost daného prvku. Význam jednotlivých hodnot shrnuje následující tabulka.

Režimy prvků třídy TBatchMove
VlastnostVýznam
batAppend Přidává záznamy k cílové tabulce. Cílová tabulka musí existovat. Tento režim je implicitní.
batUpdate Modifikuje záznamy v cílové tabulce podle odpovídajících záznamů zdrojové tabulky. Cílová tabulka musí existovat a musí mít definován vhodný index.
batAppendUpdate Pokud v cílové tabulce existuje odpovídající záznam, je modifikován. Jinak je k cílové tabulce přidán nový záznam. Cílová tabulka musí existovat a musí mít definován vhodný index.
batCopy Vytváří novou tabulku se strukturou zdrojové tabulky. Cílová tabulka nesmí existovat -- pokud ano, je touto operací zrušena.
batDelete Ruší v cílové tabulce záznamy odpovídající zdrojové tabulce. Cílová tabulka musí existovat a musí mít definován vhodný index.

Atribut Transliterate udává, zda se mají znaková data transformovat podle znakové množiny cílové tabulky.

Provedení operace

Při běhu programu použijeme k provedení operace metodu Execute. Máme-li například prvek třídy TBatchMove se jménem PridejVsechno, jeho činnost je vyvolána příkazem:

PridejVsechno.Execute;

Při tvorbě programu lze provést operaci dvojitým kliknutím na prvek třídy TBatchMove a volbou "Execute". Vlastnost MoveCount obsahuje počet záznamů přesunutých při provedení operace.

Zpracování chyb

Při operacích přesunu mohou v zásadě nastat dva druhy chyb: chyby konverze dat a porušení integritních omezení. Třída TBatchMove má několik vlastností, které se týkají zpracování chyb. Vlastnost AbortOnProblem udává, zda se má operace ukončit při chybě konverze. Atribut AbortOnKeyViol udává, zda se má operace ukončit při porušení integritního omezení.

Další vlastnosti umožňují vytvořit doplňkové tabulky, které dokumentují prováděnou operaci: