Session D-DATA

Datenbankdesigner

Peter Herzog
ProLib Software GmbH


Teil 1. Der Datenbankcontainer unter VFP 3.0

Als erstes wollen wir mit einem alten Erbe, aus der frühen Zeit von FoxPro oder besser der xBase-Zeit, aufräumen.

Das was wir bis heute DBF-Datei nannten ist keineswegs ein Database-File sondern eine einfache und schlichte Tabelle.

Warum ich es dabei so genau nehme ? Na ja, grundsätzlich kann man bei einfachen DBF-Files eben nicht von einer Datenbank sprechen, da dort wesentlich mehr vorhanden sein muß, als nur in Zeilen und Spalten gedrängte Daten. Wenn man es genau nimmt, dann ist eine DBF nichts anderes als ein Excel-Spreadsheet, denn die ist auch in Zeilen und Spalten unterteilt.

Bei einer Tabelle nennt man dies nun Felder und Datensätze, aber unter dem Strich ist es nur eine einfache Listendarstellung.

Bereits der alte BROWSE-Befehl hat beim Aufruf genau dieses angezeigt.

DBF nicht gleich Datenbank

Kommen wir zurück zur Datenbank. Was zeichnet eine Datenbank nach dem heutigen Verständnis aus.

Also da wären unsere normalen Tabellen. Dann natürlich unsere Indizes. Bis zu diesem Punkt kann bereits FoxPro 2.x folgen. Nun kommen jedoch besondere Bestandteile dazu, die eine echte Datenbank ausmachen.

Stored Procedures oder auch „gespeicherte Prozeduren“. Damit ist Programmcode gemeint, der Daten in spezieller Form manipulieren kann. Weiters gibt es da die Trigger, Rules und Defaults. Außerdem sollten spezielle Datentypen vorhanden sein, die das Speichern von Daten etwas transparenter machen. Nicht zu vergessen, die Referentielle Integrität und die Nullwerte.

Auf alles obige mußten wir bisher verzichten, bzw. wußten bisher gar nicht, daß so etwas eventuell wichtig sein konnte. Von manchen Leuten wird gemunkelt, daß sie die Wörter nicht einmal kannten, bzw. aussprechen konnten. Aber um ehrlich zu sein. Bevor ich mit einer echten Datenbank zu tun hatte (und das ist nicht besonders lange her) konnte ich mit den Ausdrücken genauso wenig anfangen.

Also gehen wir mal Schritt für Schritt durch die Materie.

Stored Procedures

Damit ist Programmcode gemeint, der Daten in ganz bestimmter Form verändern kann. In der Welt der Großrechner und SQL-Datenbanken wird dies durch die sogenannte SQL-Sprache erledigt. Eigentlich sollte die SQL-Sprache eine Abfragesprache sein, die es auch der Oma von nebenan ermöglicht Ihre Kuchenrezepte aus dem Datenhaufen herauszubekommen. Wer sich jedoch schon einmal über die Sprache darübergewagt hat, der wird bald erkennen, daß die „Oma“ wohl eher das Kochbuch zur Hand nehmen wird, als sich aus einer Datenbank Informationen zu holen.

Ich persönlich bin froh, daß SQL ein etwas schwieriger Teil der EDV ist, ansonsten wäre ich ja arbeitslos. Andererseits vermisse ich den Komfort den mir Visual FoxPro bietet.

Vom Standpunkt eines Programmierers aus, schreibt man seine Programme lokal auf seinem Rechner und greift mit bestimmten Befehlen auf die Festplatte oder das Netzlaufwerk zu. Die Stored Procedures hingegen laufen sozusagen in der Datenbank ab und belasten somit nicht das eigene Programm.

Dies hat besondere Vorteile. Als erstes ist das Schlagwort „Reuseable Code“ anzuführen. Wenn ich Programmcode zentral ablege, dann brauche ich ihn nur einmal schreiben und er steht jedem meiner Programme zur Verfügung. Außerdem muß ich dafür sorgen, daß der Code für alle Problemfälle gewappnet ist, daß heißt, daß man „ordentlich“ programmieren muß und sich keine Quick and Dirty´s leisten kann.

Trigger

Die sinngemäße Übersetzung für Trigger wäre der Abzugshebel einer Pistole. Genauso verhalten sich auch die Trigger, hinter denen eine Stored Procedure stecken kann. Es bedeutet schlicht und einfach, daß ein Ereignis eintritt und die Datenbank daraufhin einen Trigger „abfeuert“ der wiederum mit einer Aktion auf das Ereignis reagiert. War das nicht ein toller Satz ?

Für den Laien erklärt bedeutet dieses, daß es drei verschiedene Ereignisse in der Datenbank gibt, die man abfangen kann. Datensatz Einfügen, Ändern und Löschen. Es wird alles auf diese drei Ereignisse zurückzuführen sein. Wenn nun eins dieser Ereignisse eintritt, dann kann die Datenbank automatisch weitere Aktionen starten. Als Beispiel wären da Löschoperationen oder ähnliches.

Rules

