Delphi - TIBTable komponens

Interbase 4. rész

forráskód letöltése
A legegyszerűbb módszer, amivel adathozzáférést biztosíthatunk a Delphi-ben egy InterBase adatbázis tábláihoz a TIBTable komponens. Jelen cikkben ezt a komponenst ismerhetjük meg: milyen tulajdonságai, eseményei és metódusai vannak, hogyan használjuk ezeket, és hogyan építhető be egy programba a komponens. Aki már használt TTable komponenst, sok ismerős dologgal találkozhat az olvasás során. Az objektum egyszerűen egy adatbázistáblára hivatkozik. Szerepe tehát, hogy biztosítja egy fizikai tábla, rendszertábla vagy nézet adatainak elérését. Ha több táblából szeretnénk összeválogatni az adatainkat, akkor a TIBQuery, ha pedig adataink egy tárolt eljárás végrehajtásából származnak, akkor egy TIBStordProc komponenst használhatjuk.

A komponens segítségével szerkeszthetjük és nézegethetjük a tábla minden oszlopában és sorában szereplő adatokat. Dolgozhatunk a rekordok egy halmazával. Meg tudjuk szűrni az adatokat és dolgozhatunk a szűrés után az összes rekord egy részhalmazával, amely a saját szűrési feltételeink alapján állt elő. Lehetőség van a rekordok között keresni, táblákat másolni, átnevezni és törölni, valamint master/detail kapcsolatokat létrehozni a táblák között. Fontos, hogy ez a komponens csak egyetlen táblából képes adatokat kiolvasni.

A komponens használata

A következőkben nézzünk meg néhány általános utasítást arról, hogyan kell tervezési időben a komponenst használni.
1. Keressük meg a komponenst a paletta InterBase lapján és helyezzük azt a Form-unkra, vagy egy adatmodulra.
2. A Database tulajdonságot kapcsoljuk egy TIBDatabase komponenshez.
3. Állítsuk be a Transaction tulajdonságot kiválasztva az elérhető TIBTransaction komponensek közül egyet.
4. Állítsuk be az IBDatabase komponens tulajdonságait is.
5. Válasszunk ki egy táblát a TableName tulajdonságban a lenyíló listában.
6. Helyezzünk a Form-ra egy DataSource komponenst és állítsuk be a megfelelő tulajdonságait. Majd helyezzük el a megfelelő adatmegjelenítő komponenseket, állítsuk be a tulajdonságait, és végezetül a TIBTable komponens Active tulajdonságát állítsuk igaz értékűre.

Futási időben a következőképpen tudunk táblát váltani:
with IBTable1 do begin
  Active := False; {Zárjuk a táblát}
  if TableName = 'gktul' then
     TableName := 'tulajdonosok'
   else
     TableName := 'gktul';
   Active := True; {Újra megnyitjuk a táblánkat}
End;

Tábla nyitása és zárása

Ahhoz, hogy nézegessük és szerkesszük táblánk adatait egy adatmegjelenítő vezérlőben - mint amilyen például a TDBGrid - a táblánkat meg kell nyitni. Két út kínálkozik a megnyitás végrehajtásához. Beállíthatjuk az Active tulajdonságot igazra, vagy pedig meghívjuk az Open metódust. Így táblánk megnyitódik és dsBrowse (azt jelöli, hogy az adatkészlet normál böngésző üzemmódban van, amelyet az adatok nézegetésére vagy a közöttük lévő keresésre használunk) állapotba kerül, és az adatmegjelenítő vezérlőkben megjelennek az aktuális rekord értékei. Az adatok nézegetése és szerkesztése végén, a függőben lévő változásokat elpostázzuk (Post metódus) vagy eldobjuk. Ha a gyorsítótáras engedélyezés aktív (ChachedUpdates=True), akkor meg kell hívnunk az ApplyUpdates metódust is, hogy a változásokat postázzuk az adatbázis felé is. Utolsó lépésként a táblánkat bezárjuk. Szintén két út lehetséges: vagy az Active tulajdonságot állítjuk hamisra, vagy a Close metódust hívjuk meg. Így táblánk dsInactive (az adatkészlet le van zárva) állapotba kerül. A hozzá rendelt aktív adatmegjelenítő vezérlőkből az adatok eltűnnek.

