Adatbáziskezelés Delphiben – II. Rész: Mélyedjünk el az adatok kezelésében…

A cikksorozat második része tovább vezeti az olvasót a Delphi adatbáziskezelésben való elmélyülésben.

A TDataModule osztály

Ennek az osztálynak a szerepe, hogy olyan komponenseket tároljon, amelyek csak tervezési időben láthatók. Ilyen a TTimer, TTable, TDataSource és még sorolhatnánk. Ennek a jelentősége az, hogy az ilyen komponenseket elegendő egyszer elhelyezni az adatmodulban és onnan mindegyik form képes azt elérni. Ezen felül még olyan eljárásokat is megírhatunk itt, amelyeket azután minden unitban elérhetünk.

Adatmodult készíteni borzasztó egyszerű és tulajdonképpen két lehetőségünk is van rá. Az egyik, hogy használjuk a File menü New Data Module menüpontját, a másik pedig a File menü New parancsa, amely hatására megjelenő párbeszédablakban kiválasztjuk a Data Modules lapot és a ott található, előre elkészített adatmodulok közül kiválasztjuk azt, amelyik számunkra szükséges. Bármelyik megoldást is választjuk, a művelettel megjelenik egy fehér munkafelületű ablak, amelybe elhelyezhetjük a különböző vezérlőelemeket.

Az osztálynak két, gyakran használt eseménye van, az OnCreate és az OnDestroy. Az első akkor hajtódik végre, amikor létrehozza a program az adatmodult. Itt szokás táblákat megnyitni, valamint egyéb más olyan műveleteket elvégezni, amelyeket a létrehozáskor végre kell hajtani. Az OnDestroy a modul bezárásakor hajtódik végre, éppen ezért itt például bezárhatjuk a táblákat.

A DataMosule-nak csupán két tulajdonsága van, de számunkra most csak egy fontos, mégpedig az adatmodul neve (Name). Ezt mindig változtassuk meg olyan névre, amelyről azonnal fel tudjuk ismerni, hogy a programunk mely alkotórészéről van szó.

Amikor az adatmodulban található komponensekhez szeretnénk hozzáférni programból, akkor tudatni kell a unittal, hogy hol találja azokat. Éppen ezért a unit Implementation részében meg kell adni az adatmodul unitjának a nevét, majd a CTRL+F9 kombinációval le kell fordítani a programot, hogy ezek a változások érvényre jussanak. A modul megadása az alábbi módon történik:

implementation

uses UDM; //ahol az UDM az adatmodul unitjának a neve.

Ezt követően az adatmodulban található komponensekre az alábbi módon hivatkozhatunk:

adatmodul_neve.komponens_neve

DM.tblAllatok //ahol a DM az adatmodul, a tblAllatok pedig a rajta található tábla neve

Gyakorlás…

Készítsük el az előző rész végén ismertetett alkalmazást, de most a Table és a DataSource komponenseket tegyük egy adatmodulra.

Adatok kezelése

Már az előző részben is és ebben a részben is használtuk az adattáblákat, de a későbbiekben jobban bele kell mélyednünk ezek kezelésébe, annak érdekében, hogy meg tudjunk bármilyen feladatot oldani.

Az adattáblák megadott állapotban lehetnek, ezek az állapotok meghatározzák, hogy milyen műveleteket végezhetünk el rajtuk.

A táblák mindaddig dsInactive állapotban vannak, amíg egy Open művelettel meg nem nyitjuk őket. Ekkor dsBrowse állapotba kerülnek, ami az adatok tallózását és törlését teszi csak lehetővé. Amennyiben az adatokat módosítani szeretnénk, akkor az Edit művelettel dsEdit állapotba kell kapcsolnunk, amikor is ezeket a módosításokat elvégezhetjük. Előfordulhat, hogy új adatot kell felvenni, ilyenkor vagy az éppen aktuális helyre szúrunk be egy rekordot az Insert művelettel, vagy a tábla végéhez fűzünk hozzá egyet az Append metódussal. Bármelyiket is használjuk, a tábla dsInsert üzemmódba kerül. Amikor végeztünk az adatok módosításával, illetve felvételével, akkor a Post metódussal zárhatjuk azt le. Amennyiben ez nem sikerül, akkor a tábla az éppen aktuális állapotban marad, ellenkező esetben visszatér a dsBrowse állapotába. Ugyanez a helyzet akkor is, amikor akár a dsaInsert, akár a dsEdit állapotban meghívjuk a Cancel vagy a Delete metódust. Az előbbi megszakítja az éppen aktuális változtatást, míg az utóbbi kitörli az éppen aktuális rekordot.