In jeder Datenbank kann man ein Regelwerk definieren, welches darauf achtet, daß keinerlei „Mülldaten“ in die Tabellen gelangen. Wenn Sie definieren, daß ein bestimmtes Feld in einer Tabelle nicht leer sein darf, dann wird sich die Datenbank mit Händen und Füßen wehren, daß Sie einen solchen Datensatz eingeben, oder darauf ändern.

Also das alte Verhalten des „Ich lege mal schnell 5 leere Datensätze an und schreibe die Daten später hinein“ können sie sich sofort aus dem Kopf schlagen. Wenn Sie eine Regel definiert haben, so müssen Sie die Regel zuerst löschen, wenn Sie diese brechen wollen. Und mal ehrlich, wer möchte sich vom Computer schon sagen lassen, was man tun darf und was nicht. Aber dazu später.

Defaults

Wenn Sie zufällig in Deutschland wohnen und einen Kundendatensatz eingeben, dann ist es wohl sinnvoll, wenn das Länderkennzeichen mit einem „D“ vorbelegt ist. Wollten Sie dies bisher erreichen, so mußten Sie dieses in jedem Programm hineinprogrammieren, welches Datensätze in der Kundendatei anlegt. Defaults füllen die Felder bereits mit von Ihnen vorbestimmten Werten, wenn ein Datensatz neu angelegt wird und Sie diese Daten nicht explizit vorgeben.

Spezielle Datenfelder

Über die Datenfelder Zeichen, Numerisch, Datum, Logisch und Memo gibt es durchaus noch andere Möglichkeiten Informationen in Felder zu packen. Als Beispiel wäre das Datum-Zeitfeld, Integer, Double und Währung anzuführen. Es gibt bei bestimmten Datenbanken noch andere, jedoch sind dies meistens nur Abwandlungen der normalen Datentypen.

Spezielle Formen sind z.B. Das Timestamp-field und die user-defined-Datatypes, auf die wir in VFP jedoch noch verzichten müssen.

Referentielle Integrität (RI)

ist ein tolles Modewort und jeder verwendet es. Was steckt jedoch dahinter, besonders wenn man die Besonderheiten: deklarativ oder prozedural noch davor stellt.

Zur Erklärung ein kleines Beispiel.

In unserer Applikation gibt es Aufträge. Zu jedem Auftrag gibt es 1 bis n Positionen. Wenn wir nun einen Auftrag löschen, so hat es wenig Sinn die Positionen noch aufzubehalten. Die sind nun sinnlos geworden.

Ein Teil der RI ist nun die Löschweitergabe (Kaskadierende RI). Das bedeutet, daß automatisch alle Datensätze gelöscht werden, die zu diesem Auftrag dazugehörten.

Wenn nun jedoch ein Teil der Positionen bereits geliefert wurden, dann ist dieser Teil noch zu verrechnen und darf auf keinen Fall gelöscht werden. In diesem Falle ist es eine Restriktive RI, also eine Einschränkung.

Sollte dieser Fall eintreten, dann darf der gesamte Auftrag noch nicht gelöscht werden. Die RI überwacht dies selbständig und ohne daß wir irgendeinen Finger rühren müssen.

Nun kurz zum Unterschied zur deklarativen und zur prozeduralen RI.

Deklarativ bedeutet, daß ich einfach nur „sage“, daß die Datenbank darüber wachen soll. Bei der prozeduralen RI werden die Trigger eingesetzt mittels Stored Procedures darüber zu wachen.

VFP 3.0 hat prozedurale RI, jedoch kann uns das egal sein, da der dazugehörige Code sowieso automatisch erstellt wird.

Nullwerte

Allgemein bekannt ist die Tatsache, daß ein logisches Feld die Zustände „Wahr“ und „Falsch“ annehmen kann. Mit diesem alten Glauben räumt die Datenbank nun auf und übergibt uns im Falle des logischen Feldes ein eindeutiges „Vielleicht“. Sie werden nun sagen, was das nun soll. Etwa ein dritter Zustand ? Schwanger, nicht schwanger, ein bißchen Schwanger ? Nein der dritte Zustand ist eindeutig ein „Vielleicht Schwanger“

Genaugenommen gibt es diesen Zustand wirklich, selbst im richtigen Leben, wenn man es genau nimmt.

Diesen Zustand kann man nun auf alle Datentypen anwenden. Bei Numerisch ist die nun weder 0 noch nicht 0, sondern wie man es in VFP schreibt .NULL. Auch ein Datum kann einen Nullwert annehmen. Also weder {}, noch {..} oder {00.00.00}. Einfach .NULL.

Interessant wird es bei Zeichenketten. Denn selbst eine leere Zeichenkette unterscheidet sich von einem .NULL. Also genaugenommen ist dies ein neuer Wert, mit dem wir sogar arbeiten können, als ob es eine Zahl oder ein sonstiger Wert wäre.

Doch nun zu VFP 3.0. Wie wirken sich die neuen Begriffe in VFP aus, bzw. wie wurden sie verwirklicht. Als VFP gestylt wurde haben sich die Entwickler natürlich Gedanken über den zukünftigen Aufbau der FoxPro Daten gemacht. Auf der einen Seite mußte man einen Aufbewahrungsort für die neuen Bestandteile einer Datenbank finden, auf der anderen Seite hatte man ein tolles, sehr schnelles Datenzugriffsmodell.

