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 :
[email protected] http\\:www.m-soft.hu
Cache & CaIS® 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
Cache & CaIS® 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
Cache & CaIS® (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, …
Cache & CaIS® 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 .
Cache & CaIS® 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
Cache & CaIS® 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 .
Cache & CaIS® •
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 procedure procedure procedure procedure
•
DLL function declaration CikkTForm; CacheConnect; CacheDisConnect; 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
Cache & CaIS® 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 .
Cache & CaIS®
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 :
Cache & CaIS® 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 .