Session D-DATA

Visual FoxPro 7.0: Events des Datenbankcontainers

Nathalie Mengel


Einleitung

Ein neues Feature in VFP 7.0 sind die Events des Datenbankcontainers. Sie stellen eine völlig neue Möglichkeit dar, datenbezogene Aktionen zu kontrollieren. Die Events werden bei jeder Aktion gefeuert, die den Datenbankcontainer betrifft. Diese Session zeigt zunächst die Funktionsweise der Events. In der praktischen Anwendung werden Möglichkeiten gezeigt, Datenbankaktionen zu kontrollieren, bzw. zu steuern. Abgerundet wird diese Session durch einen Ausblick auf sich daraus ergebende Anwendungsmöglichkeiten.

Allgemeines

DBC-Events sind neu in Visual FoxPro 7.0. Als dieses Dokument entstand, gab es noch nicht mal eine Beta-Version des Produktes. Alles, was mir vorlag war ein Pre-Release, das sich beim Aufruf noch mit dem Arbeitstitel "Sedona" meldet und eher leidlich läuft. Es kann sich also noch einiges ändern. Methodenaufrufe und Parameter sind noch nicht komplett fertig. Vielleicht haben wir in der endgültigen VFP 7.0 dann dafür neue Bugs. Sogar die grundsätzliche Funktionsweise einiger Aufrufe könnte eventuell noch geändert werden. Besonders auffällig waren bisher die Änderungen bezüglich der Reaktion auf Returncodes aus den Events. Beachten Sie dies bitte, wenn Sie das Dokument lesen, bzw. anwenden. Es werden im Dokument einige Vorgehensweisen gezeigt, wie man die DBC-Events testen kann. Probieren Sie im Zweifelsfall lieber noch mal anhand der Testbeispiele aus, was in Ihrer VFP-Version wirklich passiert, welcher Bug zwischenzeitlich bereinigt wurde, bzw. welcher dazugekommen ist. Unter den Samples von VFP ist auch ein Beispiel für das Verhalten und die Anwendung von DBC-Events, zu finden unter "Neuerungen in Visual FoxPro 7.0".

DBC-Events sind Ereignisse, die feuern, wenn auf den Datenbankcontainer selbst oder auf eines seiner Objekte zugegriffen wird. So wird zum Beispiel ein Event gefeuert, wenn eine Tabelle geöffnet wird. Das setzt allerdings voraus, dass die Tabelle zu einem Datenbankcontainer gehört. Dabei ist es unerheblich, ob das Event programmatisch, automatisch oder über die Entwicklungsumgebung ausgelöst wird. Es feuert, wenn die Tabelle in einem Programm geöffnet wird, wenn ein View geöffnet wird, der diese Tabelle benutzt und wenn man die Tabelle über das Datensitzungs-Fenster (SET) öffnet.

Ob die DBC-Events eingeschaltet oder ausgeschaltet sind, wird dadurch bestimmt, ob die DBC-Eigenschaft DBCEVENTS auf .T. oder .F. steht. Standardmäßig sind die Events für den Datenbankcontainer ausgeschaltet. Man muss sie erst über DBSETPROP oder über den neuen Eigenschafts-Dialog des DBC (siehe unten) einschalten. Der durch die Events erzeugte Overhead ist relativ gering, er liegt nach einigen Schätzungen etwa bei 2-3%. Die Events werden z.B. durch folgenden Aufruf eingeschaltet, wobei die Datenbank geöffnet sein muss:

Wenn man die DBC-Events eingeschaltet hat, ist der Datenbankcontainer nicht mehr mit einer früheren VFP-Version zu öffnen. Man erhält bei dem Versuch, diesen DBC mit VFP 6.0 zu öffnen, die Fehlermeldung, dass der DBC mit einer späteren Version von FoxPro erstellt wurde. Sobald man allerdings die Events wieder ausschaltet, ist der Datenbankcontainer wieder rückwärtskompatibel.