Adattábla olvasása és írása

Természetes igény az adattábla olvasása és írása. Általában olvasási joggal mindenki rendelkezhet. Írási jogokat SQL alapú adatbázis-kezelők esetében már nem minden felhasználónak kell adni. Ezt a felhasználó létrehozásakor vagy jogok adományozásakor dönthetjük el (GRANT SQL parancs, erről a 15. cikkben olvashatunk majd még részletesebben).
Egy másik tulajdonság, a ReadOnly segítségével is meghatározhatjuk az írási olvasási jogokat. Ha a tulajdonságot igazra állítjuk, akkor a táblában nem lehet az adatokat szerkeszteni.

Rekord keresése

Kereshetünk rekordokat a táblában különböző utakon. Az előnyben részesített és legrugalmasabb út a keresés végrehajtásához az általános keresési metódusok Lookup és Locate használata. Lehetővé teszik, hogy bármilyen mező alapján keressünk a táblában, akár indexeltek, akár nem.
A Locate metódus használata esetén a kurzor az első feltételnek megfelelő rekordra kerül. A Locate függvény egy logikai értékkel tér vissza, mely jelzi a keresés sikerességét. A Locate hívása előtt beállíthatunk bizonyos keresési opciókat is:
  • különböztesse-e meg a kis- és nagybetűket
  • teljes vagy részleges keresést végezzen-e
Természetesen ezek csak karakterlánc típusú mezőkre vonatkoznak.
A Lookup működésileg hasonló az előzőhöz, a különbség csak az eredményben van. Ez a metódus is rákeres az adott feltételnek megfelelő első rekordra, de azt nem aktualizálja, hanem mezőértékeit eredményként visszaadja. Keresési opciókat itt nem állíthatunk be.
A komponens támogatja még a Goto és a Find metódusok használatát is. E metódusokat csak a korábbi verziókkal való kompatibilitás esetén használjuk, új alkalmazásunk esetén a Locate és a Lookup metódusokat használjuk.

Az adatok rendezése

Egy index segítségével határozhatjuk meg, hogy milyen sorrendben jelenjenek meg adataink a táblában. Általában a rekordok növekvő sorrendben jelennek meg az elsődleges kulcs alapján.
Ha ezen a sorrenden változtatni szeretnénk, akkor az adatbázisban hozzunk létre új indexeket, és az IndexFieldNames vagy az IndexName tulajdonságoknál a listából jelöljük ki a nekünk megfelelőt. Futási időben a GetIndexNames metódust használhatjuk az indexek nevének meghatározásához.
Ha nem szeretnénk az adatbázisban sok indexet létrehozni, akkor egyszerűen adjuk meg az IndexFieldNames tulajdonságban azt a mezőt, amely szerint rendezni akarjuk rekordjainkat.

Master/detail kapcsolat

Beállítása és használata olyan, mintha egy közönséges TTable komponenst használnánk.


Ezek után tekintsük át röviden, lexikális formában a komponens legfontosabb metódusait, tulajdonságait és eseményeit.