Es konnten natürlich die gesamten Zugriffstechniken von FoxPro nicht einfach weggeworfen werden, auf der anderen Seite fehlte ein Platz, in dem man die zusätzlichen Informationen speichern konnte, die für eine Datenbank fehlten.

Man ging einen Kompromiß ein. Zuallererst wurde das Aussehen einer Tabelle nur geringfügig geändert, auf der anderen Seite wurde ein sogenannter Datenbankcontainer geschaffen, der alle Teile beinhaltet, die man nicht ein eine Tabelle speichern konnte.

Der Datenbankcontainer DBC

Wollen wir uns einmal selbst einen Datenbankcontainer anschaffen. Der Befehl dazu lautet CREATE DATABASE <Name> oder einfach MODIFY DATABASE <Name>. Sollte beim MODIFY die Datenbank nicht vorhanden sein, so wird sie eben sofort angelegt.

Also frisch drauf los und MODI DATA TEST eingetippt.

Auf der Festplatte werden Sie nun drei neue Dateien finden.

Das bereits verrät uns, daß es sich nach guter alter FoxPro Manier wiederum um eine normale Tabelle handelt, die man wie gewohnt auch mit USE aufmachen kann.

Aber an dieser Stelle eine energische Warnung: Händische Änderungen im DBC können der Gesundheit Ihres Datenbankcontainers schaden, so daß Sie mit absolutem Datenverlust rechnen müssen.

Sobald wir einen Datenbankcontainer erzeugt haben, so erhalten wir ein leeres Fenster mit der Überschrift „Datenbankdesigner TEST“. Außerdem erhalten wir in der Standardtoolbar den Namen Test in einer Combobox dargestellt.

Sie können beliebig viele Datenbanken gleichzeitig öffnen und dazwischen hin und her schalten. Programmatisch geschieht dies durch des Befehl SET DATABASE TO <Name>. Achten Sie darauf, daß sie den selben Datenbankcontainer mehrmals öffnen können. Mit dem Befehl CLOSE DATA ALL können Sie alle geöffneten auch wieder schließen.

Nun können wir z.B. mit der rechten Maustaste ein Menü aufblättern, in dem wir alle Teile des DBC´s eintragen können.

Als erstes wollen wir einmal eine neue Tabelle anlegen. Nachdem wir einen Namen für die Tabelle vergeben haben, erscheint uns der Tabellendesigner, in dem wie die Hauptbestandteile einer Tabelle anlegen können.

Beachten Sie, daß sich die Tabelle nun nicht im DBC befinden wird, sondern wie in alten Zeiten, als DBF auf der Festplatte gespeichert wird. Hier sehen wir bereits den Unterschied zu einer SQL-Datenbank oder z.B. ACCESS. Dort wird nämlich alles in einer riesengroßen Datei abgespeichert.

Der Vorteil von VFP-Tabellen liegt in der enormen Geschwindigkeit, der Nachteil ist das „Verbraten“ von Filehandles, die in VFP leider noch auf 254 beschränkt sind. Dies wird sich jedoch in einer der nächsten Versionen wesentlich verbessern.

Wenn wir eine solche Tabelle anlegen, so wird im DBC der physikalische Aufenthaltsort der Tabelle und in der Tabelle selbst der Ort des DBC´s gespeichert. Dies bedeutet, daß man Tabelle und DBC nicht mehr trennen darf, da sie eine logische Einheit darstellen, die miteinander verheiratet ist. Bigamie ist auch nicht erlaubt, daß bedeutet, daß eine Tabelle nur ein einem Datenbankcontainer enthalten sein kann.

Will man explizit die Tabelle aus dem DBC entfernen, so muß der Befehl FREE TABLE angewendet werden.

Doch zurück zum Tabellendesigner.

Als erstes muß ich vor dem Dateinamen warnen. Wenn Sie unter Windows 95 oder Windows NT arbeiten, so verleitet es, den Namen über die acht Buchstaben hinaus länger zu schreiben. Wird ein solcher DBC und die Tabellen nun unter Windows 3.x angesprochen, so wird der DBC die Tabelle nicht mehr finden, da nun ein 8 Byte langes Synonym verwendet wird. Also Vorsicht und bleiben Sie bei 8 Buchstaben.

Allerdings kann ein (beinahe) beliebig langer Tabellenname als Alias verwendet werden, denn man ganz oben im rsten Feld des Tabellendesigners eintragen kann.

Nun kann frisch fröhlich Feld für Feld eingetragen werden.

Feldnamen mit 128 Zeichen Länge

Die erste Überraschung erlebt man, wenn man den Namen eines Feldes länger schreibt, als die üblichen 10 Stellen. Genau genommen sind nun 128 Stellen erlaubt, aber natürlich nicht besonders sinnvoll. Man sollte aufpassen, wenn Feldnamen verwendet werden, die länger als die üblichen 10 Stellen sind. Wie wir bereits gehört haben, hat sich die DBF-Struktur nicht geändert. Also werden in der DBF weiterhin nur 10 Stellen gespeichert. VFP 3.0 sorgt selbst dafür, daß der Feldname eindeutig bleibt und vercryptet die Feldnamen auf ähnliche Weise wie die Dateinamen unter Windows 95.