Der Code für DBC-Events kann entweder in Stored Procedures des Datenbankcontainers oder in einem separaten Programm abgelegt werden. Wo der Code liegt, wird in einer Eigenschaft des Datenbankcontainers festgelegt. Dementsprechend kann man nicht Stored Procedures und Programm mischen oder die Events in mehreren Programmdateien ablegen. Der Aufruf von weiteren Programmen aus den Events heraus ist aber natürlich möglich.

Soll der Event-Code in einem separaten Programm abgelegt werden, dann muss das Programm bereits existieren, wenn man dies im DBC einstellt. Außerdem muss sich das Programm im selben Verzeichnis wie der Datenbankcontainer befinden, was die Anwendungsmöglichkeiten solch ausgelagerter Programme doch einschränkt. Ansonsten erhält man beim Einstellen der Eigenschaft, bzw. beim Öffnen des DBC die Fehlermeldung, dass die entsprechende Datei nicht gefunden werden konnte. Es ist zu vermuten, dass dieser Bug in der endgültigen Version von VFP 7 bereinigt sein wird. Bevor man im DBC einstellt, wo der Event-Code gespeichert ist, muss die Verwendung der Events aktiviert worden sein (Eigenschaft DBCEVENTS)! Der Programmname wird in der Eigenschaft DBCEVENTFILENAME abgelegt. entweder über den Eigenschafts-Dialog des DBC (s.u.) oder über DBSETPROP wie folgt eingestellt:

Die Namen der Events selbst beginnen alle mit dem Prefix DBC_, dann folgt ein sprechender Begriff als Bezeichnung für das Event (z.B. DBC_BeforeOpenTable für das Event, das feuert, bevor eine Tabelle geöffnet wird).

Der Datenbankcontainer

Eine weitere Neuerung in VFP 7 ist der neue Eigenschafts-Dialog des Datenbankcontainers:

Neu ist der linke Teil des Dialogs, der sich ausschließlich mit den DBC-Events beschäftigt. Oben befindet sich eine Liste mit sämtlichen Events. Die Events, für die bereits Code geschrieben wurde, sind durch fette Schrift gekennzeichnet. Die Namen der Events werden hier ohne den Prefix DBC_ angezeigt. Unter der Liste ist eine kurze Erklärung für das gerade ausgewählte Event zu sehen.

Unten links befinden sich die Checkboxen "Set Events On" und "Events File" (lassen wir uns mal überraschen, wie das in der deutschen Version übersetzt wird). Mit "Set Events On" wird die Eigenschaft DBCEVENTS eingestellt. Mit "Events File" wird eingestellt, ob der Event-Code in einer separaten Datei verwaltet werden soll. Darunter steht der Dateiname des Eventcode-Programms und ein Button zum Starten des Dateiauswahl-Dialogs, um die Datei zu suchen.

Wenn man ein Event, für das noch kein Code besteht, auswählt und dann auf den Button "Edit Code" klickt, wird automatisch ein Template für den Eventcode erstellt. So braucht man nicht selbst die Parameter aus der grandiosen Hilfedatei herauszusuchen, sondern kann einfach das Template editieren.

Zum Tracen der Events kann man einfach sämtliche Events auswählen, die Templates erzeugen lassen und WAIT WINDOWS in den Event-Code einbauen. So kann man zu jeder Zeit feststellen, welches Event wann feuert. Entsprechend vorbereitete Event-Codes befinden sich auch bei den Beispielen auf der Konferenz-CD.

Beschreibung der DBC-Events

Wie werden DBC-Events verwendet?

Es gibt Events für nahezu alle Aktionen, die man mit, bzw. im Datenbankcontainer ausführen kann. Es gibt Events für den Datenbankcontainer selbst, für Tabellen, Views, Beziehungen und Connections. Die Namen der Events selbst beginnen alle mit dem Prefix DBC_, dann folgt ein sprechender Begriff als Bezeichnung für das Event (z.B. DBC_BeforeOpenTable für das Event, das feuert, bevor eine Tabelle geöffnet wird).

Für die meisten Aktionen gibt es ein Before- und ein After- Event. Wenn man im Before-Event als Returncode .F. zurückgibt, wird die entsprechende Aktion nicht ausgeführt. So wird z.B. das Öffnen des Tabellen-Designers unterbunden, wenn das Event DBC_BeforeModifyTable() den Returncode .F. zurückgibt.