Tulajdonságok:
  • Active: Megmutatja vagy beállíthatjuk segítségével, hogy a táblánk aktív-e vagy sem.
  • BufferChunks: Beállíthatjuk, hogy a buffer mérete mennyivel nőjön (rekordokban), ha betelik.
  • ChachedUpdates: A gyorsítótáras frissítés engedélyezését határozhatjuk meg. Amikor a tulajdonságot igazra állítjuk, a frissítések (módosítások, törlések, új rekord beszúrása) csak a program gyorsítótárában, a kliens gépen lesz eltárolva. Amikor végeztünk minden módosítással, az alkalmazásunk a helyben tárolt módosítást elküldi egyszerre, egy tranzakció keretében az adatbázishoz.
  • Constraints: A rekordszintű megszorításokat definiálhatjuk itt.
  • CurrentDBKey: Az aktuális sorhoz tartozó DBKey értéket adja vissza. Ez egy egyedi sorazonosító a jelenleg tartó tranzakció ideje alatt. Ezt a tulajdonságot közvetlenül nem használjuk.
  • DefaultIndex: Azt az indexet definiálja, amely szerint rendezzük rekordjainkat a tábla megnyitásakor. Ha ez a tulajdonság hamis értékű, akkor az ORDER BY záradék nem használható a táblanyitáskor az SQL-szerveren. Ha igazra állítjuk, akkor megnyitáskor a tábla rendezve lesz az elsődleges vagy egy egyedi index szerint.
  • Exists: Futás időben használhatjuk ezt a tulajdonságot, hogy megállapítsuk azt, hogy a megadott tábla létezik-e vagy sem.
  • Filter: A rekordjainkat szűrhetjük meg az általunk felállított kritérium(ok) szerint. A szintaxis ugyanaz, mint amikor egy SELECT utasításban a WHERE záradékot használjuk. Ha például szeretnénk látni a Kis nevű tulajdonosokat: VEZ_NEV = 'Kis'. Használhatjuk az SQL-ben szokásos Joker karaktereket: % és a _ a LIKE operátor mögött. Az ABC-s rendszámú kocsikat így szűrhetjük: RENDSZAM LIKE ABC%. Ha nem szeretnénk látni azokat a rekordokat, amelyekben egy adott mező üres, kiszűrhetjük azokat: ALVAZSZAM IS NOT NULL. Alkalmazhatunk összetett szűrési kritériumot is: GK_AZONOSITO IN (SELECT GK_AZONOSITO FROM GEPJARMUVEK WHERE RENDSZAM = '_BC-112'). Itt megkapjuk az összes olyan gépkocsi azonosítóját, amelyik eleget tesz a feltételnek.
  • Filtered: Megállapíthatjuk, hogy egy aktív tábla szűrt vagy nem. Ha elkészültünk a szűrési feltételek beállításával, e tulajdonságnak adjunk igaz értéket, és végrehajtódik a szűrés.
  • IndexDefs: A táblában található indexekről tartalmaz információkat. Ez egy tömb tulajdonság, ahol minden egyes elem egy-egy indexről szolgáltat adatokat. Természetesen kézzel is szerkeszthetjük az adatokat, létrehozhatunk újabb indexeket. Ebben az esetben a StoreDefs tulajdonság hamis értékűvé válik. Mielőtt a tulajdonsággal dolgoznánk, hívjuk meg az Update metódusát.
  • IndexFielCount: Meghatározza, hogy az adott index hány táblaoszlopból áll elő. Ha indexünk egy oszlop alapján működik, akkor a visszatérési értéke 1 lesz.
  • IndexFieldNames: Megmutatja, hogy az adott tábla milyen nevű indexeket tartalmaz. Itt mi is "létrehozhatunk" indexeket a kívánt mezőnév megadásával. Ha több mező alapján szeretnénk rendezni, akkor a mezőneveket pontosvesszővel (;) választjuk el. Az IndexFieldNames és az IndexName tulajdonságok közül csak az egyiket állíthatjuk be egyszerre.
  • IndexFields: Beállíthatjuk, hogy az adott index milyen mező(ke)t használjon. Azonban ezt a tulajdonságot direkt ne használjuk, értékeit az IndexFieldNames tulajdonság segítségével állítsuk be.
  • IndexName: A tulajdonság segítségével meghatározhatjuk az adatok rendezési sorrendjét. Ha az érték üres, akkor az elsődleges index szerint lesz rendezve a tábla. Ahhoz, hogy a rendezés sikeresen megvalósuljon egy létező indexet kell itt beállítanunk.
  • MasterFields: Meghatároz egy vagy több mezőt a mester táblában, amely alapján felépül a master/detail kapcsolat a két tábla között. A MasterSource tulajdonság beállítása után használhatjuk. Amennyiben a mester táblában változik az aktuális rekord, meghatározásra kerül az összekötő mező(k) új értéke, és ez alapján jelennek meg a táblánkban a megfelelő rekord (ok).
  • MasterSource: Beállíthatjuk, hogy mely adatforrás (TDataSource) alapján épüljön fel a kapcsolat. Ez a meghatározott adatforrás lesz a mestertábla.
  • ReadOnly: A tábla csak olvasható, ha a tulajdonság értéke igaz. Attól, hogy ez a tulajdonság hamis, még nem biztos, hogy a felhasználó módosítani tudja a táblát. Ehhez a megfelelő SQL jogosultságokkal is rendelkeznie kell.
  • StoreDefs: A tábla indexeiről és mezőiről hordoz információt. Ha igaz értékű, akkor az indexek és a mezők definíciója az adatmodulban vagy a Form-ban van tárolva. Alapértelmezett értéke hamis. A CreateTable metódus használata előtt értékét állítsuk igazra.
  • TableType: Beállíthatjuk, hogy a TableName tulajdonságnál a létező táblák mellett egyéb adattáblákat is szeretnénk-e látni vagy sem.
