Delphi - Multi-tier alkalmazásfejlesztés MIDAS komponensekkel

Multi-tier 3. rész

forráskód letöltése
Sorozatunk harmadik részében létrehozzuk a kiszolgálói oldal alkalmazását, a szerver programot. A cikkből megtudhatjuk azt is, hogy miként használhatjuk az adat szótárakat (dictionary). A mellékelt példa megnyitása előtt a következő teendőink vannak: adatszótár készítése a Szemely.gdb mintaadatbázishoz, melyet a múlt heti példában készítettünk el. Ehhez szükség lesz a DBPelda alias névre, melynek létrehozását a múlt héten ismertettük.

Ehhez indítsuk el az SQL Explorer-t, kattintsunk a Dictionary fülre, és hívjuk meg a Dictionary/New menüpontot. A megjelenő párbeszédablakban (Create a new Dictionary) töltsük ki a következő értékeket:

Dictionary Name: DBPeldaSzotar
Database: DBPelda
Table Name: BDESDD (ebben a táblában tárolja a rendszer az adatszótár adatait)

Ezután a Database Login ablakban adjuk meg a password-öt (masterkey), és hívjuk meg a Dictionary/Import from Database...menüpontot. A jelszó újabb beírása után válasszuk ki az adatbázist (DBPelda), majd nyomjuk meg az Ok gombot.
Néhány másodperc alatt elkészül az adatszótár. Ha a Databases fülre kattintva most újra megnézzük az adatbázisunk tábláit, láthatjuk, hogy kiegészült egy BDESDD nevű táblával, ami az adatszótár adatait tartalmazza.
Kattintsunk vissza a Dictionary fülre, és nyomjuk meg a Dictionary felirat melletti pluszjelet. A megjelenő Attribute Sets felirat melletti pluszjelre kattintva megjelennek a domain-ek, és azok a mezők, amelyeknek kitöltése kötelező (not null záradék az oszlopdefinícióban).

Ezen cikknek nem célja kimerítő módon tárgyalni az adatszótárak létrehozásának, beállításainak összes lehetőségét, így most csak annyit teszünk, hogy a példa adatbázisunk működéséhez elengedhetetlen beállításokat mutatjuk be.

Mint az előzőekben láttuk, a SZEMELYKOD-mezőt mindkét táblában "not null" záradékkal definiáltuk, mert egyébként nem lehetnének unique kulcsmezők. Ezek az adatszótárba úgy kerültek be, hogy "required" jellemzőjük automatikusan True-ra van állítva, vagyis kitöltésük kötelező. Kattintsunk a SZEMELYEKSZEMELYKOD-ra az attribútumlistában és a megjelenő jellemzői közül a "reguired"-et állítsuk False-ra. Ez azért fontos, mert a személykódot az adatbázis állítja elő a trigger lefutásakor a generátor segítségével, ez pedig az új rekord beszúrásakor (hozzáfűzésekor) aktivizálódik.
Amennyiben a "required"-et nem állítjuk False-ra, akkor a Dephi-alkalmazás "nem engedi tovább" az adatokat az adatbázis felé a személykód kitöltése nélkül, vagyis még a trigger lefutása előtt hibajelzést kapnánk! Kattintsunk a Dictionary-sorra, majd hívjuk meg az Object/Apply menüpontot. Ezzel lementettük az adatszótár összes módosítását.

Ennyi bevezetés után térjünk rá az alkalmazásszerver elkészítésére. A továbbiakban ez az alkalmazásszerver szolgáltatja az adatokat a kliensalkalmazásaink számára.


2. Alkalmazásszerver elkészítése

Az alkalmazásszerverünk egy COM-szerver lesz (Component Object Model). Ez esetünkben egy EXE, amely COM-interfészeken keresztül teszi elérhetővé a szerver szolgáltatásait a kliensek felé. A kliensek felől az adatokat Provider-eken keresztül érhetjük el.

A DCOM-szerver példaprogramunk adatmoduljának elkészítéséhez meghívtuk a Delphi-ben a File/New menüpontot, majd a megjelenő New Items panelen megnyomtuk a Multitier-fület és kiválasztottuk a Remote Data Module-t.

A megjelenő párbeszédablakban meghagytuk az alapértelmezéseket:

Instancing: Multiple Instance (Ebben az esetben minden kliens egy közös adatszolgáltatót fog használni, vagyis a COM szerverünkre egy időben több felhasználó csatlakozhat. Single Instance megadása esetén minden kliens saját szerverobjektumot indít el.)

Threading Model: Apartment (Ebben az esetben a kliens az objektum egy metódusát csak abból a szálból (thread) hívhatja meg, amelyben az objektum létre lett hozva.)

Ezen a távoli adatmodulon elhelyeztünk egy TDatabase komponenst az SQL adatbázisunkhoz való kapcsolódás céljából.
A HandleShared property-t True-ra állítottuk, hogy az egyes kliensek megosztottan tudják kezelni.
Az adatmodulra ráhelyeztünk két TTable komponenst (tblSzemelyek, tblJelentkezes), és mindkettőbe betöltöttük az adatmezőiket perzisztens mezőként.
Az adatmodulra ráhelyeztünk továbbá a MIDAS-palettáról két TDataSetProvider komponenst (dspSzemelyek, dspJelentkezes), mindkét táblához egyet-egyet. A provider-ek (szolgáltatók) DataSet tulajdonságánál megadtuk az egyes táblakomponensek neveit. A provider biztosítja az adatmodul tábláinak a kliensek felőli elérhetőségét.

Most nézzük a TDataSetProvider komponens egyes tulajdonságait (property-jeit):

Constraints (megszorítások, korlátozások)

Igaz érték esetén az adatbázisban és az adatszótárban meghatározott megszorításokat a szerver eljuttatja a kliensalkalmazásokhoz, így ezek ellenőrzése a kliensoldalon helyileg történik meg. Ilyen pl. a SZEMELYEK tábla NEM-mezője, amelynek lehetséges értékeit már az adatbázis elkészítésekor megadtuk.

DataSet:

Annak a táblakomponensnek a nevét adjuk meg itt, amelynek kliensoldali elérését biztosítani akarjuk a provider által.

Exported:

Ha értékét True-ra állítjuk, akkor a provider szolgáltatásai elérhetők a kliensoldalról az IAppServer interfészen keresztül.

Options:

poFetchBlobsOnDemand: True-érték esetén, ha a tábla tartalmaz BLOB-mezőket, azok automatikusan letöltődnek a kliensre, False-érték esetén pedig külön kell lekérni őket a TClientDataSet FetchBlobs metódusával.

poFetchDetailsOnDemand: True-érték esetén Master-detail kapcsolatnál a kliens adathalmaz (TclientDataSet) adatcsomagjába automatikusan bekerülnek a nézettáblák rekordjai is (amennyiben a szóban forgó provider egy master-táblát reprezentál, és a kliens adathalmaz FetchOnDemand property-je True-ra van állítva), egyébként a nézet- (detail) táblák rekordjait a TClientDataSet FetchDetails metódusával kérhetjük le.

poIncFieldProps: True-értéke esetén a kliens adathalmaz adatcsomagjába bekerülnek a provider által reprezentált adattábla mezőtulajdonságai is (Alignment, DisplayLabel, DisplayWidth, Visible, DisplayFormat, EditFormat, axValue, MinValue, Currency, EditMask, DisplayValues).

poCascadeDeletes: Közli a szerverrel, hogy amennyiben a provider által reprezentált tábla egy master-detail kapcsolat master-táblája, akkor ha egy master-rekordot törlünk a táblából, a szerver automatikusan törölje a hozzá tartozó detail-rekordokat. (Amennyiben az adatbázisban a master-detail kapcsolatra vonatkozó hivatkozási integritás-beállítások ezt lehetővé teszik.)

poCascadeUpdates: Közli a szerverrel, hogy amennyiben a provider által reprezentált tábla egy master-detail kapcsolat master-táblája, akkor ha egy master-rekordot módosítunk, a szerver automatikusan módosítsa a hozzá tartozó detail-rekordokat. (Amennyiben az adatbázisban a master-detail kapcsolatra vonatkozó hivatkozási integritás-beállítások ezt lehetővé teszik.)

poReadOnly: A provider által a kliens adathalmaz számára biztosított adatok csak olvashatók (nem tudunk Apply Updates-et alkalmazni).

poAllowMultiRecordUpdates: Több rekordra kiterjedő módosítások engedélyezése a provider által reprezentált táblában.