Dabei ist zu beachten, dass die Before-Events zwar vor der eigentlichen Aktion feuern, aber nach der Parameterprüfung. Wenn man also versucht, eine Tabelle umzubenennen, die es gar nicht gibt, feuert NICHT das Event DBC_BeforeRenameTable()!

After-Events feuern, nachdem die Aktion ausgeführt wurde. Also z.B. nachdem eine Tabelle umbenannt wurde (DBC_AfterRenameTable) oder nachdem der Tabellen-Dialog geschlossen wurde (DBC_AfterModifyTable). After-Events feuern nicht, wenn die Ausführung durch Rückgabe von .F. in einem Before-Event unterbunden wurde! Unglücklicherweise kann man nicht feststellen, ob die Ausführung des Events erfolgreich war, bzw. was geändert wurde. Zum Erkennen der Änderungen kann man sich nur im Before-Event den Status Quo des zu modifizierenden Objektes sichern und hinterher vergleichen.

Die Events verlangen unterschiedliche Parameter, weshalb sich das Erzeugen von Templates besonders empfiehlt. Es werden sich wahrscheinlich auch noch einige Parameter in der endgültigen Version von VFP 7 geändert haben.

Funktion ALANGUAGE()

Eine weitere Neuerung ist die VFP-Funktion ALANGUAGE(). Sie schreibt die Namen der verfügbaren Kommandos, Funktionen oder Events und ggf. Anzahl der Parameter in ein Array. Man übergibt den Namen eines Arrays und den Typ der Information, die man haben möchte. So kann man sich sämtliche möglichen DBC-Events in ein Array schreiben lassen und dieses auswerten.

Die Funktion wird wie folgt aufgerufen:

Folgende Werte sind für den Parameter nTyp möglich:

nTyp

Typ 

Rückgabe

1

Kommandos 

Eindimensionales Array mit den Namen der in VFP 7
 verfügbaren Kommandos

Funktionen

Zweidimensionales Array den in VFP 7 verfügbaren Funktionen.
Die erste Spalte enthält den Funktionsnamen. 
Die zweite Spalte enthält einen String, der sich aus folgenden Informationen zusammensetzt:
1. Flag, ob die Funktion abgekürzt werden kann ("M", wenn die Funktion nicht abgekürzt werden kann, ansonsten leer)
2. Anzahl der erforderlichen Parameter. 
3. Anzahl der optionalen ParameterDie addierte Anzahl der erforderlichen und optionalen Parameter gibt die Gesamtanzahl der Parameter.

3

Basisklassen

Eindimensionales Array mit den Namen der Basisklassen

4

DBC-Events

Zweidimensionales Array mit den in VFP 7 verfügbaren DBC-Events. (Beschreibung des Arrays siehe nTyp=2)

      

DBC-Events für Datenbankcontainer

DBC-Event Parameter / Auslöser / Bemerkungen
DBC_OpenData
cDatabaseName, lExclusive, lNoupdate, lValidate

Wenn eine Datenbank geöffnet wird oder wenn der Befehl MODIFY DATABASE für eine geschlossene Datenbank aufgerufen wird. Rückgabe von .F. verhindert die Ausführung, dann erscheint die Fehlermeldung, dass der Dateizugriff verweigert wurde. Achtung: Wenn der Event-Code in einer Stored Procedure abgelegt ist und man hier immer .F. zurückgibt, kann man den DBC nicht mehr über OPEN DATA / MODIFY DATA öffnen, um die Stored Procedure zu ändern.

DBC_ModifyData
cDatabaseName, lNoWait, lNoEdit

Wenn der Befehl MODIFY DATABASE für eine Datenbank aufgerufen wird. Rückgabe von .F. verhindert das Öffnen des Datenbankdialogs.

DBC_Activate
cDatabaseName

Wenn eine geöffnete Datenbank aktiviert wird.

DBC_Deactivate
cDatabaseName

Wenn eine Datenbank deaktiviert wird (z.B. durch Aktivierung einer anderen Datenbank oder beim schließen der Datenbank).