Die Warnung deshalb, da man bei einem eventuellem FREE TABLE die langen Feldnamen natürlich verliert und nur noch die abgekürzten Teile vorfindet.

Die neuen Feldtypen

Wenn man zur Combobox der verfügbaren Feldtypen ankommt, erlebt man bereits die erste Überraschung. Neben den alten Typen Zeichen, Numerisch, Logisch, Datum und Memo gibt es nun auch noch Integer, Double, Währung, Datum-Zeit, Zeichen Binär und Memo Binär.

Herausragende Eigenschaften dieser Feldtypen ist die Fähigkeit die Daten zu packen und dadurch Speicherplatz zu sparen. Und nebenbei wird auch noch Zeit gespart, da eine Umwandlung in ein Character-Numeric Format wegfällt.

Integer besteht aus nur 4 Byte und kann somit 32 Bit unterbringen.

Von -2147483647 bis 2147483646. Keine Nachkommastellen.

Double ist eine auf 8 Byte gepackte Fließkommazahl.

Von +/-4.94065645841247E-324 bis +/-1.79769313486232E308

Währung wurde aus dem SQL-Server Bereich übernommen, hat ebenfalls 8 Byte in der Datei jedoch ist auf 4 Nachkommastellen begrenzt und gilt

Von 922337203685477.5808 bis 922337203685477.5807

Datum-Zeit ist eine Kombination aus beiden Teilen und wird ebenfalls in 8 Byte gepackt abgespeichert.

Bei den Binären Datentypen handelt es sich um eine Spezialität aus der Codepageumwandlung. Unter FoxPro 2.x wurde grundsätzlich jedes Feld konvertiert, sobald die Tabelle mit einer Codepage versehen war. Ausnahmen konnte man mit früher dem Befehl SET NOCPTRANS TO <Feldliste> festlegen. Um diesen, heute unwichtigen, Befehl abzuschaffen wurden eben Zeichen Binär und Memo Binär eingeführt, bei denen keine Umwandlung der Zeichen zwischen den Codepages vorgenommen wird.

Zwei Einträge gibt es noch zusätzlich. Einerseits das FLOAT, welches jedoch nur noch aus Kompatiblitätsgründen vorhanden ist und dem Numerisch entspricht und das alte immer wieder grau unterlegte Picture, welches nur auf dem MAC eine Bedeutung hat.

Abhängig vom Datentyp kann man nun die Größe des Feldes eingeben und eventuell auch noch die Nachkommastellen.

Memofelder mit minimal einem Byte

Interessant wird es bei Memofeldern, da diese nur noch 4 Byte im Feld benötigen. Auch die alte Memo-Blockgrößen-Verwaltung wurde geändert. Nun kann die Blockgröße auf 0 gesetzt werden, was einem Byte entspricht. Werden also 21 Byte in das Memofeld geschrieben, so werden auch nur 21 Byte verbraucht.

Der Nullwert im Tabellenfeld

Nun kommen wir zu einer Spalte die ein NULL als Überschrift trägt. Wird hier angekreuzt, so kann dieses Feld einen .NULL. Wert enthalten. Sie können diese .NULL. in jedem Feld ankreuzen. Das Verhalten dabei, wurde weiter oben bereits beschrieben. In einem BROWSE-Fenster können Sie diesen Wert auch eingeben, in den Sie die STRG-Taste und die Taste Null drücken. Aber Achtung. Nicht die NULL auf der Nummerntastatur sondern die beim Gleichheitszeichen auf der normalen Tastatur.

Die Feld Eigenschaften

Eine der größten Errungenschaften des Datenbankcontainers sind die nachfolgenden Eigenschaften.

Jedes Feld kann mit einer Regel (Validation Rule) ausgestattet werden, die überprüft wird, sobald das Feld geschrieben wird. (bzw.: davor)

Als Regel kann natürlich auch eine Stored Procedure verwendet werden.

Beispiele für Regeln.

Wenn die Regel fehlschlägt, bzw. ein .F. zurückliefert, so wird automatisch der Validation Text verwendet und eine Fehlermeldung angezeigt. In einer Form wird die Errormethode angesprungen.

Die Default Value wurde weiter oben ebenfalls bereits beschrieben und kann ebenfalls durch eine Funktion gebildet werden, die als Stored Procedure abgespeichert werden kann.

Letztendlich noch ein Kommentarfeld, welches wahrscheinlich wie immer nicht gefüllt wird, da man dazu meist keine Zeit hat.

Indizes, wie wir sie uns wünschen

Als nächstes widmen wir uns den Indizen, bei denen sich ebenfalls etwas entscheidendes getan hat.

Einzugeben sind diese auf der zweiten Page des Tabellendesigners. Hier vermißt man allerdings die Funktionalität des alten 2.x Tabellendesigners, der einem durch Doppelklick auf ein Feld einen Index angelegt hat. Hier müssen wir selbst Hand anlegen und die Namen eintippen.

Indextypen haben wir nun vier zur Verfügung. Zuerst einmal die „alten“.