Most, hogy már ismerjük ezeket az állapotokat, nézzük meg, hogy hogyan is tudunk mozogni az adattáblán belül. Az, hogy melyik rekord az aktuális, egy mutató, a rekordmutató határozza meg. A rekordmutató léptetésével tudjuk kiválasztani azt az egyedet, amellyel dolgozni szeretnénk. Természetesen erre a feladatra is megfelelő metódusok állnak rendelkezésre. A legelső rekordra viszi a mutatót a First metódus, míg a Last pontosan a legutolsó rekordot jelöli ki. A következő rekordra ugrik a Next, míg az előzőre a Prior metódus használatakor. Ezzel már meg is tudunk oldani minden műveletet, bármelyik rekordot ki tudjuk választani.

Természetesen ezeket a metódusokat az alkalmazásunk kódjában kell használnunk, de ugyanezeket tudjuk elérni a DBNavigator felhasználásával is.

A különböző metódusok használatát mutatja be az alábbi lista:

Table1.Edit

Table1.Post

Table1.Insert

Table1.Delete

Table1.Cancel

Table1.First

Table1.Last

Table1.Next

Table1.Prior

 

Az adatkezelés alapvető feltétele, hogy hozzáférjünk a tábla mezőihez. Ehhez természetesen szükségünk lesz a mező nevére és még két dologra. Az egyik, hogy a mező nevét a FieldByName(’mezonev’) függvénnyel jelölhetjük ki, ami után meg kell adni, hogy mit szeretnénk csinálni vele. A mező értékét a Value változó adja vissza. Ennek megfelelően, amikor egy mező értékét szeretnénk megadni, akkor azt az alábbi formában tehetjük meg:

DM.tblTabla_Neve.FieldByName(’MEZONEV’).Value:=mezo_erteke;

Amint látható a fenti sorból, meglehetősen hosszú kódsort kell írnunk ahhoz, hogy egy mező értékét megadhassuk. Ha visszaemlékeznek az Olvasók az első példaprogramunkra, akkor tudhatják, hogy egy egyszerű tábla esetében is számos mező értékét kell módosítani például egy új rekord felvételekor. Mivel nagyon sokat kellene gépelni, ezért készíthetünk egy ciklust, aminek segítségével ez a művelet jelentősen lerövidül.

Ennek a  módja a következő:

with DM.tblTabla_nev do

begin

                táblakezelő metódusok;

end;

Ezt kibővíthetjük egy vizsgálattal, ami megmondja nekünk, hogy a tábla már dsEdit vagy dsInsert állapotban van-e, mert ha nem, akkor nekünk kell erről a megfelelő metódusokkal gondoskodnunk. Ez az alábbi módon történhet meg:

with DM.tblTabla_nev do

begin

      if Not (State in [dsEdit, dsInsert]) Then

            Edit; //itt állítjuk a táblát szerkesztő üzemmódba

      táblakezelő metódusok;

end;

Keresés az adattáblákban

Ha adatokat tárolunk, akkor gyorsan szembekerülhetünk azzal a feladattal, hogy a már meglévő adatokból keressük meg a bizonyos feltételeknek megfelelő rekordokat. Tulajdonképpen kétféle lehetőség kínálkozik ennek a feladatnak a megoldására. A klasszikus értelemben vett keresésnél az első megfelelő rekordnál megállítjuk a keresést. Amikor a rekordok számát szeretnénk valamilyen szempont szerint lecsökkenteni, akkor a táblát szűrnünk kell. Mivel mindkét művelet szinte minden esetben előfordul, ezért a továbbiakban ismerkedjünk meg a keresési, majd a következő számban a szűrési lehetőségekkel.

A Delphiben többféle lehetőség közül választhatunk, amikor keresését kell végrehajtanunk. A gyakorlatban ezekből leginkább kétféle eljárást használnak, éppen ezért a továbbiakban ezeket mutatjuk be, ezek más és más felhasználási körrel rendelkeznek.