poDisableInserts: True-ra állítása esetén a kliensalkalmazás nem tud új rekordokat adni a provider által reprezentált táblához.

poDisableEdits: True értékre állítás esetén a kliensalkalmazás nem tudja módosítani a reprezentált tábla adatait. (A beszúrásra és a törlésre nincs hatással.)

poDisableDeletes: True-ra állítása esetén a reprezentált tábla rekordjaiból a kliensalkalmazás nem tud törölni.

poNoReset: True-ra állítása esetén figyelmen kívül hagyja a Reset flag-et, amikor a kliens adathalmaz GetRecords-metódusa végrehajtásra kerül. (gsReset azt biztosítja, hogy a kliens adathalmaz részére leküldött adatcsomag mindig az első rekorddal kezdődik, függetlenül az előzőleg már leküldött adatcsomagok tartalmától.)

poAutoRefresh: True-értéke esetén mindig frissíti a kliens adathalmazt, ahányszor meghívjuk annak ApplyUpdates-metódusát.

poAllowCommandText: True-érték esetén lehetőséget ad arra, hogy a kliensalkalmazásból vezéreljük a provider által a kliens adathalmazba eljuttatott adatcsomagok adattartalmát (pl. az Execute metódussal SQL-utasításokat hajtathatunk végre a provider-rel, és ezek eredményei kerülnek az adatcsomagba).

Példánkban a datamodul-ra rátettünk még egy TDataSource komponenst (dsrSzemelyek) a tblSzemelyek tábla számára. Ez azért szükséges, mert be kell állítanunk egy master-detail kapcsolatot a tblSzemelyek és a tblJelentkezes táblák között.
Ezt meg is tettük, a tblJelentkezes MasterFields property-jéhez pedig beállítottuk a SZEMELYKOD-ot. A tblSzemelyek tábla TDataSetProvider-ének Options tulajdonságai között a poFetchDetailsOnDemand-ot True-ra állítottuk, hogy a kliens adathalmazba bekerüljenek az aktuális master rekordhoz tartozó nézettáblák rekordjai is.
True-ra állítottuk továbbá a dspSzemélyek poCascadeUpdates és poAutoRefresh opcióit is a fent leírtak miatt.

A regisztráláshoz az alkalmazás futtatása előtt Run/Parametes menüpont elindítása után a megjelenő párbeszédablakban a Parameters-beállításhoz meg kell adni a /regserver paramétert, majd a Run paranccsal le kell futtatni a szerveralkalmazást.
A szerver regisztrációjának megszüntetéséhez az /unregserver paramétert kell használni.
Később, a kliensalkalmazások elkészülte után le is ellenőrizhetjük a regisztrációt és a regisztráció megszüntetését, ugyanis a szerveralkalmazásunk /unregserver paraméterrel való lefuttatása után a kliensalkalmazás valóban nem fogja "látni" a szerverünket, míg a fent leírt módon újra nem regisztráljuk.

Ha megnézzük a szerveralkalmazásunk könyvtárát, láthatjuk, hogy a Delphi automatikusan létrehozott a szerverünk számára egy Szerver.tlb típuskönyvtárat és egy Midas_TLB.pas állományt, ami a típuskönyvtár adatai alapján generált típusokat tartalmazza. A Szerver.tlb tartalmaz egy IPeldaSzerver nevű, az IAppServer-ből leszármaztatott interfészt, valamint
egy PeldaSzerver nevű objektumot.
A kliensalkalmazások és csatlakozásra szolgáló komponensek ezt az IAppServer-ből leszármaztatott interfészt használják a kapcsolat felépítésére, valamint a szerver metódusainak meghívására, tulajdonságainak elérésére. (Az IAppServer interfészről és a típuskönyvtárakról bővebb információt a Delphi help-jéből szerezhetünk.)


A TRemoteDataModule metódusai:

A TRemoteDataModule rendelkezik egyrészt védett metódusokkal (ezeket az IAppServer interface-en keresztül hívhatják meg a kliensalkalmazások, a későbbiekben ismertetett egyéb komponensek metódusai segítségével), virtuális metódusokkal, és a szülőosztályokból leszármaztatott metódusokkal.

A fentiek közül a kliensalkalmazásokban használt komponensek által hívható metódusokat és a hozzájuk kapcsolódó eseményeket a későbbi példák során részletesen tárgyaljuk.

Multi-tier cikksorozat