CaIS Tapplication & Delphi OLE/COM InterSystems CACHÉ post-relációs adatbáziskezelõ és ObjectScript alkalmazás futtató Rendszer Objektum Orientált programozása ALKALMAZÁS TECHNOLÓGIÁK II. (DELPHI-OLE-DLL) / Belső használatra! / szerzõdött VAR partner (Value Added Remarketing partner) A dokumentáció változtatásának jogát fenntartjuk. Copyright (C) 2004-2005 Tel. : 06 20/ 441 4882 Fax.: 06 96/ 245 199 e-mail : m-soft@m-soft.hu http\\:www.m-soft.hu
8.4 Alkalmazott Delphi komponenesek (TStoredProc, TQReport) A következőkben bemutatunk egy a mellékelt CD-n is megtalálható cikktörzs karbantartást végző programot, amely teljes OOP jellegű mind terminálos (objectscript) mind Windows (Delphi) környezetben. A létrehozott és módosított törzsadattáblát listázzuk terminálos report kezelővel (CaIS része), valamint SQL tárolt eljárásként definiált query-t hívunk fel Delphi Quick Report segítségével. Cikktörzs karbantartás C-Terminál alkalmazás : A feltelepített adatbázis önmagában is tartalmazza, de különállóan is telepíthető az MD100 routine nevű terminálos (objectscript) program, ami a Master.Article (MMTR globál) adatait kezeli. A programot az MSOFT_PLUS NameSpace-be parancssorba belépve a Do utasítással indíthatjuk : Do ^MD100 A program funkció billentyűi a különféle lekérdezéseket hívják fel. A mintából most nézzük át a ListType lekérdezést. Ez a query a cikktörzset szűri meg a paraméterben megadott mennyiségi egység típus szerint ( esetünkben DB-re). Itt az SQL utasítás az Object Architect-ben kerül tárolás- ra, majd fordításra ; tehát gyorsabb SQL futási időt kapunk, mint ODBC hívásoknál, vagy beágyazott SQL-nél. A lekérdezés futtatásához a már ismert %ResultSet
objektumot használjuk. Ezt követően a listaképet a CaIS listakezelőnek adjuk át. A lista-kezelő biztosítja a lista adataiban történő mozgást és egyéb funkciókat (előrevissza, elejére-végére, lapozás, ablak scrollozás, kijelölés, és nyomtatás ). ODBC SQL tárolt eljárás hívása QuickReport-ban : Bármely CACHÉ lekérdezés kivetíthető SQL tárolt eljárásként is. A query Basic beállításainál adhatjuk meg ezen opciót, fordítás után aktívizálható. A tárolt SQL eljárás mindig public típusú query legyen, máskülömben nem tudjuk felhívni. Fontos ismernünk, hogy az SQL tárolt eljárás, szemben a View-al paraméterezhető, minden kliens eszközzel paraméteráttadással is használható. Bármely további Delphi komponens (DBGrid, Qreport, TListBox, TcomboBox, ) adatforrása lehet. A TstoredProc Delphi objektum használatánál meg kell adnunk a CACHÉ adatbázis nevét, majd a rendszer által felajánlott tárolt eljárások közül ki kell választanunk a megfelelőt. Szintén a Delphi hibája, hogy nem értelmezi jól a CACHÉ objektumok teljes nevét, így hasonlóan az előző fejezetekben írtakhoz a Master objektum osztály megnevezést nekünk kell beírnunk a megnevezés elé. A lekérdezés esetleges paramétereit a Tparams típus szerint adhatjuk meg. A lekérdezés futtatását az Active property Ttue-False értékével tudjuk kapcsolni. Bizonyos esetekben a CACHÉ metódusok is lehetnek tárolt SQL eljárások. Ekkor minden esetben definiálni kell a CACHÉ metódushoz visszatérési értéket (mint függvénynél). A visszatérési érték, mint egy adott algoritmus, függvény végrehajtási státuszát adhatja meg. Olyan számítások és vezérlések végrehajtásánál ajánlott, amelyet mind terminálos, mind Delphi Win32 környezetből futtatni szeretnénk, de nem akarunk SQL triggereket defini- álni. A Quick Report adatforrása
(DataSet) ezen tárolt eljárás lesz. Így a reportra felhelyezett QRBand komponensnél ha a csoportot QRSubDetails nek adjuk meg, definiálhatjuk a DataSet opciót. Ha a tárolt eljárásunk már lefutott a csoportra felhelyezett QRDBText komponenseknél, már a lekérdezés kimeneti mező oszlopai közül választhatunk a DataField propertynél. ODBC elérés MicroSoft Query-vel (Excel) : A Delphi-n kívül használhatunk más SQL kliens szoftvereket a CACHÉ adatok kinyerésére. Ezek közé tartozik a MicroSoft Office csomagban található MS-Query lekérdezés szerkesztő és exportáló program. Az általa lekérdezett adatokat exportálni tudja DDE csatornán kereszt- tül az Office csomag komponenseinek Excel, Access,
A lekérdezés szerkesztővel látványos módszerekkel lehet az egyes táblákat összekapcsolgatni, kapcsolómezőket összehúzni, gyors rendezettségi feltételeket definiálni. Sajnos a paraméterkezelés kissé ügyetlenre sikeredett, némi próbálkozás és saját kudarc után érti csak meg a felhasználó eléggé korlátolt használhatóságát. Vigyázni kell a lekérdezés készítésekor a mintafuttatásokra, amikor a lekérdezés első pár száz adatát tekinthetjük meg mintaként. Tudni illik, hogy ha a lekérdezést Excel táblába akarjuk átexportálni 64000 soradatnál nem tudunk többet kezelni. A valóságban 30000-40000 adatnál az MS-Query nem nagyon bír magával. Összegezve : a látványos lekérdezés szerkesztést gyatra teljesítmény szint teszi korlátozottan használhatóvá. A lekérdezés szerkesztő a lekérdezéseket qdy fájlokban tárolja a következő definíciók szerint: XLODBC 1 DSN=MSOFT_PLUS;SERVER=127.0.0.1;PORT=1972;DATABASE=MSOFT_PLUS;UID=_SYST EM; SELECT Article.kod, Article.nev, Article.me, Article.afa, Article.stdnetto, Article.vtsz, Article.minkesz FROM Master.Article Article WHERE Article.me=? ORDER BY Article.nev M_Egység : 9 kod nev me afa stdnetto vtsz minkesz A? karakter és a 9-es karakterek jelzik a paramétereket, sorrendjük lényeges. Ha tárololt SQL eljárást (CACHÉ query-t) szeretnénk felhívni, akkor a lekérdezés szerkesztőben az SQL utasítás ablakban ezt a CALL hívással tehetjük meg. Fontos tudnunk, hogy a MS-Query képtelen paramétert rendelni a CALL hívással futtatott lekérdezésekhez. Ezt viszont egy egyszerü szövegszerkesztővel utólag beszúrhatjuk az előző mintához hasonlóan a lekérdezés qdy definíciós állományába : XLODBC 1 DSN=RINGA_BCK;SERVER=10.216.9.2;PORT=1972;DATABASE=RINGA_BCK;UID=MSOFT; CALL Query.Arumerleg_ztempcr(?,?,?,?,?) Dátumtól : Dátumig: Csoport: Alosztálytól: Alosztályig: 9 9 9 9 9 Visszatérve az első lekérdezésünkre a paraméterként megadott M_Egység kérdés a lekérdezés futtatásakor dialógus ablakkal hívódik fel, majd a megadott értéket átadva a lekérdezés lefut. A lekérdezést Excel táblába integrálhatjuk, amivel egy adott excel tábla adatfrissítés gombjára kattintva a lekérdezés futni kezd az aktuális adatbázis adatokkal, felkérdezi a paramétereit és a végeredményt a táblázat soraiba szúrja vissza. A paraméterek definiálásánál ügyeljünk a típus kompatibilitásra.
Ha pontosan nem vagyunk tisztában az egyes windows és CACHÉ komponens típusok átjárhatósá- gával, definiáljunk String típusú paramétereket, melyeket a CACHÉ lekérdezés elején konvertálunk a megfelelő formátumra. A lekérdezések belementhetőek az Excel táblákba, biztosítva az adatfrissíthetőséget a későbbiek során. Viszont ha a tárolt SQL eljárást CACHÉ-ban módosítjuk, frissítenünk kell az Excel tábla lekérdezés csatolását is! Lekérdezés minta Excel táblába szúrva. 8.5 Delphi alkalmazás formok és DLL-ek kezelése, (TForm, TDialog) CACHÉ adatbázishoz és objektumokhoz a legoptimálisabb Delphi alkalmazást csak OLE (ActiveX) objektum kapcsolással tudunk írni. Ekkor teljes CACHÉ objektumelérésünk lesz és a legjobb futási időket tudjuk kihasználni. A CACHÉ ODBCn történő Delphi programo- zásakor egyrészt csak adatbáziskezelőt látunk a CACHÉ-ből, másrészt lassú SQL elérésre tudjuk csak használni a CACHÉ-t. Az OLE objektum elérés során a queryket és metódusokat nam tárolt SQL eljárásként hívjuk (mint ODBC elérésnél), hanem függvényként (utasításként), saját objektumként hívhatjuk meg Delphi forráskódban. Az egyes metódusok definiálásánál nagy gondot kell fordítanunk a
metódusok visszatérési értékeire, mivel objektum metódusként-függvényként fogja a Delphi fordító használni. A me- tódusok nevében lehetőleg kerüljük a _ karaktert, mivel ezt a CACHÉ az objektum és metódusnév közé automati- kusan teszi hozzá. Törekednünk kell a felhívandó metódusok hibamentességé- re, mivel az OLE interfész nem rendel- kezik hiba kivételezésekkel. Az esetle-ges hibákat csak a CACHÉ error logjában tudjuk ellenőrizni. Másrészről ezért is fontos a metódus visszatérési értéke ; ugyanis egy hibára futó CACHÉ metódus nem állítja meg feltétlenül a Delphi alkalmazást. Így ha nem kezelünk metódus visszatérési érté- keket (még ha csak futási eredmény státuszra is) egy adott CACHÉ funkcióról nem tudjuk bizonyosan, hogy végrehajtódott-e. Delphi alkalmazás készítésekor a felhasználói interakciókhoz a TForm alapkomponens és TDialog leszármazottját használjuk leggyakrabban. A TForm-ra tertszőleges komponensek helyezhetőek el : menük, adatelérés, képek, multimédia, stb A TDialog ennek némileg korlátozottabb leszármazottja, ahol kezelői inputok valósíthatóak meg, akár adattábla mezőcsatolásokkal, majd meghatározott funkciók indíthatóak el az egyes funkciógombokkal. Alkalmazás készítésekor gyakran felmerül az alkalmazás egyes részeinek önálló módosít-hatósága. Vagyis nem szerencsés az egész alkalmazást egy EXE fájlba fordítani, mivel bármely módosításkor a teljes alkalmazást kell újrafordítanunk. Másfelől a közösen használható funkciók közös könyvtárakba (library) történő szerkesztésével elérhető a kód optimalizálása is. Erre fejlesztették ki a DLL (Dynamic Linking Library) technológiát. A DLL-ekkel készített alkalmazásoknál az EXE program (főprogram) csak akkor indul el, ha az összes hivatkozott DLL rendelkezésre áll (nem feltétlenül töltödik is be!!!), ezekben tárolt kódok csak egyszer kerülnek betöltésre a memóriába, majd az EXE program többször is hívhatja a benne tárolt funkciókat. / Tudatosan nem használom a függvény szót, mivel látni fogjuk, hogy egy DLL-ben metódusok, sőt kivételként akár objektumok is elhelyezhetőek! / Mint említettem akár dinamikusan is szerkeszthetünk DLL-eket, mikor is a DLL nem töltődik be az EXE program hívása előtt a memóriába, hanem csak a belőle meghívott funkció kódja kerül betöltésre futási időben. Ekkor nagy körültekintéssel kell a hívást és paraméteráttadást kezelni, valamint tisztába kell lennünk azzal, hogy a program futása ekkor jóval lassabb lesz. Mikor használjunk tehát DLL technológiát Delphi alkalmazás készítésekor? Ha külömböző alkalmazások vagy alkalmazás részek, ugyanazon DLL-ben tárolt funkciókat hívják, akkor a DLL-ben tárolt kód csak egyszer kerül feltöltésre a memóriába. Ha más alkalmazásokkat is szeretnénk kihasználni a DLL-ben tárolt funkciókat. Akár más fejlesztői eszközzel (Visual Basic, C++, PowerBuilder, ) készített alkalmazások is használhatják ezen komponenseket.
Ha az adott program funkciókat lecserélhetővé (verzió cserélhetővé) szeretnénk tenni. Tehát, ha a paraméterek és hívási interfészek nem változnak, csak a mögötte beprogramozott algoritmusok, akkor a EXE(főprogram) által használt DLL lecserélhető, fejlesztés módosítás során csak az alkalmazás benne tárolt része kerül újrafordításra. Természetesen a DLL-ek készítésének is vannak alapszabályai : Az egyes DLL-ben tárolt és majd hívni kívánt funkciónak szerepelnie kell a DLL Export részében lévő listában, a forráskódot pedig a library deklarációval kell bevezetni (a melléklet MasterDLL library-ja a deklarált export funkciókkal): library MasterDLL; { Important note } uses SysUtils, Classes, Windows, CikkT in 'CikkT.pas' {CikkTDlg}, PrtT in 'PrtT.pas' {PrtTDlg}; exports CikkTForm, CacheConnect, CacheDisConnect; end. A hivatkozott CikkT.pas (CikkTDlg) objektumot tároló unitban az implementation deklarációt megelőzendő el kell helyezni az exportra szánt hívások fejléceit : // extern DLL function declaration procedure CikkTForm; procedure CacheConnect; procedure CacheDisConnect; procedure TCikkUpdate; A hívó programban hivatkozni kell az implementációs részben a funkciót tároló DLL-re és annak elérhetőségére. Az így deklarált funkcó ezekután tetszőleges műveletre, eseményre beprogramozható : implementation {$R *.DFM} procedure CikkTForm; external 'MasterDLLs\MasterDLL.DLL'; procedure TForm1.Cikktrzs1Click(Sender: TObject); begin CikkTForm; end; A formai előírások és szabályok után következzék a meg nem engedett, de mindenki által használt objektumot a DLL-be módszer. Egyfelől alapszabály, hogy a DLL-ben nem lehet objektumot elhelyezni, tehát formot sem. Másfelől lehetne használni, ha függvényként hívnánk fel, és minden tekintetben függvényként viselkedne a formunk. További problémákat okozhat, ha a Delphi-ben kifejlesztett DLL-be fordított formot (mint függvényt) más fejlesztői eszközzel (Visual Basic, C++,..) készített EXE program
hívja fel. A benne tárolt form Delphi módon fog megjelenni kezelődni (hibakezelése is Delphi-s lesz!), de mégis a főalkalmazással kell hogy paramétereket cseréljen. A mellékletben található CikkT.pas állományban deklarált TCikkTDlg formban azt illusztráljuk, hogy egy komplex alkalmazásnál a törzsállományok kezelésével kapcsolatos objektumokat egységbe foglaljuk egy DLL-ben és ezen formok működését is itt programozzuk be. A későbbiek során ha a törzsállományok kezelésében módosításokat kellene eszközölnünk, akkor csak ezen DLL-t kell szerkesztenünk, majd újrafordítanunk. A rend kedvéért megadjuk a CACHÉ adatbázishoz való kapcsolódás metódusát, OLE objektum kapcsolódás definiálását : procedure CacheConnect; begin if constr='' then begin VALT:=CreateOleObject('CacheObject.Factory'); {constr := VALT.ConnectDlg();} constr:='cn_iptcp:127.0.0.1[1972]:msoft_plus'; VALT.Connect(constr); end; Az alkalmazott formunkban a Master.Article objektumból csak 3 mezőt teszünk ki a formra az egyszerűség kedvéért. Az OK gombra programozzuk be az Update metódust, valamint az árucikk kód mezőről történő lelépéskor (EditExit esemény), leellenőrizzük a megadott kód-azonosító létezé- sét az adatbázisban, létezés esetén a kapcso lódó adatmezők kiírását is elvégezzük. A megadott azonosító ellenőrzésére a ListOne lekérdezést használjuk, amelynek eredményessége sorál a ResultSet-be visszakapott mezőértékeket töltjük fel a formra : Itt is ügyelnünk kell a mezők megcímzésénél a mezők sorrendjének sorszámára, amit a lekérdezés Row specification sorrendje határoz meg.
A legproblémásabb része a DLL-ünknek a form működtetése. Ugyanis nem hívhatjuk fel csak úgy egyszerűen a form ShowModal metódusát, mivel a DLL nem inicializálja (nem hozza létre automatikusan) a form objektumát, tehát nincs is ShowModal metódusunk. A form működtetését kivételként kell kezelnünk egy try-except védelmi blokkban. Ezzel védhetjük ki bármely váratlan (unexpected error.) hibát bármilyen kivétel is keletkezzék. Azért kell az összes lehetséges kivételt kezelni, mert ha egy olyan (más fejlesztő eszközzel készített) program hívja fel a DLL-t, ami nem tudja hogy kellene kezelni a felmerülő hibákat, akkor is lekezeltek legyen a hívott form hibái. A formon elvégzett műveleteket pedig a try-finally blokk védi, ezáltal a form objektuma a műveletek végeztével, vagy hiba bekövetkeztével is megsemmisül. Elsőként a try klausát követően utasítanunk kell a form objektumának megkreálására az alkalmazásvezérlőt a TCikkDlg.Create(Application) hívással. Ha nem sikerülne a formunk megkreálása a except blokkban megadott hiba messagebox lesz aktív. Ha létrejön a form, akkor a kezelését követően a finally blokk CikkTDlg.Free metódusával semmisítjük meg a form objektumát. Az alábi foráskódban megpróbáltunk egy általánosan használható sablont adni a formot objektumok DLL-ben történő használatára : A tényleges munkát a ShowModal (mint függvény) visszatérési értékével szelektíven felhívott CACHÉ Update metódus végzi el. Ezt a hívást praktikusan külön eljárásba programoztuk be a későbbi egyszerű karbantarthatóság érdekében, így csak az alábbi CACHÉ object kezelése- ket kell programoznunk :
procedure TCikkUpdate; var TcikkObj:variant; ObjRet:String; begin TcikkObj := VALT.New('Master.Article'); with CikkTDlg do ObjRet:=TcikkObj.Update(KodEdit.Text,CikknevEdit.Text, CikkMEEdit.Text,'',25,'',5); end; Mintapéldánkban néhány paraméternek fix konstans értéket adtunk, ami nem túl elegáns módszer, de gyakorlásnak megteszi. Mint láthattuk a Delphi DLL-ek használatával rugalmasan karbantartható, fejleszthető alkalmazásokat készíthetünk. A példákban pedig láthattuk hogy használhatjuk DLL-be zártan a CACHÉ objektumaink funkcióit OLE technológiával párosítva. Rövid de reméljük érthető négy fejezetes CACHÉ OOP ismeretek birtokában, leendő alkalmazásaink készítésekor hatékonyan használhatjuk ki az InterSystems CACHÉ OOP lehetőségeket a felhasználó fele akár karakteres C-Terminál CaIS, akár Win32 Delphi OLE interaktív formában.