Einfach und Eindeutig. Eindeutig hat uns bereits unter FoxPro 2.x etwas vorgetäuscht, was nicht 100%ig zutrifft. Wenn nämlich ein Index als eindeutig gekennzeichnet wird, so wird nur das erste Vorkommen dieses Ausdrucks in den Index aufgenommen. Eintragen konnte man deshalb trotzdem mehrere gleiche Werte.

Neu hinzugekommen sind Primär und Potentiell. Grundsätzlich sind beide Indextypen identisch. Jedoch kann es in der Tabelle nur einen Primären geben, deshalb sind alle anderen dieses Typs eben nur potentielle Anwärter Primar zu werden. Eine etwas lustige Beschreibung aber so ist es am einfachsten zu erklären.

Auf alle Fälle sind diese Indizes echt „Eindeutig“ und lassen keine gleichen Einträge zu. Achten Sie darauf, daß dies auch gelöschte Datensätze mit einschließt. Diesen Effekt können Sie allerdings durch eine FOR-Klausel beim Index umgehen, die .NOT.DELETED() lautet. Achten Sie jedoch darauf, daß solch eine FOR-Klausel Rushmore ausschaltet und dieser Index für keinerlei mengenorientierte Abfrage zu gebrauchen ist.

Jetzt natürlich die Frage wozu denn ein Index als Primär zu kennzeichnen ist.

Benötigt wird dieser Indextyp, um erstens einen kleinen Schlüssel zu zeichnen, der diesen Index kennzeichnet und andererseits um bei einer Referentiellen Integrität herauszufinden, wie die Daten miteinander verknüpft werden können.

Tabellen Eigenschaften

Jede Tabelle kann noch zusätzlich mit sogenannten Table-Rules ausgestattet werden. Ein Klick auf Table-Properties läßt wiederum ein Fenster erscheinen, in dem diese eingegeben werden können.

Zusätzlich zu den Feld-Rules die, die einzelnen Felder abprüfen kann auch noch eine globale Satzregel definiert werden, die beim abspeichern des Satzes durchgeführt wird. Das Verhalten ist identisch mit dem der Feldregeln.

Nun noch zu einem entscheidendem neuen Teil, der weiter oben bereits angesprochen wurde.

Die Trigger

Für jeden Datenbankvorgang (INSERT, UPDATE, DELETE) gibt es die Möglichkeit eine Prozedur zu hinterlegen, die ausgeführt wird, sobald eines dieser Ereignisse eintritt. Sollte eine der Prozeduren .F. zurückliefern, so wird das Ereignis einfach nicht zugelassen und eine Fehlermeldung produziert. In einer Form kann diese Fehlermeldung abgefangen werden.

Nun noch zum Schluß daß Kommentarfeld, welches wie meistens unberührt bleiben wird.

Wenn Sie die Tabelle nun abspeichern so erscheint sie als kleine Tabelle im Datenbankcontainer

Ein Klick auf die rechte Maustaste läßt ein kontextsensitives Menü erscheinen, daß einem die Befehle wie FREE TABLE, MODIFY STRUCTURE usw. erspart.

Stored Procedures (Gespeicherte Prozeduren)

Wie bereits beschrieben sind Stored Procedures Programmteile, die Tabellen usw. bearbeiten können. Bei VFP 3.0 ist dies natürlich FoxPro Code, was uns das Leben wesentlich leichter macht.

Eingeben können Sie diese Prozeduren durch MODIFY PROCEDURE im Befehlsfenster oder durch einen rechten Mausklick im Datenbankfenster.

Alle Prozeduren werden hintereinander geschrieben und verhalten sich wie eine normale PRG-Datei.

Sie können hier auch globalen Prozedur-Code hinterlegen, da bei angewählter Datenbank die Funktionen zur Verfügung stehen, wie eine mit SET PROC TO <Datei> zugebundene Prozedurdatei.

Das spezielle an diesem Code ist die Verfügbarkeit innerhalb der Datenbank.

Wenn Sie eine Tabelle öffnen, die in einem Datenbankcontainer verankert ist, so wird automatisch die DBC mitgeöffnet und somit stehen auch die Prozeduren zur Verfügung, da diese direkt im DBC abgespeichert werden.

Ein Schließen eines DBC´s kompiliert automatisch diesen Code. Dies kann jedoch nachträglich mit COMPILE DATABASE nachgeholt werden.

Referentielle Integrität

Ein Schlagwort, welches auch in VFP3.0 nicht mehr fehlen darf. Wenn man in mehreren Tabellen Indizes definiert hat und einer davon ein Primärer ist, so kann man eine Relation zwischen den Tabellen definieren. Dies ist ganz einfach zu bewerkstelligen, indem man den Primären Index auf einen Index einer anderen Tabelle zieht.

Nach diesem „Drag und Drop“ wird eine Linie zwischen beiden Tabellen gezogen, die eine Relation darstellt, welche als Vorschlag in einer Form herangezogen wird.

Ein Klick mit der rechten Maustaste ermöglicht das Bearbeiten der Referentiellen Integrität.

Sobald man nun die RI bearbeitet wird automatisch der sogenannte RI-Builder, ein Steuerelementeassistent gestartet.