DBC_CloseData
cDatabaseName, lAll

Wenn eine Datenbank geschlossen wird. Außerdem wird das Event DBC_Deactivate gefeuert.

DBC_BeforeValidateData
lRecover, lNoConsole, lPrint, lFile, cFileName

Bevor eine Datenbank validiert wird. Rückgabe von .F. verhindert die Ausführung des Befehls. VALIDATE DATABASE kann jetzt auch programmatisch aufgerufen werden.

DBC_AfterValidateData
lRecover, lNoConsole, lPrint, lFile, cFileName

Nachdem der Befehl VALIDATE DATABASE beendet wurde. Man erhält allerdings keine Information darüber, ob der DBC gültig ist.

DBC_PackData
-

Wenn der Befehl PACK DATABASE aufgerufen wird.

DBC_BeforeDBGetProp
cName, cType, cProperty

Bevor eine Datenbankeigenschaft ermittelt wird. Im Gegensatz zu den anderen Before-Events wird die Ausführung der Funktion nicht verhindert, wenn dieses Event .F. zurückgibt.

DBC_AfterDBGetProp
cName, cType, cProperty

Nachdem eine Datenbankeigenschaft ermittelt wurde.

DBC_BeforeDBSetProp
cName, cType, cProperty, ePropertyValue

Bevor eine Datenbankeigenschaft geändert wird. Rückgabe von .F. verhindert die Ausführung. Dieses Event wird auch ausgelöst, bevor die Eigenschaft DBCEvents auf .F. gesetzt wird.

DBC_AfterDBSetProp
cName, cType, cProperty, ePropertyValue

Nachdem die Datenbankeigenschaft geändert wurde. Dieses Event wird auch ausgelöst, nachdem die Eigenschaft DBCEvents auf .T. gesetzt wurde.

DBC-Events für Stored Procedures

DBC-Event Parameter / Auslöser / Bemerkungen
DBC_BeforeModifyProc
-

Bevor eine Stored Procedure eines geöffneten DBC verändert wird. Rückgabe von .F. verhindert die Änderung.

DBC_AfterModifyProc
-

Nachdem eine Stored Procedure gespeichert wurde. Das Schließen des Editors für Stored Procedures löst nicht dieses Event aus! Man kann nicht feststellen, was an der Prozedur geändert wurde.

DBC_BeforeAppendProc
cFileName, nCodePage, lOverwrite

Bevor die Stored Procedures eingefügt werden. Rückgabe von .F. verhindert das Einfügen der Stored Procedures.

DBC_AfterAppendProc
cFileName, nCodePage, lOverwrite

Nachdem die Stored Procedures eingefügt wurden

DBC_BeforeCopyProc
cFileName, nCodePage, lAdditive

Bevor die Stored Procedures kopiert werden. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterCopyProc
cFileName, nCodePage, lAdditive

Nachdem die Stored Procedures kopiert wurden.

  
DBC-Events für Tabellen

DBC-Event Parameter / Auslöser / Bemerkungen
DBC_BeforeAddTable
cTableName, cLongTableName

Bevor eine freie Tabelle dem DBC hinzugefügt wird. Rückgabe von .F. verhindert die Ausführung

DBC_AfterAddTable
cTableName, cLongTableName

Nachdem eine freie Tabelle zum DBC hinzugefügt wurde.

DBC_BeforeCreateTable
cTableName, cLongTableName

Bevor eine Tabelle in einem geöffneten DBC erstellt wird. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterCreateTable
cTableName, cLongTableName

Nachdem eine Tabelle im DBC erstellt wurde.

DBC_BeforeDropTable
cTableName, lRecycle

Bevor eine Tabelle aus dem DBC entfernt und von der Festplatte gelöscht wird. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterDropTable
cTableName, lRecycle

Nachdem eine Tabelle aus dem DBC entfernt und von der Festplatte gelöscht wurde.

DBC_BeforeOpenTable
cTableName

Bevor eine Tabelle oder ein View geöffnet wird. Rückgabe von .F. verhindert die Ausführung, dann erscheint die Fehlermeldung, dass der Dateizugriff verweigert wurde. Wenn die Tabelle oder der View unter einem anderen Alias geöffnet wird, dann wird der Alias anstatt des Tabellen-, bzw. Viewnamens an dieses Event übergeben.

