Está en la página 1de 20

Delphi +

ZeosLib

+ Firebird

Instalacin, comentarios y ejemplos de uso

A ZEOS basics tutorial not only for Firebird ...


Author Michael Seeger (ZeosLib Development Team) Date 26.03.2008, 16:01 Views 6143 at 22,03,2010 Description A ZEOS basics tutorial not only for Firebird ... Category Firebird / Interbase Type The ZeosLib DBOs 6.1.5 - With Delphi 7 and Firebird 1.5 This little article shows how

to access Firebird databases by using the ZEOS component Library in version 6.1.5 (including Patches 1&2) and how to use these components in database applications. It does not matter if you use the "real" SQL-Server or the embedded version which is restricted to local held databases. A couple of examples (also migrated Delphi-BDE demos) shall explain how to use the ZEOS components.

Although this article describes the usage of the ZEOS Library using Firebird, all the basics can be used with other SQL servers / databases that are supported by ZEOS. Note: The Firebird Server can be downloaded from download section of http://www.ibphoenix.com http://www.firebirdsql.org

The ZEOS Library


The name "ZEOS" has no special meaning. The founders of ZEOS found that this name just sounded good. Since that time the Library is called "ZEOS". Generally we can say about the ZEOS Library that the developers are inteneded to copy the functions and the behaviour of the corresponding BDE components as good as possible. The intension is to minimize the learning courve for developers who migrate from BDE to ZEOS. Of course there must have been made some compromises so that they are not a hundred percent compatible because the ZEOS components shall be applicable universally. The ZEOS Library in version 6.1.5 consists of the following nine components which shall be introduced in the following: TZConnection TZQuery TZReadOnlyQuery TZUpdateSQL TZTable TZStoredProc TZSQLProcessor TZSQLMonitor TZSQLMetadata