Pro angelegter Relation wird eine Zeile angezeigt, in der man die Beziehung zueinander festlegen kann.

Anfangs stehen alle Beziehungen auf „Ignorieren“. Durch Klick in die jeweilige Zeile kann die Datenbeziehung zueinander beliebig eingeschränkt oder weitergebend, definiert werden. Sobald man seine Einstellungen definiert hat, wird automatisch Code generiert, der eine prozedurale RI im DBC verankert. Es werden dabei auch automatisch Trigger in den betroffenen Tabellen eingerichtet.

Aufpassen muß man nur, wenn man verschiedene Sprachversionen von VFP untereinander mischt. In einer englischen Version wird folgender Code ziemlich am Anfang generiert.

IF (UPPER(SYS(2011))="RECORD LOCKED" and !deleted()) OR !RLOCK()

In der deutschen Version wird daraus

IF (UPPER(SYS(2011))="DATENSATZ GESPERRT" and !deleted()) OR !RLOCK()

was sich natürlich negativ auf das Verhalten auswirkt. Allerdings können Sie das Problem umgehen, wenn Sie den RI-Code in der richtigen Version, im Datenbankcontainer neu generieren lassen.

Ansichten (Views)

Eine Besonderheit einer Datenbank ist die sogenannte View. Das bedeutet, daß man Tabellen oder nur Teile davon in spezieller Art „ansieht“. Eingestellt werden diese Ansichten im View- oder Ansichtendesigner. Zu erreichen ist dieser durch ein CREATE / MODIFY VIEW <Viewname> im Befehlsfenster oder wieder durch die rechte Maustaste im Datenbankdesigner.

Unterm Strich gesehen ist dieser Designer (fast) identisch mit dem Query-Designer, denn wir bereits als RQBE in FoxPro 2.x kennengelernt haben.

Auch hier wird ein SQL-Statement interaktiv erzeugt, welches Daten aus einer oder mehreren Tabellen zusammenführt, einschränkt, sortiert und gruppiert.

Das Besondere daran ist jedoch, daß diese SQL-Befehle keine Einbahnstraßen darstellen, wie es die Cursor des Querydesigners darstellen. Die hier erzeugten Ansichten sind direkt mit den Originaltabellen verknüpft und können direkt Daten ändern wenn man dies erlaubt.

Das „Erlauben“ geschieht in der letzten Page des Viewdesigners.

Die wichtigsten Bestandteile bei den „Update Criteria“ sind die Hacken bei „Send SQL Updates“ und unterhalb des Schlüssel- und Stiftsymbols.

Der Hacken unter dem Schlüssel gibt an, welches der Schlüsselbegriff der Datei ist, um den Datensatz eindeutig wiederzufinden. Ein Hacken unter dem Stift gibt an, daß dieses Feld „Updateable“ d.h. beschreibbar ist.

Der Hacken bei „Send SQL Updates“ schließlich gibt an, daß Updates an die originalen Tabellen geschickt wird.

Die restlichen Einstellungsmöglichkeiten haben nur bei sogenannten Remote Views reelle Bedeutung.

Sobald diese Einstellungen gemacht wurden und die View unter einem X-beliebigen Namen abgespeichert wurde, so kann man die View, gleich einer Tabelle, mit USE öffnen und es wird sofort ein SQL-Befehl ausgeführt, der einem die Daten in der gewünschten Form darstellt.

Man kann nun wie in einer normalen Tabelle mit SKIP oder GO <Datensatz> arbeiten. Alle Felder, die als Updateable gekennzeichnet wurden werden auch automatisch zurückgeschrieben, wenn man einen Wert ändert.

REMOTE VIEWS

Wie bereits erwähnt gleicht sich der Viewdesigner bei den lokalen Tabellen und den sogenannten Remote Tabellen. Remote Tabellen sind alles, was man über ODBC ansprechen kann. Inzwischen liegt einem beinahe die gesamte Welt offen und jeder Datenbankhersteller bietet einen ODBC-Treiber für seine Datenbank an.

Somit haben wir unter VFP 3.0 eines der stärksten ODBC-Tools in Händen, daß zur Zeit am Markt existiert.

Hier noch ein kleiner Tip, bzw. eine Warnung.

Alle Datensätze einer View werden in einer lokalen DBF gespeichert.

Also wenn die Anzahl der Datensätze des SQL-Befehls eine Million Datensätze beträgt, so wird dementsprechend lokal eine große Menge an Plattenplatz benötigt um diese Datei unterzubringen.

Eine SELECT * FROM <Tabelle> ist also auf alle Fälle zu vermeiden. Um die Auswahl zu beschränken hat uns VFP3.0 das Fragezeichen mit auf den Weg gegeben.

Wenn in den Selektionskriterien im Feld Beispiel ein Fragezeichen eingegeben wird, so versucht die View den nachfolgenden Ausdruck als Variable zu verwerten. Ist eine Solche Variable nicht vorhanden, so bekommen Sie ein Fenster in dem Sie den Wert eingeben können.