Dieses Event feuert auch für jede Tabelle, die Basis für den View ist, der geöffnet werden soll, unabhängig davon, ob die Tabelle bereits geöffnet ist oder nicht - und zwar sowohl beim Öffnen als auch beim REQUERY() des Views.

Achtung: beim REQUERY() von Views feuern nur die Open-Events der Tabellen, nicht die des Views selbst!

DBC_AfterOpenTable
cTableName

Nachdem eine Tabelle oder ein View geöffnet wurde. Wenn eine Tabelle oder der View unter einem anderen Alias geöffnet wurde, dann wird der Alias anstatt des Tabellen-, bzw. Viewnamens an dieses Event übergeben.

Dieses Event feuert auch für jede Tabelle, die Basis für den View ist, der geöffnet werden soll, unabhängig davon, ob die Tabelle bereits geöffnet war oder nicht, sowohl beim Öffnen als auch beim REQUERY() des Views.

Achtung: beim REQUERY() von Views feuern nur die Open-Events der Tabellen, nicht die des Views selbst!

DBC_BeforeCloseTable
cTableName

Bevor eine Tabelle oder ein View geschlossen wird. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterCloseTable
cTableName

Nachdem eine Tabelle oder ein View geschlossen wurde.

DBC_BeforeRemoveTable
cTableName, lDelete, lRecycle

Bevor eine Tabelle aus dem DBC entfernt wird. Rückgabe von .F. verhindert die Ausführung. Das Event feuert nicht bei DROP TABLE.

DBC_AfterRemoveTable
cTableName, lDelete, lRecycle

Nachdem eine Tabelle aus dem DBC entfernt wurde. Rückgabe von .F. verhindert die Ausführung. Das Event feuert nicht bei DROP TABLE.

DBC_BeforeRenameTable
cPreviousName, cNewName

Bevor eine Tabelle umbenannt wird. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterRenameTable
cPreviousName, cNewName

Nachdem eine Tabelle umbenannt wurde. Innerhalb dieser Prozedur gilt noch der alte Tabellenname!

DBC_BeforeModifyTable
cTableName

Bevor eine Tabelle, verändert wird. z.B. bevor der Tabellendialog aufgerufen wird. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterModifyTable
cTableName, lCancelled

Nachdem eine Tabelle verändert wurde. z.B. nachdem der Tabellen-Designer beendet wurde.

                  
DBC-Events für Views

DBC-Event Parameter / Auslöser / Bemerkungen
DBC_BeforeCreateOffline
cViewName, cPath

Bevor ein View offline gesetzt wird. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterCreateOffline
cViewName, cPath

Nachdem ein View offline gesetzt wurde.

DBC_BeforeDropOffline
cViewName

Bevor ein Offline-View auf online gesetzt wird. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterDropOffline
cViewName

Nachdem ein Offline-View auf online gesetzt wurde.

DBC_BeforeCreateView
cViewName,lRemote

Bevor ein View erstellt wird, bzw. bevor der View-Designer geöffnet wird. Rückgabe von .F. verhindert die Ausführung. Beim Erstellen eines Views werden die Events DBC_BeforeOpenTable() und DBC_AfterOpenTable() der Tabellen, die die Datenquelle für den View darstellen, doppelt aufgerufen.

DBC_AfterCreateView
cViewName,lRemote

Nachdem ein View erstellt wurde, bzw. der neue View im View-Designer gespeichert wurde. Das Schließen des View-Designers selbst löst nicht dieses Event aus.

DBC_BeforeDropView
cViewName

Bevor ein View aus dem Datenbankcontainer entfernt wird. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterDropView
cViewName

Nachdem ein View aus dem Datenbankcontainer entfernt wurde.

DBC_BeforeRenameView
cPreviousName, cNewName

Bevor ein View umbenannt wird. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterRenameView
cPreviousName, cNewName

Nachdem ein View umbenannt wurde.

DBC_BeforeModifyView
cViewName