- ttSystem: Láthatóak lesznek a nézetek és a rendszertáblák is.
- ttView: A nézetek láthatóak.
  • TableName: Beállíthatjuk, hogy az adott TIBTable komponens milyen táblával vagy nézettel dolgozzon.
  • TableNames: Az elérhető táblák listájával tér vissza.
  • UniDirectional: Beállíthatjuk, hogy a kétirányú kurzorok engedélyezettek legyenek-e a tábla számára.
  • UpdateObject: Itt egy kapcsolódást adhatunk meg egy TIBUpdateSQL komponens felé, amelyet akkor használ az alkalmazás, ha frissíteni kell egy csak olvasható eredményt. Ezzel a lehetőséggel a 11. részben foglalkozunk behatóbban.
Események:
Nagyon sok, a TTable komponensnél már megismert tulajdonsággal találkozhatunk. Itt csak az újabbakkal ismerkednénk meg.
  • AfterDatabaseDisconnect: Az esemény akkor aktiválódik, miután az adatbázissal megszakadt a kapcsolatunk.
  • BeforeDatabaseDisconnect: A kapcsolat megszakadása előtt váltódik ki ez az esemény.
  • DatabaseFree: Az esemény bekövetkezik, amint az adatbázis által használt memória felszabadul.
  • AfterTransactionEnd: Egy tranzakció befejezése után aktiválódó esemény.
  • BeforeTransactionEnd: A tranzakció befejezése előtt következik be ez az esemény.
  • TransactionFree: Az esemény akkor váltódik ki, miután a tranzakció által használt memória felszabadul.
Metódusok:
A következő fontosabb metódusokat kell megemlítenünk:
  • AddIndex: Új indexet hozhatunk létre a táblához. Paraméterek:
- Name: Az index neve.
- Fields: Azon mezők neve pontosvesszővel (;) elválasztva, amelyek részt vesznek az index felépítésében.
- Options: Három értéke lehet:
ixPrimary: elsődleges index.
ixUnique: nem ismétlődő érték szerepelhet az indexelt mezőben.
isDescending: A rendezés csökkenő sorrendben történik.
  • CreateTable: A megadott definíciók alapján futásidőben új táblát hozhatunk létre. Ha nem ellenőrizzük, hogy a megadott tábla létezik, a metódus felülírja. Ezért használata előtt vizsgáljuk meg az Exists tulajdonság visszaadott értékét. Ha a FieldsDef tulajdonság tartalmaz értékeket, akkor innen építi fel az adatbázis mezőit. Egyébként a Fields tulajdonságot használja erre. Az IndexDefs tulajdonság segítségével hozhatjuk létre az indexeket.
  • DeleteIndex: Töröl egy indexet a táblából. A metódus paramétereként kell megadnunk a törölni kívánt index nevét.
  • DeleteTable: Töröl egy létező táblát az adatbázisból. A táblának zárva kell lennie, ha meghívjuk ezt az eljárást. Ha a tábla adatokat tartalmaz, azok is törlődnek.
  • EmptyTable: Törli az összes rekordot a megadott táblából. Ha a felhasználó nem rendelkezik a törléshez szükséges rendszerprivilégiummal, nem tud törölni a táblából.
  • GetIndexNames: A tábla elérhető indexeivel tér vissza a megadott listában. A listának már léteznie kell az eljárás meghívása előtt.
  • GotoCurrent: Lehetőséget biztosít arra, hogy szinkronizáljuk a kurzor pozícióját a táblánkban egy másik táblában lévő kurzor pozíciója alapján. A két táblának ugyanarra az adattáblára kell mutatnia. Ezt a metódust olyan alkalmazásokban használjuk, amelyekben van két tábla komponens, amelyek ugyanahhoz az adatbázistáblához kapcsolódnak különböző DataSource komponenseken keresztül.

A nézetek

Ha már ismerjük az InterBase adatbázis többi elemét, akkor a nézeteket sem hagyhatjuk ki.
A nézet (view) egy vagy több tábla adatait gyűjti össze egy SELECT utasítással. Általában a statikus adatokat szoktuk nézetekben összegyűjteni.
Amikor egy kliens alkalmazásban meg akarjuk jeleníteni az adatokat, megnyitjuk a lekérdezést (pontosabban a nézetre irányított táblakomponenst). Ilyenkor lefut a nézet SELECT lekérdezése, amely összegyűjti a kívánt adatokat. A lényeg tehát az, hogy nem kell kliens oldalon összeállítani és elutaztatni az adatbázis-szerverhez, a nézet már eleve ott van, így most annak tartalmát kérdezzük le. Kliens oldalon a nézet úgy viselkedik, mint egy tábla, mintha ténylegesen adatot tartalmazna, holott csak az SQL lekérdezés tárolódik előfordított állapotban. Delphiből a nézetek adatait InterBase adatbázis esetében TIBTable komponenssel érhetjük el. A gyakran lekérdezendő adatokat már az adatbázis megtervezésekor érdemes egy nézetben összegyűjteni, így ezek kényelmesen hozzáférhetőek. Természetesen egy nézet is csak akkor szerkeszthető, ha a lekérdezése is az lenne. Erre az SQL-92 szabvány szabályai vonatkoznak.

Hozzunk létre egy FONTOS_ADATOK nevű nézetet, amely a TULAJDONOSOK táblából veszi az adatokat, és megjeleníti az azonosítószámot, a teljes nevet, címet és a születési adatokat.
Az SQL utasítás a nezet.sql állományban található. Futtatása történhet egy TIBQuery komponens, vagy a sorozat 2. cikkében már említett Interactive SQL segédprogram használatával.

A kurzorok