Dadurch wird es möglich eine View sozusagen „fernzusteuern“. Eine Änderung des Variablenwerts allerdings verändert nicht automatisch die View. Eine solche Aktion müssen Sie selbst durch die Funktion =REQUERY() veranlassen, daß den SQL-Befehl noch einmal ausführt.

Teil 2. Der Datenbankcontainer unter 5.0

Im ersten Teil haben Sie die Grundfunktionen des datenbankcontainer kennengelernt. Die Bildschirmfotos wurden auch unter VFP3.0 gemacht. Nun gibt es seit kurzem die Version 5.0 und wie man es sich denken kann, hat sich das grafische Bild wieder einmal geändert.

Als Beispiel der MODI STRU Dialog:

Wie Sie erkennen können werden nun die neuen Pageframes verwendet. Außerdem ist der gesamte Aufbau etwas übersichtlicher geworden.

Als besonderes „Zuckerl“ sei hier die Spalte Index hervorzuheben, welche es ermöglicht sofort einen Index auf einem Feld zu definieren.

Zusätzlich zu den Feldern Caption, Rule, Message, Default value und Field comment sind nun Format, Input mask, Display library und Display class dazugekommen.

Format und Input mask.

Aus dem Maskendesigner sind uns diese Properties bereits bekannt. Wenn man hier bereits Werte definiert, so werden diese automatisch übernommen, wenn man aus dem Dataenvironment oder aus dem Projekt dieses Feld auf die Maske zieht.

Genau so wird dies mit den Definitionen von Display library und Display class gehandhabt.

Füe die Einsteiger untr uns: Man kann direkt aus dem Dataenvironment ein Datenfeld in die Maske ziehen. In der Version 3.0 wurde als Basisklasse für die textboxes und labels die FoxPro interne Baseclass verwendet, was teilweise sehr störend sein konnte, da man die SCX-Datei dann per Hand verändern musste um nicht jedes Feld zu Fuß zu definieren. Jetzt können Sie hier Ihre eigene Klassendefinition unterbringen, was die Entwicklungszeit erheblich verkürzt.

Bei den Indizes hat sich in der Version 5.0 nicht neues getan.

Auf der Page „Table“ wird der Rest der Informationen aus der datenbank angezeigt. Auch hier hat sich nur das Aussehen verändert. Funktionell ist alles beim alten geblieben.

Modifizieren des Datenbankcontainers

Wenn man einen Datenbankcontainer verändert, bzw. Den Datenbankdesigner geöffnet hat, so sind nun ein paar neue Funktionen dazugekommen, welche das Arbeiten erheblich erleichtern. Als erstes sei erwähnt, daß ein bekannter Bug behoben wurde, der die Systemresourcen betraf, sobald man den Rollbalken mehrmal nach unten und wieder nach oben gezogen hat. (Dies als kleiner Nachtrag für die Version 3.0)

Über die rechte Maustaste erhalten Sie ein Zusatzmenü welches in der Version 5.0 erweitert wurde. Dazugekommen ist unter anderem eine Suchfunktion, um ein Objekt in listenartiger Form auszuwählen.

Auch neu ist die Möglichkeit Connections (ODBC-Verbindungen) zu editieren ohne den MODI CONN Befehl zu verwenden.

Und noch ganz neu: Die Properties. Hier kann man die Anzeige eines Objekttypes verhindern. Sollten alle Teile ausgeschalten sein, so erscheint uns der Datenbankcontainer völlig leer. Ein etwas witziges Feature. <g>

Zusätzlich ist im Menü noch ein Programmpunkt names Arrange dazugekommen.

Sollten Sie Ihren Datenbankcontainer in einem chaotischem Zustand vorfinden, können Sie hier wieder Ordnung hineinbringen. Allerdings wird eine sauber verteilte „Ordnung“ ebenfalls wieder zunichte gemacht.

Der erzeugte RI-Code im DBC und Stored Procedures.

Ahhhh Yeah. Man hat es endlich geschafft eine Funktion zu schaffen, welche den Sperrstatus eines Datensatzes zurückliefert. Also vorbei mit dem alten Problem des RI-Codes, welcher unter einer englischen Version anders reagierte als in einer deutschen, wenn man die Versionen mischte.

Die Funktion islocked() ersetzt die alte SYS(2010) Funktion, die einen eingedeutschten Text geliefert hat, was sich unter einer englischen FoxPro Version böse ausgewirkt hat.

Aber leider habe ich schon wieder einen Wehrmutstropfen zu vermelden. (Sagen wir lieber eine Jumbo Wehrmutsflasche <g>)

In der Version 5.0 wurde der Binärcode eines VFP-Programmes geändert, was vorraussetzt, daß man jeden VFP-Code durch den Compiler schicken muß. Leider ist der RI-Code und die Stored Procedures in VFP-Code geschrieben. Also kann eine VFP3.0 Version nicht mit den Stored Procedures einer 5.0 Version umgehen und umgekehrt. Einmal Version 5.0 immer Version 5.0

Rushmore Optimierung

Eine willkommene Erweiterung zum Thema Rushmore liefert uns die SYS(3054) Funktion. Nachdem Sie eine Abfrage in VFP gemacht haben, können Sie mit ?SYS(3054,1) feststellen, ob die Abfrage optimiert, nicht optimiert oder teilweise optimiert war. Aber wie gesagt, nach der Abfrage.