Vor dem Öffnen des View-Designers zum Ändern eines Views. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterModifyView
cViewName

Nachdem der View im View-Designer gespeichert wurde. Das Event feuert auch, wenn der View im View-Designer gar nicht verändert wurde. Das Schließen des View-Designers selbst löst nicht dieses Event aus.

DBC-Events für Beziehungen

DBC-Event Parameter / Auslöser / Bemerkungen
dbc_BeforeAddRelation
cDBCName, cTableName, cRelationID, cRelatedChild, 
cRelatedTable, cRelatedTag

Bevor eine persistente Beziehung erstellt wird. Rückgabe von .F. verhindert die Ausführung.

dbc_AfterAddRelation
cDBCName, cTableName, cRelationID, cRelatedChild,
cRelatedTable ,cRelatedTag

Nachdem eine persistente Beziehung erstellt wurde.

dbc_BeforeDropRelation
cDBCName, cRelationID, cTableName, cRelatedChild,
cRelatedTable, cRelatedTag

Bevor eine persistente Beziehung aus dem DBC entfernt wird. Rückgabe von .F. verhindert die Ausführung.

dbc_AfterDropRelation
cDBCName, cRelationID, cTableName, cRelatedChild, 
cRelatedTable, cRelatedTag

Nachdem eine persistene Beziehung aus dem DBC entfernt wurde.

DBC-Events für Verbindungen

DBC-Event Parameter / Auslöser / Bemerkungen
DBC_BeforeCreateConnection
cConnectionName, cDataSourceName,cUserID, 
cPassword, cConnectionString

Bevor eine Connection erstellt wird. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterCreateConnection
cConnectionName, cDataSourceName,cUserID, 
cPassword, cConnectionString

Nachdem eine Connection erstellt wurde.

DBC_BeforeRenameConnection
cPreviousName, cNewName

Bevor eine Connection umbenannt wird. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterRenameConnection
cPreviousName, cNewName

Nachdem eine Connection umbenannt wurde. DBC_BeforeModifyConnection cConnectionName Bevor der Connection-Designer zum Ändern einer Connection aufgerufen wird. Rückgabe von .F. verhindert die Ausführung. DBC_AfterModifyConnection cConnectionName Nachdem eine Connection im Connection-Designer geändert und gespeichert wurde. Das Schließen des Connection-Designers selbst löst dieses Event nicht aus.

DBC_BeforeDeleteConnection
cConnectionName

Bevor eine Connection gelöscht wird. Rückgabe von .F. verhindert die Ausführung.

DBC_AfterDeleteConnection
cConnectionName 

Nachdem eine Connection gelöscht wurde.

 

Event-Reihenfolge

Allgemeines

Die folgenden Beispiele zeigen den Ablauf von Events auf, die durch eine Aktion ausgelöst werden. Es gibt natürlich noch andere Aktionen, die gleich mehrere Events auslösen, aber hier soll nur exemplarisch gezeigt werden, wie die Events voneinander abhängen.

Öffnen und Schließen von Datenbanken

Die folgende Tabelle zeigt aufeinanderfolgende Aktionen und die dadurch ausgelösten Events in der entsprechenden Reihenfolge. Beim Öffnen einer Datenbank wird zunächst das Event DBC_OpenData() und dann das DBC_Activate() gefeuert. Wenn man dann eine andere Datenbank öffnet, wird die bisher aktive Datenbank deaktiviert und das entsprechende Event gefeuert. Beim Schließen der Datenbanken wird zunächst das Event DBC_CloseData des aktiven DBC gefeuert. Dann werden alle offenen Tabellen dieses DBCs geschlossen, mit Auslösung der entsprechenden Events. Erst danach wird der DBC deaktiviert. Danach wird der daraufhin aktive DBC mit entsprechender Eventauslösung geschlossen.