Az SQL-kiszolgálók az adatok logikai halmazaival foglalkoznak, aminek semmi köze a fizikai sorrendhez. Egy relációs adatbázis-kiszolgáló a relációs modellnek megfelelően kezeli az adatokat, a matematikai halmazelmélet alapján.
A legfontosabb, hogy a relációs adatbázisokban a táblák rekordjait nem helyük azonosítja, hanem egy úgynevezett elsődleges kulcs, amely egy vagy több mezőből állhat. Ha megkaptunk egy rekordhalmazt, a kiszolgáló mindegyiknél megadja, hogy melyik az azt követő rekord. Ennek segítségével gyorsan lépkedhetünk egy rekordról a következőre, viszont rettentően lelassul a visszalépés az előző rekordra. Ezért általában azt mondjuk, hogy a relációs adatbázis-kezelő rendszerek egyirányú kurzort használnak. Ha egy Table vagy Query komponenst egy DBGrid vezérlőhöz kapcsolunk, visszafelé haladva a rekordok böngészése meglehetősen lassú lesz (nagy rekordszám esetén ez már érzékelhető is). Sokat segít az, ha a helyi gyorsítótárban tartjuk a betöltött rekordokat: ha előre haladunk, akkor az SQL-kiszolgáló felé küldünk egy kérést, ha visszafelé, akkor a mentett adatokhoz fordulunk. Így kétirányúvá tehetjük a kurzorokat, ám ez igen sok módszert emészt fel. A megoldás az lehet, ha csak a szükséges rekordokat töltjük le.

Rendszertáblák

Az InterBase adatbázis a következő rendszertáblákat tartalmazza:
  • RDB$CHARACTER_SETS: az érvényes karakterkészletek.
  • RDB$LOG_FILES: nem használt.
  • DB$COLLATIONS: leválogatási sorrend.
  • RDB$PAGES: az adatbázis által lefoglalt lapok adatai.
  • RDB$CHECK_CONSTRAINTS: az adatellenőrző megszorításokról mutat adatokat.
  • RDB$PROCEDURE_PARAMETERS: az adatbázis eljárásainak paraméterei.
  • RDB$DATABASE: adatbázis definíció.
  • RDB$PROCEDURES: az adatbázisban tárolt eljárások.
  • RDB$DEPENDENCIES: táblák és oszlopok függőségi viszonyai.
  • RDB$REF_CONSTRAINTS: a referencia-integritás adatai.
  • RDB$EXCEPTIONS: kivételek tárolt eljárásokhoz.
  • RDB$RELATION_CONSTRAINTS: integritások a táblákhoz.
  • RDB$FIELD_DIMENSIONS: egy tömb típusú oszlop dimenziója.
  • RDB$RELATION_FIELDS: az oszlopok listája és tulajdonságaik.
  • RDB$FIELDS: az oszlopok tulajdonságai.
  • RDB$RELATIONS: tulajdonságok a táblák és a nézetek számára.
  • RDB$FILES: másodlagos fájlok adatai.
  • RDB$ROLES: szerepkörök listája.
  • RDB$FILTERS: BLOB szűrőkről tartalmaz információt.
  • RDB$SECURITY_CLASSES: a hozzáférési jogok listája és ezek hozzárendelése az adatbázis különböző tábláihoz, nézeteihez.
  • RDB$FORMATS: az oszlopok formai követelményeiről ad információkat.
  • RDB$TRANSACTIONS: információk a tranzakciókról.
  • RDB$FUNCTION_ARGUMENTS: függvények argumentumai.
  • RDB$TRIGGER_MESSAGES: a triggerek üzenetei és ezek hozzárendelése egy adott triggerhez.
  • RDB$FUNCTIONS: felhasználó által létrehozott függvények.
  • RDB$TRIGGERS: a triggerek listája.
  • RDB$GENERATORS: információk a generátorokról.
  • RDB$TYPES: a felhasználó által létrehozott különböző adattípusok.
  • RDB$INDEX_SEGMENTS: adatok a mezőkről, amelyek valamelyik indexhez tartoznak.
  • RDB$USER_PRIVILEGES: a felhasználói privilégiumok.
  • RDB$INDICES: indexek struktúrái a gyorsabb elérés érdekében.
  • RDB$VIEW_RELATIONS: SQL objektumok nem használják.

A példaprogramok a PELDA, GotoCurrent és a CreateTable könyvtárakban találhatók. Magyarázatok a forráskódokban vannak.

Interbase cikksorozat