A Locate függvény használatakor a rekordmutató az első olyan rekordra ugrik, amely megfelel a megadott feltételeknek. A Locate logikai függvény, ami azt jelenti, hogy egy igaz vagy egy hamis értékkel tér vissza attól függően, hogy a keresés eredményre vezetett-e. Ennek megfelelően rendszerint egy feltételben használjuk, annak érdekében, hogy ki tudjuk íratni, ha nincs találat.

with DM.tblTabla_neve do

begin

      if Not Locate (’MEZONEV’, ertek, [opciok]) then

        ShowMessage (’Nincs talállat);

end;

 

A fenti, nagyon egyszerű kód bemutatja általánosságban, hogyan kell használni a függvényt. Amennyiben nincs találat, egy erre figyelmeztető hibaüzenet jelenik meg a képernyőn (ShowMessage).

Előfordulhat olyan eset is, amikor több mezőben szeretnénk feltételeket megadni. Ilyen esetben a mezőneveket egymástól pontosvesszővel elválasztva felsoroljuk, majd az értékeket egy tömbben helyezzünk el. Erre mutat példát az alábbi kódrészlet:

with DM.tblTabla_neve do

begin

      if Not Locate (’MEZONEV1; MEZONEV2’, VarArrayOf([’ertek1’, ’ertek2’]), [opciok]) then

        ShowMessage (’Nincs találat’);

end;

Mint látható, erre a célra a VarArrayOf () függvényt kell segítségül hívnunk.

Felmerülhet az olvasóban a kérdés, hogy miért szerepel a függvényben az [opciok] kapcsoló? Azért, mert meg lehet adni két opciót is a Locate-nek. Az egyikkel azt határozhatjuk meg, hogy szükségünk van-e a kis- és nagybetűk megkülönböztetésére. Ezt a loCaseInsensitive paraméterrel tehetjük meg. Amennyiben használjuk ezt, akkor a keresésnél a Delphi nem tesz különbséget a kis- és a nagybetűk között. A másik opcióval, ami a loPartialKey névre hallgat, tudathatjuk a Delphivel, hogy szótöredékekre is keresni kívánunk. Ez azt jelenti, hogy nem csak pontos egyezésnél kapunk vissza eredményt. Ez hasznos lehet, amikor nem tudjuk a pontos értékét a mezőnek, hanem csak egy részét, de mégis vigyázni kell vele, mert könnyen adhat hamis találatot. Ne feledjük, hogy a Locate a rekordmutatót az első olyan rekordra viszi, ami a feltételnek eleget tesz.

A másik keresési lehetőség a Lookup függvény használata, amely nagyon hasonlít működés szempontjából a Locate-re. Ebben az esetben azonban a rekordmutató mozgatására nem kerül sor, a keresési feltételnek megfelelő rekord megadott mezőjének értékét adja vissza eredményül. Ennek a függvénynek nincsenek opciói, tehát ilyen lehetőségeket nem adhatunk meg. Mivel itt nem logikai visszatérési értékről van szó, éppen ezért máshogyan kell ezt a függvényt használni.

var Valtozo: variant;

...

with DM.tblTabla_Neve do

begin

Valtozo := Lookup (mezo_amiben_keresunk, ertek_amit_keresunk, eredmenymezo_neve);

end;

Amint látható, definiálnunk kell egy változót, aminek a típusa variant, mivel bármilyen típusú lehet. Azután ebbe a változóba tesszük bele annak a mezőnek az értékét, ami a feltételnek megfelelő rekordban található.

Több mező értékét is megadhatjuk feltételnek, a szintaktika hasonló, mint amit a Locate függvénynél már megismertünk. Itt is felsoroljuk a mezőneveket, majd egy tömbben elhelyezzük azok értékeit. Ezt mutatja az alábbi kódrészlet:

var Valtozo: variant;

...

with DM.tblTabla_Neve do

begin

Valtozo := Lookup (’MEZO1’, ’MEZO2’,

VarArrayOf ([’ERTEK1’,’ERTEK2’]), eredmenymezo_neve);

end;

A fentiekből már látható, hogy egyszerű eszközökkel nagyon gyorsan lehet az adatokat megkeresni. Azonban nem mindig elég, ha egy rekordot keresünk meg, sok esetben a rekordok számának a szűkítése a cél. Ez a művelet a szűrés, amely annyira gyakori, hogy a következő számot ennek a témának szenteljük.

Markó Imre