InstallingtheZEOSLibraryandadditionalstuff
TheinstallationoftheZEOSLibraryunderDelphi7professionalisnotthatcomplicated.Oncethecurrent ZEOSversionandallthepatches(whilewritingthisarticleitwaslibraryversion6.1.5andthecorresponding patches1&2)aredownloadedandunzippedintoadirectoryofyourchoicecompletelyyouonlyhaveto followtheinstallationinstructions(note:FirebirddoesnotneedanyadditionalDLL's,here!): OpenthedelphiprojectgroupZeosDbo.bpgfromsubdirectorypackages\delphi7ZeosDbo.bpgandinstall thefollowingcomponentsingivenorder: ZCore.bpl ZParseSql.bpl ZPlain.bpl ZDbc.bpl ZComponent.bpl

Note:Ifthereoccursomeerrorswhilecompilingthatsaythatacertaindcufilecouldnotbefoundthenjust addthesubdirectorypackages\delphi7\buildtodelphislibrarypath.Alldcufilesthatarecreatedwhile compilationarelocatedhere. Attention:TheclientlibraryofFirebirdServerversion1.5.1(notembedded!)wasdeliveredas"gds32.dll" andnot"fbclient.dll".ThiscausestroublewhileaccessingviaZEOSbecausetheprotocol"firebird1.5" aassumesaDLLnamed"fbclient.dll".Aworkaroundistocopythe"gds32.dll"andrenamethiscopyto "fbclient.dll".

Additive:EventAlertercomponent(TZIBEventAlerter) Anadditionalcomponent,thatonlyexistsforFirebird(andalsoInterbase)interceptsall(registered)events, thataretriggeredbyStoredProceduresofadatabase,andmakesitpossibletoreactuponthem.This componentwaspostedbyAlexeyGilev(aka"GAF")intotheZEOSForumandmadeavailabletotheZEOS Team.Theoriginalversioncanbedownloadedhere: http://sourceforge.net/tracker/index.php?func=detail&aid=911233&group_id=35994&atid=415826 TheeventalerterisonlytestedforZEOSversion6.1.4butrunswithsomemodificationswithoutany problemsinversion6.1.5(withPatch1&2).TheeventalerterthatwasportedtoZEOSversion6.1.5willbe installedasfollows(pleaseconsidertheReadMefile!I'mnotgoingtogiveanywarrentythatthissolutionis errorfree!Youuseitatyourownrisk!): DownloadpatchforZIBEventAlerter(integrated)here unzipthefilesanddistributethemtotheaccordingZEOSdirectories ifnecessaryrecompileandreinstallZEOS(seeabove)

Basics:Transactions
SomemandatorybasicsabouttransactionshavetobetoldinordertounderstandhowtheTZConnection componentworksinternallyandhowtoworkwithit. Ingeneral:Youonlycanhaveaccesstoadatabasewithinthecontextofavalid("running")transaction.A transactionhastofulfillthefollowingfourcharacteristicsthatareknownasACIDcharacteristicsofa transaction.

Atomicity Allactionsperformedonadatabasehavetobeexecutedsuccessfully.Ifonlyoneerroroccursthenthe originalstateofthedatabasehastoberestored.Accordingtotheprinciple"allornothing". Consitency Atransaktiontransfersadatabasefromoneconsitentstatetoanotherconsistentstate.Ifanerroroccurs thentheoriginalstateofthedatabasehastoberestored. Isolation Atransactionhastobehandledbytheserverasifitwastheonlyonerunning.Thismeansithastorun indepentlyfromothertransactions.Ausermustnotnoticethechangesdonebyotherusers. Durability ChangesinthedatasetofadatabasethatarecausedbySQLstatementsthatareexecutedbetweenthe startofatransactionandaCOMMIThavetobefixedirrevocably. Transactionsencapsulateconsecutiveaccessesonadatabase.Adatabaseaccessmaybeofreadingor writingnature(INSERT,UPDATE,DELETE)oritmaychangethestructureofadatabase.Transactionsare terminatedbyCOMMITorROLLBACK.COMMITconfirmsallchangesinadatabasesincethestartofa transaction.ROLLBACKresetsallchangesinadatabasesincethestartofatransaction. Transactionsrunningontheserverhavetobeisolatedfromeachother.Sotheymayrunindependently.A transactionhastobehandledbytheserverasitwastheonlyonethatiscurrentlyrunning.Thismeansfor theuserthathemustneverseethechangesofotheruserswhileheisinarunningtransactionbecausethe otherchangeshavenothingtodowithhistransaction.Thisiscalledtheisolationofatransaction.Byusing differenttransactionisolationlevels(TILs)thedevelopermayprotectthedataofanSQLresultsetfrom accessbyothertransactions.Thebehaviourdescribedaboveiscalledthestandardisolationlevelknownas SERIALIZABLE.ThestandardisolationlevelofFirebirdiscalledSNAPSHOTandcomesverycloseto SERIALIZABLE.

TZConnection
TheTZConnectioncomponentisacombinationofaBDETDatabaselikecomponentacomponentthat handlesatransaction.ThiscombinationmakessensebecauseallaccesstoaFirebirddatabase(andalso otherdatabases)isalwaysmadeinarunningtransaction.SuchatransactionisstartetbytheZEOSLibrary wheneveraconnection(methodConnectofTZConnection)toadatabaseisopened.Thiscausesthateach databaseaccessisdonewithinthecontextofarunningtransaction,automatically.Thesocalled AutoCommitmodeisalwayson(setto"True").ThisisalsothestandardbehaviourofthecorrespondingBDE component.IfAutoCommitisactivatedtheneverychangeofanSQLstatementwillbeconfirmedinthe databasebyCOMMITateritssuccessfullexecution.Ifthisbehaviourshallbeturnedoffandanexplicit transactionshallbestartedthenthemethodStartTransactionhastobecalled.Withinthisexplicittransaction itispossibletoexecuteacoupleofSQLstatementsthatmakechangestothedatabase,insuccession. Thesestatementsthencanbeconfirmedasa"group"byCOMMIT.Ifanexplicittransactionisactivethen AutoCommitisalwaysturnedoff.ByCallingtheMethodCommitallthechangesmadewithinthisexplicit transactionareconfirmed.CallingthemethodRollbackresetsthesechanges.InbothcasesAutoCommitwill besettoTruewhenthemethodcall(CommitorRollback)isdone.Theexplicittransactionhasended.

Retaining AfterconfirmingthechanesmadeinatransactionbyCOMMITorresettingthembyROLLLBACKthe transactionnormallyisgoingtobeendedandanexistingresultsetofaqueryorstoredprocedurewillbe discarded.TheseCOMMITsandROLLBACKsarecalled"hard"commitor"hard"rollback.Byusingthe ZEOSlibrarythiswillbecomealittlebitdifferent.ZEOSkeepstheresultsetalive.Thisisachievedbyclosing transactionwith"soft"commitsor"soft"rollbacks.AllthisisdonebytheTZConnectionobject.Thismethodis

calledretaining.TheCOMMITandROLLBACKcommandsareexecutedwiththeadditionRETAINING. Retainingcausestheclosingofthecurrenttransactionandimmediatelyopeninganewtransactionwithall thedataandresources(especiallytheresultset)ofthe"old"transaction. Retainingbecomesaproblemifitisusesforhugetables.Itconstrainstheinternalcleanupmechanismof firebird(garbagecollection).Thisleads(becauseoftheversioningandthemultigenerationalarchitectureof Firebird)toalotofoldrecordsthathavetobekeptbutwillnotbeneededanymore.Thisinfluencesthe server'sperformancedinanegativeway.Asocalledsweepwoulddiscardtheseoldversionsandimprove theperformance.Thissweepwillonlybeexecutedbysendinga"hard"COMMITorROLLBACK.TheZEOS Libraryonlyexecutesthese"hard"commandswhenendingthedatabaseconnection(closingconnection).It isnotpossibletosendthemwhileadatabaseconnectionisactive.Sothedatabaseconnectionshouldbe deactivatedandimmediatelyactivatedoccasionallytoachievethisperformanceimprovement.

TransactionIsolationLevelsofTZConnection TheTZConnectioncomponentprovidesfourusefulandpredefinedTransactionIsolationLevels(TIL): tiRepeatableRead ItcorrespondstotheTIL"SNAPSHOT"whichisthestandardofFirebirdservers.Itisacombinationofthe trasactionparameters"concurrency"and"nowait".Asnapshotofthecurrentdatabaseismade.Otherusers areonlyinfluenced(constrained)iftwotransactionsworkononerecordsimultaneously.Ifconflictsarise whileaccessingdataanerrormessagewillbereturned.Changeswithinothertransactionswillnotbe noticed.ThisTILcoverstherequirementoftheSQLstandard(SERIALIZABLE)widely. tiReadCommitted ItcorrespondstotheTIL"READCOMMITTED".Itisacombinationofthetransactionparameters "read_committed","rec_version"and"nowait".ThisTILrecognizesallchangesinothertransactionthathave beenconfirmedbyCOMMIT.Theparameter"rec_version"isresponsibleforthebehaviourthatthemost currentvaluesthatwerecommittedbyotheruserswillbeconsidered.theparameter"nowait"isresposiblefor thebehaviourthatthereisnowaitingforthereleaseofalockedrecord.Sotheserverismorestressedthan inTILtiRepeatableReadbecauseithastodoalltherefreshestogetthesevaluesagainandagain. tiSerializable ItcorrespondstotheTIL"SNAPSHOTTABLESTABILITY".Itisusedtogetanexclusiveaccesstotheresult set.Realizedbytransactionparameter"consistency"itpreventsthat"foreign"transactionmayaccessthe writtendata.Onlythetransactionwhichhaswrittenthedatamayaccessthem.Thispreventsalsoamulti useraccesstothewrittendata.BecausethisTILisveryrestrictivebyaccessingwrittendataitshouldbe appliedwithcautionandcare. tiNone NoTILisusedtoisolatethetransaction. TheTILtiReadUncommittedisnotsupportedbyFirebird.IfthisTILisused,anerrorwillbetriggerdedand thetransactionwillnotbeisolated(likeusingtiNone). Recommendation ItisadvisabletoisolatetransactionswithtransactionisolationleveltiRepeatableRead(theFirebirdstandard). ThisTILcoverstherequirementoftheSQLstandard(SERIALIZABLE)widely.Itpreventsallproblems concerningconsistencythatmayarisebyusingtransactions.SecondchoicewouldbetiReadCommittedbut thisdependsontheapplicationandthenecessityifthereseultsetalwayshastobecurrent.

CustomizingTILs IfyouwanttocustomizeyourTILsorexpandagivenTILthenyoucandothisbyusingtheparametersof TZConnection.ThemostimportantthingaboutthisisthattheTILthatshouldbeexpandedhastobesetin propertyIsolationLevel.IfitissettheTILparameters(seeIB/FBAPIreference)youwanttoaddmaybe addedinsourcecode.ThefollowingexampleshowstheexpansionofaTILpresettotiNone: : ZConnection.TransactIsolationLevel := tiNone; ZConnection.Properties.Add('isc_tpb_concurrency'); ZConnection.Properties.Add('isc_tpb_wait'); ZConnection.Connect; :

Protocol ThemostimportantsettinginaTZConnectionobjectistheserverprotocolitissetinpropertyProtocol.It determineswhichprotocolshallbeusedandthuswhichSQLserverwillbeaccessed.Thismethodmakes ZEOSsoflexible.Youdon'thavetoinstallspecialcomponentsforeachdatabaseyouwanttoaccessasit wasinVersions5.xandearlier.Thecomponentswillbeinstalledonce.Thisisenough.Youonlychoosethe protocolforthesupportedSQLserveryouwanttoaccessandyouaredone.Soyousetprotocol"firebird 1.5"toaccessFirebird1.5server. ReadOnlyConnection ThedatabaseconnectionmaintainedbyaTZConnectionobjectissettoreadonlybydefault(ReadOnly= True).Thismeansthatnowritingaccesstotheconnecteddatabaseisallowed.Togetwritingaccesstothe databaseyouhavetosetReadOnlytoFalse. Codepages Codepageswillbedeterminedbysettingparameter"lc_ctype"or"Codepage"inTZConnection.This parametermustbeaddedtothepropertyProperties.E.g.: ZConection.Properties.Add ('lc_ctype=ISO8859_1'); or ZConnection.Properties.Add ('Codepage=ISO8859_1');

Note:TheCodepagesupportofFirebird(alsoembeddedversion)inversion1.5withZEOSisalittlebit buggy.ThesebugsarecorrectedinFirebirdversion1.5.1. FeaturesoftheFirebirdembeddedserver NormallytheservernameorIPaddressoftheserverisgiveninpropertyHostName.ByusingaFirebird embeddedserveryoumayleavethispropertyempty.OnlypropertyDatabasehastobedetermined.Here youhavetospecifydrivepathandnameofthedatabaseincludingextension. Anotherfeatureoftheembeddedserveristhatyoumayspecifyanyloginnamewithapaswordofyour choice.Itdoesn'tmatterwhatyouchooseyouwillgetconnected. SettingtheTZConnectionobjectpropertyConnectedtoTrueindesigntimeisextremelybadifyoudon'treset

ittoFalsebeforecompiling.IfyouthenstartthecompiledapplicationwithIDErunningyouwillgetanerror thatsaysthatthedatabasecannotbeopenedbecauseitisalreadyinuse.Soyoushouldestablishthe connectiontothedatabasewhenstartingtheapplication(e.g.inOnCreateeventofthemainform)andthen opentheneededqueriesandtables.Deactivatingtheconnectionshouldalsobedoneinmainform(e.g.in OnDestroy).Itisnotnecessarytocloseallopenqueriesandtables.Thiswillbedonewhenclosingthe connectionoftheTZConnectionobject.Ifyouusedatamodelformsyouhavetotakecarethatthedatamodel formiscreatedbeforethemainformiscreated(setintheIDE'sprojectoptions).. UsefulTZConnectionparameters AdditionalparametersforestablishingconnectionstoFirebirddatabasesare:: CreateNewDataBase: AnewdatabasewillbecreatedbasedonthespecifiedCREATEDATABASEstatements.Whenthedatabase iscreatedtheconnectionwillbeestablishedimmediately.AllthishappensbycallingtheConnectmethodof TZConnection. : ZConnection1.Database := 'd:\db1.fdb'; ZConnection1.Protocol := 'firebird-1.5'; ZConnection1.Properties.Add ('CreateNewDatabase=CREATE DATABASE ' + QuotedStr ('d:\db1.fdb') + ' USER ' + QuotedStr ('sysdba') + ' PASSWORD ' + QuotedStr ('masterkey') + ' PAGE_SIZE 4096 DEFAULT CHARACTER SET ISO8859_1'); ZConnection1.Connect; :

ToexecutethiscorrectlyyouhavetosettheDatabaseandProtocolpropertiesatminimum(alsopossiblein objectinspector). Dialect: ThisparametersetsFirebird'sSQLdialiect.Tosetdialect"1"youhavetousethefollowingcode: ZConnection.Properties.Add ('Dialect=1');

ThedialectofFirebird1.5.xissetto"3"bydefault. Rolename: Thisparametersetsarolename.Aloggedinuserthenworksinthecontextoftherole'srightsbutbeforethe userhastobeassignedtothisrole.TheFirebirdembeddedserverdoesnotsupportthisfeature.

TZQuery
TheusageofTZQueryissimilartotheusageofBDE'sTQuerycomponent. Recommandation:RequestLiveandTZUpdateSQL IfanSQLdatasetshallbeupdatablethenRequestLivehastobesettotrueandyoushouldgenerallyuse accordingupdateSQLstatementsthatwillbedefinedinTZUpdateSQL.Ifthisisdonejustassign TZUpdateSQLtotheTZQueryobject.Nowallchangesthatwillbemadeintheresultsetwillbedonetothe databasebyusingthedefinedstatementsofTZUpdateSQL.AccordingtoexperienceRequestLivemode runsmoresmoothlybyusingTZUpdateSQL.

UsageofparametersinSQLstatements UsingparametersinSELECTstatmentsisaseasyasusingthemwithBDE'sTQuery.IfTZQueryhasa resultsetthenyouhavetousetheOpenmethod.IfyouwanttoexecuteanSQLstatementwhichhasno resultset(e.g.:INSERTorUPDATE)youhavetouseExecSQL(seealso:TZStoredProc).

TZReadOnlyQuery
ThisisaQuerycomponentthatisquitesimilartotheTZQuerycomponent.Thereisjustonedifference:The resultsetisreadonly.ThereisnopossibilitytoassignaTZUpdateSQLobject.

TZUpdateSQL
ATZUpdateSQLobjectprovidesstatementstomodifythedataofaresultsetthatisretrievedbyaTZQuery object.TheTZUpdateSQLcomponentiscomparabletoBDE'sTUpdateSQLcomponent.Hereisanexample howtodefinethestatementsofanSQLstatementwithcorrespondingupdatestatements(basedonadialect 3database): SQL.Sql: SELECT * FROM names UpdateSQL.InsertSql: INSERT INTO names (recno, name) VALUES (:recno, :name) UpdateSQL.ModifySql: UPDATE names SET recno = :RecNo, name = :name WHERE recno = :old_recno UpdateSQL.DeleteSql: DELETE FROM names WHERE recno = :old_recno

The"OLD_"parameterprefixforSQLstatements The"old_"prefixishandledaccordingtothehandlingwithBDEcomponents.Byusing"OLD_"asprefixfora fieldnameyouareabletoaccessthevalueofthefieldbeforeitwaschanged.Thisisveryhelpfulifyouhave tocomparefieldvaluesinaWHEREclause. Querieswithreadonlyresultsets IngenealaTZUpdateSQLobjectisassignedtoaTZQueryobjectthathasareadonlyresultset.Thismakes itpossibletochangeitsdata.Suchreadonlyqueriesarequeriesthatjoinmultipletables.Butalsowith "normal""RequestLive"resultsetsyoumayuseTZUpdateSQL(see:TZQuery).

MultiplestatementsinTZQueryandTZUpdateSQL ThecomponentsTZQueryandTZUpdateSqlprovidethepossibilitytoexecutemultiplestatements,internally. SoitispossibletoplacemultipleSQLstatements(evenwithparameters)forexecutioninSQLproperty. Theyonlyhavetobeseparatedbysemicolon.Hereanexample: : With Query do Begin Sql.Clear; Sql.Add('DELETE FROM table1;'); Sql.Add('INSERT INTO table1 VALUES (:Val1, :Val2);'); Sql.Add('INSERT INTO table2 VALUES (:Val3, :Val2);'); Sql.Add('UPDATE table3 SET field1 = :Val4;'); Params.ParamByName('Val1').AsInteger := 123; : ExecSql; End; :

Thestatementswillbeexecutedingivenorder.Itisalsopossibletoexecutemultiplestatementsiftheyare groupedinthismannerinsidemultipleTZUpdateSqlObjectsinordertoupdatemultipletables.

TZTable
TZTableactslikeBDE'sTTable.AsaprincipleyouonlyshoulduseTZTableinaC/Sapplicationifyouhave verysmalltablesbecauseallrecordsofthetablewillbetransferredfromserverintoclient'smemoryby openingtheTZTable.Thisisabahavioursimilartoa"SELECT*FROMXYZ"statement.Youshouldeven preventastatementlikethisinaC/Sapplication.Theintensionistokeeptheresultsetthathastobe transferredfromservertoclientassmallaspossible(perferablyonleonerecord).

TZStoredProc
TZStoredProcprovidesthepossiblitytoexecutestoredproceduresthataresavedinadatabase.Thereare twokindsofstoredprocedures:Proceduresthatreturnaresultsetandproceduresthatdonotreturna resultset.TZStoredProcworkssimilartoBDE'sTStoredProc.Theonlydifferencebetweenthemisthatyou don'thavetocallPreparebeforeyoucalltheExecProcmethod. StoredProcedureswithResultsets IfastoredprocedurereturnsaresultsetthenitwillbeactivatedbycallingtheOpenmethod(whenall existingparametershavegottheirvalues): : With spSumByName do Begin Close; ParamByName ('Name').Value := 'DontKnowHow'; Open; End; :

TheresultsetcanbeworkedonlikearesultsetofaTZQuery.

StoredProcedureswithoutResultsets IfastoredprocedurehasnoresultsetthenitwillbeexecutedbycallingtheExecProcmethod(whenall existingparametershavegottheirvalues).Hereisanexample(conConnection.AutoCommit=True): : With spDeleteByName do Begin ParamByName ('Name').Value := 'DontKnowHow'; conConnection.StartTransaction Try // execute StoredProc ExecProc; Except conConnection.Rollback; End; conConnection.Commit; End; :

Attention :BuginZEOSLibraryV6.1.5! IfastoredprocedurewasexecutedviaExecProcatleastonetime,anexceptionwillbetriggeredwhen disconnectingTZConnection(usedbyTZStoredProc)fromdatabase.Exception'sMessageis:"invalid statementhandle".SQLerrornumberis901.ThisExceptionwillnotbetriggeredifthestoredprocedureis executedusingaTZQueryorTZReadOnlyQuery.Executionofthestoredprocedurewillbedonebycalling theprocedureusingthefollowingSQLcommand(putintotheSQLproperty): [syntax="sql"]EXECUTEPROCEDUREDeleteByName(:Name)[/color][/font][/list] ExecutingastoredprocedurethiswayissimilartoexecutioninTZStoredProc(conConnection.AutoCommit= True): : // using a TZQuery object With qryDeleteByName do Begin ParamByName ('Name').Value := 'DontKnowHow'; conConnection.StartTransaction Try ExecSQL; // execute SQL statement in TZQuery Except conConnection.Rollback; End; conConnection.Commit; End; : Info:Evenwithadialect3databaseitisnotneededtoputthenameofthestoredprocedureintoquotation marksNamesofstoredproceduresinFirebirdarenotcasesensitive. ProblemswithTZStoredProcwhenusingdialect1databases Theproblemwhenusingdialect1databasesisthatthemetadataofstoredproecedureisnotproperly transferredtotheTZStoredProcobjectswhenchoosingthestoredprocedureinobjectinspector.All parapeterdataisnotproperlyinterpreted.Anupdatefromdialect1todialect3solvesthisproblem.Isthe dialect1databasevitalfortheapplicationsystemthenaTZQueryorTZReadOnlyQueryhastobeusedas workaround.

TZSQLProcessor
ThiscomponentprovidesthefunctiontoprocessSQLscriptsthatcanbeloadedbycallingthemethods LoadFromStream()orLoadFromFile().TheloadedSQLScriptisputintoanaccordingpropertycalledScript. Importanisthatthecorrectdelimiterforthescriptisset(PropertyisalsoDelimiter).Bydefault";"willbeset asdelimiter.Thisissufficientforthemostscripts.Butifyouwanttocreatestoredproceduresortriggersvia scriptyoushouldsetdelimiteraccordingtothesettingofthescript's"SETTERM>newDelimiter< >oldDelimiter<"command(normally"^"isusedforthis).InadditiontothisthepropertyDelimiterTypehasto besettodtSetTerm.HeresomelinesofcodethatshowhowtoprocessanSQLscript: : sqlScript.Script.Clear; sqlScript.LoadFromFile('c:\temp\createdb.sql'); conConnection.StartTransaction; Try sqlScript.Execute; Except conConnection.Rollback; End; conConnection.Commit; : TheSQLscriptisprocessedwithinanexplicittransaktion(AutoCommitisturnedon).Ifexecutionsucceeds thechangeswillbecommittedotherwisetheywillberolledback.

TZSQLMonitor
UsingtheTZSQLMonitorcomponentyoumaylogcertainactionsoreventsoftheZEOSdatabase components.ThejournalmaybewrittenasfileorcollectedinaTMemoobjectorsomethinglikethat. Writingtheactionsoreventstoalogfileonlyneedsafewsettings: : sqlMonitor.FileName := 'C:\Log\MyAppLog.log'; sqlMonitor.Active := True; sqlMonitor.AutoSave := True; : TocollecttheloggedactionsoreventsinaTMemoobjectyouhavetoimplementtheOnLogTraceeventas follows: Procedure Tfrm_MyApp.sqlMonitorLogTrace (Sender: TObject; Event: TZLoggingEvent); Begin If Trim (Event.Error) > '' Then memMontor.Lines.Add (DateTimeToStr (Event.Timestamp) + ': ' + Event.Message + #13#10 + ' Error: ' + Event.Error) Else memMontor.Lines.Add (DateTimeToStr (Event.Timestamp) + ': ' + Event.Message); End; // sqlMonitorLogTrace TheOnLogTraceeventisalwaystriggeredwhenanactionoreventwasloggedbysqlMonitor.LogEvent (oEvent).TheoEventparameterstandsforaninstanceofaTZLoggingEventclassobject.

PropertiesofTZLoggingEvent Category(TZLoggingCategory):Standsforthecategoryoftheloggedactionorevent(lcConnect, lcDisconnect,lcTransaction,lcExecuteorlcOther) Protocol(String):Theprotocolthatisusedtoaccessthedatabase(see:TZConnection) Message(String):Thetextthatislogged. ErrorCode(Integer):Theerrorcodeincaseofanerror. Error(String):Theerrortextincaseofanerror. Timestamp(TDateTime):Dateandtimeoftheloggedactionorevent.

TZSQLMetadata
WiththisspecialTDataSetcomponentitispossibletoaccessthemetadataofadatabaseliketables, columns,etc.(Thischapterisstilltobeexpanded!)

TZIBEventAlerter(AddOnonlyforFirebirdandInterbase)
ByusingthiscomponentyouareabletointercepteventstriggeredbystoredproceduresofaFirebird databaseandreacttothem.Youonlyhavetoregistertheevent'stext(string)youwanttoreacttoinproperty Eventswhichisastringlist.Youcandothisusingobjectinspectororinsidethesourcecode.Theeventalerter isactivatedbyregisteringthelistedevents.TodothisyoushouldcalltheRegistereventsmethodbecause thePropertiesAutoRegisterandRegistereddonotworkproperly.Ifyouoncehaveregisteredtheeventsthe componentisabletoreacttothem.Alleventsareunregistered(deleted)bycallingmethodUnregisterEvents andtheeventalertetisturnedoff. Registrationofeventsand"activation"oftheeventalerter: : EventAlerter.Events.Add ('Minimum Stock Level Reached'); EventAlerter.Events.Add ('Credit Limit Exceeded'); EventAlerter.RegisterEvents; :

Master/DetailwithZEOSLibrary
ZEOSDataSetcomponentscomewithtwokindsofmaster/detailconnections:thosewithaserversidedfilter andthosewithaclientsidedfilter.BothkindsandonekindinadditiointhatisindependentfromZEOS(and thuswithoutanycomfort)willbedescribedhere. Note:Ifwetalkabout"master"or"detail"thenaTDataSetdescendant(TZQuery/TZReadOnlyQuery, TZTableoraTZStoredProc)ismeantthataccesseseitheramasterresultsetoradetailresultsetofa master/detailconnection.

Master/Detailwithserversidedfilters ThismethodisthedefaultbehaviouroftheBDE'sTQuerycomponent.Amaster/detailconnectionoftwo DataSetsisestablishedasfollows: Themaster'sDataSourceisassignedtotheDataSourceofthedetail. Allprimarykeyfieldsofthemasterhavetobecomparedwiththeforeignkeyfieldsofthedetailinthe detailSQLstatement.

Thisisanexampleforasimplemaster/detailqueries.Requirement:WeuseTZQueryorTZReadOnlyQuery toestablishthemaster/detailconnection: MasterSQL: SELECT id, feld1, feld2, feld3 FROM master [*]DetailSQL: SELECT feld1, feld2, master_id FROM detail WHERE master_id = :id Parameter:idstandsforthecontentofmaster's"id"field(istheprimarykey)becausethemaster's DataSourceisassignedtothepropertyDataSourceofthedetail.Sothisparameterreferencestothe"id" fieldofthemaster.Therield"master_id"indetailqueryistheforeignkeyfieldofthedetailtablewhich referencestheprimarykeyofthemaster. Ifthecursorofthemasterchangesitspositionwhileserversidedfiltersareused,theSQLstatementofthe detailisexecutedusingthecurrentkeyvalues.Sotheresultsetofthedetailisautomaticallyrefreshed. Master/Detailwithclientsidedfilters ThisisthedefaultbehaviourofaBDETTablecomponent.Hereamaster/detailconnectionbetweentwo DataSetsisestablishedasfollows: TheDataSourceofthemasterisassignedtothepropertyMasterDataSourceofthedetail. TheprimarykeyfieldsofthemasterareassignedtopropertyMasterFieldofthedetail. Theforeignkeyofthedetailwhichreferencestheprimarykeyofthemasterisassignedtopropety IndexFieldNames.

Thisisanexampleforasimplemaster/detailqueries.Requirement:WeuseTZQueryorTZReadOnlyQuery toestablishthemaster/detailconnection: MasterSQL: SELECT id, feld1, feld2, feld3 FROM master DetailSQL: SELECT feld1, feld2, master_id FROM detail WHERE master_id = :id Parameter:idstandsforthecontentofmaster's"id"field(istheprimarykey)becausethemaster's DataSourceisassignedtothepropertyDataSourceofthedetail.Sothisparameterreferencestothe"id"

fieldofthemaster.Therield"master_id"indetailqueryistheforeignkeyfieldofthedetailtablewhich referencestheprimarykeyofthemaster. Ifthecursorofthemasterchangesitspositionwhileserversidedfiltersareused,theSQLstatementofthe detailisexecutedusingthecurrentkeyvalues.Sotheresultsetofthedetailisautomaticallyrefreshed. Master/Detailwithclientsidedfilters ThisisthedefaultbehaviourofaBDETTablecomponent.Hereamaster/detailconnectionbetweentwo DataSetsisestablishedasfollows: TheDataSourceofthemasterisassignedtothepropertyMasterDataSourceofthedetail. TheprimarykeyfieldsofthemasterareassignedtopropertyMasterFieldofthedetail. Theforeignkeyofthedetailwhichreferencestheprimarykeyofthemasterisassignedtopropety IndexFieldNames.

WithclientsidedfiltersbothDataSetsfirsttransferalltablerowsfromservertoclient.Thedetailthensetsa filter(onclientside)togetthedetailsaccordingtothecurrentmasterrecord. Incaseofcreatinganewdetailrecordforamaster/detailconnectionwithaclientsidedfilterthereisakindof automatism:TheForeignkeyfieldsofthedetail(setinpropertyIndexFieldNamesofthedetail)willbefilled automaticallywiththeaccording(current)primarykeydataofthemaster(setinpropteryMasterFieldofthe detail).Note:Withserversidedfiltersyouhavetocareaboutthisfunctionality,manuallyinyourprogram's code.ThiscanbeachievedbyimplementingtheOnNewRecordeventofthedetail.Thiseventisalways triggeredwhenannewrecordistobecreated(see:DelphionlinehelpforTDataSet).AccordingtotheSQL statements,definedaboveyouonlyhavetoimplementthefollowing: Procedure dmMasterDetail.qryDetailNewRecord (DataSet: TDataSet); Begin qryDetailMASTER_ID.Value := qryMasterID.Value; End; CorrespondingTFieldswerecreatedforthefields"master_id"ofthedetailand"id"ofthemasterusingthe fieldeditor. Formaster/detailconnectionsinZEOSthereisanadditionaloptionthatissetinpropertyOptions:Itis doAlwaysResyncDetail.Ifthisoptionissetthentheresultsetofthedetailisonlyrefreshedwhenpostis calledorarecordchanges(bothwithinmasterDataSet). Master/Detail"byhand" Normallyyouimplementamaster/detailconnectionaccordingtothemethodusedbyserversidedfilters.The SQLstatementsforthislookexactlylikethat.Onlythepropertiesthataresetinmasteranddetail(see above)willnotbesethere.BothTZQuerisareworkingindependently.Thismeans:ThedetailDataSetdoes notrecognizeanychangesinmasterDataSet.Itssynchronzationhastobeimplemented,manually.Thiswill bedoneintheOnChangeeventofthemaster.OnChangeistriggeredwhenchangingtoanewrecordor fielddatahasbeenchanged(see:DelphionlinehelpforTDataSource).Synchronizationofthedetail (accordingtotheexampleabove)wouldbeimplementedlikethis: Procedure dmMasterDetail.dsMasterDataChange ( Sender: TObject; Field: TField); Begin With qryDetail do Begin Close; ParamByName('id').Value := qryMasterID.Value; Open; End; End;

ThisisthesamefunctionthatZEOSexecutesautomaticallywhenusingserversidedfilters:Thedetailquery isexecuted(agin)withthecurrentIDvalueofthemasterwhichwillbeassignedtoparameter":id"inthe detailquery.Sotheresultsetofthedetailwillberefreshedaccordingtothecurrentmasterrecord. IfanewrecordshallbecreatedindetailDataSetthenyouhavetoactthesamewayaswithserversided filters(seeabove).

CachedUpdates
ThedevelopersoftheZEOSLibraryareintendedtoimplementthefunctionalityoftheBDEcomponentsas goodaspossible.ThisiswhythereisalsothepossibilityofcachedupdateswithZEOS.Youonlyhavetoset thepropertyCachedUpdatesofaDataSetdescendant(TZTable,TZQueryoderTZStoredProc)totrue.From thistimeonallchangesintheresultsetwillbecachedandtheycanbeeasilycommittedtothedatabaseby callingApplyUpdatesandCommitUpdatesoneaftertheothereitherautomaticallyinyourprogramcodeor triggeredmanuallybyauser.CancelUpdatescausesthatthecangeswillnotbecommittedtothedatabase. Inthiscaseallcachedchangeswillbereset(likeusingaROLLBACK).Hereyouwillfindalittlecodesnippet thattriestoshowyouhowcachedupdatesareimplemented(don'targueaboutthesenseinthis...). AutoCommitmodeofTZConnectinisturnedon(True): : With DataSet do Begin bEverythingOK := True; CachedUpdates := True; DataSet.First; While (not DataSet.EOF) and (bEverythingOK) do Begin DataSet.Edit; : // process record : DataSet.Post; DataSet.Next; : bEverythingOK := AFunctionForValidation; End; If bEverythingOK Then Begin ApplyUpdates; CommitUpdates; End Else CancelUpdates; CachedUpdates := False; End; :

BLOBFields
AccordingtoBDE'scomponentsthecomponentsoftheZEOSLibraryarecapableofhandlingBLOBfields. HereisanexamplehowanewrecordwithaBLOBfieldiscreated.TheBLOBfieldisfilledwithabitmap.To achievethiswehavetouseaStream: : Var TheStream : TMemoryStream; Begin TheStream := TMemoryStream.Create; Try Image1.Picture.Bitmap.Savetostream(TheStream); With qryBlobInsert do Begin Sql.Text := 'INSERT INTO EVENTS (EventNo,EVENT_PHOTO) ' + 'VALUES (100,:ThePicture)'; Params.Clear; Params.CreateParam(ftBlob,'ThePicture', ptInput); ParamByName('ThePicture').LoadfromStream(TheStream,ftBlob); ExecSQL; End; Finally TheStream.Free; End; End; : Thissectionaboutblobfieldsisnotcompleted,yet.PleasefeelfreetosendmeaprivatemessageoreMailif youhaveanyissuesaboutblobsinordertoexpandthissection.

Sampleproject:"EasyQuery"
TopreventbeingtootheoreticalnowwewillcreateasmallsampleprojectthodemonstratehowtheZEOS componentsareusedingeneral.Wewillcreateasmallapplicationthataccessesthetables"Customer"and "Country"oftheFirebirdsampledatbase"Employee".Youshouldbeabletonavigateintable"Customer" andedititsdata.AndnotbeintooboringwewillimplementaDBLookupComboboxforfield"Country"intable "Customer".Thisfieldisaforeignkeythatreferencestofield"Country"intable"Country". Solet'sgetstarted! FirstofallwehavetocreateanewprojectinDelphi.Additionalytothedefaultformwehavetocreatea DataModule. ThefollowingpropertiesoftheDataModulehavetobeset: Name:dmEasyQuery ComponentsfortheDataModule

TZConnection Database:Employee.fdb Name:conEmployee Password:"password" Protocol:firebird1.5 ReadOnly:False TransactionIsolationLevel:tiReadCommitted User:"username"

TZQuery Connection:conEmployee Name:qryCustomer RequestLive:True SQL:SELECT*FROMcustomerORDERBYcustomer UpdateObject:updCustomer

Note:YouhavetocreatepersistentTFieldsforalltablefieldsusingthefieldeditor! TheOnAfterPosteventofqryCustomerwillbeimplementedlikethis: procedure TdmEasyQuery.qryCustomerAfterPost(DataSet: TDataSet); begin // Refresh of resultset to actualize (sort) data shown in DBGrid. qryCustomer.Refresh; end;

TZReadOnlyQuery Connection:conEmployee Name:roqryCountry SQL:SELECTcountryFROMcountryORDERBY1

Note:YouhavetocreatepersistentTFieldsforalltablefieldsusingthefieldeditor! TZUpdateSQL DeleteSQL:createdbyUpdateSqleditor InsertSQL:createdbyUpdateSqleditor ModifySQL:createdbyUpdateSqleditor Name:updCustomer

Thedelete,insertandmodifyStatementsfortheTZUpdateSQLobjectarecreatedwiththeUpdateSQL editor,automatically.TheeditorwillbeactivatedbydoubleclickingontheTZUpdateSQLcomponent.Askey fieldyouhavetoselectthefieldCUST_NO.ThefieldsADDRESS_LINE1,ADDRESS_LINE2, CITY,STATE_PROVINCE,COUNTRYundPOSTAL_CODEwillselectedasupdatefieldsinlist"Update

Fields".Nowthestatementswillbegeneratedbyclickingbutton"GenerateSQL".Ifyouonlyhavesucheasy queriesyoucansavealotoftypingbyusingtheUpdateSQLeditor.Ifitgetsalittlemorcomplexyoushould createtheneededstatements"byhand".

TDataSource DataSet:sqlCustomer Name:dsCustomer

TDataSource DataSet:rosqlCountry Name:dsCountry

NowthecreatedDataModulewillbesavedasdm_EasyQuery.pas.[/list] Componentsfortheform

Themainformwillhavethefollowingcomponentsandisinitializedasfollows: Properties Caption:EasyQueryDemo Name:frmEasyQuery IntheUnit'sinterfaceyouhavetoadddm_EasyQuerytotheusesclausetogetaccesstothe databasecomponents. Thefollowingeventsofthemainformhavetobeimplemented:: OnCreate Whencreatingtheformtheconnectiontothedatabasewillbeestablished.Afterconnectingtothe databasethequerieswillbeopened: procedure TForm1.FormCreate(Sender: TObject); begin dmEasyQuery.conEmployee.Connect; dmEasyQuery.qryCustomer.Open; dmEasyQuery.roqryCountry.Open; end; OnDestroy Whenclosingtheapplication(destroyingthemainform)thedatabaseconnectionwillbecut.All querieswillbeclosedautomaticallybeforedisconnecting. procedure TForm1.FormDestroy(Sender: TObject); begin dmEasyQuery.conEmployee.Disconnect; end; TLabel Caption:CUSTOMER

TDBGrid DataSource:dmEasyQuery.dsCustomer Options.dgTabs:False IncolumneditorwewillcreateaTColumnsettingitspropertyFieldNameto"CUSTOMER".Afterthat theaccordingcolumninDBGrid1willbeenlarged.

TDBEdit (5x) TLabel] (5x) TheseobjectswillbecreatedbyusingthecolumneditorofqryCustomer:Selectcolumns ADDRESS_LINE1,ADDRESS_LINE2,CITY,STATE_PROVINCEandPOSTAL_CODEanddragand dropthemontothenmainform.Alignthemandadaptthemtothelayoutyouseeinthescreenshot. TLabel Caption:COUNTRY TDBLookUpComboBox DataField:COUNTRY DataSource:dmEasyQuery.dsCustomer KeyField:COUNTRY ListField:COUNTRY ListSource:dmEasyQuery.dsCountry TDBNavigator DataSource:dmEasyQuery.dsCustomer

Nowthecreatedformwillbesavedasfrm_EasyQuery.pas.

Note:Thefollowingprojectoptionshavetobechanged: dmEasyQueryhastobeplacedontopofthecreationorderinlist"Createautomatically".This ensuresthatallobjectsoffrmEasyQuerymayaccessthedatabaseobjects.frmEasyQueryisstill themainform.

AdditionalExamples
FishFact ThisisthemostpopulardatabasedemoforDelphi.ItwasmigratedtouseZEOScomponents. Transactions Asampleapplicationconcerning"transactionswithZEOS".Itusesasmallselfmadetestdatabase. StoredProc Thisisasampleapplikationthatshowshowtousestoredproecedures.ThedatabaseistheFirebird Employeesampledatabase. MasterDetail Asmallapplicationthatshowshowmaster/detailconnections(serverandclientsided)willbeimplemented. EventDemo AlsoaDelphidatabasesamplethatwasmigratedfromIBXtoZEOS.ItusesthecomponentTIBEventAlerter. ThisapplicationneedsthedatabaseEvents(shippedwithDelphi)thathadtobemigratedtodialect3toget thissamplerunning. YouwillfindtheseExamplesherefordownload. AdownloadablePDFVersionofthisTutorialisalsoonitsway!

MichaelSeeger ZeosLibDevelopmentTeam

También podría gustarte