Aktion Events
OPEN DATABASE data1
DBC_OPENDATA(data1
DBC_ACTIVATE(data1)
OPEN DATABASE data2
DBC_OPENDATA(data2)
DBC_DEACTIVATE(data1)
DBC_ACTIVATE(data2)
USE data2!table1
DBC_BeforeOpenTable(table1)
DBC_AfterOpenTable(table1)
CLOSE DATABASES ALL
DBC_CloseData(data2)
DBC_BeforeCloseTable(table1)
DBC_AfterCloseTable(table1)
DBC_Deactivate(data2)
DBC_CloseData(data1)
DBC_Deactivate(data1)

Erstellen eines Views

Beim Erstellen eines Views werden die Events zum Öffnen der dazugehörigen Tabellen doppelt gefeuert. Ob dies ein Bug ist, der noch beseitigt wird, ist derzeit unklar. 

Aktion Events
CREATE VIEW view1 AS SELECT * FROM table1
DBC_BeforeCreateView (view1)
DBC_BeforeOpenTable(table1)
DBC_AfterOpenTable(table1)
DBC_BeforeOpenTable(table1)
DBC_AfterOpenTable(table1)
DBC_AfterCreateView (view1)

Öffnen eines lokalen Views

Beim Öffnen des lokalen Views werden die Open-Events der dazugehörigen Tabellen ebenfalls gefeuert.

Aktion Events
USE view1
DBC_BeforeOpenTable(view1)
DBC_BeforeOpenTable(table1)
DBC_AfterOpenTable(table1)
DBC_AfterOpenTable(view1)

Öffnen eines Remote Views

Im folgenden Beispiel wird direkt auf die VFP-Datenbank zugegriffen. In der Datenbank befindet sich ein Remote-View, der auf Tabellen einer anderen VFP-Datenbank zugreift (hier nur zu Demozwecken). Da Database-Events nicht über ODBC feuern, werden beim Öffnen des Remote Views nur die Events des DBC gefeuert, auf den direkt zugegriffen wird. 

Aktion Events
USE view2
DBC_BeforeOpenTable(view2)
DBC_AfterOpenTable(view2)

Einschränkungen

Einschränkungen in der Nutzbarkeit von DBC-Events gibt es natürlich leider auch. Dazu gehört die Tatsache, dass die Parameter von der aufgerufenen Funktion geprüft werden, bevor das entsprechende Event feuert. Außerdem können die übergebenen Parameter nicht verändert werden. Somit ist es nicht möglich, in den DBSetProp()-Mechanismus steuernd einzugreifen, wie man es bei Eigenschaften von Objekten über Access- und Assign-Methoden kann.

Ein erheblicher Wehrmustropfen ist, dass die DBC-Events nicht feuern, wenn man über ODBC auf den DBC zugreift. Das liegt daran, dass die ODBC-Treiber nicht weiterentwickelt wurden und auch nicht weiterentwickelt werden. Wenn man über ADO auf den DBC zugreift, feuern die Events.

Anwendung von DBC-Events

Logging

Über Open-Events kann ein Logging für die Datenbank, oder auch ganz gezielt für bestimmte Tabellen durchgeführt werden. Man kann z.B. die Benutzer der Datenbank mit Zeitstempel in eine Protokolldatei aufnehmen (es sei denn, der Betriebsrat hat etwas dagegen....). Auch zurückgewiesene Datenbankzugriffe können protokolliert werden. Beispiele dafür sind auf der Konferenz-CD.

Security

Sicherheitsmechanismen können in zweierlei Hinsicht implementiert werden. Zum einen kann man über die Open-Events verhindern, dass Benutzer auf Daten zugreifen, zu denen sie keinen Zugriff haben sollen. Zum anderen kann man die Datenbank über BeforeModify-Events vor unerlaubten Veränderung schützen. Beides geschieht, indem man den angemeldeten Benutzer in den entsprechenden Events prüft und die Ausführung ggf. stoppt. Beispiele dafür sind auf der Konferenz-CD.

Diese Vorgehensweise kann vor halbwissenden Benutzern schützen, die über eine VFP-Entwicklungsumgebung verfügen und somit Zugriff auf die Datenbank haben. Dann sollte man die Events in ein kompiliertes Programm auslagern, damit sie nicht auch einfach vom Halbwissenden geändert werden können. Wenn das Programm mit den Events ‚versehentlich' gelöscht wird, dann wird die Datenbank überhaupt nicht mehr geöffnet! Wie gesagt, dieser Schutz hilft nur gegen Halbwissende, denn der DBC kann immer noch als Tabelle oder mit einem Hex-Editor geöffnet werden. Aber dann muss man schon genau wissen, welches Flag zum Ausschalten der Events geändert werden muss.

Standards

In den meisten Firmen gibt es Standards, nach denen z.B. Tabellen benannt werden sollen. Oft sind auch für jede Tabelle bestimmte Felder zwingend vorgesehen, z.B. ein Timestamp für Angebotstabellen. Man kann nun in die ModifyAfter-Events Funktionsaufrufe einbaut, die diese Standards prüfen. Wenn die Standards nicht eingehalten wurden, kann man Warnungen ausgeben oder - vielleicht noch besser - diese erzwingen, indem man sie automatisch ausführt (also z.B. das Timestamp-Feld automatisch zur Tabelle hinzufügt).

Team-Entwicklung

Oft gibt es Projektteams, die nicht über eine zentrale Stelle zur Datenbankpflege verfügen. Dort arbeitet jeder Mitarbeiter auf einer lokalen Datenbankkopie, mit der er seine Änderungen zunächst testet, bevor er sie den anderen Entwicklern zur Verfügung stellt. Wenn der Entwickler nun seine Änderungen auf der zentralen Datenbank nachzieht, vergisst er oft, sämtliche Datenbankänderungen korrekt nachzuziehen. Wie schön wäre es da doch, hätte man ein Logbuch, in dem alle Änderungen eingetragen sind. Allerdings ist es derzeit noch nicht möglich, in den ModifyAfter-Events direkt festzustellen, was sich z.B. genau an einer Tabelle geändert hat.

Und wie erfahren die Kollegen meistens, dass sich die Datenbank geändert hat? Per Email, Mundpropaganda oder vielleicht, weil sich irgendein Programm wieder nicht ausführen ließ? Wenn man bei Datenbankänderungen gleich automatisch eine Email an die Kollegen verschicken läßt, dann werden diese Informationslücken geschlossen.

Programme mit geänderter Datenbank abgleichen

Man könnte z.B. nach dem Umbenennen von Tabellen prüfen, welche Programme auf diese Felder zugreifen und eine entsprechende Liste erstellen, welche Programme geändert werden müssen. In Anbetracht der Tatsache, dass meistens nicht nur ein Projekt mit einer Datenbank arbeitet und dass Umbenennungen von Feldern oder Views nicht so einfach festzustellen sind, stellt dies allerdings einen recht hohen Aufwand dar.

Aktualisierung von Meta-Daten

Diverse Anbieter von Datenbank-Tools arbeiten mit Meta-Daten, die aktualisiert werden müssen, sobald sich die Datenbank ändert. Zum Beispiel das Stonefield Database Toolkit von der Stonefield Systems Group. Das Stonefield Database Toolkit ermöglicht es, Datenbankänderungen an einer bestehenden Datenbank automatisch durchführen zu lassen. So kann man in die Datenbank in der Entwicklungsumgebung ändern, während der Benutzer bereits auf Produktionsdaten arbeitet. Die Änderungen werden in eine Metadatei geschrieben, über die dann die Datenbankänderungen abgeglichen werden. 

Die Aktualisierung der Metadaten kann nun automatisch über DBC-Events angestoßen werden. Doug Hennig von der Stonefield Systems Group hat dazu die entsprechenden Events geschrieben und dankenswerter Weise zur Verfügung gestellt. Beispiele dazu sind auf der Konferenz-CD.

Zusätzliche Aktionen

Beim Öffnen von Tabellen oder Views können nun datenbankgesteuert zusätzliche Aktionen ausgeführt werden. Zum Beispiel kann man einen View nach dem Öffnen mit einem Index versehen. Allerdings ist dabei zu beachten, dass beim REQUERY() von Views lediglich die Open-Events für die Tabellen gefeuert werden, die dem View zugrunde liegen. Also muss man anstatt REQUERY() aufzurufen, den View jedes mal wieder neu öffnen, wenn neue Daten gezogen sollen und ein neuer Index erstellt werden soll.