Offline Views

Was eine View ist, daß sollte uns ja nun bekannt sein. Aber zur Sicherheit noch einmal eine andere Erklärung um den Begriff einer Offline View zu verstehen.

Sobald man eine View öffnet, wird aufgrund eines SQL-Befehls eine temporäre Datei erstellt, welche man nach einer Änderung mit den Befehlen Tableupdate oder Tablerevert wieder zurückschicken oder verwerfen kann.

Es ist natürlich nun naheliegend, daß man eine solche temporäre Datei nicht einfach verwirft, sondern als Offline weiter auf der Festplatte führt und mit den Daten arbeitet, als ob man noch mit der original physikalischen Datei verbunden wäre. Auch über einen Systemstart hinweg bleibt eine solche Offline View bestehen.

Erst wenn man explizit bestimmt, daß die Daten wieder weggeschickt werden sollen, wird zur physikalischen Datei ein Kanal geöffnet und die Daten nach den gewohnten Regeln des Optimistischen Sperrens weggeschickt.

Diese Funktionalität erlangen Sie durch die Befehle CREATEOFFLINE( ) und DROPOFFLINE( ).

Neue SELECT-SQL Klauseln

Ein jahrelanger Traum wird wahr.

Endlich sind diese Zusätze möglich um Daten auf verschiedenste Art und Weise zu verknüpfen.

Rushmore kein Problem ??
oder die schlimmsten Fehler.

FoxPro wurde bekannt als die schnellste Datenbank der Welt auf Industrie-PC´s. Andererseits ist es 10 mal leichter, einen Rushmore-Fehler zu begehen, als es richtig zu machen.

Der Begriff Rushmore kommt angeblich daher, daß man einen Namen für die Technologie suchte und zufälligerweise der Berühmte Hitchcock-Streifen „der dritte Mann“ im Fernsehen lief. Da nun der Höhepunkt des Films am Mount Rushmore stattfand und sich der Name „gut anhörte“, war der Name schon gefunden.

Rushmore ist relativ leicht zu begreifen, wenn man ein paar Grundkenntnisse hat.

Zuerst einmal der Index. Dieser liegt in komprimierter Form auf der Festplatte. Also ist der Datenzugriff schneller als bei einem nicht komprimierten.

Wenn wir nun eine Abfrage an VFP abschicken wird der Ausdruck als erstes durchsucht, ob nicht einer der Teilafragen in irgendeiner Art und Weise als Index abgespeichert wurde. VFP geht da sehr einfache Wege. Es sucht sich einfach alle Audrücke heraus, die irgendwo in einem Index vorkommen.

Wurde also ein Index mit „INDEX ON UPPER(Nachname) TAG Nachname“ erstellt, so muß der fragende Ausdruck ebenfalls die Funtkion UPPER beinhalten. Eine solche Frage könnte folgendermassen gestellt werden

BROWSE FOR UPPER(Nachname) = „HERZOG“

Sollten Sie die Abfrage auf

BROWSE FOR Nachname = UPPER(„Herzog“)

lauten lassen, so werden Sie kein Glück haben, da der Indexausdruck auf UPPER(Feldname) lautet. Dies ist so ziemlich der häufigste Fehler.

Ein anderes Problem stellt der Befehl SET DELETED ON dar. Mit diesem Befehl befehlen Sie VFP alle gelöschten Datensätze zu unterdrücken. Wie erkennt aber VFP, daß es sich um gelöschte Datensätze handelt ?

Im Datensatz, genauer gesagt an Byteposition 1, ist ein Byte reserviert, welches den Gelöschtstatus beinhaltet. Wenn Sie nun die Anzeige der gelöschten unterdrücken wollen, so muß VFP bei jedem Datensatz nachsehen, ob er nun gelöscht ist, oder eben nicht.

Das ist mit Festplattenzugriffen verbunden, welche die das gesamte System lahmlegen können. AM einfachsten umgehen Sie das Problem, indem Sie einfach einen Index auf dem Gelöscht-Flag erzeugen.

INDEX ON DELETED() TAG _gel

Der TAGname selbst ist völlig egal. VFP schaut immer mal im Index nach, ob nicht doch irgendeine Möglichkeit besteht die Abfrage zu verschnellern.

Ein ebenfalls häufig gemachter Fehler ist das Verwenden von verschiendenen Collatesequenzen. Das bedeutet, daß ein SET COLLATE TO ‘GERMAN’ auf einen Index, erzeugt unter der Collatesequenz ‘MACHINE’, die Rushmoreoptimierung einfach ausschaltet.

Vermeiden Sie FOR-Klauseln im INDEX ON Befehl. Sobald eine FOR-Klausel vorkommt, so wird ebenfalls Rushmore nicht mehr verwendet. (Nicht zu verwechseln durch die FOR-Klausel in den Abfragebefehlen)

Nachdem Sie es geschafft haben bis hierher vorzudringen, hoffe ich, daß Ihnen ein paar Aha´s von den Lippen gekommen sind und dieser Artikel Ihnen das arbeiten mit Visual FoxPro erleichtern wird.