Access 2000 Programmierung
Access 2000 Programmierung eBook Die nicht autorisierte Weitergabe dieses eBooks an Dritte ist eine Verletzung des Urheberrechts!
Markt&Technik Verlag
Die Deutsche Bibliothek – CIP-Einheitsaufnahme Ein Titeldatensatz für diese Publikation ist bei der Deutschen Bibliothek erhältlich Die Informationen in diesem Buch werden ohne Rücksicht auf einen eventuellen Patentschutz veröffentlicht. Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt. Bei der Zusammenstellung von Texten und Abbildungen wurde mit größter Sorgfalt vorgegangen. Trotzdem können Fehler nicht vollständig ausgeschlossen werden. Verlag, Herausgeber und Autoren können für fehlerhafte Angaben und deren Folgen weder eine juristische Verantwortung noch irgendeine Haftung übernehmen. Für Verbesserungsvorschläge und Hinweise auf Fehler sind Verlag und Herausgeber dankbar. Alle Rechte vorbehalten, auch die der fotomechanischen Wiedergabe und der Speicherung in elektronischen Medien. Die gewerbliche Nutzung der in diesem Produkt gezeigten Modelle und Arbeiten ist nicht zulässig. Fast alle Hardware- und Softwarebezeichnungen, die in diesem Buch erwähnt werden, sind gleichzeitig auch eingetragene Warenzeichen oder sollten als solche betrachtet werden. Umwelthinweis: Dieses Buch wurde auf chlorfrei gebleichtem Papier gedruckt. Die Einschrumpffolie – zum Schutz vor Verschmutzung – ist aus umweltverträglichem und recyclingfähigem PE-Material.
10 9 8 7 6 5 4 3 2 1 04 03 02 01 00
ISBN 3-8272-5706-9 © 2000 by Markt&Technik Verlag, ein Imprint der Pearson Education Deutschland GmbH, Martin-Kollar-Straße 10–12, D-81829 München/Germany Alle Rechte vorbehalten Übersetzung und fachliche Begutachtung: G&U Technische Dokumentation, Flensburg Lektorat: Rainer Fuchs,
[email protected] Herstellung: Claudia Bäurle,
[email protected] Einbandgestaltung: Grafikdesign Heinz H. Rauner, München Satz: reemers publishing services gmbh, Krefeld Bildnachweis: VCL/Bavaria Druck und Verarbeitung: Bercker, Kevelaer Printed in Germany
Inhaltsverzeichnis
Vorwort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Symbole im Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 Die Autorin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Teil I
Grundlagen der Entwicklung mit Access . . . . . . . . . . . . . . . . . 23
1
Access als Entwicklungswerkzeug . . . . . . . . . . . . . . . . . . . . .25
1.1 1.2 1.3 1.4 1.5 1.6 1.7
Welche Arten von Anwendungen können mit Access entwickelt werden? . Access als skalierbares Produkt . . . . . . . . . . . . . . . . . . . . . . . . Was genau ist eine Datenbank ? . . . . . . . . . . . . . . . . . . . . . . . . Datenbankobjekte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Objektbenennung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Hardwareanforderungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . Wie beginne ich mit der Entwicklung einer Access-Anwendung? . . . . . .
2
Was jeder Entwickler über Tabellen wissen sollte . . . . . . . . . . 53
2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9
Mit Tabellen arbeiten . . . . . . . . . . . . . . . . . . . Eine Tabelle von Grund auf entwerfen . . . . . . . . . . Den für Ihre Daten geeigneten Feldtyp auswählen . . . Feldeigenschaften . . . . . . . . . . . . . . . . . . . . . Der allgegenwärtige Primärschlüssel . . . . . . . . . . Der Nachschlage-Assistent . . . . . . . . . . . . . . . . Tabelleneigenschaften . . . . . . . . . . . . . . . . . . Mit Hilfe von Indizes die Geschwindigkeit verbessern . Access-Tabellen und das Internet . . . . . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . .
. . . . . . . . .
. . . . . . .
. . . . . . . . .
. 25 . 30 . 30 . 31 . 42 . 43 . 44
. 53 . 54 . 57 . 63 . 74 . 75 . 77 . 79 . 79
6
Inhaltsverzeichnis
3
Beziehungen: Ihr Schlüssel zur Datensicherheit . . . . . . . . . . . 89
3.1 3.2 3.3 3.4 3.5
Beziehungstypen . . . . . . . . . . Beziehungen einrichten . . . . . . Für referentielle Integrität sorgen Vorteile von Beziehungen . . . . . Indizes und Beziehungen . . . . .
4
Was jeder Entwickler über Abfragen wissen sollte . . . . . . . . . 105
4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10 4.11 4.12 4.13
Was ist eine Abfrage und wann wird sie eingesetzt? . . . Alles, was Sie über Abfragen wissen sollten. . . . . . . . Ihr Abfrage-Ergebnis sortieren . . . . . . . . . . . . . . . Ihre Abfrage mit Hilfe von Kriterien verbessern . . . . . . In Kriterien mit Datumsangaben arbeiten . . . . . . . . . Abfrage-Ergebnisse aktualisieren . . . . . . . . . . . . . Abfragen auf der Grundlage mehrerer Tabellen erstellen Berechnete Felder erstellen . . . . . . . . . . . . . . . . . Der Ausdrucks-Generator . . . . . . . . . . . . . . . . . . Daten mit Hilfe von Abfragen zusammenfassen. . . . . . Felder aus der Ausgabe ausschließen . . . . . . . . . . . Nullwerte und Abfrage-Ergebnisse . . . . . . . . . . . . . Ihre Abfragen mit Hilfe von Feld-, Feldlisten- und Abfrage-Eigenschaften verbessern . . . . . . . . . . . . . Parameterabfragen, wenn die Kriterien beim Entwurf noch nicht bekannt sind . . . . . . . . . . . . . . . . . . .
4.14
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . . . . . . . . .
. . . . .
. . . . . . . . . . . .
. . . . .
. . . . . . . . . . . .
. . . . .
. . . . . . . . . . . .
. . . . .
. . . . . . . . . . . .
. . . . .
. . . . . . . . . . . .
. . . . .
. . . . . . . . . . . .
. . . . .
. . . . . . . . . . . .
. . . . .
. . . . . . . . . . . .
. . . . .
. . . . . . . . . . . .
. . . . .
. . . . . . . . . . . .
. 89 . 92 . 96 . 101 . 102
. 105 . 106 . 112 . 113 . 116 . 118 . 119 . 125 . 127 . 128 . 132 . 133
. . . . . . . . . . . . 136 . . . . . . . . . . . . 138
5
Was jeder Entwickler über Formulare wissen sollte . . . . . . . . . 143
5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8
Verwendungen für Formulare . . . . . . . . . . . . . . . . . . . . . Aufbau eines Formulars . . . . . . . . . . . . . . . . . . . . . . . . Ein neues Formular erstellen . . . . . . . . . . . . . . . . . . . . . Mit dem Formularentwurfsfenster umgehen . . . . . . . . . . . . Das geeignete Steuerelement auswählen . . . . . . . . . . . . . . Ein Steuerelement durch ein anderes ersetzen . . . . . . . . . . . Bedingte Formatierung . . . . . . . . . . . . . . . . . . . . . . . . Welche Formulareigenschaften stehen zur Verfügung und warum sollten sie benutzt werden? . . . . . . . . . . . . . . . . . Welche Steuerelementeigenschaften stehen zur Verfügung und warum sollten sie benutzt werden? . . . . . . . . . . . . . . . . . Gebundene, ungebundene und berechnete Steuerelemente . . . Formulare mit Hilfe von Ausdrücken erweitern . . . . . . . . . . .
5.9 5.10 5.11
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. . . . . . .
. 143 . 146 . 147 . 151 . 159 . 169 . 170
. . . . . . . 171 . . . . . . . 179 . . . . . . . 185 . . . . . . . 185
7
Inhaltsverzeichnis
5.12 5.13 5.14 5.15
Die Befehlsschaltflächen-Assistenten: Programmierung ohne Eingabe Formulare auf der Grundlage mehrerer Tabellen . . . . . . . . . . . . . Formulare auf Abfragen aufsetzen . . . . . . . . . . . . . . . . . . . . . Access-Formulare und das Internet . . . . . . . . . . . . . . . . . . . .
6
Was jeder Entwickler über Berichte wissen sollte . . . . . . . . . . 205
6.1 6.2 6.3 6.4 6.5 6.6
6.14
Berichtstypen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Aufbau eines Berichts . . . . . . . . . . . . . . . . . . . . . . . . . Einen neuen Bericht erstellen . . . . . . . . . . . . . . . . . . . . Das Berichtsentwurfsfenster . . . . . . . . . . . . . . . . . . . . . Das geeignete Steuerelement auswählen . . . . . . . . . . . . . . Welche Berichtseigenschaften stehen zur Verfügung und warum sollten sie benutzt werden? . . . . . . . . . . . . . . . . . Welche Steuerelementeigenschaften stehen zur Verfügung und warum sollten sie benutzt werden? . . . . . . . . . . . . . . . . . Seitenumbrüche einfügen . . . . . . . . . . . . . . . . . . . . . . Gebundene, ungebundene und berechnete Steuerelemente . . . Berichte mit Hilfe von Ausdrücken erweitern . . . . . . . . . . . . Berichte auf der Grundlage mehrerer Tabellen . . . . . . . . . . . Sortierreihenfolge und Gruppierung . . . . . . . . . . . . . . . . . Durch Aufsetzen der Berichte auf gespeicherte Abfragen Geschwindigkeit und Wiederverwendbarkeit verbessern . . . . . Access-Berichte und das Internet . . . . . . . . . . . . . . . . . .
7
VBA: Eine Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251
7.1 7.2
Was ist VBA? . . . . . . . . . . . . . . . . . . . . . Was sind die Klassen-, Standard-, Formular- und Berichtsmodule von Access? . . . . . . . . . . . . Mit Variablen arbeiten. . . . . . . . . . . . . . . . Kommentare in den Code einfügen . . . . . . . . Das Zeichen für die Fortsetzung der Zeile . . . . . Die VBA-Steuerstrukturen. . . . . . . . . . . . . . Parameter über- und Werte zurückgeben . . . . . Vom Modulfenster aus Prozeduren ausführen . . Das Objekt DoCmd: Makro-Aktionen durchführen Integrierte Funktionen. . . . . . . . . . . . . . . . Mit Konstanten arbeiten . . . . . . . . . . . . . . Werkzeuge für die Arbeit im VBE . . . . . . . . . . Den VBE individuell anpassen . . . . . . . . . . .
6.7 6.8 6.9 6.10 6.11 6.12 6.13
7.3 7.4 7.5 7.6 7.7 7.8 7.9 7.10 7.11 7.12 7.13
. . . . .
. . . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
. . . . .
. . . .
187 189 193 195
. 205 . 210 . 211 . 215 . 219
. . . . . . . 223 . . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. 227 . 230 . 231 . 231 . 231 . 238
. . . . . . . 242 . . . . . . . 243
. . . . . . . . . . . . . . . . 251 . . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. 254 . 265 . 270 . 271 . 271 . 280 . 281 . 281 . 282 . 287 . 290 . 302
8
Inhaltsverzeichnis
8
Objekte, Eigenschaften, Methoden und Ereignisse . . . . . . . . . 307
8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 8.10
Das Objektmodell von Access. . . . . . . . . . . . . . . . . . Objekte, Eigenschaften, Ereignisse und Methoden . . . . . . Access-Objekte mit Hilfe des Objektkatalogs kennen lernen Sich auf Objekte beziehen. . . . . . . . . . . . . . . . . . . . Eigenschaften und Methoden leicht gemacht . . . . . . . . . Objektvariablen deklarieren und zuweisen . . . . . . . . . . Unterschiede zwischen Objekten und Auflistungen . . . . . Objekte an Unterroutinen und Funktionen übergeben . . . . Den Typ eines Steuerelements bestimmen . . . . . . . . . . Spezielle Eigenschaften mit Objektbezug . . . . . . . . . . .
9
Fortgeschrittene Verwendung von Formularen . . . . . . . . . . . . 335
9.1 9.2 9.3 9.4 9.5 9.6 9.7
9.17
Formulare ergänzen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Was sind Formularereignisse und wann sollten sie verwendet werden? . . Die Reihenfolge der Formularereignisse . . . . . . . . . . . . . . . . . . . . Abschnitts- und Steuerelementereignisse und ihre Verwendung . . . . . . Die Reihenfolge der Steuerelementereignisse . . . . . . . . . . . . . . . . Das Schlüsselwort Me . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Welche Arten von Formularen kann ich erstellen und wann sind sie geeignet? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Integrierte Dialogfelder . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Formularen benutzerdefinierte Menüs, Symbolleisten und Kontextmenüs hinzufügen. . . . . . . . . . . . . . . . . . . . . . . . . . . . Die integrierten Funktionen zur Formularfilterung ausnutzen . . . . . . . . Objekte aus anderen Anwendungen einfügen: Verknüpfen oder Einbetten OpenArgs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Datenherkunft eines Formulars wechseln . . . . . . . . . . . . . . . . . Fortgeschrittener Umgang mit Kombinations- und Listenfeldern . . . . . . Fortgeschrittener Umgang mit Unterformularen . . . . . . . . . . . . . . . Ein Formular mit der zu Grunde liegenden Datensatzgruppe in Einklang bringen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Benutzerdefinierte Eigenschaften und Methoden erstellen . . . . . . . . .
10
Fortgeschrittene Verwendung von Berichten . . . . . . . . . . . . . 399
10.1 10.2 10.3
Mit Berichten arbeiten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 Für Berichte verfügbare Ereignisse und wann sie verwendet werden sollten . 399 Ereignisreihenfolge für Berichte . . . . . . . . . . . . . . . . . . . . . . . . . . 403
9.8 9.9 9.10 9.11 9.12 9.13 9.14 9.15 9.16
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . .
. 307 . 312 . 316 . 320 . 321 . 323 . 325 . 327 . 328 . 330
. 335 . 336 . 346 . 348 . 354 . 355
. . 356 . . 364 . . . . . . .
. 368 . 373 . 375 . 377 . 377 . 380 . 388
. . 389 . . 390
9
Inhaltsverzeichnis
10.4 10.5 10.6
Für Berichtsabschnitte verfügbare Ereignisse und wann sie verwendet werden sollten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 Spezielle Berichtseigenschaften . . . . . . . . . . . . . . . . . . . . . . . . . . 408 Praktische Anwendungen für Berichtsereignisse und -eigenschaften . . . . . 410
11
Fortgeschrittene Abfragetechniken . . . . . . . . . . . . . . . . . . . . 431
11.1 11.2 11.3 11.4 11.5 11.6 11.7 11.8 11.9 11.10 11.11 11.12 11.13
Aktionsabfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Spezielle Abfrage-Eigenschaften . . . . . . . . . . . . . . . . . . . . Abfragen optimieren. . . . . . . . . . . . . . . . . . . . . . . . . . . Kreuztabellenabfragen . . . . . . . . . . . . . . . . . . . . . . . . . Äußere Verknüpfungen . . . . . . . . . . . . . . . . . . . . . . . . . Selbstverknüpfungen . . . . . . . . . . . . . . . . . . . . . . . . . . SQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Union-Abfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pass-Through-Abfragen . . . . . . . . . . . . . . . . . . . . . . . . . Die Weitergabe von Nullwerten und Abfrage-Ergebnisse . . . . . . Unterabfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Das Ergebnis einer Funktion als Abfragekriterium verwenden . . . Die Werte für eine Parameterabfrage aus einem Formular einlesen
12
Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte? . . . 479
12.1 12.2 12.3 12.4 12.5 12.6 12.7 12.8 12.9 12.10 12.11 12.12
Datenzugriffsobjekte . . . . . . . . . . . . . . . . . . . . . . . . . . . ActiveX-Datenobjekte und Datenzugriffsobjekte im Vergleich . . . . Das Datenobjektmodell von ActiveX . . . . . . . . . . . . . . . . . . . Arten von ADO-Datensatzgruppen . . . . . . . . . . . . . . . . . . . . Mit ADO-Recordset-Eigenschaften und -Methoden umgehen . . . . . Tabellendaten mit Hilfe von ADO-Code bearbeiten. . . . . . . . . . . Datenbankobjekte mit Hilfe von ADO-Code erstellen und bearbeiten Das Datenzugriffsobjektmodell (DAO) . . . . . . . . . . . . . . . . . . DBEngine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . CurrentDB(). . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Arten von DAO-Datensatzgruppen . . . . . . . . . . . . . . . . . . . . Zwischen den verfügbaren Arten von DAO-Datensatzgruppenobjekten wählen . . . . . . . . . . . . . . . . Mit DAO-Recordset-Eigenschaften und -Methoden umgehen . . . . . Tabellendaten mit Hilfe von DAO-Code bearbeiten. . . . . . . . . . . Datenbankobjekte mit Hilfe von DAO-Code erstellen und bearbeiten Die DAO-Container-Auflistung . . . . . . . . . . . . . . . . . . . . . .
12.13 12.14 12.15 12.16
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. 432 . 441 . 444 . 450 . 457 . 459 . 460 . 467 . 468 . 469 . 470 . 471 . 473
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. 479 . 480 . 481 . 486 . 490 . 500 . 504 . 508 . 516 . 517 . 517
. . . . .
. . . . .
. . . . .
. . . . .
. 519 . 519 . 531 . 535 . 539
10
Inhaltsverzeichnis
Teil II Falls etwas nicht nach Plan läuft . . . . . . . . . . . . . . . . . . . . . . 545 13
Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung . . . . 547
13.1 13.2 13.3 13.4 13.5 13.6 13.7 13.8 13.9 13.10 13.11
Fehler vermeiden . . . . . . . . . . . . . . . . . . . . . Die Leistungsfähigkeit des Direktfensters nutzen . . Den Debugger aufrufen . . . . . . . . . . . . . . . . . Haltepunkte einsetzen . . . . . . . . . . . . . . . . . . Code schrittweise durchgehen . . . . . . . . . . . . . Die nächste auszuführende Anweisung festlegen . . Das Fenster Aufrufeliste . . . . . . . . . . . . . . . . . Mit dem Lokal-Fenster arbeiten. . . . . . . . . . . . . Mit Überwachungsausdrücken arbeiten . . . . . . . . Die Ausführung nach einem Laufzeitfehler fortsetzen Gefundenes im Direktfenster ansehen . . . . . . . . .
14
Fehlerbehandlung: Vorbereitung auf das Unvermeidliche . . . . 575
14.1 14.2 14.3 14.4 14.5 14.6 14.7 14.8 14.9 14.10 14.11 14.12
Fehler beheben . . . . . . . . . . . . . . . . . . . . . . . . . . . . Fehlerbehandlung implementieren . . . . . . . . . . . . . . . . . Mit Fehlerereignissen arbeiten . . . . . . . . . . . . . . . . . . . On Error-Anweisungen . . . . . . . . . . . . . . . . . . . . . . . . Resume-Anweisungen . . . . . . . . . . . . . . . . . . . . . . . . Fehlerinformationen löschen . . . . . . . . . . . . . . . . . . . . Verschachtelte Fehlerbehandlungsroutinen. . . . . . . . . . . . Das Objekt Err . . . . . . . . . . . . . . . . . . . . . . . . . . . . Einen Fehler auslösen . . . . . . . . . . . . . . . . . . . . . . . . Die Auflistung Errors . . . . . . . . . . . . . . . . . . . . . . . . . Eine allgemeine Fehlerbehandlungsroutine erstellen . . . . . . Verhindern, dass die eigene Fehlerbehandlung aufgerufen wird
15
Optimieren Ihrer Anwendung . . . . . . . . . . . . . . . . . . . . . . . . 603
15.1 15.2 15.3 15.4 15.5 15.6 15.7 15.8 15.9
Mehr Leistung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Einführung in die Optimierung . . . . . . . . . . . . . . . . . . . . . Hard- und Software-Konfiguration modifizieren . . . . . . . . . . . Was bringt Jet 4.0 für die Verbesserung der Leistung? . . . . . . . . Mit Hilfe der Leistungsanalyse Problembereiche ermitteln . . . . . Tabellen mit dem Ziel optimaler Leistung gestalten . . . . . . . . . Abfragen mit dem Ziel optimaler Leistung gestalten . . . . . . . . . Anders programmieren, um die Leistung zu optimieren . . . . . . . Formulare und Berichte mit dem Ziel optimaler Leistung gestalten
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . .
. 548 . 549 . 555 . 555 . 558 . 562 . 563 . 565 . 565 . 571 . 572
. 575 . 576 . 577 . 579 . 582 . 584 . 585 . 586 . 586 . 588 . 589 . 600
. 603 . 603 . 604 . 608 . 610 . 611 . 613 . 614 . 624
11
Inhaltsverzeichnis
Teil III Mehrbenutzer- und Unternehmensanwendungen entwickeln . 629 16
Eine Strategie für die Entwicklung von Access-Anwendungen . 631
16.1 16.2 16.3 16.4 16.5 16.6 16.7
Leistungssteigerungen . . . . . . . . . . . . . . . . . . . . . . . . Datenbanken in Tabellen und andere Objekte zerlegen . . . . . . Abfragen oder eingebettete SQL-Anweisungen als Grundlage für Formulare und Berichte . . . . . . . . . . . . . . . . . . . . . . . . Die Laufzeit-Engine von Access. . . . . . . . . . . . . . . . . . . . Eine ausführbare Datei und eine Access-Datenbank im Vergleich Die Bedeutung der Absicherung der Datenbank . . . . . . . . . . Access als Front-End. . . . . . . . . . . . . . . . . . . . . . . . . .
17
Mehrbenutzeranwendungen entwickeln . . . . . . . . . . . . . . . . 649
17.1 17.2 17.3 17.4 17.5 17.6 17.7 17.8 17.9 17.10 17.11 17.12 17.13
Anwendungsentwicklung unter Berücksichtigung der Ansprüche mehrerer Benutzer . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Sperrmechanismen von Access . . . . . . . . . . . . . . . . . Strategien zum Sperren und Aktualisieren . . . . . . . . . . . . . Sperrstrategien für Formulare . . . . . . . . . . . . . . . . . . . . Datensatzgruppen sperren . . . . . . . . . . . . . . . . . . . . . . Sperrkonflikte effizient erledigen . . . . . . . . . . . . . . . . . . Einen Datensatz auf seinen Sperrstatus prüfen . . . . . . . . . . Code zum Aktualisieren oder erneuten Abfragen. . . . . . . . . . Die .LDB-Datei . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Benutzerliste. . . . . . . . . . . . . . . . . . . . . . . . . . . . Benutzerdefinierte Zähler erstellen . . . . . . . . . . . . . . . . . Ungebundene Formulare . . . . . . . . . . . . . . . . . . . . . . . Höhere Leistung durch Replikation . . . . . . . . . . . . . . . . .
18
Externe Daten verwenden . . . . . . . . . . . . . . . . . . . . . . . . . . 681
18.1 18.2 18.3 18.4 18.5 18.6 18.7 18.8 18.9 18.10
Verbindung mit externen Datenquellen . . . . . . . . . . . . . Daten importieren, verknüpfen und öffnen: wann und warum Externe Daten importieren . . . . . . . . . . . . . . . . . . . . Eine Verknüpfung zu externen Daten erstellen . . . . . . . . . Eine externe Tabelle öffnen . . . . . . . . . . . . . . . . . . . . Die Einstellungen in der Windows-Registry . . . . . . . . . . . Die Eigenschaft Jet OLEDB:Link Provider String . . . . . . . . Mit Kennwörtern arbeiten . . . . . . . . . . . . . . . . . . . . . Verknüpfungen aktualisieren und löschen . . . . . . . . . . . Spezielle Überlegungen . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . 631 . . . . . . . 632 . . . . .
. . . . . . . . . . . . .
. . . . . . . . . .
. . . . .
. . . . . . . . . . . . .
. . . . . . . . . .
. . . . .
. . . . . . . . . . . . .
. . . . . . . . . .
. . . . .
. . . . . . . . . . . . .
. . . . . . . . . .
. . . . .
. . . . . . . . . . . . .
. . . . . . . . . .
. . . . .
. . . . . . . . . . . . .
. . . . . . . . . .
. 634 . 635 . 642 . 643 . 644
. 649 . 655 . 656 . 660 . 663 . 667 . 674 . 675 . 676 . 677 . 678 . 678 . 678
. 681 . 682 . 685 . 689 . 697 . 699 . 700 . 701 . 702 . 704
12
Inhaltsverzeichnis
18.11 18.12 18.13
Problemlösung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706 Leistung und Verknüpfungen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 706 Mit HTML-Dokumenten arbeiten . . . . . . . . . . . . . . . . . . . . . . . . . . 707
19
Client-Server-Techniken . . . . . . . . . . . . . . . . . . . . . . . . . . . 715
19.1 19.2 19.3 19.4 19.5 19.6 19.7 19.8 19.9 19.10 19.11 19.12 19.13
Das Client-Server-Modell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Soll das Client-Server-Modell eingesetzt werden? . . . . . . . . . . . . . . . Die Rollen, die Access im Anwendungsentwurfsmodell spielt . . . . . . . . . Die Client-Server-Schlagworte . . . . . . . . . . . . . . . . . . . . . . . . . . Upsizing: Was dabei zu bedenken ist . . . . . . . . . . . . . . . . . . . . . . Das Upsizing aktiv vorbereiten . . . . . . . . . . . . . . . . . . . . . . . . . . Der Upsizing-Assistent. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Eine ODBC-Datenquelle definieren . . . . . . . . . . . . . . . . . . . . . . . . Mit einem Datenbank-Server Verbindung aufnehmen . . . . . . . . . . . . . Mit verknüpften Tabellen arbeiten . . . . . . . . . . . . . . . . . . . . . . . . Pass-Through-Abfragen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Gespeicherte Prozeduren erstellen und ausführen . . . . . . . . . . . . . . . Über ein Microsoft Access-Datenprojekt auf Client-Server-Daten zugreifen .
20
Client-Server-Strategien . . . . . . . . . . . . . . . . . . . . . . . . . . . 765
20.1 20.2 20.3 20.4 20.5 20.6
Effizientes Vorgehen . . . . . . . . . . . . . . . . . . . . Den günstigsten Typ für eine Datensatzgruppe wählen Pass-Through-Abfragen und gespeicherte Prozeduren. Access-Datenprojekte . . . . . . . . . . . . . . . . . . . Den Umgang mit Daten optimieren. . . . . . . . . . . . Abfragen und Formulare optimieren . . . . . . . . . . .
21
Eine Client-Server-Anwendung in Aktion . . . . . . . . . . . . . . . . 777
21.1 21.2 21.3
Zum Gesamtzusammenhang . . . . . . . . . . . . . . . . . . . . . . . . . . . . 777 Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen . . . . 777 Eine Client-Server-Anwendung mit Hilfe eines Access-Datenprojekts erstellen . . . . . . . . . . . . . . . . . . . . . . . . . . . 798
22
Transaktionsverarbeitung . . . . . . . . . . . . . . . . . . . . . . . . . . 809
22.1 22.2 22.3 22.4 22.5
Von Atomarität bis Konsistenz . . . . . . . . . . . . Die Vorteile . . . . . . . . . . . . . . . . . . . . . . . Das Standardverhalten verändern . . . . . . . . . . Explizite Transaktionsverarbeitung implementieren Einige Bemerkungen zur Transaktionsverarbeitung
. . . . .
. . . . .
. . . . . .
. . . . .
. . . . . .
. . . . .
. . . . . .
. . . . .
. . . . . .
. . . . .
. . . . . .
. . . . .
. . . . . .
. . . . .
. . . . . .
. . . . .
. . . . . .
. . . . .
. . . . . .
. . . . .
. . . . . .
. . . . .
. . . . . .
. . . . .
. . . . . .
. . . . .
. 715 . 716 . 722 . 725 . 726 . 730 . 730 . 734 . 740 . 740 . 748 . 750 . 753
. 765 . 765 . 768 . 768 . 769 . 769
. 809 . 810 . 812 . 813 . 815
13
Inhaltsverzeichnis
22.6 22.7
Transaktionsverarbeitung in einer Mehrbenutzerumgebung . . . . . . . . . . 820 Transaktionsverarbeitung in einer Client-Server-Umgebung . . . . . . . . . . 825
23
Replikation leicht gemacht . . . . . . . . . . . . . . . . . . . . . . . . . 831
23.1 23.2 23.3 23.4 23.5 23.6 23.7 23.8 23.9 23.10 23.11 23.12 23.13 23.14 23.15
Datenänderungen weiterreichen . . . . . . . . . . . . . . . . . . . . . . . . Einsatzmöglichkeiten der Replikation . . . . . . . . . . . . . . . . . . . . . Wann ist Replikation nicht geeignet? . . . . . . . . . . . . . . . . . . . . . Replikation implementieren . . . . . . . . . . . . . . . . . . . . . . . . . . Die Architektur der Replikation: Was setzt die Replikation in Bewegung? . Replikationstopologien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Änderungen an Ihrer Datenbank durch Replikation . . . . . . . . . . . . . Eine Datenbank replikationsfähig machen . . . . . . . . . . . . . . . . . . Verhindern, dass Objekte repliziert werden. . . . . . . . . . . . . . . . . . Zusätzliche Replikate erstellen . . . . . . . . . . . . . . . . . . . . . . . . . Replikate synchronisieren . . . . . . . . . . . . . . . . . . . . . . . . . . . Replikationskonflikte beheben . . . . . . . . . . . . . . . . . . . . . . . . . Den Replikations-Manager verwenden . . . . . . . . . . . . . . . . . . . . Partielle Replikation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Replikation mittels Code implementieren . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . .
. 831 . 832 . 834 . 834 . 836 . 838 . 841 . 843 . 845 . 847 . 848 . 850 . 852 . 865 . 867
Teil IV Fortgeschrittene Programmierung . . . . . . . . . . . . . . . . . . . . 873 24
Fortgeschrittene VBA-Techniken . . . . . . . . . . . . . . . . . . . . . 875
24.1 24.2 24.3 24.4 24.5 24.6 24.7 24.8 24.9 24.10
Für erfahrenere Programmierer. . . . . . . . . . . . . . . . . . Was sind benutzerdefinierte Typen und wozu können sie verwendet werden? . . . . . . . . . . . . . . . . . . . . . . . . Mit Konstanten arbeiten . . . . . . . . . . . . . . . . . . . . . Mit Datenfeldern arbeiten. . . . . . . . . . . . . . . . . . . . . Fortgeschrittene Methoden der Verwendung von Funktionen Mit Empty und Null arbeiten . . . . . . . . . . . . . . . . . . . Benutzerdefinierte Auflistungen erstellen und verwenden . . Kompilieroptionen verstehen und effektiv nutzen . . . . . . . Code-Module im- und exportieren . . . . . . . . . . . . . . . . Mit Projekteigenschaften arbeiten . . . . . . . . . . . . . . . .
25
ActiveX-Steuerelemente verwenden . . . . . . . . . . . . . . . . . . . 907
25.1 25.2
Wozu dienen ActiveX-Steuerelemente? . . . . . . . . . . . . . . . . . . . . . . 907 ActiveX-Steuerelemente im Rahmen von Access 2000 verwenden . . . . . . . 908
. . . . . . . . . 875 . . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. 876 . 878 . 882 . 886 . 891 . 896 . 899 . 900 . 901
14
25.3 25.4 25.5 25.6 25.7 25.8 25.9 25.10 25.11 25.12
Inhaltsverzeichnis
Eigenschaften eines ActiveX-Steuerelements während des Entwurfs festlegen . . . . . . . . . . . . . . . . . . . . . . . Behandlungsroutinen für die Ereignisse eines ActiveX-Steuerelements programmieren . . . . . . . . . . Das Kalender-Steuerelement verwenden . . . . . . . . . . Das Steuerelement UpDown verwenden. . . . . . . . . . . Das Steuerelement StatusBar verwenden . . . . . . . . . . Das Steuerelement Common Dialog . . . . . . . . . . . . . Das RichText-Steuerelement verwenden . . . . . . . . . . Das TabStrip-Steuerelement verwenden . . . . . . . . . . Das ImageList-Steuerelement verwenden . . . . . . . . . . Aspekte der Weitergabe und Lizenzierung . . . . . . . . .
. . . . . . . . . . . 914 . . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. 915 . 917 . 920 . 922 . 924 . 927 . 930 . 933 . 934
26
Automatisierung: Mit anderen Anwendungen kommunizieren . . . . . . . . . . . . . . 937
26.1 26.2 26.3 26.4 26.5 26.6 26.7 26.8 26.9 26.10 26.11
Von außen mit Access arbeiten . . . . . . . . . . . . . . . . . . . Begriffe zur Automatisierung . . . . . . . . . . . . . . . . . . . . Einen Objektvariablenverweis auf Ihre Anwendung deklarieren Ein Automatisierungsobjekt erstellen . . . . . . . . . . . . . . . Ein Automatisierungsobjekt anpassen . . . . . . . . . . . . . . . Excel mit Access steuern. . . . . . . . . . . . . . . . . . . . . . . Ein Excel-Automatisierungsobjekt schließen . . . . . . . . . . . Mit Hilfe von Access ein Diagramm erstellen . . . . . . . . . . . Word von Access aus steuern . . . . . . . . . . . . . . . . . . . . PowerPoint von Access aus steuern . . . . . . . . . . . . . . . . Access von anderen Anwendungen aus steuern . . . . . . . . .
27
Die Leistungsfähigkeit des Windows-API ausschöpfen . . . . . . 965
27.1 27.2 27.3 27.4 27.5 27.6 27.7 27.8
Fundgrube Windows-Bibliotheken . . . . . . . . . . . . . . . . . . Eine externe Funktion für den Compiler deklarieren . . . . . . . . Mit Konstanten und Typen arbeiten . . . . . . . . . . . . . . . . . DLL-Funktionen aufrufen: Wichtige Aspekte . . . . . . . . . . . . Unterschiede zwischen 16- und 32-Bit-APIs . . . . . . . . . . . . . API-Funktionen verwenden . . . . . . . . . . . . . . . . . . . . . . Informationen über die Arbeitsumgebung erlangen . . . . . . . . Laufwerkstypen und verfügbaren Platz auf Laufwerken ermitteln
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . .
. . . . . . . . . . .
. . . . . . . .
. . . . . . . . . . .
. . . . . . . .
. . . . . . . . . . .
. . . . . . . .
. . . . . . . . . . .
. . . . . . . .
. . . . . . . . . . .
. . . . . . . .
. 937 . 938 . 939 . 940 . 942 . 943 . 947 . 947 . 952 . 954 . 957
. 965 . 966 . 972 . 979 . 979 . 980 . 980 . 986
15
Inhaltsverzeichnis
28
Die Leistungsfähigkeit von Klassenmodulen ausnutzen . . . . 991
28.1 28.2 28.3 28.4 28.5 28.6
Die Vorteile von Klassenmodulen . . . . . . . . Objektorientierung – Eine Einführung . . . . . . Klassenmodule erstellen und verwenden . . . . Mehrere Instanzen von Klassen erstellen . . . . Die Ereignisse Initialize und Terminate . . . . . Mit benutzerdefinierten Auflistungen arbeiten .
29
Eigene Bibliotheken erstellen . . . . . . . . . . . . . . . . . . . . . . 1021
29.1 29.2 29.3 29.4 29.5
Bibliotheksdatenbanken . . . . . . . . . . . . . . . . . . . . Eine Datenbank zur Verwendung als Bibliothek vorbereiten Einen Verweis erstellen . . . . . . . . . . . . . . . . . . . . . Fehlersuche in einer Bibliotheksdatenbank. . . . . . . . . . Eine Access-Bibliothek sichern . . . . . . . . . . . . . . . . .
30
Generatoren, Assistenten und Menü-Add-Ins einsetzen . . . . 1039
30.1 30.2 30.3 30.4
Hilfsmittel – Aufbau und Installation. Generatoren verwenden. . . . . . . . Assistenten einsetzen . . . . . . . . . Menü-Add-Ins verwenden. . . . . . .
31
Access und das Internet. . . . . . . . . . . . . . . . . . . . . . . . . . . 1065
31.1 31.2 31.3 31.4 31.5 31.6 31.7 31.8 31.9 31.10 31.11 31.12 31.13
Neuerungen von Access im Zusammenhang mit dem Internet . . . Datenbankobjekte als HTML speichern . . . . . . . . . . . . . . . . Verknüpfungen mit HTML-Dateien . . . . . . . . . . . . . . . . . . . HTML-Dateien importieren . . . . . . . . . . . . . . . . . . . . . . . Zwischen statischen und dynamischen HTML-Formaten abwägen . Mit Active Server Pages (ASP-Dateien) arbeiten . . . . . . . . . . . Mit HTX/IDC-Dateien arbeiten . . . . . . . . . . . . . . . . . . . . . Testen der ASP- und HTX/IDC-Dateien. . . . . . . . . . . . . . . . . Mit HTML-Vorlagen arbeiten . . . . . . . . . . . . . . . . . . . . . . Daten an einen FTP- oder HTTP-Server senden . . . . . . . . . . . . Hyperlinks nutzen . . . . . . . . . . . . . . . . . . . . . . . . . . . . Die Symbolleiste Web . . . . . . . . . . . . . . . . . . . . . . . . . . Replikation über das Internet implementieren . . . . . . . . . . . .
32
Datenzugriffsseiten verwenden . . . . . . . . . . . . . . . . . . . . . 1083
32.1 32.2
Datenzugriffsseiten verstehen . . . . . . . . . . . . . . . . . . . . . . . . . . 1083 Datenzugriffsseiten erstellen . . . . . . . . . . . . . . . . . . . . . . . . . . . 1084
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . . . .
. . . .
. . . . . .
. . . .
. . . . . .
. . . .
. . . . . .
. . . .
. . . . . .
. . . .
. . . . . .
. . . .
. . . . . .
. . . .
. . . . . .
. . . . .
. . . .
. . . . . .
. . . . .
. . . .
. . . . . .
. . . . .
. . . .
. . . . . .
. . . . .
. . . .
. . . . . .
. . . . .
. . . .
. . . . . . . . . . . . .
. . . . . .
. . . . .
. . . .
. . . . . . . . . . . . .
. . . . . .
. . . . .
. . . .
. . . . . . . . . . . . .
. . . . . .
. . . . .
. . . .
. . . . . . . . . . . . .
. 991 . 992 . 993 . 997 . 997 . 998
. . . . .
. . . .
. . . . . . . . . . . . .
1021 1022 1024 1033 1034
1039 1040 1051 1057
1065 1066 1069 1072 1073 1074 1075 1076 1077 1078 1080 1081 1082
16
32.3 32.4 32.5 32.6
Inhaltsverzeichnis
Wichtige Eigenschaften einer Datenzugriffsseite anpassen . . Ändern der Eigenschaften zur Navigation in den Datensätzen Gruppierte Datenzugriffsseiten erstellen . . . . . . . . . . . . Datenzugriffsseiten mit VBScript ausbauen . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
1093 1095 1097 1100
Teil V Die Anwendung abrunden . . . . . . . . . . . . . . . . . . . . . . . . . 1107 33
Datenbanksicherheit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1109
33.1 33.2
33.6
Vom Kennwort bis zur Hochsicherheit . . . . . . . Sicherheit auf Freigabe-Ebene implementieren: Ein Datenbank-Kennwort einrichten . . . . . . . . Eine Datenbank verschlüsseln . . . . . . . . . . . Sicherheit auf Benutzerebene einrichten . . . . . Eine zusätzliche Sicherheitsebene bereitstellen: Eine MDE-Datei erstellen . . . . . . . . . . . . . . Spezielle Fragestellungen . . . . . . . . . . . . . .
34
Fortgeschrittene Sicherheitstechniken . . . . . . . . . . . . . . . . 1147
34.1 34.2 34.3 34.4 34.5 34.6 34.7 34.8 34.9 34.10 34.11 34.12
Sicherheit für Gruppenarbeit . . . . . . . . . . . . . . . . . . . . . . . . . . Gruppen mit Hilfe von Code verwalten . . . . . . . . . . . . . . . . . . . . . Benutzer mit Hilfe von Code verwalten . . . . . . . . . . . . . . . . . . . . Alle Gruppen und Benutzer auflisten . . . . . . . . . . . . . . . . . . . . . . Mit Kennwörtern arbeiten . . . . . . . . . . . . . . . . . . . . . . . . . . . . Berechtigungen für Objekte mit Hilfe von Code zuweisen und widerrufen . Eine Datenbank mit Hilfe von Code verschlüsseln . . . . . . . . . . . . . . Mit Hilfe von Abfragen Sicherheit auf Feldebene erreichen . . . . . . . . . Benutzer und Gruppen von der Erstellung von Objekten ausschließen . . Sich als ein anderer Benutzer anmelden, um verbotene Aufgaben auszuführen. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Client-Server-Anwendungen schützen . . . . . . . . . . . . . . . . . . . . . Sicherheit und Replikation . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
Anwendungsdokumentation . . . . . . . . . . . . . . . . . . . . . . . . 1173
35.1 35.2 35.3 35.4
Für Systempflege, zum Nachschlagen . . . . . . . . . . . Ihrer Anwendung die Dokumentation selbst überlassen . Der Datenbank-Dokumentierer . . . . . . . . . . . . . . . Mit Hilfe von Code eine eigene Dokumentation erstellen
33.3 33.4 33.5
. . . . . . . . . . . . . . . 1109 . . . . . . . . . . . . . . . 1110 . . . . . . . . . . . . . . . 1111 . . . . . . . . . . . . . . . 1113 . . . . . . . . . . . . . . . 1137 . . . . . . . . . . . . . . . 1139
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . . . . . . .
1147 1148 1151 1157 1160 1164 1167 1167 1169
. 1170 . 1170 . 1170
. . . .
1173 1174 1181 1185
Inhaltsverzeichnis
17
36
Ihre Anwendung warten . . . . . . . . . . . . . . . . . . . . . . . . . . 1189
36.1 36.2
Weg mit ungenutztem Speicher . . . . . . . . . . . . . . . . . . . . . . . . . 1189 Ihre Datenbank komprimieren . . . . . . . . . . . . . . . . . . . . . . . . . . 1189
37
Ihre Anwendung verteilen . . . . . . . . . . . . . . . . . . . . . . . . . 1197
37.1 37.2 37.3 37.4
Eine Applikation für viele . . . . . . . . . . . . . . . . . . . . . . . Der Package and Deployment Wizard . . . . . . . . . . . . . . . . Das Package and Deployment Wizard-Add-In laden . . . . . . . . Ihre Anwendung zur Ausführung mit einer vollständigen Kopie von Access verteilen . . . . . . . . . . . . . . . . . . . . . . . . . . Vollversionen im Unterschied zu Laufzeitversionen von Access . Ihre Datenbank für die Verwendung mit der Laufzeitversion von Access vorbereiten. . . . . . . . . . . . . . . . . . . . . . . . . . . Andere Fragestellungen . . . . . . . . . . . . . . . . . . . . . . . .
37.5 37.6 37.7
. . . . . . 1197 . . . . . . 1198 . . . . . . 1198 . . . . . . 1200 . . . . . . 1200 . . . . . . 1203 . . . . . . 1225
Teil VI Anhänge . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1231 A
Namenskonventionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1233
B
Die Buch-CD-ROM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1241 Stichwortverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1243
Vorwort Zum Thema »Access« gibt es bereits eine Vielzahl hevorragender Bücher. Warum sollte man noch ein weiteres schreiben? In den Gesprächen mit vielen Kursteilnehmern, denen ich bei meinen Reisen durch das Land begegnete, wurde immer wieder eine Beschwerde geäußert. Anstelle mehrerer großartiger Bücher für die Benutzergemeinde oder einer Fülle ausgezeichneter Bücher für erfahrene Access-Entwickler wünschen sich meine Schüler ein Buch für Entwickler, die über Grund- oder fortgeschrittene Kenntnisse verfügen. Sie wünschen sich ein Buch, das mit den Grundlagen beginnt und so gewährleistet, daß keine Wissenslücken entstehen, und ihnen einige der fortgeschrittenen Aspekte der Entwicklung mit Access näherbringt. Begleitend wünschen sie sich praktische Programmierbeispiele, die sie leicht in ihre eigenen Anwendungen einbinden können. Ich habe dieses Buch speziell im Hinblick auf diese Anforderungen geschrieben. Es beginnt mit einer Einführung in die Entwicklung mit Access. Darin wird erläutert, welche Arten von Anwendungen mit Access entwickelt werden können, und es werden die Komponenten einer Access-Anwendung vorgestellt. Nachdem Sie verstanden haben, was eine Access-Anwendung ist und wann die Entwicklung einer solchen sinnvoll ist, lernen Sie die zum Programmieren einer richtigen AccessAnwendung notwendigen Schritte kennen. Vor dem Erstellen der ersten Anwendungskomponente werden mehrere Vorgehensweisen erörtert. Damit wird sichergestellt, dass Sie sich als Entwickler dieser Anwendung bewusst machen, welche Punkte Sie beim Entwurf speziell für Ihre Umgebung berücksichtigen müssen. Nachdem Sie das Gesamtbild kennengelernt haben, sind Sie bereit, sich an Einzelheiten der Objekte einer Access-Datenbank heranzuwagen. Die Kapitel 2 bis 6 behandeln die Grundlagen von Tabellen, Beziehungen, Abfragen, Formularen und Berichten. Diese Kapitel sollen einen Ansatz für die Entwicklung dieser Datenbankobjekte aus der Sicht des Entwicklers bereitstellen. Obwohl dieser Text mit den Grundlagen beginnt, liefert er viele Tipps, Tricks und Einwände, die der Dokumentation oder den für Endanwender bestimmten Büchern nicht zu entnehmen sind. Wenn Sie im Hinblick auf das Erstellen von Tabellen, Abfragen, Formularen und Berichten über eine solide Wissensgrundlage verfügen, sind Sie in der Lage sich ganz auf die Programmierung zu konzentrieren. Die Kapitel 7 und 8 geben Ihnen einen
20
Vorwort
tiefen Einblick in die Sprache VBA. Wieder beginnen Sie mit den Grundlagen und werden langsam an die Finessen von Visual Basic für Applikationen und dem Objektmodell von Access herangeführt. Im Text werden viele praktische Beispiele vorgestellt, damit Sie jedes Thema wirklich eingehend verarbeiten können. Die Kapitel 9 bis 11 umfassen eine fortgeschrittene Erörterung von Abfragen, Formularen und Berichten. Wenn Sie an dieser Stelle angelangt sind, sollten Sie mit den Grundlagen des Erstellens von Datenbankobjekten vertraut sein. In diesen Kapiteln werden die Grundlagen des Entwurfs von Tabellen, Abfragen, Formularen und Berichten mit den in den Kapiteln 7 und 8 behandelten Techniken zur Verwendung von VBA und Objekten kombiniert. Die in Kapitel 9 bis 11 beschriebenen leistungsfähigen Methoden verleihen Ihnen die Fachkenntnisse, die Sie zum Entwerfen der für Ihre Anwendung erforderlichen komplexen Abfragen, Formulare und Berichte brauchen. Bevor Sie die Grenze zu den vielen Feinheiten der Access-Entwicklungsumgebung überschreiten, bleibt noch ein grundlegendes Thema zu erörtern. Kapitel 12 gibt eine Einführung in ActiveX-Datenobjekte und Datenzugriffsobjekte. Nachdem Sie Kapitel 12 gelesen haben, werden Sie den Unterschied zwischen ActiveX-Datenobjekten und Datenzugriffsobjekten verstehen. Sie werden erfahren, wie Sie sich von gebundenen Objekten lösen können, indem Sie die Daten innerhalb Ihrer Datenbank mit Hilfe von Code bearbeiten. Leider verlaufen die Dinge nicht immer wie geplant. Unabhängig vom Grad Ihrer Fachkenntnisse werden Sie häufiger ratlos über einem Programm-Code sitzen und nach Antworten suchen. Kapitel 13 zeigt Ihnen, wie Sie die Fehlersuche wirksam einsetzen können, um mögliche Probleme mit dem Programm-Code zu lösen. Alle Aspekte der Fehlersuche werden in diesem Kapitel behandelt. Selbst wenn Ihre Anwendung sorgfältig auf Fehler überprüft wurde, sind Sie dafür verantwortlich, eine Möglichkeit zu schaffen, mit der Fehler innerhalb Ihrer Anwendung behandelt werden können. Kapitel 14 zeigt Ihnen alles, was Sie wissen müssen, um die Fehlerbehandlung in Ihre Anwendung zu implementieren. Im Text sowie auf der CDROM mit Programmierbeispielen finden Sie eine generische Fehlerbehandlungsroutine, die Sie leicht in eine beliebige eigene Anwendung einbinden können. Mit der in den ersten 15 Kapiteln geschaffenen Grundlage sind Sie für den Übergang zu den umfangreicheren und komplexeren Gesichtspunkten der Sprache VBA und der Access-Entwicklungsumgebung gerüstet. Die Kapitel 16 bis 23 behandeln alle Aspekte der Entwicklung von Anwendungen für eine Mehrbenutzer- oder ClientServer-Umgebung. Sie lernen Sperrstrategien kennen und erfahren, wie Sie mit Fremddateiformaten in Access umgehen und wie Sie ODBC zum Entwerfen von Client-Server-Anwendungen einsetzen. Transaktionsverarbeitung, Anwendungsoptimierung und Replikation werden ebenfalls in diesem Kapitel behandelt. Als Access-Entwickler ist Ihre Welt nicht nur auf Access begrenzt. Um als solcher effektiv und produktiv zu sein, müssen Sie wissen, wie Sie mit anderen Anwendungen kommunizieren können und wie Sie ActiveX-Steuerelemente, Bibliotheken,
Symbole im Text
21
Menü-Add-ins, Assistenten und Generatoren verwenden, die Ihnen bei der Anwendungsentwicklung helfen. Die Kapitel 25 bis 30 befassen sich mit OLE, indem ActiveX-Steuerelemente, Access und das Internet verwendet werden und die Anwendungsentwicklung mit Visual SourceSafe, Bibliotheken und Add-ins vorgenommen wird. Nach dem Studium dieser Kapitel werden Sie verstehen, wie Sie sich die Verwendung externer Objekte und Funktionen zunutze machen können, um Ihre Anwendungen ohne große Mühe vielseitig zu gestalten. Schließlich sind Sie bereit, Ihrer Anwendung den Feinschliff zu geben. Die Kapitel 31 bis 37 beschäftigen sich mit dem Windows-API, der Sicherheit, der Dokumentation, der Pflege, der Hilfe und der Verteilung. Sie werden lernen, wie Sie Ihre Anwendung richtig sichern, so dass der Entwicklungsaufwand für die Anwendung nicht beeinträchtigt wird. Außerdem erfahren Sie, wie einfach es ist, der Anwendung den letzten Schliff zu verleihen, der ihr ein professionelles Aussehen verleiht und sie von anderen Anwendungen abhebt.
Anmerkung des Übersetzers Dieses Buch verwendet für jedes seiner Kapitel amerikanische Beispieldatenbanken. Daher kann es vorkommen, dass in manchen Formularen und Berichten sowie dementsprechend natürlich auch in einigen Screenshots Felder enthalten sind, für die es im deutschsprachigen Raum keine genaue Entsprechung gibt. Als Beispiele erfüllen diese Inhalte jedoch ihren Zweck.
Symbole im Text Wir verwenden im Text verschiedene Symbole, die eine schnelle Orientierung in diesem umfangreichen Kompendium sicherstellen. Im Text werden Sie den folgenden Sinnbildern begegnen: An dieser Stelle geben wir Praxistipps und lassen Sie so an unseren Erfahrungen aus der täglichen Arbeit mit dem Programm teilhaben.
Hier geben wir Ihnen Hinweise, die auf Besonderheiten aufmerksam machen oder allgemeine Informationen zu entsprechenden Funktionen vermitteln. An einigen Stellen sind so auch Warnungen hervorgehoben.
Dieses Icon verweist auf eine Folge von Arbeitsschritten, die Sie zu einem Ergebnis führen.
22
Vorwort
Mit dem CD-Symbol sind Verweise auf die Buch-CD gekennzeichnet. Hier finden Sie z.B. die Bezeichnungen der im Buch verwendeten Beispieldateien. Außerdem sind hier häufig kommentierende Hinweise angehängt.
Die Autorin Alison Balter ist Präsidentin der 1990 gegründeten Marina Consulting Group LLC, einem Unternehmen in Westlake Village, Kalifornien, und eine erfahrene Ausbilderin und Beraterin für Anwendungsschulungen und -entwicklungen unter Windows. Während ihrer fünfzehnjährigen Tätigkeit in der Computerindustrie hat sie in vielen großen Unternehmen und Regierungsbehörden Schulungen und Beratungen durchgeführt. Bei der Marina Consulting Group LLC handelt es sich um einen von Microsoft zertifizierten Lösungslieferanten, und auch Alison Balter wurde von Microsoft als Fachberaterin zertifiziert. Als eine der ersten in der Computerindustrie wurde sie von Microsoft als so genannter Solution Provider anerkannt. Alison Balter ist die Autorin von über 200 weltweit vertriebenen EDV-Schulungsvideos. Sie hält in ganz Nordamerika Schulungen über Microsoft Access, Visual Basic, Visual InterDev und Visual Basic for Applications ab. Außerdem ist sie regelmäßig in Live-Sendungen der National Technological University vertreten. Sie schreibt regelmäßig für Computerzeitschriften und ist als Buchautorin bekannt. Außerdem nimmt sie immer wieder an nationalen Gesprächsrunden über Access, Visual Basic und Visual InterDev teil. Als aktive Teilnehmerin vieler Benutzergruppen und anderer Organisationen war Alison Balter die Präsidentin der Independent Computer Consultants Association of Los Angeles und der Los Angeles Clipper Users' Group.
Grundlagen der Entwicklung mit Access
Teil I
1 2 3 4 5 6 7 8 9 10 11 12
Access als Entwicklungswerkzeug Was jeder Entwickler über Tabellen wissen sollte Beziehungen: Ihr Schlüssel zur Datenintegrität Was jeder Entwickler über Abfragen wissen sollte Was jeder Entwickler über Formulare wissen sollte Was jeder Entwickler über Berichte wissen sollte VBA: Eine Einführung Objekte, Eigenschaften, Methoden und Ereignisse Fortgeschrittene Formulartechniken Fortgeschrittene Berichtstechniken Fortgeschrittene Abfragetechniken Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Access als Entwicklungswerkzeug
Kapitel
Hier lesen Sie:
Welche Arten von Anwendungen können mit Access entwickelt werden? Access als skalierbares Produkt Was genau ist eine Datenbank? Datenbankobjekte Objektbenennung Hardwareanforderungen Wie beginne ich mit der Entwicklung einer Access-Anwendung?
1.1
Welche Arten von Anwendungen können mit Access entwickelt werden?
Access bietet eine Vielzahl von Möglichkeiten für unterschiedliche Datenbankanforderungen. Es kann zur Entwicklung von sechs verschiedenen Arten von Anwendungen verwendet werden:
Persönliche Anwendungen Anwendungen für kleinere Geschäftsbereiche Anwendungen für Unternehmensabteilungen Anwendungen für gesamte Unternehmen Als Front-End für unternehmensweite Client-Server-Anwendungen Anwendungen für Intranet/Internet-Anwendungen
26
1.1.1
Kapitel 1: Access als Entwicklungswerkzeug
Access als Entwicklungsplattform für persönliche Anwendungen
Auf unterster Ebene kann Access verwendet werden, um einfache persönliche Datenbankanwendungen zu entwickeln. Dennoch warne ich Benutzer vor diesem Gedanken. Benutzer, die Access kaufen, um damit alles zu vereinfachen, von der Verwaltung ihres Weinkellers bis zur Übersicht über ihre privaten Finanzen, werden oft enttäuscht. Denn der Schein trügt, Access sei kinderleicht zu benutzen. Seine wundervollen integrierten Assistenten machen Access zu einem Produkt, das scheinbar jedermann leicht benutzen kann. Nach dem Beantworten einer Reihe von Fragen verfügen Sie bereits über fertige Übersichten, Dateneingabemasken, Berichte usw. Als Access auf den Markt kam, fragten mich viele Leute, ob ich nicht davon betroffen sei, dass nun mein Beruf als Programmierer und Ausbilder unwichtig würde, weil doch mit Access nun wirklich jedermann Datenbankanwendungen selbst schreiben könne. Dazu möchte ich aber Folgendes bemerken: Es ist zwar richtig, dass ein Benutzer einfache Access-Anwendungen erstellen kann, ohne sich einen einzigen Gedanken über den Entwurf zu machen und ohne eine einzige Programmzeile selbst zu schreiben, aber es bedarf doch für die meisten Anwendungen zumindest eines Minimums an Entwurf und Programmierung. Sie werden keinerlei Probleme haben, solange Sie sich mit einer von einem AccessAssistenten erzeugten persönlichen Anwendung mit nur wenigen kleinen Verfeinerungen zufrieden geben. Sie werden aber sehr schnell auf Probleme stoßen, sobald Sie eine solche Anwendung wirklich an Ihre persönlichen Bedürfnisse anpassen wollen.
1.1.2
Access als Entwicklungsplattform für kleinere Geschäftsbereiche
Access eignet sich sehr gut zum Entwickeln von Anwendungen für kleinere Geschäftsbereiche. Die Assistenten ermöglichen den Entwicklern das schnelle und leichte Entwerfen von Anwendungen, mit Programm-Modulen lassen sich ganze Bibliotheken mit immer wieder benutzbaren Funktionen zusammenstellen, und die Möglichkeit, Programmteile mit Formularen und Berichten zu verknüpfen, erlaubt das Erstellen besonders leistungsfähiger Formulare und Berichte. Die wesentliche Einschränkung beim Einsatz von Access zum Entwickeln von Anwendungen für kleinere Geschäftsbereiche sind die Zeit und das Geld, die man für eine Entwicklung aufzuwenden bereit ist. Viele Benutzer verwenden zu Beginn ihrer Anwendungsentwicklung Access-Assistenten und erst später bemerken sie, dass sie die Anwendungen vervollständigen wollen und dass sie die dazu nötigen Arbeitsschritte nicht mehr beherrschen. Die Inhaber kleiner Firmen haben dieses Problem häufig in noch ausgeprägterer Form. Die Anforderungen an Anwendungen für kleinere Geschäftsbereiche sind üblicherweise viel höher als die Anforderungen an persönliche Anwendungen. Ich selbst wurde oft von Ärzten, Rechtsanwälten und
Welche Arten von Anwendungen können mit Access entwickelt werden?
27
anderen Selbstständigen zu Hilfe gerufen, die während der Entwicklung einer Anwendung in eine Sackgasse geraten waren. Immer waren sie erschrocken darüber, wie teuer es wurde, ihre Anwendung wirklich einsetzbar zu machen.
1.1.3
Access als Entwicklungsplattform für Unternehmensabteilungen
Access eignet sich ideal für das Entwickeln von Abteilungsanwendungen in großen Unternehmen. Es ist recht einfach, die Arbeitspatzrechner aller Benutzer einer überschaubaren Abteilung auf die für Access erforderliche Hardware aufzurüsten, und es ist zum Beispiel erheblich einfacher, für nur 15 Benutzer zusätzlichen Hauptspeicher zu kaufen als für 4.000 Benutzer. Das Leistungsvermögen von Access reicht für die meisten Abteilungsanwendungen, die noch ohne eine Client-Server-Lösung auskommen können. Schließlich verfügen die meisten Abteilungen in großen Unternehmen über eigene Entwicklungsbudgets, um gut entworfene Anwendungen zu erstellen. Glücklicherweise findet sich außerdem in fast jeder Abteilung ein PC-Begeisterter, der überglücklich ist, wenn er beim Entwurf von Formularen und Berichten mitwirken kann. Dies gibt der Abteilung dann sogar ein besonderes Gefühl der Verbundenheit mit ihren Anwendungen, weil ihre eigenen Mitarbeiter ja bei deren Entwicklung mitgeholfen haben. Und es macht auch mein Dasein als hauptberuflicher Entwickler erheblich einfacher: Ich kann mich auf die wesentlichen Kernpunkte der Anwendungsentwicklung konzentrieren und den Entwurf von Formularen und Berichten getrost den PC-Spezialisten in den jeweiligen Abteilungen überlassen.
1.1.4
Access als Entwicklungsplattform für das gesamte Unternehmen
Am besten eignet sich Access aber wohl für die Entwicklung von Anwendungen, die über ein ganzes Unternehmen verteilt eingesetzt werden. Wie erfolgreich ein solches Bemühen ist, hängt jedoch vom einzelnen Unternehmen ab. Die Zahl der AccessBenutzer, die gleichzeitig auf eine Access-Anwendung zugreifen, ist ebenso wie die Anzahl der Datensätze innerhalb einer Tabelle begrenzt, sofern man Wert auf eine akzeptable Anwendungsgeschwindigkeit legt. Diese Grenzwerte hängen unter anderem von folgenden Fragen ab:
Wie stark ist das Netzwerk belastet? Mit wieviel Arbeitspeicher und mit wie vielen Prozessoren ist der Server ausgestattet?
Wie wird der Server eingesetzt? Müssen Microsoft Office-Anwendungen zunächst vom Server auf die einzelnen Arbeitspatzrechner heruntergeladen werden?
Welche Arten von Aufgaben werden von den Benutzern der Anwendung erledigt? Sind dies einfache Abfragen, geben die Benutzer Daten ein, werden umfangreiche Berichte erzeugt usw.?
28
Kapitel 1: Access als Entwicklungswerkzeug
Laufen Access und Ihre Access-Anwendung auf dem Server oder auf Ihrer eigenen Arbeitsstation?
Welches Netzwerksystem wird benutzt? Meine übliche Faustregel für eine Access-Anwendung ist, dass sich bei mehr als zehn bis fünfzehn gleichzeitigen Benutzern und bei mehr als 100.000 Datensätzen allgemein schlechte Antwortzeiten einstellen, wenn es sich nicht um eine Client-Server-Anwendung handelt. Bedenken Sie jedoch, dass diese Zahlen über einen breiten Bereich variieren können, weil sie von den genannten Faktoren abhängen und auch davon beeinflusst werden, was Sie und andere Benutzer unter guten Antwortzeiten verstehen. Die Kriterien für einen Übergang zu einem Client-Server-Datenbanksystem sind in Kapitel 19 beschrieben. Entwickler verstehen oft nicht, welche Bedeutung Access beim Einsatz in einem Client-Server-System zukommt. Ich werde oft gefragt: »Ist Access denn kein Client-Server-System?« Die Antwort sieht so aus, dass Access ein außergewöhnliches Programm ist, weil es einerseits eine Datei-Server-Anwendung außerhalb der eigenen Arbeitsstation ist, während es andererseits als Front-End für eine Client-ServerDatenbank dienen kann. Hier eine Erklärung: Wenn Sie Access kaufen und eine Anwendung entwickeln, die Daten in eine Access-Datenbank auf einem Datei-Server schreibt, so findet dennoch die eigentliche Verarbeitung der Daten auf dem Arbeitsplatzrechner statt. Dies bedeutet, dass bei jedem Start einer Abfrage oder eines ganzen Berichts zunächst alle Daten vom Datei-Server auf die Arbeitsstation übertragen werden müssen. Die Abfrage selbst läuft dann auf der Arbeitsstation ab, und deren Ergebnis wird als Tabelle oder als Bericht angezeigt. Es ist offensichtlich, dass diese Arbeitsweise erheblichen Datenverkehr im Netzwerk verursacht, ganz besonders, wenn mehrere Benutzer gleichzeitig auf große Access-Tabellen zugreifen. Tatsächlich können derartige Anwendungen ein ganzes Netzwerk weitgehend lahmlegen.
1.1.5
Access als Entwicklungsplattform für unternehmensweite ClientServer-Anwendungen
Eine Client-Server-Datenbank, wie etwa Microsoft SQL Server oder Oracle, verarbeitet Datenbankabfragen auf dem Server und überträgt danach nur die Ergebnisse zur Arbeitsstation. Die Server-Software selbst kann dem Benutzer aber keine Daten anzeigen – dazu ist Access nötig. Als Front-End kann Access die Ergebnisse von Datenbankabfragen in Berichten, Tabellen oder Formularen optisch aufbereiten. Werden die Daten in einer solchen Tabelle vom Benutzer wiederum verändert, so werden diese veränderten Daten anschließend an die Back-End-Datenbank zurückübertragen. Dies geschieht entweder durch eine Verknüpfung mit den externen Datenbanken – diese erscheinen dem Benutzer dann wie interne Access-Tabellen – oder durch die unmittelbare Verwendung der Client-Server-Fähigkeiten von Access.
Welche Arten von Anwendungen können mit Access entwickelt werden?
29
Bei Access 2000 gibt es so genannte Access-Projektdateien (nicht zu verwechseln mit Microsoft-Projektdateien), die besonders das Entwickeln von Anwendungen unterstützen, die für Client-Server-Umgebungen geeignet sind. Diese Access-Projektdateien, die oft auch als ADP-Dateien bezeichnet werden, enthalten alle Formulare, Berichte, Makros, Programmteile und Datenzugriffsseiten. Das Projekt wird mit der Back-End-Datenbank verknüpft, welche die Datentabellen, Prozeduren, virtuellen Sichten und Datenbankdiagramme enthält, über die das Programm auf die Datenbank zugreift. Aus einer Projektdatei heraus können Sie leicht die auf einem Server gespeicherten Objekte verändern und beeinflussen, indem Sie die bequeme grafische Benutzerschnittstelle von Access verwenden. ADP-Dateien können den Entwicklungsablauf für Client-Server-Anwendungen erheblich beschleunigen. Weil Access 2000 einen integrierten Datenspeicher enthält, ist es sogar möglich, eine Client-Server-Anwendung auf der Arbeitsstation zu entwickeln und sie danach auf einfache Weise in eine SQL Server 6.5- oder SQL Server 7-Datenbank zu übertragen. Die verschiedenen Möglichkeiten und Techniken für das Entwickeln von Client-ServerAnwendungen sind in Kapitel 19 und Kapitel 20 genauer beschrieben. Access wird zu einem ganz besonders leistungsfähigen Entwicklungswerkzeug, wenn man die Netzwerkbelastung dadurch vermindert, dass die eigentlichen Datenbankabfragen auf dem Back-End-System ausgeführt werden. Dann kann Access riesige Datenmengen verarbeiten und zahlreiche gleichzeitig aktive Benutzer bedienen. Die wesentliche Frage für Entwickler solcher großer Access-Anwendungen ist dann, über welche Hardware jeder einzelne Benutzer verfügt. Denn obwohl die Datenbankabfragen auf dem Server abgewickelt werden, was das Datennetz erheblich entlastet, muss sich doch die Anwendung selbst im Speicher jedes einzelnen Rechners befinden. Die Hardwareanforderungen für eine Access-Anwendung werden später in diesem Kapitel noch ausführlicher erläutert. Grundsätzlich gilt: Bevor Sie mit der Entwicklung einer großen und leistungsfähigen Access-Anwendung beginnen, müssen Sie zunächst die Hardwareausstattung aller späteren Benutzer dieser Anwendung kennen.
1.1.6
Access als Entwicklungsplattform für Intranet-/InternetAnwendungen
Intranet- und Internet-Benutzer können ihre Anwendungsdaten verändern, indem sie für den Zugriff einen Browser und so genannte Datenzugriffsseiten verwenden. Datenzugriffsseiten sind HTML-Dokumente, die direkt mit den Daten in einer Datenbank verknüpft sind. Sie werden außerhalb der eigentlichen Datenbank gespeichert und genauso verwendet wie normale Access-Formulare; allerdings werden sie üblicherweise in Verbindung mit dem Microsoft Internet Explorer 5.0 anstatt mit Microsoft Access eingesetzt. Der Internet Explorer 5.0 wird zusammen mit Office 2000 ausgeliefert. Verwendet man Datenzugriffsseiten, so wird im Hintergrund dynamisch HTML benutzt. Da Datenzugriffsseiten ausschließlich vom Internet Explorer 5.0 unterstützt werden, sind sie allerdings weit besser für den Einsatz in Intranets als für Internet-Lösungen geeignet.
30
Kapitel 1: Access als Entwicklungswerkzeug
Außer über Datenzugriffsseiten können Sie Ihre Datenbankobjekte auch als statische oder als dynamische HTML-Seiten veröffentlichen. Statische Seiten sind StandardHTMLs und können mit einem beliebigen Browser betrachtet werden. Datenbankobjekte lassen sich entweder im HTX/IDC- oder im ASP-Dateiformat, aber auch dynamisch publizieren. HTX/IDC-Dateien werden vom Webserver dynamisch angezeigt und hängen nicht vom verwendeten Browser ab. ASP-Dateien, die von Microsoft Access bereitgestellt werden, werden ebenfalls dynamisch vom Webserver veröffentlicht, sie benötigen aber den Internet Explorer 4.0 oder höher auf der ClientArbeitsstation. Intranet- und Internet-Entwicklung unter Microsoft Access wird in Kapitel 31 und Kapitel 32 genauer beschrieben.
1.2
Access als skalierbares Produkt
Eine der stärksten Seiten von Access ist seine leichte Anpassbarkeit an unterschiedlich große Aufgaben. So kann eine Anwendung, die zunächst für eine einzige Arbeitsstation entwickelt wurde, nach und nach zu einer unternehmensweiten Client-Server-Anwendung erweitert werden. Auf diese Weise lässt sich eine Anwendung mit wenig oder sogar ohne jeden zusätzlichen Aufwand an größere Aufgaben anpassen, wenn nur der ursprüngliche Datenbankentwurf gut ist. Diese Eigenschaft macht Access zu einem hervorragenden Werkzeug für aufstrebende Unternehmen und für Anwendungen, die zunächst nur auf Abteilungsebene entwickelt und getestet werden, um erst später im ausgereiften Zustand unternehmensweit zum Einsatz zu kommen. Eine weitere hervorstechende Eigenschaft von Access besteht darin, dass es einen hohen Sicherheitsstandard und das Festlegen von Datenbankregeln zulässt und dass dies sowohl beim Front- als auch beim Back-End möglich ist – früher ging dies nur bei Back-End-Datenbanken. In Kapitel 33 und Kapitel 34 werden Sie sehen, dass sich Sicherheitsregeln auf jedes Element einer Access-Datenbank anwenden lassen, und zwar sowohl auf Benutzer- als auch auf Gruppenebene. Regeln für die referentielle Integrität lassen sich für die ganze Datenbank definieren, so dass man zum Beispiel sicherstellen kann, dass Bestellungen für nicht vorhandene Kunden gar nicht erst eingegeben werden können. Plausibilitätsprüfungen für Daten können auf Feldoder Datensatzebene definiert werden, um so die Datenintegrität in der Datenbank sicherzustellen. Mit anderen Worten: Access bietet nun eine Reihe von Eigenschaften, die bisher nur für Datenbank-Server der obersten Leistungs- und Preisklasse verfügbar waren.
1.3
Was genau ist eine Datenbank ?
Der Begriff »Datenbank« hat für unterschiedliche Personen zwei recht unterschiedliche Bedeutungen: Lange Zeit, insbesondere in der Welt der xBase-Datenbanken (dBase, FoxPro, CA-Clipper), bezeichnete der Begriff lediglich eine Ansammlung von
Datenbankobjekte
31
Feldern und Datensätzen (die in Access Tabelle genannt wird). In einer Client-Server-Umgebung bezeichnet »Datenbank« dagegen die Gesamtheit aller Daten, einschließlich der damit verbundenen Datenstrukturen, Indizes, Regeln, Trigger und Prozeduren. Bei Access schließlich umfasst der Begriff die Gesamtheit aller Tabellen, Abfragen, Formulare, Berichte, Datenzugriffsseiten, Makros und Code-Module, die das gesamte System ausmachen.
1.4
Datenbankobjekte
Access-Datenbanken bestehen aus Tabellen, Abfragen, Formularen, Berichten, Datenzugriffsseiten, Makros und Code-Modulen. Jedes dieser Objekte hat besondere Aufgaben. Die Access-Umgebung enthält noch einige weitere Objekte, wie zum Beispiel Beziehungen, Befehlsschaltflächen, Datenbankeigenschaften und Angaben zum Import und Export von Daten. Mit diesen Objekten lassen sich leistungsfähige, benutzerfreundliche und vielfältige Anwendungen erstellen. Abbildung 1.1 zeigt das Access-Datenbankfenster. Beachten Sie hier im linken Bildteil die sieben aufgeführten Objektklassen. Diese Objektklassen, die eine Access-Datenbank ausmachen, werden Sie in den folgenden Abschnitten kennenlernen.
1.4.1
Tabellen: Ein Lager für Ihre Daten
Tabellen sind der Ausgangspunkt jeder Anwendung. Ob Ihre Daten in einer AccessDatenbank gespeichert sind oder ob Sie auf externe Daten zugreifen, indem Sie verknüpfte Tabellen verwenden, immer greifen alle anderen Objekte Ihrer Datenbank direkt oder indirekt auf Tabellen zu.
Abbildung 1.1: Das Datenbankfenster von Access mit Symbolen für jede Art von Datenbankobjekten
32
Kapitel 1: Access als Entwicklungswerkzeug
Um alle Tabellen zu sehen, die in einer geöffneten Datenbank enthalten sind, müssen Sie das Symbol TABELLEN in der Objektliste anklicken. (Beachten Sie jedoch, dass ausgeblendete Tabellen unsichtbar sind, wenn sie nicht zuvor ausdrücklich über das Kontrollkästchen AUSGEBLENDETE OBJEKTE der Registerkarte ANSICHT des über EXTRAS|OPTIONEN erreichbaren Dialogfelds OPTIONEN eingeblendet werden.) Die Daten innerhalb einer Tabelle können Sie mit einem Doppelklick auf den Namen dieser Tabelle anzeigen. Das gleiche erreichen Sie, wenn Sie den Namen der Tabelle und anschließend die Schaltfläche ÖFFNEN anklicken. Die Daten in der Tabelle werden auf einem Datenblatt angezeigt, welches alle Felder und Datensätze enthält (siehe Abbildung 1.2). Viele Eigenschaften eines Datenblatts lassen sich verändern und Sie können Daten im Datenblatt suchen und filtern. Ist die Tabelle mit einer anderen Tabelle verknüpft (zum Beispiel mit der Kunden- oder Bestellungentabelle der Nordwind-Datenbank), so können Sie sogar die verknüpfte Tabelle anzeigen, um die darin gespeicherten Daten zu sehen. Diese Möglichkeiten werden jedoch in diesem Buch nicht behandelt, da sie im Access-Benutzerhandbuch und in jedem anderen einführenden Access-Buch beschrieben sind.
Abbildung 1.2: Datenblattansicht der Tabelle Kunden in der Nordwind-Datenbank
Als Entwickler müssen Sie oft auf den Entwurf einer Tabelle zurückgreifen, den man als deren Bauplan oder als Schablone bezeichnen könnte. Um den Tabellenentwurf zu sehen, markieren Sie die Tabelle und klicken dann die Schaltfläche ENTWURF (siehe Abbildung 1.3). In der Entwurfsansicht können Sie alle Feldnamen, Datentypen, Feld- und Tabelleneigenschaften betrachten und verändern. Access bietet Ihnen jede Möglichkeit, um den Entwurf Ihrer Tabelle Ihren besonderen Bedürfnissen anzupassen. Diese Punkte sind Gegenstand von Kapitel 2.
33
Datenbankobjekte
Abbildung 1.3: Der Entwurf der Kundentabelle
1.4.2
Beziehungen: Die Tabellen miteinander verbinden
Um die Integrität Ihrer Daten zu gewährleisten und das Zusammenwirken mit anderen Objekten der Datenbank zu erleichtern, müssen Sie zwischen den Tabellen Ihrer Datenbank Beziehungen definieren. Dies geschieht mittels des Fensters BEZIEHUNGEN. Zu diesem Fenster gelangen Sie durch Auswahl des Eintrags BEZIEHUNGEN aus dem Menü EXTRAS oder durch Anklicken der Schaltfläche BEZIEHUNGEN in der Symbolleiste (siehe Abbildung 1.4). In diesem Fenster können Sie die Beziehungen innerhalb der Datenbank betrachten und verändern. Wenn Sie oder ein anderer Entwickler einige Beziehungen definiert hat, die in dem Fenster BEZIEHUNGEN aber nicht sichtbar sind, so wählen Sie BEZIEHUNGEN|ALLE ANZEIGEN, um die möglicherweise ausgeblendeten Tabellen und Beziehungen sichtbar zu machen. Beachten Sie, dass viele der Beziehungen in Abbildung 1.4 durch eine Linie angedeutet sind, an deren einem Ende eine 1 und an dem anderen ein Unendlich-Symbol steht. Dies zeigt an, dass zwischen den verbundenen Tabellen eine 1:n-Beziehung besteht. Durch einen Doppelklick auf die Verbindungslinie öffnet sich das Dialogfeld BEZIEHUNGEN BEARBEITEN (siehe Abbildung 1.5). Dort können Sie den genauen Typ der Beziehung zwischen den Tabellen festlegen. Die Beziehung zwischen den Tabellen Kunden und Bestellungen ist zum Beispiel eine 1:n-Beziehung mit so genannter »referentieller Integrität«, was bedeutet, dass keine Bestellungen für nicht vorhandene Kunden eingegeben werden können. Beachten Sie, dass das Kontrollkästchen AKTUALISIERUNGSWEITERGABE AN DETAILFELD aktiviert ist. Dies zeigt an, dass beim Verändern einer Kundennummer (CustomerID) alle Datensätze, in denen diese Kundennummer enthalten ist, ebenfalls verändert werden. Da das Kontrollkästchen LÖSCHWEITERGABE AN DETAILDATENSATZ nicht aktiviert ist, lassen sich Kunden nicht aus der Kundentabelle löschen, solange es noch zugehörige Bestellungen in der Bestellungentabelle gibt.
34
Kapitel 1: Access als Entwicklungswerkzeug
Abbildung 1.4: Das Fenster Beziehungen, in dem Sie die Beziehungen in der Datenbank betrachten und verwalten
Abbildung 1.5: Das Dialogfeld Beziehungen bearbeiten, in dem Sie die Eigenschaften einer Beziehung zwischen Tabellen festlegen können
Kapitel 3 behandelt ausführlich das Festlegen und Pflegen von Beziehungen zwischen Tabellen. Vorläufig ist für Sie nur wichtig, dass Beziehungen schon beim Entwurf einer Datenbank so früh und so genau wie möglich festgelegt werden sollten. Dies ist eine wesentliche Voraussetzung für den erfolgreichen Entwurf und die erfolgreiche Entwicklung Ihrer Anwendung.
1.4.3
Abfragen: Gespeicherte Fragen oder Aktionen zur Anwendung auf Ihre Daten
Access-Abfragen sind leistungsfähig und vielseitig. Auswahlabfragen erlauben es, die in einer Tabelle vorhandenen Daten anzuschauen, Zusammenfassungen zu erstellen und Berechnungen mit diesen Daten durchzuführen. Aktionsabfragen ermöglichen das Addieren, Verändern und Löschen von Daten. Um eine Abfrage auszuführen, wählen Sie im Datenbankfenster unter OBJEKTE eine Abfrage aus und starten diese
Datenbankobjekte
35
durch einen Doppelklick. (Das gleiche bewirken Sie auch durch einfaches Anklicken und anschließendes Klicken auf ÖFFNEN.) Beim Ausführen einer Auswahlabfrage erscheint ein Datenblatt, das alle in der Abfrage aufgeführten Datenfelder enthält und alle Datensätze anzeigt, die den in der Abfrage genannten Auswahlkriterien entsprechen (siehe Abbildung 1.6). Wenn Sie eine Aktionsabfrage starten, wird die dort vorgesehene Aktion ausgeführt. So könnte zum Beispiel eine neue Tabelle erstellt oder eine vorhandene Tabelle um neue Datensätze erweitert werden. Grundsätzlich können Sie die Daten im Ergebnis einer Abfrage aktualisieren, weil es sich bei diesem Ergebnis tatsächlich um eine dynamische Menge von Datensätzen handelt, die als »Dynaset« bezeichnet wird und auf den Daten Ihrer Tabelle beruht.
Abbildung 1.6: Das Ergebnis der Ausführung der Abfrage Personalumsätze
Wenn Sie eine Abfrage speichern, so werden nur deren Definition sowie die Struktur und das Aussehen des Ergebnisdatenblatts in der Datenbank gespeichert. Access bietet ein leicht bedienbares, benutzerfreundliches Werkzeug für den Entwurf Ihrer Abfragen, das in Abbildung 1.7 zu sehen ist. Um dieses Fenster zu öffnen, wählen Sie in der Objektliste des Datenbankfensters den Eintrag ABFRAGEN, wählen die zu ändernde Abfrage aus und klicken auf ENTWURF. Die in Abbildung 1.6 gezeigte Abfrage wählt Daten aus den Tabellen Personal und Bestellungen sowie der Abfrage Bestellzwischensummen aus. Aus der Tabelle Personal werden die Felder Land, Nachname und Vorname, aus Bestellungen die Felder Versanddatum und Bestell-Nr und aus der Abfrage Bestellzwischensummen das Feld Zwischensumme dargestellt, wobei in der Ausgabemenge nur Daten aus einem bestimmten Zeitraum enthalten sind. Diese besondere Abfrageart heißt »Parameterabfrage«, weil einige oder alle Abfragebedingungen als Parameter eingegeben werden können, deren aktueller Wert erst beim Beginn der Abfrage feststeht. Abfragen werden in Kapitel 4 und in Kapitel 11 ausführlich behandelt. Weil Abfragen aber die Grundlage für die meisten Formulare und Berichte sind, finden sie auch in anderen Kapiteln dieses Buchs Berücksichtigung, wann immer Abfragen auf andere Objekte einer Datenbank Bezug nehmen.
36
1.4.4
Kapitel 1: Access als Entwicklungswerkzeug
Formulare: Daten anzeigen, bearbeiten und hinzufügen
In der Datenblattansicht einer Tabelle können Sie zwar Daten eingeben und verändern, es ist aber kaum möglich, die Benutzertätigkeiten zu steuern oder die Dateneingabe zu vereinfachen. Hierfür verwendet man in Access Formulare. Access-Formulare können sehr unterschiedlich sein und einen sehr großen Funktionsumfang besitzen.
Abbildung 1.7: Der Entwurf einer Abfrage, die Daten aus den Tabellen Personal und Bestellungen sowie der Abfrage Bestellzwischensummen anzeigt
Um ein Formular zu betrachten, wählen Sie aus der Objektliste den Eintrag FORMULARE aus und aktivieren diesen durch Doppelklick. Alternativ können Sie auch einmal auf FORMULARE und anschließend auf ÖFFNEN klicken. Abbildung 1.8 zeigt ein Formular in der Formularansicht. Dieses Formular besteht eigentlich aus drei einzelnen Formularen, nämlich einem Hauptformular und zwei Unterformularen. Das Hauptformular enthält Daten aus der Kundentabelle, und die Unterformulare zeigen Daten aus den Tabellen Bestellungen und Bestelldetails. Wenn nun der Benutzer sich die Kunden nacheinander ansieht, so werden ihm jeweils auch die mit diesen Kunden verknüpften Bestellungen angezeigt, und beim Anklicken einer Einzelbestellung eines Kunden sieht er die einzelnen Positionen dieser Bestellung. Wie Tabellen und Abfragen können auch Formulare in der Entwurfsansicht betrachtet werden. Um einen solchen Formularentwurf zu sehen, klicken Sie in der Objektliste auf FORMULARE, wählen das anzupassende Formular aus und klicken dann auf ENTWURF. Abbildung 1.9 zeigt das Formular Kundenbestellungen in der Entwurfsansicht. Beachten Sie die beiden Unterformulare innerhalb des Hauptformulars. Formulare werden ausführlich in Kapitel 5 und in Kapitel 9 erläutert. Außerdem werden sie an zahlreichen anderen Stellen dieses Buchs beschrieben, wenn sie beim Entwurf einer Beispielanwendung eine Rolle spielen.
Datenbankobjekte
37
Abbildung 1.8: Das Formular Kundenbestellungen umfasst Informationen zu den Kunden, zu den Bestellungen und zu den Bestelldetails
Abbildung 1.9: Der Entwurf des Formulars Kundenbestellungen enthält zwei Unterformulare
1.4.5
Berichte: Daten in Informationen verwandeln
Formulare dienen hauptsächlich der Eingabe und Bearbeitung von Informationen, mit Berichten können Sie dagegen Ihre Daten übersichtlich aufbereiten und zum Beispiel auf einem Drucker ausgeben. Abbildung 1.10 zeigt einen Bericht in der so genannten »Vorschau«. Um einen Bericht in der Vorschau anzusehen, wählen Sie in der Objektliste den Eintrag BERICHTE und doppelklicken auf den gewünschten Bericht oder Sie klicken zuerst auf den Bericht und dann auf VORSCHAU. Beachten Sie die in den Bericht eingebettete Grafik sowie andere Einzelheiten, wie etwa die schattierte Zeile. Berichte können wie Formulare sehr kunstvoll und aufwendig gestaltet sein und wertvolle Informationen enthalten.
38
Kapitel 1: Access als Entwicklungswerkzeug
Abbildung 1.10: Eine Voransicht des KatalogBerichts
Falls Sie es bisher noch nicht erraten haben: Auch Berichte können in einer Entwurfsansicht betrachtet werden (siehe Abbildung 1.11). Um den Entwurf eines beliebigen Berichts zu sehen, wählen Sie in der Objektliste den Eintrag BERICHTE, wählen den gewünschten Bericht aus und klicken danach auf ENTWURF. Abbildung 1.11 zeigt einen Bericht mit mehreren Abschnitten. Sie können den Berichts- und den Seitenkopf, einen Kopfbereich Kategoriename und den Detailbereich sehen – und das sind nur einige wenige der innerhalb eines Berichts möglichen Abschnitte. Ebenso wie ein Formular Unterformulare enthalten kann, kann auch ein Bericht Unterberichte enthalten. Berichte werden ausführlich in Kapitel 6 und Kapitel 10 sowie an vielen anderen Stellen dieses Buchs behandelt, weil sie in zahlreichen Beispielen Verwendung finden.
Abbildung 1.11: Entwurfsansicht des KatalogBerichts
Datenbankobjekte
1.4.6
39
Datenzugriffsseiten: Formulare, die mit einem Browser betrachtet werden
Datenzugriffsseiten, die schon weiter oben erwähnt wurden, sind in Access 2000 neu hinzugekommen. Sie bieten Ihnen die Möglichkeit, Daten in Ihrer Datenbank mit Hilfe eines Browsers zu betrachten und zu verändern. Obwohl sie außerhalb der Access-Datenbankdateien gespeichert werden, ähnelt ihre Erstellung und Pflege der von Formularen. Abbildung 1.12 zeigt eine Datenzugriffsseite, die innerhalb von Access betrachtet wird. Zwar werden Datenzugriffsseiten normalerweise für die Betrachtung in einem Browser erstellt, doch sie können auch innerhalb einer AccessAnwendung angesehen werden. Auch Datenzugriffsseiten können in einer Entwurfsansicht betrachtet und verändert werden. Abbildung 1.13 zeigt eine Datenzugriffsseite in der Entwurfsansicht. Wie Sie sehen, ähnelt die Entwurfsansicht einer Datenzugriffsseite derjenigen eines Formulars. Dadurch gestaltet sich das Arbeiten mit Datenzugriffsseiten und das Verbreiten Ihrer Anwendung über ein Intranet sehr einfach.
Abbildung 1.12: Ein Beispiel einer Datenzugriffsseite auf der Grundlage der Tabelle Personal
1.4.7
Makros: Ihr System automatisieren
Makros in Access unterscheiden sich deutlich von Makros in anderen Sprachen. Sie können nicht aufgezeichnet werden, wie dies bei Word und Excel möglich ist, und sie werden auch nicht als VBA-Programm gespeichert. Mit Access-Makros können Sie die meisten der manuell über Tastatur, Menü oder Symbolleisten ausführbaren Anweisungen automatisch ablaufen lassen. Makros erlauben sogar das Formulieren logischer Abhängigkeiten für den Ablauf Ihrer Datenbankanwendung. Sollen jedoch
40
Kapitel 1: Access als Entwicklungswerkzeug
Abbildung 1.13: Eine Datenzugriffsseite in der Entwurfsansicht
die Tätigkeiten Ihrer Anwendung besonders effektiv durchgeführt werden, so empfiehlt sich zum Programmieren VBA (Visual Basic für Applikationen) anstelle von Makros, denn VBA bietet deutlich mehr Möglichkeiten. Obwohl in früheren Versionen von Access einige Abläufe ausschließlich mit Hilfe von Makros realisiert werden konnten, werden sie von Entwicklern heutzutage nur sehr selten verwendet. Die Entwicklung von Anwendungen mit Makros wird deshalb in diesem Buch nicht behandelt. Um ein Makro auszuführen, gehen Sie folgendermaßen vor: Wählen Sie aus der Objektliste den Eintrag MAKROS, klicken Sie das gewünschte Makro an und klicken Sie danach auf AUSFÜHREN. Anschließend werden die im Makro definierten Anweisungen ausgeführt. Um den Entwurf eines Makros zu sehen, wählen Sie aus der Objektliste den Eintrag MAKROS aus, klicken das zu verändernde Makro an und klicken danach auf ENTWURF, um so das Entwurfsfenster zu öffnen (siehe Abbildung 1.14). Das hier abgebildete Makro verfügt über vier Spalten. Die erste Spalte ist die Namensspalte, in der die Namen von Unterprogrammen innerhalb von Makros festgelegt werden können. In der zweiten Spalte können Sie Bedingungen formulieren, die erfüllt sein müssen, damit die Aktion in der dritten Spalte ausgeführt wird. In die vierte Spalte schließlich können beliebige Kommentare eingetragen werden. In der unteren Hälfte des Entwurfsfensters geben Sie Argumente für die ausgewählte Aktion an. In Abbildung 1.14 wurde die Aktion MsgBox ausgewählt, die vier Argumente akzeptiert: Meldung, Signalton, Typ und Titel.
41
Datenbankobjekte
Abbildung 1.14: Der Entwurf des Makros Kunden mit Makronamen, Bedingungen, Aktionen und Kommentaren
1.4.8
Module: Die Grundlage der Anwendungsentwicklung
»Module« sind die Grundlage jeder Anwendung und erlauben Ihnen den Aufbau von Funktionsbibliotheken, deren einzelne Elemente Sie anschließend überall in Ihrer Anwendung einsetzen können. Module werden üblicherweise aus Unterroutinen und Funktionen gebildet, wobei Funktionen immer einen Wert zurückgeben, was bei Unterroutinen nicht der Fall ist. Mit Hilfe von Code-Modulen können Sie folgende Aufgaben erledigen:
Fehler behandeln Variablen deklarieren und verwenden Datensatzgruppen durchlaufen und bearbeiten Funktionen des Windows-API oder anderer Bibliotheken aufrufen Systemobjekte wie Tabellen und Abfragen erstellen und bearbeiten Transaktionen verarbeiten Funktionen ausführen, die nicht als Makros verfügbar sind komplexe Abläufe testen und korrigieren Bibliotheksdatenbanken erstellen Dies sind nur einige der vielen Möglichkeiten, die Sie sich mit der Benutzung von Modulen erschließen. Um ein schon bestehendes Modul zu betrachten, klicken Sie in der Objektliste auf MODULE, wählen das gewünschte Modul aus und klicken dann auf Entwurf, um das Entwurfsfenster zu öffnen (siehe Abbildung 1.15). Das hier gezeigte Code-Modul enthält einen Abschnitt Allgemeine Deklarationen sowie eine
42
Kapitel 1: Access als Entwicklungswerkzeug
Funktion mit dem Namen IsLoaded. Module und VBA sind in Kapitel 7 und in Kapitel 24 beschrieben und werden darüber hinaus an sehr vielen Stellen des ganzen Buchs behandelt.
Abbildung 1.15: Das globale CodeModul in der Entwurfsansicht mit dem Abschnitt Allgemeine Deklarationen der Funktion IsLoaded
1.5
Objektbenennung
Eine wesentliche Grundlage für erfolgreiches Programmieren in Access wie in jeder anderen Programmiersprache ist es, Namenskonventionen festzulegen, die für die weitere Arbeit absolut verbindlich sein müssen. Achten Sie beim Festlegen solcher Konventionen vor allem auf diese drei Dinge:
Einfachheit Lesbarkeit Akzeptanz in Entwicklerkreisen Die so genannten »Reddick-Namenskonventionen«, die von Greg Reddick stammen, sind mit Abstand die besten, die bisher für das Entwickeln von Anwendungen vorgeschlagen wurden. Die Reddick-Namenskonventionen unterstützen ein standardisiertes Vorgehen bei der Benennung von Objekten. Sie wurden von den Leszynski/Reddick-Namenskonventionen abgeleitet, die schon in Access 1.x und 2.0 überaus beliebt waren. Diese Standards wurden von den Programmentwicklern anerkannt und intensiv angewendet, so dass sie in den meisten guten Büchern über Programmentwicklung und in vielen Zeitschriftenartikeln der letzten Jahre zu finden sind. Die neuen ReddickNamenskonventionen wurden überarbeitet, um vor allem solche Entwickler zu unterstützen, die die VBA-Sprache gleichzeitig in Access, Visual Basic, Excel und anderen Microsoft-Produkten einsetzen. Diese Konventionen bieten Ihnen eine
Hardwareanforderungen
43
leicht benutzbare und nachvollziehbare Richtschnur für Objektnamen in allen diesen Programmumgebungen. Eine Zusammenfassung der Reddick-Namenskonventionen finden Sie im Anhang. Ich werde von diesen Vereinbarungen überall im Buch Gebrauch machen und auf bestimmte Aspekte gezielt eingehen, wenn sie gerade von Bedeutung sind.
1.6
Hardwareanforderungen
Ein Nachteil von Access sind die ständig steigenden Hardwareanforderungen bei neuen Versionen. Die Hardwareanforderungen eines Entwicklers sind andere als die eines Endbenutzers, weshalb dieser Abschnitt aus zwei Teilen besteht. Achten Sie beim Lesen dieser Anforderungen außerdem immer auf den Unterschied zwischen tatsächlich erforderlicher und empfohlener Hardwareausstattung.
1.6.1
Welche Hardware benötigt der Entwickler?
Gemäß Microsoft-Handbuch sind dies die offiziellen Mindestvoraussetzungen, um Access 2000 einsetzen zu können:
386DX-Prozessor (empfohlen: 486) Windows 95 oder Windows NT 3.51 oder höher 12 MB RAM für Windows 95 16 MB RAM für Windows NT VGA-Grafikkarte (empfohlen: SVGA, 256 Farben) Zeigegerät (zum Beispiel eine Maus) Trotzdem sind meine eigenen Empfehlungen für einen Entwicklungsrechner noch sehr viel höher, weil Sie ja möglicherweise neben Access noch andere Anwendungen auf Ihrem System einsetzen wollen. Außerdem ist es mit Sicherheit in Ihrem Interesse, die Wahrscheinlichkeit eines Systemabsturzes oder anderer Probleme zu verringern, die durch einen zu kleinen Arbeitsspeicher verursacht werden können. Ich empfehle deshalb für ein Entwicklungssystem die folgende Ausstattung:
Pentium 133 oder höher 64 MB RAM für Windows 95 oder 98, 64 MB RAM für Windows NT (oder mehr, falls Sie mehrere Anwendungen gleichzeitig einsetzen wollen)
hochauflösender Bildschirm – je größer, desto besser, und möglichst mit SVGAGrafikkarte
44
Kapitel 1: Access als Entwicklungswerkzeug
Wenn Sie Anwendungen an einem hochauflösenden Bildschirm entwickeln, sollten Sie die Formulare trotzdem so gestalten, dass sie auch auf dem schlechtesten üblicherweise eingesetzten Bildschirm noch richtig angezeigt werden können. Auch wenn Ihnen die hohe Auflösung Ihres eigenen Systems beim Entwickeln Vorteile bietet, sollten Sie dennoch stets daran denken, dass viele Benutzer nur Bildschirme mit geringerer Auflösung einsetzen. Grundsätzlich gilt für die Hardware eines Entwicklungssystems: je mehr, desto besser. Man kann nie genügend Arbeitsspeicher und nie genügend Plattenplatz haben. Sie werden umso mehr Freude mit Access haben, je mehr Arbeits- und Plattenspeicher Sie in Ihre Arbeitsstation eingebaut haben.
1.6.2
Welche Hardware benötigt der Benutzer?
Wenngleich ein Benutzersystem bei weitem nicht so gut ausgestattet sein muss wie ein Entwicklersystem, empfehle ich dennoch zusätzlich zu den von Microsoft genannten Anforderungen Folgendes:
Pentium 133 oder höher 48 MB RAM für Windows 95 oder Windows 98, 64 MB RAM für Windows NT (oder noch mehr, wenn Ihre Anwendung OLE unterstützt oder Ihr Benutzer neben Access noch andere Programme einsetzt)
1.7
Wie beginne ich mit der Entwicklung einer Access-Anwendung?
Viele Entwickler erliegen dem Trugschluss, man brauche für das Entwickeln einer Access-Anwendung keinerlei Systemanalyse und keinerlei Datenbankentwurf, weil Access doch eine so bequeme und weitgehend automatisierte Entwicklungsumgebung bietet. Ein größeres Missverständnis ist kaum denkbar: Schon früher in diesem Kapitel habe ich erwähnt, dass sich Access-Anwendungen trügerisch leicht erstellen lassen, was aber ohne eine saubere Planung schnell zu einem heillosen Durcheinander führen kann.
1.7.1
Aufgabenanalyse
Der erste Schritt beim Entwicklungsablauf besteht darin, die gewünschte Aufgabe gründlich zu analysieren oder jeden einzelnen Vorgang im Laufe eines Arbeitstages des späteren Benutzers genau zu überdenken – eine sehr lästige, aber unumgängliche Arbeit. Als ich selbst in einem großen Unternehmen meine erste Stelle als Programmierer in einer Großrechnerumgebung angetreten hatte, musste ich eine Checkliste für Arbeitsabläufe sorgfältig befolgen. Ich musste herausfinden, welche täglichen
Wie beginne ich mit der Entwicklung einer Access-Anwendung?
45
Aufgaben jeder Benutzer des Systems hatte, jeden Arbeitsschritt beschreiben, den Ablauf der einzelnen Arbeitsschritte von einem Benutzer zum nächsten dokumentieren, den Zusammenhang der einzelnen Arbeitsschritte untereinander herausfinden und schließlich den Zusammenhang der Arbeitsschritte mit den Unternehmenszielen beschreiben. Heute, im Zeitalter der schnellen Anwendungsentwicklung und des schnellen Technologiewandels, verschwindet dieser Teil des Entwicklungsprozesses offenbar aus dem Blickfeld. Ich behaupte jedoch, dass ein Entwickler später wesentliche Teile seiner Anwendung neu schreiben muss, wenn er die einzelnen Arbeitsschritte nicht zu Beginn der Entwicklung sorgfältig untersucht hat.
1.7.2
Datenanalyse und Entwurf
Nachdem Sie alle Arbeitsschritte untersucht und beschrieben haben, die für Ihr Entwicklungsprojekt wichtig sind, können Sie mit der Datenanalyse und dem Entwurf Ihrer Anwendung beginnen. Dabei müssen Sie für jeden einzelnen Arbeitsschritt jede erforderliche Einzelinformation beschreiben. Diese Einzeldaten werden danach zu Themen zusammengefasst und aus jedem Thema entsteht anschließend eine Tabelle in Ihrer Datenbank. Ein Thema könnte beispielsweise ein Kunde sein, dann wird jedes Datenelement, das zu diesem Kunden in irgendeiner Beziehung steht, ein Feld in der Kundentabelle. Name, Adresse, Telefonnummer, Kreditlimit und andere wichtige Informationen würden also Felder in der Kundentabelle. Für jedes Datenelement sollten Sie die folgenden Eigenschaften festlegen:
den geeigneten Datentyp die benötigte Feldgröße Gültigkeitsregeln Außerdem sollten Sie für jedes Datenelement bestimmen, ob es später veränderbar sein soll und ob die Daten vom Benutzer eingegeben werden oder ob der Inhalt vom System selbst errechnet wird. Dann können Sie herausfinden, ob Ihre Tabellenstrukturen in Normalform vorliegen oder nicht. Regeln leicht gemacht Mit dem Begriff »Normalisierung« beschreibt man das Überprüfen eines Tabellenentwurfs hinsichtlich einer Reihe bestimmter Regeln, die – wenn sie eingehalten werden – bewirken, dass eine Anwendung möglichst effektiv abläuft. Diese Regeln beruhen auf der Mengenlehre und wurden erstmals von Dr. E. F. Codd vorgeschlagen. Obwohl Sie sich jahrelang mit dem Thema Normalisierung beschäftigen können, so ist doch das Hauptziel der Normalisierung sehr einfach zu formulieren: Eine Anwendung soll möglichst effektiv ablaufen, ohne dass nennenswerte Veränderungen an der Datenstruktur oder an den Programmen vorgenommen werden müssen. Es folgen sechs wichtige Regeln für die Normalisierung:
46
Kapitel 1: Access als Entwicklungswerkzeug
Felder sollen atomar sein, was bedeutet, dass Daten so weit wie möglich zerlegt werden sollten. Beispielsweise würden Sie anstelle eines Feldes Name eher zwei Felder erstellen: eines für den Vor- und eines für den Nachnamen. Auf diese Weise lassen sich Daten erheblich leichter handhaben. Nur so kann man zum Beispiel bequem und ohne nennenswerten Aufwand alle Daten der Tabelle unabhängig von den Nachnamen nach den Vornamen sortieren oder nach einem bestimmten Vornamen suchen.
Jeder Datensatz sollte eine eindeutige Kennzeichnung enthalten, die ihn von jedem anderen Datensatz der Tabelle unterscheidet. Wenn Sie zum Beispiel Kundendaten verändern, können Sie auf diese Weise sicherstellen, dass wirklich die Daten des richtigen Kunden verändert werden. Eine solche eindeutige Kennzeichnung nennt man einen »Primärschlüssel«.
Der Primärschlüssel besteht aus einem Feld oder einer Gruppe von Feldern, die einen Datensatz eindeutig kennzeichnen. Manchmal lässt sich hier ein natürlicher Schlüssel verwenden, wie etwa das Geburtsdatum in einem Personaldatensatz, die ja einem Mitarbeiter eindeutig und unveränderbar zugeordnet ist. Der Kundenname in einem Kundendatensatz lässt sich dagegen nicht als Primärschlüssel benutzen, weil mehrere Kunden den gleichen Namen haben können. In solchen Fällen muss man einen künstlichen Primärschlüssel erzeugen, wie zum Beispiel eine Kundennummer.
Ein Primärschlüssel soll kurz, einfach und feststehend sein. »Kurz« bedeutet, er soll nur wenige Zeichen lang sein, »einfach« bedeutet, dass die Benutzer bequem mit ihm umgehen können, und »feststehend« bedeutet, dass er selten oder nie geändert wird. Eine Kundennummer würde sich zum Beispiel im Gegensatz zu einem Kundennamen nur selten ändern.
Jedes Feld innerhalb einer Tabelle sollte zusätzliche Informationen über den mit dem Primärschlüssel gekennzeichneten Datensatz enthalten. Jedes Feld eines Kundensatzes enthält beispielsweise zusätzliche Daten über diesen Kunden mit seiner eindeutigen Kundennummer.
Informationen sollten stets nur einmal, also nur an einer einzigen Stelle, in der Datenbank gespeichert sein. So sollte beispielsweise ein Kundenname nicht in mehreren Datensätzen auftauchen. Betrachten wir ein Beispiel: Das in Abbildung 1.16 dargestellte Datenblatt ist ein Beispiel für eine nicht normalisierte Tabelle. Beachten Sie, dass das Feld CustInfo bei jeder Bestellung wiederholt wird. Würde sich nun die Adresse des Kunden ändern, müsste man diese Änderung in sämtlichen Bestelldatensätzen nachträglich vornehmen. Das Feld CustInfo ist außerdem nicht atomar: Eine Sortierung nach Städtenamen ist unmöglich, weil sich diese nicht am Anfang der Adresse befinden. Wenn der Name eines Artikels geändert wird, müsste man diese Änderung ebenfalls in allen entsprechenden Datensätzen einzeln nachtragen. Das vielleicht schwierigste Problem in diesem Beispiel betrifft aber die bestellten Artikel: Bei dieser Datenbank-
Wie beginne ich mit der Entwicklung einer Access-Anwendung?
47
struktur benötigt man für jede bestellte Position vier Datenfelder: Name, Lieferant, Bestellmenge und Preis. Mit einer solchen Datenbankstruktur ist es extrem aufwendig, zusammenfassende Berichte zu erstellen, die Benutzer für ihre tägliche Arbeit benötigen.
Abbildung 1.16: Eine nicht normalisierte Tabelle
Abbildung 1.17 zeigt die gleichen Daten in normalisierter Form. Beachten Sie, dass die Daten sich nun in vier unterschiedlichen Tabellen befinden: tblCustomers, tblOrders, tblOrderDetails und tblSuppliers. Die Tabelle tblCustomers enthält ausschließlich Datensätze, die jeweils die Daten eines bestimmten Kunden enthalten und durch eine Kundennummer (CustID) eindeutig gekennzeichnet sind. Dieses Feld dient außerdem zur Verknüpfung mit der Tabelle tblOrders, d.h. mit den Bestellungen. Die Tabelle tblOrders enthält ihrerseits nur Informationen über die Bestellungen als Ganzes, nicht jedoch Angaben zu den einzelnen Bestellpositionen. Sie umfasst insbesondere das Feld CustID des Kunden, von dem die Bestellung stammt, sowie das Bestelldatum. Die Tabelle tblOrders steht über eine Bestellnummer (OrderID) mit der Tabelle tblOrderDetails in Beziehung. Die Tabelle tblOrderDetails speichert Informationen über jeden im Rahmen einer Bestellung bestellten Artikel, wobei die Anzahl der bestellten Artikel unbegrenzt ist. Je mehr Positionen bestellt werden, um so mehr Datensätze werden an diese Tabelle tblOrderDetails angefügt. Schließlich sind die Lieferantendaten in einer eigenen Tabelle tblSuppliers abgelegt, so dass eine eventuelle Veränderung von Lieferantendaten in der Datenbank nur an einer einzigen Stelle zu berücksichtigen ist.
48
Kapitel 1: Access als Entwicklungswerkzeug
Abbildung 1.17: Den Regeln entsprechend in vier getrennte Tabellen aufgeteilte Daten
1.7.3
Prototypen
Bei der Untersuchung der betrieblichen Abläufe und der Datenstrukturen hat sich seit den Tagen der Großrechner nicht viel getan, die Erstellung von Prototypen funktioniert aber mittlerweile vollkommen anders. Bei der Entwicklung von Anwendungssystemen für Großrechner oder für DOS-basierende Sprachen war es wichtig, jede Bildschirmmaske und jeden Bericht sehr genau und sehr aufwendig zu beschreiben. Ich erinnere mich daran, dass damals die Benutzer jeden Bildschirm- und Berichtsentwurf vorab gegenzeichnen mussten. Dies galt auch für einfache Änderungen wie etwa das Verschieben eines Feldes auf dem Bildschirm oder das Einfügen einer zusätzlichen Summenzeile in einen Bericht. Nachdem der Benutzer den Entwurf abgezeichnet hatte, verschwanden die Programmierer für mehrere Tage und arbeiteten hart an dieser Änderung. Wollten die Benutzer nach einigen Monaten abermals Änderungen an Masken oder Berichten, bedeutete dies erneute Planungsarbeit, erneute Entwürfe und erneuten Programmieraufwand. Dieser Entwicklungsprozess läuft heute ganz anders ab. Sobald die Arbeitsabläufe beschrieben und die Daten grundlegend analysiert sind, kann der Entwickler die Tabellen und deren Beziehungen zueinander entwerfen. Danach kann er mit dem Entwurf der Formulare und Berichte beginnen. Während es früher Wochen oder Monate dauerte, ehe ein Entwickler seine Arbeitsergebnisse dem Benutzer vorzeigen konnte, dauert es heute nur wenige Tage, um mit den Access-Assistenten schnell erste Prototypen von Formularen und Berichten zu entwerfen.
1.7.4
Testen
Testen kann man nie genug, auch wenn die Tests noch so sorgfältig sind. Ich empfehle Ihnen, Ihre Anwendung, wenn diese später unter Windows 95, 98 und NT laufen soll, in jeder dieser Umgebungen zu testen. Ich rate Ihnen außerdem, Ihre Anwendung auf einem System zu testen, das sozusagen den kleinsten gemeinsamen
Wie beginne ich mit der Entwicklung einer Access-Anwendung?
49
Nenner aller späteren Benutzer darstellt – denn es könnte sein, dass die Anwendung auf Ihrem eigenen leistungsfähigen System ganz hervorragend läuft, während sie auf einem leistungsschwächeren Benutzersystem einbricht. Meistens ist es hilfreich, sowohl die einzelnen Teile einer Anwendung als auch die Anwendung als Ganzes zu testen. Suchen Sie sich einen Stab von Testpersonen und achten Sie darauf, dass dabei vom blutigen Anfänger bis zum Computerexperten alle denkbaren Benutzertypen vertreten sind. Denn diese unterschiedlichen Personen werden möglicherweise ganz unterschiedliche Probleme in Ihrer Anwendung entdecken. Ganz besonders wichtig ist, dass nicht Sie selbst der einzige Tester Ihrer Anwendung sind, weil ein Entwickler für das Finden von Fehlern in seiner eigenen Anwendung ziemlich ungeeignet ist.
1.7.5
Implementierung
Nach der Testphase können Sie Ihre Anwendung auf die Menschheit loslassen – oder zumindest hoffen Sie das. Verteilen Sie Ihre Anwendung zunächst nur an einige Ihrer Benutzer und erklären Sie diesen, dass es sich vorläufig noch um eine Testphase handelt. Machen Sie diesen Benutzern deutlich, dass es eine Ehre ist, als erste ein neues System testen und benutzen zu dürfen, aber erwähnen Sie auch, dass noch Fehler auftreten können und dass solche Fehler unbedingt an Sie, den Entwickler, zu melden sind. Wenn Sie anders vorgehen, also Ihre neue Anwendung gleich an viele Benutzer verteilen und sich dann schwerwiegende Fehler in Ihrer Anwendung herausstellen, ist es erfahrungsgemäß recht schwierig, das erschütterte Vertrauen der Benutzer wiederzugewinnen. Deshalb ist es so überaus wichtig, Ihre neue Anwendung behutsam im betrieblichen Alltag einzuführen.
1.7.6
Systempflege
Da Access auf die schnelle Anwendungsentwicklung ausgelegt ist, wird die für die Systempflege aufzuwendende Zeit länger, als dies in der Vergangenheit bei den Großrechnern der Fall war. Die Benutzeransprüche werden immer größer, d.h., je mehr Wünsche Sie erfüllen, umso mehr Wünsche werden die Benutzer haben. Für einen Berater ist das großartig. Aber achten Sie darauf, nicht in eine ungewollte Abhängigkeit zu geraten: Wenn Sie sich nur noch mit der Pflege Ihrer alten Anwendungen befassen, werden Sie irgendwann keine Zeit mehr für neue Entwicklungen haben. Man kann drei Arten von Pflegearbeiten unterscheiden: Fehlerbeseitigung, zusätzliche Benutzeranforderungen und Feinheiten. Fehler müssen immer schnellstmöglich beseitigt werden. Die Auswirkungen zusätzlicher Benutzeranforderungen müssen den Benutzern deutlich vor Augen geführt werden, einschließlich des nötigen zeitlichen und finanziellen Aufwands. Und Feinheiten, nebensächliche Verzierungen an Formularen und Berichten? Da sollten Sie versuchen, die Benutzer möglichst stark mit einzubeziehen. Zeigen Sie den Benutzern, wie sie selbst Formulare erweitern und
50
Kapitel 1: Access als Entwicklungswerkzeug
Berichte ihren Wünschen anpassen können. Bedenken Sie stets: zufriedene und produktive Benutzer sind das wichtigste Ziel jeder Entwicklung.
1.7.7
Für die Praxis
Ein Beratungsunternehmen in der Computerbranche Im Verlauf dieses Buchs wird beispielhaft eine Anwendung entwickelt, nämlich ein Zeit- und Abrechnungssystem für ein Beratungsunternehmen in der Computerbranche. Zunächst wollen wir für diese Anwendung eine grobe Struktur entwerfen: Das geplante System soll Kunden, Kundenkontakte und Kundenprojekte aufzeigen. Der Benutzer soll damit alle berechneten Stunden und alle aufgelaufenen Kosten pro Kunde und pro Projekt ausweisen können. Es soll außerdem möglich sein, über jeden Angestellten und jeden Subunternehmer wichtige Informationen abzurufen. Die Tabellen in dem geplanten System sollen zunächst mit dem Datenbank-Assistenten erstellt werden, danach werden sie bei Bedarf angepasst und erhalten Namen nach den Reddick-Namenskonventionen. Das von Ihnen entworfene System wird anschließend weit leistungsfähiger und vielseitiger sein als das vom DatenbankAssistenten bereitgestellte. Wir werden in diesem System zehn Tabellen verwenden. Einige dieser Tabellen werden in Kapitel 2 erstellt und Sie finden alle Tabellen in den Anwendungsdatenbanken auf der beiliegenden CD-ROM:
tblClients – Diese Tabelle enthält alle kundenspezifischen Informationen und steht in Beziehung zur Tabelle tblProjects, in der alle Daten für jedes Projekt eines Kunden gespeichert sind.
tblProjects – Diese Tabelle enthält alle projektspezifischen Informationen und steht gleich zu mehreren Tabellen in Beziehung: tblClients, tblPayments, tblEmpoyees und tblTimeCardExpenses.
tblTimeCardHours – In dieser Tabelle werden für jedes Projekt und für jeden Angestellten alle aufgewendeten Arbeitsstunden aufgezeichnet. Es bestehen Beziehungen zu tblProjects, tblTimeCards und tblWorkCodes.
tblPayments – In diese Tabelle werden alle Zahlungen gespeichert, die mit einem bestimmten Projekt in Zusammenhang stehen. tblPayments steht in Beziehung zu den Tabellen tblProjects und tblPaymentMethods.
tblTimeCardExpenses – Diese Tabelle enthält alle Spesen pro Projekt und Mitarbeiter und steht in Beziehung zu tblProjects, tblTimeCards und tblExpenseCodes.
tblEmployees – Diese Tabelle enthält personalbezogene Daten und steht in Beziehung zu tblProjects und tblTimeCards.
Wie beginne ich mit der Entwicklung einer Access-Anwendung?
51
tblTimeCards – In dieser Tabelle werden die Arbeitszeiten jedes einzelnen Mitarbeiters eingetragen. Tatsächlich dient tblTimeCards als Verbindung zwischen der m:n-Beziehung zwischen den Tabellen tblEmployees und tblTimeCardExpenses und der Beziehung zwischen tblEmployees und tblTimeCardHours. tblTimeCards steht in Beziehung zu tblEmployees, tblTimeCardHours und tblTimeCardExpenses.
tblExpenseCodes – Diese Tabelle dient zum Nachschlagen der gültigen Codes für die unterschiedlichen Spesenarten und steht in Beziehung zu tblTimeCardExpenses.
tblWorkCodes – Diese Tabelle dient zum Nachschlagen der gültigen Codes für die unterschiedlichen Arten von Arbeit und steht in Beziehung zu tblTimeCardHours.
tblPaymentMethods – Diese Tabelle dient zum Nachschlagen der gültigen Codes für die unterschiedlichen Zahlungsweisen und steht in Beziehung zu tblPayments. Die Beziehungen zwischen diesen Tabellen werden in Kapitel 3 ausführlich behandelt und sind in Abbildung 1.18 grafisch dargestellt.
Abbildung 1.18: Beziehungen zwischen den Tabellen im Zeitund Abrechnungssystem
Was jeder Entwickler über Tabellen wissen sollte
Kapitel
Hier lesen Sie:
Mit Tabellen arbeiten Den für Ihre Daten geeigneten Feldtyp auswählen Feldeigenschaften Der allgegenwärtige Primärschlüssel Der Nachschlage-Assistent Tabelleneigenschaften Mit Hilfe von Indizes die Geschwindigkeit verbessern Access-Tabellen und das Internet
2.1
Mit Tabellen arbeiten
Es gibt mehrere Möglichkeiten, zu einer schon bestehenden Access 2000-Datenbank eine neue Tabelle hinzuzufügen: Sie können sich den Entwurf durch einen AccessAssistenten erleichtern, eine Tabelle von Grund auf entwerfen, ein datenblattähnliches Format in eine Tabelle umwandeln, eine Tabelle aus einer anderen Datenbank kopieren und Ihre Datenbank mit einer externen Tabelle verknüpfen. In diesem Kapitel wird beschrieben, wie man eine Tabelle von Grund auf entwirft – das Importieren und Verknüpfen von Tabellen wird sehr ausführlich in nahezu allen Kapiteln dieses Buches behandelt. Auf die beiden anderen Möglichkeiten wird jedoch in diesem Buch nicht eingegangen, weil sie für die meisten betrieblichen Anwendungen nicht geeignet sind. Wenn Sie eine neue Tabelle entwerfen wollen, müssen Sie zunächst in der Objektliste des Datenbankfensters das Symbol TABELLEN anklicken. Dies gilt für alle oben genannten Möglichkeiten. Danach erscheinen Symbole, die Ihnen das Erstellen
54
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
einer Tabelle in der Entwurfsansicht, mit Hilfe des Tabellen-Assistenten oder durch die Eingabe von Daten ermöglichen (siehe Abbildung 2.1).
Abbildung 2.1: Um eine neue Tabelle zu erstellen, klicken Sie auf das Tabellensymbol im Datenbankfenster
2.2
Eine Tabelle von Grund auf entwerfen
Eine Tabelle von Grund auf zu entwerfen bietet eine besonders große Flexibilität und fördert gute Entwurfsprinzipien. Für den Entwurf einer normalen betrieblichen Anwendung ist dies fast immer der beste Weg. Um eine Tabelle von Grund auf zu entwerfen, wählen Sie in der Objektliste TABELLEN|NEU und klicken danach zweimal auf das Symbol ERSTELLT EINE TABELLE IN DER ENTWURFSANSICHT. Danach erscheint das Tabellenentwurfsfenster, wie es in Abbildung 2.2 zu sehen ist. Führen Sie dann die folgenden Schritte aus: 1. Geben Sie jedem Tabellenfeld in der Spalte FELDNAME einen Namen. Sie können stattdessen auch die Schaltfläche AUFBAUEN auf der Symbolleiste anklicken (die Schaltfläche mit dem Zauberstab), um das Dialogfeld FELD-GENERATOR zu öffnen, das in Abbildung 2.3 dargestellt ist. Dieser Generator erlaubt die Auswahl vordefinierter Felder mit vordefinierten Eigenschaften. Natürlich können Sie diese Eigenschaften jederzeit nach Ihren eigenen Vorstellungen verändern. 2. Springen Sie mit dem Tabulator zur Spalte FELDDATENTYP. Wählen Sie den Standard-Feldtyp Text aus, oder entscheiden Sie sich mit Hilfe des aufklappbaren Kombinationsfeldes für einen anderen Feldtyp. Hinweise zur Auswahl des für Ihre Daten geeigneten Feldtyps finden Sie im Absatz »Den für Ihre Daten geeigneten Feldtyp auswählen« in diesem Kapitel. Beachten Sie beim Benutzen des Feld-Generators, dass Sie den hier angebotenen Feldtyp jederzeit an Ihre Bedürfnisse anpassen können.
Eine Tabelle von Grund auf entwerfen
55
Abbildung 2.2: Die Tabellenentwurfsansicht wird benutzt, um Feldnamen, Datentypen und Beschreibungen für alle Felder in einer Tabelle einzugeben
Abbildung 2.3: Das Dialogfeld Feld-Generator gibt Ihnen die Möglichkeit, aus einer Liste vordefinierter Felder mit vordefinierten Eigenschaften auszuwählen
3. Springen Sie mit dem Tabulator zur Spalte BESCHREIBUNG. Was Sie in diese Spalte schreiben, erscheint später in der Statuszeile, wenn der Benutzer Daten in dieses Feld eingibt. Diese Spalte ist also besonders wichtig für die Dokumentation der Daten, die in diesem Feld gespeichert werden. 4. Geben Sie nun bei Bedarf noch weitere Felder ein. Wenn Sie ein zusätzliches Feld zwischen zwei vorhandenen Feldern einfügen wollen, klicken Sie in der Symbolleiste auf die Schaltfläche ZEILEN EINFÜGEN. Das neue Feld wird so oberhalb des von Ihnen angeklickten Feldes eingefügt. Um dagegen ein Feld zu entfernen, klicken Sie auf die Schaltfläche ZEILEN LÖSCHEN. 5. Um Ihre Angaben zu speichern, klicken Sie in der Symbolleiste auf die Schaltfläche SPEICHERN. Es erscheint nun das Dialogfeld SPEICHERN UNTER (siehe Abbildung 2.4). Geben Sie jetzt noch einen Namen für Ihre neue Tabelle an und klicken Sie dann auf OK. Danach erscheint ein Dialogfeld, das Ihnen vorschlägt, einen Primärschlüssel festzulegen, denn jede Tabelle sollte einen Primärschlüssel haben. Primärschlüssel werden ausführlich im noch folgenden Abschnitt »Der allgegenwärtige Primärschlüssel« behandelt.
56
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Abbildung 2.4: Verwenden Sie das Dialogfeld Speichern unter, um einer Tabelle einen Namen zu geben
Die Namensregeln für Tabellen ähneln den Regeln für Feldnamen, allerdings sollten Tabellennamen immer mit den drei Buchstaben tbl beginnen. Die Namensregeln werden ausführlich in Kapitel 1 und im Anhang beschrieben.
Feldnamen können bis zu 64 Zeichen lang sein. Aus praktischen Gründen ist aber eine Beschränkung auf zehn bis fünfzehn Zeichen zu empfehlen – das ist genug, um einem Feld einen aussagekräftigen Namen zu geben.
Feldnamen können jede beliebige Kombination von Buchstaben, Ziffern, Leerzeichen und anderen Zeichen enthalten, mit Ausnahme von Punkten, Ausrufezeichen, Fragezeichen, Akzenten und Klammern. Ich empfehle Ihnen aber, ausschließlich Buchstaben zu verwenden. Leerzeichen innerhalb von Feldnamen können bei der Formulierung von Abfragen, Modulen und anderen Datenbankobjekten schnell zum Problem werden. Seien Sie nicht beunruhigt darüber, dass Ihre Benutzer diese Feldnamen ohne Leerzeichen später sehen könnten; weiter hinten in diesem Kapitel werden Sie erfahren, wie Sie die für einen Benutzer sichtbaren Feldbeschriftungen festlegen können. Feldnamen dürfen nicht mit Leerzeichen beginnen. Wie schon erwähnt, sollten Feldnamen grundsätzlich gar keine Leerzeichen enthalten, so dass diese Einschränkung nicht von Belang ist. Versuchen Sie nie, Eigenschaftswörter, Schlüsselwörter, Funktionsnamen oder die Namen anderer Access-Objekte als Feldnamen zu verwenden. Obwohl Ihr Programm unter gewissen Umständen korrekt ausgeführt werden könnte, könnten Sie in anderen Fällen unvorhersehbare Ergebnisse erhalten. Sie sollten auch berücksichtigen, dass nicht alle Back-End-Datenbanken sämtliche bei Access möglichen Feldtypen verarbeiten können. Wenn Sie daran frühzeitig denken, können Sie später recht einfach den Übergang von einem Einzelplatzsystem zu einem Client-Server-System durchführen. Außerdem sollten Sie berücksichtigen, dass bei den meisten Back-End-Datenbanken die Länge von Feldnamen und die in den Feldnamen erlaubten Sonderzeichen stärker eingeschränkt sind, als dies bei Access der Fall ist. Um Probleme bei der Übergabe von Access-Tabellen auf BackEnd-Datenbank-Server zu vermeiden, sollten Sie dies bei der Benennung von Datenfeldern rechtzeitig bedenken.
Den für Ihre Daten geeigneten Feldtyp auswählen
57
Ich empfehle Ihnen dringend, Ihre Tabellen, Abfragen, Formulare, Berichte, Makros und Module immer ausführlich zu beschreiben. Diese Dokumentation hilft später Ihnen selbst oder demjenigen, der Ihre Anwendungen zu pflegen hat, notwendige Änderungen durchzuführen. Die Dokumentation Ihrer Anwendung wird ausführlich in Kapitel 35 behandelt.
2.3
Den für Ihre Daten geeigneten Feldtyp auswählen
Der Datentyp, den Sie für die einzelnen Felder wählen, kann auf die Leistung und die Funktionalität Ihrer Anwendung einen sehr starken Einfluss haben. Mehrere Faktoren können die Wahl des Datentyps für die Felder Ihrer Tabelle beeinflussen:
die Art der Daten, die in dem Feld gespeichert werden ob die Daten in Berechnungen verwendet werden müssen ob die Daten in diesem Feld sortiert werden sollen die Art und Weise, wie Sie diese Daten sortieren wollen wie wichtig Plattenspeicherplatz für Sie ist Die Art der Daten, die in den Feldern gespeichert werden sollen, hat den größten Einfluss auf die Wahl des für Ihre Daten geeigneten Feldtyps. Müssen Sie zum Beispiel Zahlen mit führenden Nullen speichern, können Sie kein Zahlenfeld verwenden, weil bei diesem führende Nullen unterdrückt werden. Diese Einschränkung betrifft zum Beispiel Postleitzahlen, die ja durchaus mit führenden Nullen beginnen können, sowie Abteilungsnummern. Wenn es unwichtig ist, ob führende Nullen tatsächlich in den Tabellen gespeichert werden, und wenn Sie die führenden Nullen nur bei der Ausgabe von Formularen und Berichten benötigen, so lässt sich dies mit den so genannten Formatierungseigenschaften bewerkstelligen. Diese werden im Abschnitt »Feldeigenschaften« dieses Kapitels genauer beschrieben. Sofern die in einem Datenfeld gespeicherten Daten in Berechnungen verwendet werden sollen, müssen Sie für dieses Datenfeld den Feldtyp ZAHL oder WÄHRUNG auswählen, da kein anderer Feldtyp sich in Berechnungen verwenden lässt. Die einzige Ausnahme ist das Datumsfeld, welches in Berechnungen benutzt werden kann, die auf dem Datum oder der Zeit beruhen. Sie müssen auch beizeiten überlegen, ob Sie die in einem Feld gespeicherten Daten sortieren oder als Index verwenden wollen. Bedenken Sie, dass Memo-, OLE- und
58
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Hyperlink-Felder nicht sortiert werden können. Verwenden Sie diese Feldtypen also nicht, wenn ein Feld sortiert oder als Index verwendet werden soll. Weiterhin müssen Sie darüber nachdenken, wie die Daten später sortiert werden sollen. Zahlen, die in einem Textfeld gespeichert sind, werden zum Beispiel in der Reihenfolge 1, 10, 100, 2, 20, 200 usw. sortiert, was der normalen ASCII-Reihenfolge entspricht. Andererseits werden Zahlen, die in einem numerischen oder in einem Währungsfeld gespeichert sind, in der erwarteten numerischen Reihenfolge sortiert (also: 1, 2, 10, 20, 100, 200 usw.). Auch wenn Sie nun glauben, das Sortieren von Zahlen in ASCII-Reihenfolge könne gar nicht sinnvoll sein: es gibt durchaus sinnvolle Einsatzgebiete, wie etwa das Sortieren unterschiedlich langer Telefonvorwahlen. Schließlich sollten Sie noch bedenken, wie wichtig und kostbar Plattenspeicher für Sie ist. Die verschiedenen Datentypen benötigen unterschiedlich viel Speicherplatz. Auch dies kann wichtig werden, wenn Sie einen Feldtyp für ein Datenfeld auswählen. Es gibt in Access neun verschiedene Felddatentypen: Text, Memo, Zahl, Datum/Zeit, Währung, AutoWert (in Access 2.0 als Zähler bekannt), Ja/Nein, OLE-Objekt und Hyperlink. Tabelle 2.1 enthält alle wichtigen Informationen für die Verwendungszwecke dieser Feldtypen und gibt darüber hinaus auch Auskunft über die jeweilige Speicherbelegung. Feldtyp
Verwendungszweck
Speicherbelegung
Text
Abhängig von den tatsächlich im Daten, die aus Text oder Zahlen Feld gespeicherten Daten: 0 bis 255 oder einer Kombination von Text und Zahlen bestehen, sofern mit den Bytes Zahlen nicht gerechnet wird; zum Beispiel Namen, Adressen, Abteilungsnummern, Telefonnummern
Memo
0 bis 64.000 Bytes Beliebiger Text, der aus beliebigen Zeichen bestehen kann; zum Beispiel Anmerkungen und Beschreibungen
Zahl
1, 2, 4 oder 8 Bytes, abhängig von der Daten (aber keine Währungsangaben), mit denen auch Berechnungen gewählten Feldgröße (16 Bytes bei Replikations-ID) durchgeführt werden können; zum Beispiel Jahreszahlen, Codes wie etwa Mitarbeiternummern oder Zahlungsweisen
Datum/Zeit
Datum und Uhrzeit; zum Beispiel Bestelldatum oder Geburtstag
8 Bytes
Tabelle 2.1: Geeignete Verwendungszwecke und Speicherbelegung für die verschiedenen Feldtypen von Access
Den für Ihre Daten geeigneten Feldtyp auswählen
59
Feldtyp
Verwendungszweck
Speicherbelegung
Währung
Währungsangaben; zum Beispiel Gebühren und Preise
8 Bytes
AutoWert
Ausschließlich fortlaufende Zahlen oder Zufallszahlen; zum Beispiel Rechnungs- oder Projektnummern
4 Bytes (16 Bytes bei ReplikationsID)
Ja/Nein
Felder, die nur einen von zwei Wer- 1 Bit ten annehmen können (ja/nein, wahr/falsch); zum Beispiel eine Angabe, ob eine Rechnung schon bezahlt ist oder nicht, oder eine Angabe, ob eine Stelle unbefristet ist
OLE-Objekt
Objekte wie etwa Word-Dokumente 0 Bytes bis zu einem Gigabyte, oder Excel-Tabellen; zum Beispiel abhängig von den tatsächlich im Feld Mitarbeiterberichte oder Budgetügespeicherten Daten bersichten
Hyperlink
Text oder eine Kombination von Text und Zahlen, die als HyperlinkAdresse verwendet wird; zum Beispiel Webseiten oder Netzwerkdateien
0 bis 2048 Bytes für jeden der drei Teile, aus denen eine Adresse besteht (insgesamt bis zu 64.000 Zeichen)
Tabelle 2.1: Geeignete Verwendungszwecke und Speicherbelegung für die verschiedenen Feldtypen von Access (Forts.)
Der Felddatentyp Hyperlink enthält ein Hyperlink-Objekt, das aus drei Teilen besteht. Der erste Teil wird Anzeigetext genannt und ist der Text, der im Feld selbst erscheint. Der zweite Teil ist der aktuelle Dateipfad (UNC) oder die aktuelle Seite (URL), auf die dieses Feld verweist. Der dritte Teil enthält die Unteradresse, d.h. eine Adresse innerhalb der Datei oder der Seite. Der schwierigste Teil beim Auswählen eines Feldtyps besteht darin, herauszufinden, welcher Typ in welcher Situation der beste ist. Im Folgenden wird deshalb ausführlich beschrieben, welche Eigenschaften jeder einzelne Feldtyp hat und wie er am sinnvollsten zu verwenden ist. Das wird Sie bei dieser schwierigen Aufgabe unterstützen.
2.3.1
Textfelder: Der gebräuchlichste Felddatentyp
Die meisten Felder sind Textfelder. Viele Entwickler begreifen nicht, dass es am besten ist, auch Zahlen in Textfeldern zu speichern, sofern sie nicht für irgendwelche
60
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Berechnungen benötigt werden. Beispiele sind Telefonnummern, Teilenummern oder Postleitzahlen. Textfelder sind zwar standardmäßig nur 50 Zeichen lang, sie können aber bei Bedarf bis zu 255 Zeichen aufnehmen. Access belegt Plattenspeicherplatz dynamisch, was bedeutet, dass für jedes Feld nur soviel Platz verwendet wird, wie dies der Anzahl der tatsächlich im Feld gespeicherten Zeichen entspricht. Ein sehr groß vereinbartes Feld belegt also nicht zwangsläufig auch sehr viel Speicherplatz. Dennoch können Sie die Verarbeitungsgeschwindigkeit erhöhen, wenn Sie die Feldgröße möglichst klein angeben. Die maximale Anzahl von Zeichen, die Sie in einem Textfeld speichern können, kann mit Hilfe der Eigenschaft Feldgröße festgelegt werden.
2.3.2
Memofelder: Für die langen Notizen und Kommentare
Memofelder können bis zu 64 Kilobyte Text aufnehmen (also etwa 64.000 Zeichen). Dies entspricht annähernd 16 eng bedruckten Seiten. Memofelder eignen sich hervorragend für jede Art von Dokumentation oder für Anmerkungen, die Sie zusammen mit den eigentlichen Tabellendaten speichern wollen. Bedenken Sie aber, dass Memofelder nicht als Sortierkriterien benutzt werden können.
2.3.3
Zahlenfelder: Wenn Sie rechnen müssen
Zahlenfelder verwendet man für Daten, mit denen irgendwelche Berechnungen durchgeführt werden sollen. Wenn jedoch Geldbeträge in Berechnungen eingehen und das Ergebnis dieser Berechnungen besonders genau sein soll, sollten Sie eher Währungs- als Zahlenfelder benutzen. Man kann ein Zahlenfeld auf sechs verschiedene Arten vereinbaren, weil es nämlich bei Access 2000 sechs unterschiedliche Zahlendarstellungen gibt: Der Datentyp BYTE speichert ganze Zahlen zwischen 0 und 255, der Datentyp INTEGER kann eine ganze Zahl zwischen -32.768 und 32.767 aufnehmen und der Datentyp LONG INTEGER erlaubt das Speichern einer ganzen Zahl zwischen -2.147.483.648 und 2.147.483.647. Alle drei Datentypen gestatten sehr schnelle Berechnungen, wobei jeder Typ eine zunehmende Menge an Speicherplatz benötigt. In zwei weiteren Datentypen, SINGLE und DOUBLE, werden Zahlen im Fließkommaformat gespeichert, was die Rechengeschwindigkeit deutlich herabsetzt. SINGLE erlaubt eine Genauigkeit von sieben Stellen, während bei DOUBLE sogar vierzehn Stellen möglich sind. Der siebte Datentyp, REPLIKATIONS-ID, unterstützt einen eindeutigen Bezeichner, der für die Synchronisierung von Daten erforderlich ist.
2.3.4
Datum/Uhrzeit-Felder: Verfolgen, wann Ereignisse eintreten
In Datum/Uhrzeit-Feldern werden Kalenderdaten und Uhrzeiten gespeichert. Mit diesen Daten lassen sich dann typische Berechnungen durchführen, wie etwa die Ermittlung des Zeitraums zwischen zwei Uhrzeiten oder zwischen zwei Kalenderdaten. Beim Sortieren wird die für Kalenderdaten und Uhrzeiten gebräuchliche Rei-
Den für Ihre Daten geeigneten Feldtyp auswählen
61
henfolge berücksichtigt. Access speichert Datum und Uhrzeit intern als acht Byte lange Fließkommazahl, die Uhrzeit wird als Bruchteil eines ganzen Tages dargestellt. Jede Änderung des Datums oder der Uhrzeit, die Sie über die Systemsteuerung von Windows vornehmen, wirkt sich unmittelbar auf alle Ihre Datum/Uhrzeit-Felder aus. Dies gilt auch für Datumsformate: ändern Sie zum Beispiel das Format DATUM, KURZ in den Ländereinstellungen, so verändern Sie damit unmittelbar auch alle Datumsformate in Ihren Formularen, Berichten und Datenblättern.
2.3.5
Währungsfelder: Geldbeträge speichern
Ein Währungsfeld ist eine besondere Form eines Zahlenfeldes, in dem ausschließlich Geldbeträge gespeichert werden. Ein Währungsfeld kann vor dem Komma bis zu fünfzehn Stellen aufnehmen, nach dem Komma wird hingegen nur mit vier Stellen gerechnet, um Rundungsfehler zu vermeiden. Zu bemerken ist, dass Berechnungen mit solchen Währungsfeldern recht langsam ablaufen, was an der hohen Stellenzahl und Genauigkeit dieses Feldtyps liegt. Jede Änderung, die Sie in der Windows-Systemsteuerung am Format von Währungsdaten vornehmen, wird unmittelbar in Ihre Daten übernommen. Natürlich wandelt Access nicht von selbst die Währungsbeträge gemäß dem aktuellen Währungskurs um, wenn Sie etwa das Währungssymbol von Dollar in DM umsetzen. Aber wie bei den Datumsformaten wird auch ein in den Ländereinstellungen der Windows-Systemsteuerung verändertes Währungssymbol unmittelbar in allen Ihren Formularen, Berichten und Datenblättern angepasst.
2.3.6
AutoWert-Felder: Für eindeutige Datensatzbezeichner
Das AutoWert-Feld von Access 2000 entspricht dem Zähler-Feld von Access 2.0. Die Einträge in AutoWert-Feldern werden immer dann automatisch erzeugt, wenn ein Datensatz zur Datenbank hinzugefügt wird. In Access 2.0 mussten die Werte in Zähler-Feldern fortlaufend sein, während die AutoWert-Felder in Access 2000 sowohl fortlaufende als auch Zufallszahlen erlauben. Zufallszahlen sind immer dann nützlich, wenn verschiedene Benutzer unabhängig voneinander zusätzliche Datensätze in die Datenbank eingeben, denn es ist sehr unwahrscheinlich, dass Access zwei verschiedenen Datensätzen die gleiche zufällig erzeugte Zahl als Datensatzbezeichner zuweist. Ein Sonderfall eines AutoWert-Feldes ist die Replikations-ID: Hier, bei der Replikation von Datenbanken, dient die Zufallszahl zur eindeutigen Kennzeichnung, um damit die Replikate zu synchronisieren. Einige wichtige Punkte über fortlaufende AutoWert-Felder sollten Sie sich einprägen: Wenn ein Benutzer einen Datensatz aus einer Tabelle löscht, ist dessen eindeutige Datensatznummer für immer verloren. Ebenso verschwindet die eindeutige
62
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Nummer eines Datensatzes, der von einem Benutzer hinzugefügt, danach aber wieder durch »Rückgängig machen« entfernt wird. Sie können sich jedoch Ihre eigenen Zählerwerte erzeugen, falls Sie in Ihrer Anwendung dieses Verhalten von Access nicht akzeptieren wollen. Dieses Thema wird in Kapitel 17 beschrieben.
2.3.7
Ja/Nein-Felder: Wenn eine von zwei Antworten korrekt ist
In Ja/Nein-Feldern können Sie ein logisches Wahr oder Falsch bzw. ein Ja oder Nein speichern. Tatsächlich enthält ein solches Feld den Wert -1 für Ja und 0 (Null) für Nein (oder keinen Wert für keine Angabe). Das Ausgabeformat für ein solches Ja/ Nein-Feld bestimmt, was der Benutzer wirklich zu sehen bekommt (normalerweise Ja/Nein, Wahr/Falsch, Ein/Aus oder eine dritte Angabe – keinen Wert – wenn Sie die Eigenschaft DreifacherStatus aktiviert haben). Ja/Nein-Felder eignen sich für solche Daten, die nur genau zwei Werte annehmen können. Sie belegen im Speicher nur ein einziges Bit und schränken den Benutzer auf nur zwei mögliche Eingabewerte ein.
2.3.8
OLE-Objektfelder: Wo Sie nahezu alles speichern können
In OLE-Objektfeldern kann man beliebige Daten speichern, die von irgendeiner anderen OLE-Anwendung unter Windows übermittelt werden, einschließlich Datenblättern aus Tabellenkalkulationen, Textdokumenten, Audio- und VideoDateien. Es gibt viele betriebliche Anwendungen für OLE-Objektfelder, wie zum Beispiel das Speichern von Lebensläufen, Mitarbeiterbeurteilungen, Budgets oder Video-Clips. Dennoch ist es oftmals effizienter, ein Hyperlink-Feld zu verwenden, um lediglich eine Adresse zu speichern, als das ganze Objekt selbst in einem OLEObjektfeld abzulegen.
2.3.9
Hyperlink-Felder: Ihre Verknüpfung zum Internet
In Hyperlink-Feldern werden so genannte URLs gespeichert (URL – Uniform Resource Locator). Hierbei handelt es sich um Verknüpfungen auf Seiten, die irgendwo im WWW (World Wide Web) bzw. im Internet gespeichert sind. Auch das Speichern von UNC-Pfaden (UNC – Universal Naming Convention), also von Verknüpfungen mit anderswo gespeicherten Dateiverzeichnissen, ist möglich. Ein Hyperlink-Feld besteht genaugenommen aus drei Teilen: erstens aus dem, was der Benutzer sieht, zweitens aus dem URL oder der UNC und drittens aus einer Unteradresse, wie zum Beispiel einem Bereichsnamen oder einem WWW-Lesezeichen. Sobald ein Eintrag in ein Hyperlink-Feld aufgenommen wurde, dient dieser Eintrag als direkte Verknüpfung mit der Seite oder der Datei, die durch diese Adresse gekennzeichnet wird. Hyperlink-Felder werden im Abschnitt »Access-Tabellen und das Internet« am Ende dieses Kapitels ausführlich beschrieben.
Feldeigenschaften
2.4
63
Feldeigenschaften
Nachdem Sie Felder zu Ihrer Tabelle hinzugefügt haben, müssen Sie deren Eigenschaften festlegen. Mit Hilfe der Feldeigenschaften können Sie steuern, wie die Daten später gespeichert werden, wie sie zu verwenden sind und welche Daten in diese Felder eingegeben werden können. Die verfügbaren Feldeigenschaften hängen von dem zuvor ausgewählten Felddatentyp ab. Die umfassendsten Eigenschaften bietet der Feldtyp Text (siehe Abbildung 2.5). In den folgenden Abschnitten wird jede einzelne Feldeigenschaft einzeln beschrieben.
Abbildung 2.5: Feldeigenschaften für ein Textfeld
2.4.1
Feldgröße: Die Feldeingabe begrenzen
Die erste Eigenschaft eines Feldes ist die Feldgröße, die jedoch nur bei Text- und Zahlenfeldern angegeben werden kann. Wie bereits erwähnt, sollte die Größe eines Feldes auf den kleinstmöglichen Wert festgelegt werden, um Speicherplatz zu sparen und besonders bei Zahlenfeldern die spätere Verarbeitungsgeschwindigkeit zu erhöhen. Erstellen Sie eine Tabelle mit folgenden Feldern und Feldtypen: CompanyID (Firmennummer): AutoWert CompanyName (Firmenname): Text State (Land): Text
64
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
PhoneNumber (Telefon): Text ContactDate (Kontaktdatum): Datum/Uhrzeit CreditLimit (Kreditlimit): Währung 1. Um die Feldgröße des Feldes STATE auf zwei Zeichen zu begrenzen, klicken Sie irgendwo auf dieses Feld und geben danach die Ziffer 2 in die Zeile FELDGRÖSSE ein. 2. Wechseln Sie zur Datenblatt-Ansicht. Sie werden nun aufgefordert, die Tabelle zu speichern. Geben Sie ihr den Namen tblCustomers. Da Sie bisher keinen Primärschlüssel vergeben haben, werden Sie nun dazu aufgefordert. Sobald Sie Daten in das Feld State eingeben, werden Sie feststellen, dass hier höchstens zwei Zeichen möglich sind. Dieses Beispiel ist wie alle noch folgenden Beispiele auch auf der beiliegenden CDROM enthalten. Sie finden dieses Beispiel unter dem Namen Chap2TryIt.MDB. Überprüfen Sie anhand dieser Angaben, ob Sie die Feldeigenschaften richtig angegeben haben.
2.4.2
Format: Bestimmen, wie Daten angezeigt werden
Die zweite Feldeigenschaft ist das FORMAT, das für alle Feldtypen außer für OLEObjektfelder anzugeben ist. Mit Hilfe der Feldeigenschaft FORMAT legen Sie fest, wie Ihre Daten angezeigt werden. Access bietet Ihnen die Möglichkeit, aus mehreren vorhandenen Formaten auszuwählen oder Ihre eigenen Formate zu erstellen. Die verfügbaren Formate hängen jeweils vom Felddatentyp ab. So können Sie in Access zum Beispiel aus einer Vielzahl unterschiedlicher Formate für Datum und Uhrzeit auswählen (zum Beispiel: Datum, kurz (21.10.99), Datum, mittel (21. Okt. 99), Datum, lang (Donnerstag, 21. Oktober 1999), Zeit, kurz (18:30), Zeit, lang (18:30:54). Dabei hängen die genauen Formate und Sprachen auch noch von der in der Windows-Systemsteuerung vorgenommenen Ländereinstellung ab. Bei Währungsfeldern sind u.a. diese Formate möglich: Standardzahl (4.311,52), Festkommazahl (4311,52) und Währung (4.311,52 DM). Setzen Sie das Format des Feldes ContactDate auf Datum, mittel. Wechseln Sie danach zur Datenblattansicht und geben Sie einige Daten in unterschiedlichen Formaten ein, zum Beispiel 07/08/99 und 13. September 1999. Beachten Sie, dass es keine Rolle spielt, in welchem Format Sie die Daten eingeben: sobald die Daten vollständig eingegeben sind, werden sie im Format Datum, mittel, also in der Form 13. Sep. 99, angezeigt.
Feldeigenschaften
2.4.3
65
Eingabeformat: Bestimmen, wie Daten in ein Feld übernommen werden
Eine andere wichtige Feldeigenschaft ist das Eingabeformat, das für die Feldtypen Text, Zahl, Datum/Uhrzeit und Währung verfügbar ist. Die Angabe Format gibt an, wie Daten angezeigt werden, während Eingabeformat bestimmt, welche Daten eingegeben werden dürfen. Mit Hilfe des Eingabeformats können Sie auch zeichenweise überprüfen, welche Art von Daten eingegeben wird (Buchstaben, Ziffern, Sonderzeichen) und ob ein bestimmtes Zeichen erforderlich ist. Der Eingabeformat-Assistent (siehe Abbildung 2.6) hilft Ihnen beim Erstellen üblicherweise benutzter Eingabeformate für Text- und Zahlenfelder. Den Eingabeformat-Assistenten rufen Sie auf, indem Sie im Eingabeformatfeld die rechte Schaltfläche anklicken. Der Eingabeformat-Assistent ist nur dann verfügbar, wenn Sie beim Einrichten von Access die Komponente ERWEITERTE ASSISTENTEN ausgewählt haben.
Abbildung 2.6: Der Eingabeformat-Assistent hilft Ihnen beim Festlegen eines Eingabeformats
Das Eingabeformat 000-00-0000;;_ (das in die Form 000\-00\-0000;;_ umgewandelt wird, sobald Sie das Eigenschaftsfeld mit der Tabulatortaste verlassen) sorgt beispielsweise dafür, dass eine gültige amerikanische Sozialversicherungsnummer eingegeben wird. Alle Zeichen vor dem ersten Semikolon bezeichnen das aktuelle Eingabeformat. Die Nullen zeigen an, dass hier nur Ziffern von 0 bis 9 eingegeben werden dürfen. Die Bindestriche sind Füllzeichen und erscheinen später zur optischen Gliederung im Eingabeformat. Zwischen den beiden Semikolons können Sie noch ein Zeichen eingeben, das festlegt, ob die im Eingabeformat angezeigten Füllzeichen (hier die Bindestriche) ebenfalls im Feld gespeichert werden sollen: 0 bedeu-
66
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
tet, dass diese Füllzeichen gespeichert werden, 1 oder Leer unterdrückt die Speicherung. Das letzte Zeichen (nach dem zweiten Semikolon, in diesem Fall ein Unterstrich) gibt an, welches Zeichen dem Benutzer die Stelle im Eingabeformat anzeigen soll, an der er das nächste Zeichen einzugeben hat. Ein etwas ausführlicheres Beispiel: Im Eingabeformat \(999”) ”000\-0000;;_ bewirkt der erste Backslash (\), dass das danach folgende Zeichen (Klammer auf) später genau so angezeigt wird. Die Ziffern 999 erlauben wahlweise die Eingabe von Ziffern oder Leerzeichen, die beiden folgenden Zeichen zwischen den beiden Anführungszeichen (Klammer zu und Leerzeichen) sollen wiederum genauso in das Eingabeformat übernommen werden. 000 verlangt die Eingabe von drei Ziffern zwischen 0 und 9. Der Bindestrich nach dem nächsten umgekehrten Schrägstrich wird abermals genau so in das Eingabeformat übernommen. Danach verlangt 0000 die Eingabe von vier Ziffern zwischen 0 und 9. Zwischen den beiden folgenden Semikolons befindet sich kein weiteres Zeichen, was bedeutet, dass die weiter vorne angegebenen Anführungszeichen nicht in das Eingabeformat übernommen werden. Nach dem zweiten Semikolon folgt noch ein Unterstrich, der im Eingabeformat festlegt, dass hier der Benutzer das nächste Zeichen einzugeben hat. Benutzen Sie den Eingabeformat-Assistenten, um ein Eingabeformat für das Feld PhoneNumber hinzuzufügen, das Sie als Textfeld eingerichtet haben sollten.
1. Klicken Sie zunächst auf das Feld PhoneNumber und dann auf EINGABEFORMAT. 2. Klicken Sie auf die Schaltfläche mit den drei Punkten. 3. Wählen Sie TELEFONNUMMER aus der Liste der vorhandenen Eingabeformate, und legen Sie fest, dass die Daten ohne Symbole gespeichert werden sollen. 4. Wechseln Sie zur Datenblattansicht und geben Sie nun eine Telefonnummer ein. Beachten Sie, wie die Einfügemarke die Trennzeichen überspringt. Versuchen Sie, das Feld für die Vorwahl freizulassen (dies sollte möglich sein). 5. Versuchen Sie nun, irgendwo in dieses Feld einen Buchstaben einzugeben. Dies sollte nicht möglich sein. 6. Versuchen Sie abschließend, innerhalb der Telefonnummer ein Leerzeichen statt einer Ziffer einzugeben. Access sollte auch dies verhindern. Wenn Sie ein Eingabefeld verwenden, befindet sich der Benutzer stets im Überschreibmodus. Dieses Verhalten ist in Access standardmäßig vorgesehen und lässt sich nicht verändern.
Feldeigenschaften
2.4.4
67
Beschriftung: Eine große Zeitersparnis
Die nächste verfügbare Feldeigenschaft ist die Beschriftung. Der hier von Ihnen eingegebene Text wird später als Spaltenüberschrift in der Datenblattansicht, in Formularen und in Berichten angezeigt. Er erscheint außerdem als Beschriftung für gebundene Steuerelemente, wenn Sie sie in Formularen und Berichten verwenden. Die Eigenschaft Beschriftung ist besonders wichtig, wenn Ihre Feldnamen keine Leerzeichen enthalten und deshalb für Benutzer schwer verständlich sein können. Der Benutzer sieht später nur die hier angegebenen Beschriftungen und nicht die ursprünglichen Feldnamen. Der Begriff »gebundenes Steuerelement« bezieht sich auf ein Steuerelement, das mit dem Feld einer Tabelle oder einer Abfrage verbunden ist. Der Begriff der »gebundenen Bezeichnung« wird als Bezug auf ein Bezeichnungsfeld verwendet, das zu einem gebundenen Steuerelement gehört.
Es ist wichtig, die Eigenschaft Beschriftung für Felder festzulegen, bevor Sie irgendwelche Formulare oder Berichte definieren, die darauf Bezug nehmen. Beim Generieren eines Formulars oder Berichts sucht Access zunächst nach der aktuell vorhandenen Beschriftung. Wird die Beschriftung erst zu einem späteren Zeitpunkt hinzugefügt oder geändert, werden die Überschriften für dieses Feld in bereits vorhandenen Formularen und Berichten nicht angepasst.
2.4.5
Standardwert: Zeit für die Dateneingabe einsparen
Eine weitere wichtige Feldeigenschaft ist der Standardwert. Dieser definiert den Wert, den Access in ein Feld einträgt, wenn der Benutzer neue Datensätze zu einer Tabelle hinzufügt. Standardwerte, bei denen es sich sowohl um Texte als auch um Ausdrücke handeln kann, können der Person, welche die Daten in die Datenbank eingibt, viel Zeit sparen. Die Richtigkeit der eingegebenen Daten wird jedoch nicht überprüft. Standardwerte werden automatisch in alle Abfragen und Formulare übertragen, in denen dieses Feld enthalten ist. Im Gegensatz zur Feldeigenschaft Beschriftung geschieht dies unabhängig davon, ob eine Abfrage oder ein Formular vor oder nach der Eingabe eines Standardwerts in ein Feld erstellt wurde.
68
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Tragen Sie die folgenden Standardwerte für die Felder State, ContactDate und CreditLimit ein: State: CA ContactDate: =Date() CreditLimit: 1000 Wechseln Sie nun in die Datenblattansicht und fügen Sie einen neuen Datensatz hinzu. Beachten Sie, dass die obigen Standardwerte für die Felder State, ContactDate und CreditLimit erscheinen. Diese Standardwerte können Sie jedoch bei Bedarf mit anderen Werten überschreiben.
2.4.6
Gültigkeitsregel: Steuern, was in ein Feld eingegeben wird
Die Feldeigenschaft Standardwert schlägt dem Benutzer einen Wert vor, die Feldeigenschaft Gültigkeitsregel schränkt dagegen die Werte ein, die ein Benutzer in ein Feld eingeben kann. Die Datenbank-Engine achtet danach streng darauf, dass solche Gültigkeitsregeln nicht verletzt werden. Wie die Feldeigenschaft Standardwert kann auch die Feldeigenschaft Gültigkeitsregel Text oder einen gültigen Access-Ausdruck enthalten. Benutzerdefinierte Funktionen lassen sich hier jedoch ebensowenig verwenden wie Formulare, Abfragen oder Tabellen. Wenn Sie die Feldeigenschaft Gültigkeitsregel setzen, ohne eine Gültigkeitsmeldung festzulegen, zeigt Access automatisch eine Standardfehlermeldung an, wann immer die Gültigkeitsregel verletzt wird. Um eine benutzerdefinierte Fehlermeldung anzuzeigen, müssen Sie Ihren Meldungstext in die Feldeigenschaft Gültigkeitsmeldung eintragen.
Fügen Sie die folgenden Gültigkeitsregeln zu den Feldern Ihrer Tabelle hinzu (Access setzt die Kürzel der amerikanischen Bundesstaaten in Anführungszeichen, sobald Sie das Eigenschaftsfeld mit dem Tabulator verlassen): State: In (CA, AZ, NY, MA, UT) ContactDate: <= Date() CreditLimit: Zwischen 0 und 5000 1. Wechseln Sie in die Datenblattansicht. Sofern die Tabelle Daten enthält, wenn Sie die Änderungen an Ihren Gültigkeitsregeln speichern, erscheint die in Abbildung 2.7 gezeigte Nachricht.
Feldeigenschaften
69
Abbildung 2.7: Das Nachrichtenfeld fragt Sie, ob Sie die Gültigkeit vorhandener Daten überprüfen möchten
Wenn Sie JA wählen, versucht Access, alle vorhandenen Daten anhand der neuen Gültigkeitsregeln zu überprüfen. Falls dabei Fehler entdeckt werden, erhalten Sie eine allgemeine Warnung, Sie werden jedoch nicht im Einzelnen über die fehlerhaften Datensätze informiert (siehe Abbildung 2.8). Wollen Sie die Datensätze herausfinden, die Gültigkeitsregeln verletzen, müssen Sie also zunächst eine entsprechende Abfrage formulieren.
Abbildung 2.8: Eine Warnung, dass nicht alle Daten die Gültigkeitsregel erfüllen
Wenn Sie NEIN auswählen, überprüft Access Ihre vorhandenen Daten nicht anhand der Gültigkeitsregeln und Sie erhalten auch keine entsprechende Warnung. 2. Sobald Sie sich in der DATENBLATTANSICHT befinden, versuchen Sie, das Kürzel eines nicht erlaubten Bundesstaates einzugeben. Sie sollten dann ein Nachrichtenfeld sehen, wie es in Abbildung 2.9 gezeigt wird. Beachten Sie, dass dies standardmäßig keine besonders benutzerfreundliche Meldung ist. Dies ist der Grund, weshalb Sie in der Feldeigenschaft Gültigkeitsmeldung eine benutzerdefinierte Meldung festlegen sollten. Abbildung 2.9: Die angezeigte Nachricht, wenn eine Gültigkeitsregel verletzt wird, ohne dass eine Gültigkeitsmeldung eingegeben wurde
70
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Gültigkeitsregeln, die auf Tabellenebene eingeben werden, wirken sich automatisch auch auf Formulare und Abfragen aus, die auf dieser Tabelle basieren. Dies geschieht unabhängig davon, ob die Gültigkeitsregel vor oder nach der Abfrage oder dem Formular formuliert wurde. Wenn Sie eine Gültigkeitsregel für ein Feld festlegen, verlangt Access die Eingabe von Werten, das heißt, das Feld darf nicht leer bleiben. Wenn Sie zulassen wollen, dass das Feld leer bleibt, müssen Sie dies im Gültigkeitsausdruck ausdrücklich angeben: In (CA, AZ, NY, MA, UT) Oder Ist Null
2.4.7
Gültigkeitsmeldung: Dem Benutzer Fehlermeldungen bereitstellen
Verwenden Sie die Feldeigenschaft Gültigkeitsmeldung, um Fehlermeldungen zu formulieren. Anhand dieser Fehlermeldungen können später Benutzer Ihres Systems sehen, ob sie Gültigkeitsregeln verletzen. Die Feldeigenschaft Gültigkeitsmeldung darf nur Text enthalten; Ausdrücke sind hier nicht erlaubt.
Fügen Sie folgende Gültigkeitsmeldungen zu den Feldern State, ContactDate und CreditLimit hinzu:
State: Hier muss eines der folgenden Kürzel angegeben werden: CA, AZ, NY, MA oder UT. ContactDate: Das Kontaktdatum muss heute oder früher sein. CreditLimit: Das Kreditlimit muss zwischen 0 und 5000 liegen. Versuchen Sie, in jedes der drei Felder ungültige Werte einzugeben, und beobachten Sie die Fehlermeldungen.
2.4.8
Eingabe erforderlich: Dafür sorgen, dass der Benutzer einen Wert eingeben muss
Die Feldeigenschaft Eingabe erforderlich ist sehr wichtig – sie bestimmt, ob Sie verlangen, dass der Benutzer in ein Feld einen Wert eingeben muss. Diese Feldeigenschaft eignet sich für Fremdschlüsselfelder, wenn Sie sichergehen wollen, dass auch wirklich Daten in diese Felder eingegeben werden. Außerdem ist sie für alle Felder hilfreich, die Informationen enthalten, die aus betrieblichen Gründen notwendig sind (zum Beispiel der Firmenname).
71
Feldeigenschaften
Ein Fremdschlüsselfeld ist ein Feld, das in einer anderen Tabelle nachgeschlagen wird. Zum Beispiel könnten eine Kundentabelle und eine Bestellungentabelle jeweils ein Feld mit Kundennummern enthalten. In der Kundentabelle ist die Kundennummer der Primärschlüssel. Dann ist die Kundennummer in der Bestellungentabelle das Fremdschlüsselfeld, weil ihr Wert jeweils in der Kundentabelle gesucht wird.
Setzen Sie die Feldeigenschaft Eingabe erforderlich der Felder CompanyName und PhoneNumber auf Ja. Wechseln Sie zur Datenblattansicht und versuchen Sie einen neuen Datensatz hinzuzufügen. Lassen Sie dabei die Felder CompanyName und PhoneNumber leer. Geben Sie in mindestens eines der anderen Felder im Datensatz einen Wert ein. Wenn Sie nun versuchen, den Datensatz freizugeben, erscheint die in Abbildung 2.10 gezeigte Fehlermeldung. Abbildung 2.10: Wenn Sie ein Feld leer lassen, dessen Eigenschaft Eingabe erforderlich den Wert Ja hat, erscheint eine Nachricht
2.4.9
Leere Zeichenfolge: Situationen mit nicht existierenden Daten begegnen
Die Feldeigenschaft Leere Zeichenfolge ähnelt der Feldeigenschaft Eingabe erforderlich. Benutzen Sie sie, wenn Sie dem Benutzer das Eingeben einer leeren Zeichenfolge erlauben wollen (»«). Beachten Sie jedoch, dass eine leere Zeichenfolge nicht dasselbe ist wie gar keine Eingabe: Eine leere Zeichenfolge zeigt an, dass für dieses Feld keine Eingabedaten vorhanden sind. Zum Beispiel hat ein ausländischer Mitarbeiter möglicherweise gar keine Sozialversicherungsnummer. Ein Benutzer, der Daten in das System eingibt, kann also durch das Eingeben einer leeren Zeichenfolge deutlich machen, dass in diesem Fall keine Sozialversicherungsnummer vorhanden ist. Fügen Sie ein neues Feld ContactName (Kontaktname) hinzu und setzen Sie die Feldeigenschaft Eingabe erforderlich auf Ja. Versuchen Sie nun, einen neuen Datensatz anzulegen, und geben Sie nur zwei Anführungszeichen (»«) in das Feld ContactName ein. Dann sollte die in Abbildung 2.11 gezeigte Fehlermeldung erscheinen. Gehen Sie zurück zum Entwurf der Tabelle. Ändern Sie dort die Feldeigenschaft
72
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Leere Zeichenfolge auf Ja, gehen Sie dann zur Datenblattansicht und versuchen Sie erneut, zwei Anführungszeichen in das Feld ContactName einzugeben. Diesmal sollte das klappen: Ihr
mit einer leeren Zeichenfolge belegtes Feld sollte leer erscheinen, wenn Sie dieses Feld verlassen. Abbildung 2.11: Das Ergebnis der Eingabe von »«, wenn die Eigenschaft Leere Zeichenfolge auf Nein gesetzt ist
Vergessen Sie nicht, die (ESC)-Taste einmal zu drücken, wenn Sie Änderungen in einem Feld löschen wollen. Um alle Änderungen in einem Datensatz rückgängig zu machen, müssen Sie die (ESC)-Taste zweimal drücken.
Die Feldeigenschaften Eingabe erforderlich und Leere Zeichenfolge stehen in einer wechselseitigen Beziehung zueinander. Wenn Eingabe erforderlich auf Ja gesetzt ist und Leere Zeichenfolge auf Nein, sind Sie mit Ihren Benutzern besonders streng. In diesem Fall müssen diese nämlich nicht nur einen Wert eingeben, sondern dieser Wert darf auch keine leere Zeichenfolge sein. Wenn Eingabe erforderlich und Leere Zeichenfolge beide auf Ja gesetzt sind, verlangen Sie zwar, dass Ihre Benutzer einen Wert eingeben, aber dieser Wert darf auch eine leere Zeichenfolge sein. Wenn allerdings die Feldeigenschaften Eingabe erforderlich und Leere ZeichenfolgE beide auf Nein gesetzt sind, erlauben Sie den Benutzern zwar, das Feld frei zu lassen, aber Sie gestatten ihnen nicht, eine leere Zeichenfolge einzugeben. Wenn Sie schließlich die Feldeigenschaft Eingabe erforderlich auf Nein und Leere Zeichenfolge auf Ja setzen, so sind Sie mit Ihren Benutzern besonders nachsichtig. In diesem Fall können die Benutzer das Feld leer lassen oder eine leere Zeichenfolge eingeben.
2.4.10
Indiziert: Suchvorgänge beschleunigen
Indizes werden verwendet, um beim Suchen eines bestimmten Feldes die Ausführungsgeschwindigkeit zu erhöhen. Obwohl es deshalb im Allgemeinen besser ist, eher zu viele Indizes zu definieren als zu wenige, haben Indizes doch auch einige Nachteile. Grundsätzlich ist es empfehlenswert, Indizes für alle die Felder vorzusehen, nach denen normalerweise gesucht oder sortiert wird oder die als Kriterien für Abfragen dienen sollen.
Feldeigenschaften
73
Setzen Sie die Feldeigenschaft Indiziert der Felder CompanyName, ContactName und State auf Ja (Duplikate möglich).Klicken Sie auf die Schaltfläche Indizes auf der Symbolleiste. Dann sollte Ihr Bildschirm wie in Abbildung 2.12 aussehen.
Abbildung 2.12: Das Indizes-Fenster zeigt Ihnen alle für eine Tabelle definierten Indizes
Um aus mehreren Feldern bestehende Indizes zu erstellen, die keinen Primärschlüssel bilden, müssen Sie das Fenster INDIZES verwenden. In diesem Dialogfeld erstellen Sie einen Index mit einem Namen und mehreren Feldern. Abbildung 2.13 zeigt einen Index mit dem Namen StateByCredit, der eine Kombination der Felder CreditLimit und State darstellt. Beachten Sie, dass nur das erste Feld im Index einen Indexnamen trägt. Das zweite Feld, State, erscheint in der Zeile unterhalb des ersten Feldes und hat keinen Indexnamen. Indizes beschleunigen das Suchen, das Sortieren und das Gruppieren von Daten. Der Nachteil ist, dass sie Plattenspeicher benötigen und das Bearbeiten, Hinzufügen und Entfernen von Daten verlangsamen. Sie sollten also nicht jedes Feld Ihrer Tabelle als Index deklarieren, obwohl der Nutzen von Indizes deren Nachteile meistens überwiegt. Definieren Sie Indizes nur für die Felder oder die Kombinationen von Feldern, nach denen die Benutzer suchen oder sortieren werden. Definieren Sie dagegen keine Indizes für Felder, die immer wieder gleiche Daten enthalten, also zum Beispiel nicht für Felder, die nur jeweils einen von zwei möglichen Werten enthalten können. Und indizieren Sie niemals Felder, in denen nur die Werte Ja oder Nein gespeichert werden. Diese Felder belegen nur ein einziges Bit im Speicher und können somit nur genau zwei Werte annehmen. Deshalb bieten Indizes mit solchen Feldern überhaupt keine Vorteile.
2.4.11
Unicode-Komprimierung
Die letzte Feldeigenschaft ist die Unicode-Komprimierung. Diese Eigenschaft gibt es nur bei Text- und Memofeldern. Benutzen Sie sie, um anzuzeigen, ob Sie die in einem Feld gespeicherten Daten der Unicode-Komprimierung unterziehen wollen oder nicht. Vor Access 2000 wurden Daten im DBCS-Format gespeichert, um zum
74
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Abbildung 2.13: Ein aus mehreren Feldern bestehender Index mit dem Namen StateByCredit, der aus einer Kombination der Felder CreditLimit und State besteht
Beispiel chinesische Zeichen verwalten zu können. In Access 2000 kommt dafür das so genannte Unicode-Format zum Einsatz, das auf einer 2-Byte-Darstellung beruht. Obwohl dieses Format für jedes einzelne Zeichen mehr Speicherplatz benötigt (zwei Bytes statt einem), erlaubt die Unicode-Komprimierung das Komprimieren solcher Daten, wann immer dies möglich ist. Sofern der verwendete Zeichensatz Komprimierung zulässt und die Feldeigenschaft Unicode-Komprimierung auf Ja gesetzt ist, werden die Daten in der entsprechenden Spalte in einem komprimierten Format gespeichert.
2.5
Der allgegenwärtige Primärschlüssel
Der wichtigste Index einer Tabelle ist der Primärschlüsselindex. Dieser bietet die Gewähr dafür, dass die Inhalte des für die Indizierung benutzten Feldes jeweils eindeutig sind, was bedeutet, dass der Inhalt eines Feldes niemals in einem weiteren Feld vorhanden sein kann. Damit eignet sich ein solches Feld als Index und gibt einer Tabelle ihre Grundordnung. Einen Primärschlüssel müssen Sie für die Felder auf der 1-Seite einer 1:n-Beziehung immer angeben. Um einen Primärschlüsselindex zu erzeugen, wählen Sie die Felder aus, die Sie dazu benötigen, und klicken dann auf die Schaltfläche PRIMÄRSCHLÜSSEL auf der Symbolleiste. Abbildung 2.14 zeigt die Tabelle tblCustomers mit einem Primärschlüsselindex, der auf dem Feld CompanyID beruht. Beachten Sie, dass der Indexname des Feldes, das als Primärschlüssel vorgesehen ist, die Bezeichnung PrimaryKey trägt. Beachten Sie ebenfalls, dass die Eigenschaften Primärschlüssel und Eindeutig für diesen Index beide auf Ja gesetzt sind.
Der Nachschlage-Assistent
75
Abbildung 2.14: Ein Primärschlüsselindex auf der Grundlage des Feldes CompanyID
2.6
Der Nachschlage-Assistent
Wenn Sie den Nachschlage-Assistenten benutzen, können Sie erreichen, dass die Inhalte eines Feldes in einer anderen Tabelle oder Abfrage nachgeschlagen oder aus einer festen Werteliste entnommen werden. Sie können ebenfalls eine Liste gültiger Werte in einem Kombinationsfeld oder einem Listenfeld anzeigen. Ein solches Nachschlagen wird bei einer 1:n-Beziehung grundsätzlich durch den Fremdschlüssel (auf der Mehrfachseite) beim Primärschlüssel (auf der Einerseite) bewirkt. Den Nachschlage-Assistenten können Sie aufrufen, indem Sie aus der Liste der Felddatentypen Nachschlage-Assistent auswählen. Das erste Dialogfeld des Assistenten fragt, ob Sie die Daten in einer Tabelle nachschlagen oder selbst eingeben wollen. Ich empfehle Ihnen, die Daten immer in einer Tabelle oder einer Abfrage nachzuschlagen, da sich Ihre Anwendung dadurch besser pflegen lässt. Das zweite Dialogfeld bittet Sie, die Tabelle oder Abfrage anzugeben, in der die Werte nachzuschlagen sind. Wählen Sie eine Tabelle oder Abfrage aus und klicken Sie auf WEITER, um das dritte Dialogfeld zu öffnen. Dieser Schritt des Nachschlage-Assistenten fordert Sie auf, die Felder in der Tabelle oder Abfrage auszuwählen, die für das Nachschlagen benutzt werden sollen. Der vierte Schritt des Nachschlage-Assistenten gibt Ihnen die Möglichkeit, die Breite der Spalten in Ihrem Kombinations- oder Listenfeld festzulegen (siehe Abbildung 2.15).
76
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Abbildung 2.15: Im vierten Schritt des NachschlageAssistenten können Sie die Spaltenbreite festlegen
Am besten arbeiten Sie dieses Beispiel anhand der Musterdatenbank Chap2.MDB durch. Alle Nachschlagetabellen wurden zu dieser Musterdatenbank bereits hinzugefügt.
Wenn Sie zum Nachschlagen mehrere Felder auswählen und eines davon eine Schlüsselspalte, etwa eine eindeutige Nummer, ist, so erscheint das Kontrollkästchen SCHLÜSSELSPALTE AUSBLENDEN. Sie sollten dieses Kästchen aktivieren. Es blendet automatisch die Schlüsselspalte beim Nachschlagen aus, auch wenn das Endergebnis mit dem Schlüsselfeld verbunden ist. Schließlich erlaubt Ihnen der Nachschlage-Assistent, eine Beschriftung für Ihr Kombinationsfeld anzugeben. Wenn Sie das Feld FERTIG STELLEN anklicken, werden Sie aufgefordert, die Tabelle zu speichern, und alle entsprechenden Eigenschaften werden vom Assistenten ausgefüllt; sie erscheinen auf der Registerkarte NACHSCHLAGEN des Feldes (siehe Abbildung 2.16). Die Eigenschaft Steuerelement anzeigen wird auf KOMBINATIONSFELD gesetzt, was bewirkt, dass das Kombinationsfeld verwendet wird, um die gültigen Werte anzuzeigen. Das Kombinationsfeld erscheint unabhängig davon, ob sich der Benutzer nun in der Datenblattansicht oder in einem Formular befindet. Der Herkunftstyp gibt an, ob die Quelle für das Kombinationsfeld eine Tabelle oder eine Abfrage ist, und das Feld DATENSATZHERKUNFT zeigt die aktuelle SQL-SELECT-Anweisung, mit der das Kombinationsfeld gefüllt wird. Andere Eigenschaften zeigen, welche Spalte im Kombinationsfeld mit Daten verbunden ist, wie viele Spalten sich darin befinden, die Größe des Kombinationsfeldes und die Breite
77
Tabelleneigenschaften
jeder einzelnen Spalte innerhalb des Kombinationsfeldes. Diese Eigenschaften werden ausführlich in Kapitel 5 beschrieben. Die SQL-Anweisung für das Kombinationsfeld können Sie bei Bedarf nachträglich ändern.
Abbildung 2.16: Die durch den NachschlageAssistenten festgelegten Feldeigenschaften
2.7
Tabelleneigenschaften
Zusätzlich zu den Feldeigenschaften können Sie Eigenschaften festlegen, welche die Tabelle als Ganzes betreffen. Klicken Sie in der Entwurfsansicht auf die Symbolleistenschaltfläche EIGENSCHAFTEN, um zu den Tabelleneigenschaften zu gelangen. Die verfügbaren Tabelleneigenschaften sind in Abbildung 2.17 dargestellt. Die Eigenschaft Beschreibung wird vorwiegend für Dokumentationszwecke verwendet. Gültigkeitsregeln werden benutzt, um Gültigkeitsbereiche anzugeben, die eher auf Datensatzebene relevant sind als auf Feldebene. Zum Beispiel könnte das Kreditlimit vom Herkunftsland des einzelnen Kunden abhängen und deshalb bei den Kunden unterschiedlich sein. In einem solchen Fall hängt die Eingabe in ein Feld vom Inhalt eines anderen Feldes ab. Bei der Eingabe einer Gültigkeitsregel auf Tabellenebene ist es gleichgültig, in welcher Reihenfolge der Benutzer die Daten eingibt. Die Gültigkeitsregel stellt sicher, dass die genaue Abhängigkeit zwischen einzelnen Feldern immer gewährleistet ist. Eine solche Gültigkeitsregel könnte zum Beispiel die folgende Form haben: [State] In ( ”CA”, ”NY” ) Und [CreditLimit] <= 2500 Oder _ [State] In ( ”MA”, ”AZ” ) Und [CreditLimit] <= 3500 Oder _ [State] Nicht In ( ”CA”, ”NY”, ”MA”, ”AZ” )
Diese Gültigkeitsregel schreibt für Einwohner von Kalifornien (CA) oder New York (NY) ein Kreditlimit von höchstens 2.500 Dollar, für Einwohner von Massachusetts
78
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
(MA) oder Arizona (AZ) dagegen ein Kreditlimit von höchstens 3.500 Dollar vor. Für Einwohner anderer Staaten wird kein Kreditlimit angegeben. Gültigkeitsregeln auf Tabellenebene können nicht in Konflikt mit Gültigkeitsregeln auf Feldebene geraten. Die Tabelleneigenschaft Gültigkeitsmeldung legt die Meldung fest, die erscheint, wenn der Benutzer die Gültigkeitsregel verletzt. Ist kein solcher Text eingegeben, erscheint im Fehlerfall auch keine Meldung.
Abbildung 2.17: Die verfügbaren Tabelleneigenschaften betrachten
Die Tabelleneigenschaft Filter wird benutzt, um eine Auswahl von Datensätzen anzuzeigen, die in einem Datenblatt, einem Formular oder einer Abfrage erscheinen. Die Tabelleneigenschaft Sortiert nach legt eine Standardreihenfolge für die Datensätze fest. Diese beiden Tabelleneigenschaften müssen nicht immer angegeben werden. Die Tabelleneigenschaft Unterdatenblattname legt den Namen einer Tabelle fest, die als eingebettete Tabelle verwendet wird. Ist diese Eigenschaft auf Automatisch gesetzt, wird die Untertabelle aufgrund der in der Datenbank festgelegten Beziehungen automatisch herangezogen. Die Eigenschaften Verknüpfen Nach und Verknüpfen Von bezeichnen die Felder, die zum Verbinden der aktuellen Tabelle mit jener Tabelle benutzt werden, die in der Eigenschaft Unterdatenblattname bezeichnet ist. Diese Felder sollten leer bleiben, wenn die Eigenschaft Unterdatenblattname auf Automatisch gesetzt ist. Die Eigenschaft Unterdatenblatthöhe dient zur Angabe der maximalen Höhe des Unterdatenblatts und mit der Eigenschaft Unterdatenblatt erweitert wird festgelegt, ob das Unterdatenblatt automatisch in einem erweiterten Zustand angezeigt wird.
Mit Hilfe von Indizes die Geschwindigkeit verbessern
2.8
79
Mit Hilfe von Indizes die Geschwindigkeit verbessern
Wie bereits erwähnt, können Ihnen Indizes helfen, die Verarbeitungsgeschwindigkeit Ihrer Anwendung zu erhöhen. Sie sollten deshalb für alle Felder Indizes anlegen, die Sie zum Sortieren, Gruppieren, Verknüpfen oder als Suchkriterien verwenden wollen, es sei denn, die Feldinhalte unterscheiden sich kaum voneinander. Abfragen können durch Indizes erheblich beschleunigt werden. Dies gilt besonders, wenn Indizes für Felder erstellt werden, die als Kriterien zum Einsatz kommen, der Abfragesortierung dienen oder zum Verknüpfen zweier Tabellen verwendet werden, die nicht permanent in Beziehung zueinander stehen, sondern lediglich über eine Abfrage verknüpft sind. Tatsächlich sollten Sie Indizes immer für die Felder auf beiden Seiten einer Verknüpfung erstellen. Auch wenn Ihre Benutzer das Dialogfeld SUCHEN verwenden, können Indizes die Suchzeit verkürzen. Bedenken Sie aber, dass Indizes auch Nachteile aufweisen: sie benötigen zusätzlichen Plattenspeicher und verlangsamen das Hinzufügen, Löschen und Verändern von Datensätzen. Sie sollten zur Beurteilung der Geschwindigkeit immer Ihre eigene Anwendung heranziehen, aber Sie werden Indizes dennoch bei vielen Gelegenheiten als sehr nützlich empfinden. Wenn Sie eine 1:n-Beziehung zwischen zwei Tabellen einrichten, wird für die Tabelle auf der Mehrfachseite der Beziehung automatisch ein Index erstellt (das Fremdschlüsselfeld). Wenn Sie zum Beispiel die Tabellen tblOrders und tblCustomers über das Feld CustomerID miteinander verknüpfen, wird für das Feld CustomerID in der Tabelle tblOrders automatisch ein Index erstellt. Es ist deshalb nicht erforderlich, ausdrücklich einen Fremdschlüsselindex anzulegen. Beziehungen werden in Kapitel 3 behandelt.
2.9
Access-Tabellen und das Internet
Microsoft hat das Entwickeln Internet-geeigneter Anwendungen durch zwei Dinge erleichtert: durch den Felddatentyp Hyperlink und durch die Möglichkeit, Tabellendaten im HTML-Format zu speichern. Der Felddatentyp Hyperlink erlaubt es Ihren Benutzern, einfach UNC- oder URL-Adressen in ihren Tabellen zu speichern. Die Möglichkeit, Tabellendaten im HTML-Format zu speichern, vereinfacht für Sie und Ihre Benutzer das Veröffentlichen von Tabellendaten auf einer Internet- oder einer Intranet-Seite. Diese Merkmale werden in den folgenden Abschnitten erläutert.
80
2.9.1
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Der Feldtyp Hyperlink
Ihre Benutzer können für jeden Datensatz einer Tabelle eine unterschiedliche UNCoder URL-Adresse speichern, wenn Sie den Feldtyp Hyperlink verwenden. Obwohl eine UNC- oder URL-Adresse direkt in ein Feld eingegeben werden kann, ist es doch erheblich einfacher, solche Adressen mit Hilfe des Dialogfeldes HYPERLINK EINFÜGEN auszuwählen (siehe Abbildung 2.18). Hier können Benutzer über eine grafische Schnittstelle Hyperlink-Adressen und -Unteradressen suchen. Die gewünschte Adresse wird dann beim Verlassen des Dialogfeldes automatisch übernommen. Sie erreichen das Dialogfeld HYPERLINK EINFÜGEN, indem Sie die Einfügemarke auf das Hyperlink-Feld setzen und danach EINFÜGEN|HYPERLINK auswählen oder die Schaltfläche HYPERLINK EINFÜGEN anklicken.
Abbildung 2.18: Im Dialogfeld Hyperlink einfügen können Benutzer ein Hyperlink-Objekt für das Feld erstellen oder auswählen
Das Textfeld TEXT ANZEIGEN ALS wird benutzt, um den Text einzugeben, den ein Benutzer sieht, wenn er das Datenfeld in der Datenblattansicht, in einem Formular oder in einem Bericht betrachtet. Der Hyperlink kann auf eines der folgenden Objekte verweisen:
eine vorhandene Datei oder eine Webseite ein anderes Objekt in der aktuell bearbeiteten Datenbank eine neue Datenzugriffsseite eine E-Mail-Adresse Um eine vorhandene Datei oder eine Webseite auszuwählen, klicken Sie auf das entsprechende Symbol unter LINK ZU und geben den Dateinamen oder den Namen der
Access-Tabellen und das Internet
81
gewünschten Webseite ein oder Sie wählen ihn aus der Liste der zuletzt verwendeten Dateien, der besuchten Webseiten oder der eingefügten Hyperlinks aus. Die Schaltfläche DATEI wird benutzt, um eine vorhandene Datei zu suchen, und die Schaltfläche WEBSEITE dient zum Suchen einer vorhandenen Webseite. Um zu einem Objekt in der aktuellen Datenbank zu gelangen, klicken Sie auf das entsprechende Symbol unter LINK ZU. Klicken Sie danach auf ein Pluszeichen (+), um die Liste der Tabellen, der Formulare, der Berichte, der Seiten, der Makros oder der Module einzublenden. Danach klicken Sie das Objekt an, zu dem Sie eine Verknüpfung herstellen wollen. Um eine Verknüpfung zu einer Datenzugriffsseite herzustellen, die Sie neu erstellen, klicken Sie auf das nächste Symbol unter LINK ZU. Geben Sie den Namen der neuen Seite ein und entscheiden Sie, ob Sie diese neue Seite jetzt oder später bearbeiten wollen. Um eine E-Mail-Adresse zu benennen, zu der Sie eine Verknüpfung anlegen wollen, klicken Sie ebenfalls auf das entsprechende Symbol unter LINK ZU. Geben Sie die E-Mail-Adresse und das Thema ein oder wählen Sie eine Adresse aus der Liste der zuletzt benutzten E-Mail-Adressen aus. Nachdem alle notwendigen Informationen eingegeben wurden, wird die Verknüpfung eingerichtet und der Hyperlink in das Feld eingetragen. Wenn ein UNC-Pfad eingegeben wurde, ruft das Anklicken des Hyperlinks die Anwendung auf, die mit dieser Adresse verknüpft ist. Die ausgewählte Datei wird geöffnet, und der Benutzer wird in den in der Unteradresse bezeichneten Teil des Dokuments verzweigt. Wurde dagegen ein URL angegeben und arbeitet der Benutzer gerade im Internet oder im Intranet seiner Firma, so wird der Benutzer direkt mit der festgelegten Seite verbunden. Arbeitet der Benutzer jedoch gerade nicht im Internet oder in einem Intranet, so erscheint das Dialogfeld VERBINDEN MIT, das ihm oder ihr den Aufbau einer Verbindung zu einem geeigneten Netzwerk anbietet.
2.9.2
Tabellendaten als HTML speichern
Tabellendaten können leicht als HTML gespeichert werden, so dass sie auf einer Internet- oder Intranet-Seite veröffentlicht werden können. Sie können eine Datei im HTML-Format speichern, indem Sie den Menübefehl DATEI|EXPORTIEREN verwenden. Führen Sie nacheinander diese Schritte aus: 1. Wählen Sie DATEI|EXPORTIEREN. 2. Wählen Sie HTML-DOKUMENTE (*.HTML; *.HTM) aus dem Kombinationsfeld DATEITYP. 3. Wählen Sie einen Namen und einen Ort für die .HTM-Datei und klicken Sie auf SPEICHERN. Wenn Sie eine Datei auf diese Weise im HTML-Format speichern, wird dazu nicht der Browser geladen.
82
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Abbildung 2.19 zeigt Ihnen, wie Ihre so veröffentlichte Access-Seite aussehen könnte. In Abbildung 2.20 sehen Sie den zugrunde liegenden HTML-Code, den Sie mit einem HTML-Editor auch verändern können.
Abbildung 2.19: Ein HTML-Dokument im Internet Explorer, nachdem eine Tabelle als HTML gespeichert wurde (beachten Sie die unschönen Lücken für Felder, in denen keine Daten vorhanden sind)
Abbildung 2.20: Der HTML-Code einer als HTML gespeicherten Tabelle
Access-Tabellen und das Internet
83
In den Kapiteln 31 und 32 wird das Schreiben von Anwendungen für das Internet ausführlich behandelt.
2.9.3
Für die Praxis
Entwurf der Tabellen, die für das Zeit- und Abrechnungssystem eines Consulting-Unternehmens in der Computerbranche benötigt werden Erstellen Sie nun eine neue Datenbank und versuchen Sie, einige der Tabellen zu entwerfen, die für das Zeit- und Abrechnungssystem eines Consulting-Unternehmens in der Computerbranche benötigt werden. Sie werden die Tabellen tblClients und tblProjects erzeugen, wobei tblClients die wichtigste Tabelle dieser Anwendung ist. In ihr werden die wesentlichen Informationen der einzelnen Kunden festgehalten. Tabelle 2.2 zeigt die Feldnamen, die Datentypen und die Größe jedes Feldes in tblClients. Sie sollten Indizes für alle Felder außer für das Feld NOTES vorsehen. Tabelle 2.3 zeigt die Eigenschaften, die für jedes dieser Felder angegeben werden müssen. Die zweite Tabelle, tblProjects, wird benutzt, um alle wichtigen Informationen über die Kundenprojekte zu speichern, an denen die Benutzer arbeiten. Tabelle 2.4 zeigt die Felder, die Datentypen und die Feldgrößen in tblProjects, und in Tabelle 2.5 sind die Eigenschaften zu sehen, die für diese Felder angegeben werden müssen. Sie sollten auch hier für alle Felder Indizes vorsehen, außer für das Feld ProjectDescription. Feldname
Datentyp
Feldgröße
ClientID
AutoWert
Long Integer (4 Bytes)
CompanyName
Text
50
Address
Text
255
City
Text
30
StateProvince
Text
20
PostalCode
Text
20
Country
Text
20
ContactFirstName
Text
30
ContactLastName
Text
50
ContactTitle
Text
50
OfficePhone
Text
30
Tabelle 2.2: Feldnamen, Datentypen und Größen für die Felder in tblClients
84
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Feldname
Datentyp
Feldgröße
Fax
Text
30
Cellular
Text
30
Home
Text
30
EMailAddress
Text
30
ReferredBy
Text
30
AssociatedWith
Text
30
IntroDate
Datum/Uhrzeit
8 Bytes
DefaultRate
Währung
8 Bytes
Notes
Memo
-
HomePage
Hyperlink
-
Tabelle 2.2: Feldnamen, Datentypen und Größen für die Felder in tblClients (Forts.) Feldname
Eigenschaft
Wert
ClientID
Beschriftung
Kundennummer
ClientID
Als Primärschlüssel verwendet
CompanyName
Beschriftung
Firmenname
CompanyName
Eingabe erforderlich
Ja
StateProvince
Beschriftung
Staat, Region
StateProvince
Standardwert
CA
StateProvince
Eingabeformat
>LL (falls nur Daten aus den USA
eingegeben werden) PostalCode
Beschriftung
Postleitzahl
PostalCode
Eingabeformat
00000-99999;;_ (falls nur Daten aus den USA eingegeben werden)
ContactFirstName
Beschriftung
Vorname der Kontaktperson
ContactLastName
Beschriftung
Nachname der Kontaktperson
Tabelle 2.3: Für die Felder in zu setzende Eigenschaften
Access-Tabellen und das Internet
85
Feldname
Eigenschaft
Wert
ContactTitle
Beschriftung
Titel der Kontaktperson
OfficePhone
Beschriftung
Telefon geschäftlich
OfficePhone
Eingabeformat
!\(999\)000\-0000
Fax
Eingabeformat
!\(999\)000\-0000
Cellular
Eingabeformat
!\(999\)000\-0000
Home
Eingabeformat
!\(999\)000\-0000
EMailAddress
Beschriftung
E-Mail-Adresse
ReferredBy
Beschriftung
Benannt von
AssociatedWith
Beschriftung
Zugeordnet zu
IntroDate
Beschriftung
Aufnahmedatum
IntroDate
Standardwert
=Datum()
IntroDate
Gültigkeitsregel
<=Datum()
IntroDate
Gültigkeitsmeldung
Das eingegebene Datum muss heute sein oder in der Vergangenheit liegen.
IntroDate
Eingabe erforderlich
Ja
DefaultRate
Beschriftung
Standardtarif
DefaultRate
Standardwert
125
DefaultRate
Gültigkeitsregel
Zwischen 75 und 150
DefaultRate
Gültigkeitsmeldung
Tarif muss zwischen 75 und 150 liegen
DefaultRate
Eingabeformat
Währung
HomePage
Beschriftung
Home Page
Tabelle 2.3: Für die Felder in zu setzende Eigenschaften (Forts.)
86
Kapitel 2: Was jeder Entwickler über Tabellen wissen sollte
Feldname
Datentyp
Feldgröße
ProjectID
AutoWert
Long Integer (4 Bytes)
ProjectName
Text
50
ProjectDescription
Memo
-
ClientID
Zahl
Long Integer (4 Bytes)
PurchaseOrderNumber
Text
30
ProjectTotalEstimate
Währung
8 Bytes
EmployeeID
Zahl
Long Integer (4 Bytes)
ProjectBeginDate
Datum/Uhrzeit
8 Bytes
ProjectEndDate
Datum/Uhrzeit
8 Bytes
Tabelle 2.4: Feldnamen, Datentypen und Größen für die Felder in tblProjects
Feldname
Eigenschaft
Wert
ProjectID
Beschriftung
Projektnummer
ProjectID
Als Primärschlüssel verwendet
ProjectName
Beschriftung
Projektname
ProjectName
Eingabe erforderlich
Ja
ProjectDescription
Beschriftung
Projektbeschreibung
ClientID
Beschriftung
Kundennummer
ClientID
Nachschlagen in Tabelle tblClients im Feld ClientID
ClientID
Eingabe erforderlich
Ja
PurchaseOrderNumber
Beschriftung
Bestellnummer
ProjectTotalEstimate
Beschriftung
Geschätzte Gesamtprojektkosten
ProjectTotalEstimate
Eingabeformat
Währung
EmployeeID
Beschriftung
Angestelltennummer
Tabelle 2.5: Für die Felder in tblProjects zu setzende Eigenschaften
Access-Tabellen und das Internet
Feldname
Eigenschaft
Wert
ProjectBeginDate
Beschriftung
Starttermin des Projekts
ProjectEndDate
Beschriftung
Endtermin des Projekts
87
Tabelle 2.5: Für die Felder in tblProjects zu setzende Eigenschaften (Forts.)
Die übrigen Tabellen, die Sie für das Zeit- und Abrechnungssystem benötigen, sind vollständig in der Datenbank CHAP2.MDB enthalten. Diese Datei und alle weiteren Dateien, auf die in diesem Buch Bezug genommen wird, finden Sie auf der beiliegenden CD-ROM.
Beziehungen: Ihr Schlüssel zur Datensicherheit
Kapitel
Hier lesen Sie:
Beziehungstypen Beziehungen einrichten Für referentielle Integrität sorgen Vorteile von Beziehungen Indizes und Beziehungen Eine Beziehung zwischen Tabellen liegt dann vor, wenn ein oder mehrere Schlüsselfelder denjenigen einer anderen Tabelle zugeordnet sind. Die Felder in beiden Tabellen haben normalerweise denselben Namen, denselben Datentyp und dieselbe Größe. Beziehungen ergeben sich zwangsläufig aus der systematischen Datenaufteilung, die im Mittelpunkt von Kapitel 1 steht, und verhindern soll, dass Informationen in einer Tabelle doppelt vorhanden sind. Dies wird durch Aufteilung dieser Informationen in einzelne Tabellen erreicht, die jeweils über einen eindeutigen Wert, den Primärschlüssel, verfügen. Obwohl die Aufteilung der Daten gemäß Normalform viele Vorteile mit sich bringt, müssen Sie die einzelnen Tabellen in Ihrem System so in Beziehung setzen, dass die Benutzer die Daten als eine Einheit erfassen können. Nachdem Sie die Beziehungen definiert haben, können Sie Abfragen, Formulare, Berichte und Datenzugriffsseiten erstellen, die Informationen aus mehreren Tabellen kombinieren. Auf diese Weise genießen Sie alle Vorteile der Datenaufteilung und stellen sicher, dass Ihre Datenbank die Benutzer mit allen benötigten Informationen versorgt.
3.1
Beziehungstypen
Es gibt drei verschiedene Typen von Beziehungen zwischen Tabellen in einer Datenbank: 1:n-, 1:1- und m:n-Beziehungen. Es ist unbedingt notwendig, den richtigen Beziehungstyp für zwei Tabellen Ihrer Datenbank zu finden. Die richtige Beziehung zwischen zwei Tabellen sichert Ihnen:
90
Kapitel 3: Beziehungen: Ihr Schlüssel zur Datensicherheit
Datensicherheit optimale Leistung einfaches Benutzen und Erstellen von Systemobjekten Die Gründe für diese Vorteile werden in diesem Kapitel erläutert. Bevor Sie sie nachvollziehen können, müssen Sie zuerst die möglichen Beziehungstypen verstehen.
3.1.1
1:n-Beziehungen
1:n-Beziehungen sind die am häufigsten verwendeten Beziehungen. In einer 1:nBeziehung kann ein Datensatz einer Tabelle mit mehreren anderen Datensätzen einer weiteren Tabelle verbunden sein. Ein übliches Beispiel hierfür ist die Beziehung zwischen einer Kundentabelle und einer Tabelle mit Bestellungen. Für jeden Kunden in der Kundentabelle möchten Sie mehrere Bestellungen in der Bestellungentabelle haben. Eine Bestellung kann jedoch nur zu einem bestimmten Kunden gehören. Die Kundentabelle befindet sich auf der 1-Seite dieser Beziehung, die Bestellungentabelle auf der n-Seite. Um eine solche Beziehung zu erstellen, muss das Feld, das beide Tabellen verbindet, auf der 1-Seite eindeutig sein. In unserem Beispiel kann man einen Kunden in der Kundentabelle eindeutig an seiner Kundennummer erkennen. Dies ist das Verbindungsfeld. Hätten mehrere Kunden die gleiche Nummer, könnte man eine Bestellung nicht mehr sicher einem Kunden zuordnen. Aus diesem Grund muss das Feld, das beide Tabellen verknüpft, auf der 1-Seite ein Primärschlüssel sein oder einen eindeutigen Index haben. In fast allen Fällen handelt es sich hierbei um den Primärschlüssel. Das zugehörige Feld der Tabelle auf der n-Seite wird »Fremdschlüssel« genannt.
3.1.2
1:1-Beziehungen
In einer 1:1-Beziehung kann jeder Datensatz der Tabelle auf der 1-Seite nur einen passenden Datensatz in der Tabelle auf der n-Seite der Beziehung haben. Dieser Beziehungstyp ist nicht üblich und wird nur unter ganz speziellen Umständen benutzt. Normalerweise sollten Sie, wenn Sie eine 1:1-Beziehung einrichten wollen, die Daten beider Tabellen zu einer Tabelle zusammenfassen. Die folgenden Gründe können eine solche Beziehung jedoch erforderlich machen:
Die Menge der für eine Tabelle benötigten Felder übersteigt die von Access gesetzte Obergrenze.
Bestimmte Felder einer Tabelle enthalten vertraulichere Daten als die übrigen in dieser Tabelle enthaltenen Felder.
Einige Felder werden nur für eine kleine Zahl von Datensätzen in der Tabelle benötigt. Die maximale Anzahl von Feldern, die Sie in einer Access-Tabelle verwenden dürfen, beträgt 255. Es gibt nur wenige plausible Umstände, unter denen eine Tabelle mehr
Beziehungstypen
91
als 255 Felder haben muss. Schon wenn Sie sich dieser Zahl nähern, sollten Sie die Struktur Ihrer Datenbank gründlich unter die Lupe nehmen. In den seltenen Fällen, in denen Sie mehr als 255 Felder benötigen, können Sie eine einzelne große Tabelle vortäuschen, indem Sie einen Teil der Daten in einer zweiten Tabelle speichern und dann zwischen beiden eine 1:1-Beziehung einrichten. Der zweite Grund, weshalb es erforderlich sein kann, Daten, die logisch gesehen zu einer Tabelle gehören, auf zwei Tabellen zu verteilen, ist die Sicherheit. Ein Beispiel hierfür ist eine Tabelle mit Daten über Angestellte. Einige Informationen wie der Name, die Adresse, die private Telefonnummer und die Bürodurchwahl werden möglicherweise von mehreren Benutzern einer Datenbank verwendet. Andere Informationen wie das Einstellungsdatum, das Gehalt, das Geburtsdatum oder die Steuerklasse sind streng vertraulich. Den einzelnen Feldern einer Access-Tabelle können Sie keinen Sicherheitsgrad zuweisen. Sie können eine solche feldbezogene Datensicherheit jedoch erreichen, indem Sie eine spezielle Eigenschaft von Abfragen benutzen, die als »Ausführung mit Besitzerberechtigung« bezeichnet wird. Diese Möglichkeit wird in Kapitel 11 erläutert. Eine Alternative zu dieser Methode ist das Zusammenfassen aller Daten, die allgemein zugänglich sind, und der vertraulichen Daten in jeweils einer Tabelle. Nur einem Benutzer mit Administratorrechten wird der Einblick in die Tabelle mit den vertraulichen Informationen gewährt. Um die Felder der vertraulichen Tabelle bei Bedarf anzuzeigen, kommt DAO-Code (DAO – Data Access Objekts) zum Einsatz. Dies geschieht mit einer Abfrage, deren Eigenschaft Ausführungsberechtigungen auf Besitzer gesetzt ist und die auf den speziellen Administratorberechtigungen der streng vertraulichen Daten basiert. Dieses Verfahren wird in Kapitel 34 näher erläutert. Der letzte Grund für eine 1:1-Beziehung liegt vor, wenn einige Felder einer Tabelle nur für eine relativ kleine Anzahl von Datensätzen benutzt werden. Ein Beispiel hierfür sind eine Angestelltentabelle und eine Tabelle mit freien Mitarbeitern. Wenn nur wenige Ihrer Mitarbeiter Freiberufler sind, ist es nicht ratsam, alle Felder, die Informationen über freie Mitarbeiter enthalten, mit in die Angestelltentabelle hereinzunehmen. Dies würde zu viel Speicherplatz verbrauchen und die Geschwindigkeit ihrer Datenbank herabsetzen, besonders wenn für diese Informationen viele Felder benötigt werden. Wenn Sie jedoch die Informationen in zwei Tabellen aufteilen und eine 1:1-Beziehung zwischen ihnen einrichten, können Sie Speicherplatz sparen und die Geschwindigkeit erhöhen. Diese Verbesserung macht sich besonders bei einer großen Angestelltentabelle bemerkbar.
3.1.3
m:n-Beziehungen
In einer m:n-Beziehung gibt es zu Datensätzen in beiden Tabellen passende Datensätze in der jeweils anderen. Eine m:n-Beziehung kann in Access nicht direkt erstellt werden. Sie müssen diese Art von Beziehung zwischen zwei Tabellen mit Hilfe einer weiteren Tabelle herstellen, die als Verknüpfungstabelle bezeichnet wird. Die Verknüpfungstabelle steht zu beiden Tabellen in einer 1:n-Beziehung. Ein Beispiel hier-
92
Kapitel 3: Beziehungen: Ihr Schlüssel zur Datensicherheit
für sind eine Produkt- und eine Bestellungentabelle. Jede Bestellung kann mehrere Produkte umfassen und ein Produkt kann in mehreren Bestellungen vorkommen. Um dem gerecht zu werden, müssen Sie eine dritte Tabelle mit Bestelldetails einfügen. Die Bestelldetailtabelle steht mit der Bestellungentabelle über das Bestellnummernfeld und mit der Produkttabelle über das Feld ARTIKELNUMMER jeweils in einer 1:n-Beziehung.
3.2
Beziehungen einrichten
Beziehungen richten Sie unter Access im Fenster BEZIEHUNGEN ein, das Sie in Abbildung 3.1 sehen. Um dieses Fenster zu öffnen, wechseln Sie zum Datenbankfenster und klicken in der Symbolleiste auf BEZIEHUNGEN oder wählen BEZIEHUNGEN aus dem Menü EXTRAS. Wenn noch keine Beziehungen definiert sind, wird das Dialogfeld TABELLE ANZEIGEN angezeigt. In diesem Dialogfeld können Sie Tabellen dem Beziehungsfenster hinzufügen. Im Beziehungsfenster werden die Beziehungstypen für alle Tabellen dargestellt. Alle in der Datenbank definierten 1:n- und 1:1Beziehungen werden durch Verbindungslinien symbolisiert. Wenn zwischen den beiden Tabellen einer 1:n-Beziehung referentielle Integrität festgelegt wurde, erscheint auf der 1-Seite der Beziehung eine 1 und auf der anderen Seite ein Unendlichzeichen. Bei 1:1-Beziehungen wird an beiden Enden der Verbindungslinie eine 1 angezeigt
Abbildung 3.1: Das BeziehungenFenster gibt Ihnen die Möglichkeit, Beziehungen zwischen Tabellen zu betrachten, hinzuzufügen, zu verändern und zu entfernen
Beziehungen einrichten
3.2.1
93
Eine Beziehung zwischen zwei Tabellen einrichten
Um eine Beziehung zwischen zwei Tabellen einzurichten, vollziehen Sie bitte die folgenden Schritte nach: 1. Öffnen Sie das BEZIEHUNGEN-Fenster. 2. Wenn Sie das Dialogfeld BEZIEHUNGEN für die aktuelle Datenbank noch nie geöffnet haben, erscheint das Dialogfeld TABELLE ANZEIGEN. Markieren Sie alle Tabellen, die Sie zueinander in Beziehungen setzen wollen, und klicken Sie auf HINZUFÜGEN. 3. Wenn Sie in Ihrer Datenbank bereits Beziehungen definiert haben, erscheint das BEZIEHUNGEN-Fenster. Falls die Tabelle, die Sie in eine Beziehung einfügen möchten, nicht angezeigt wird, klicken Sie auf das Symbol TABELLE ANZEIGEN oder wählen Sie den entsprechenden Befehl aus dem Menü BEZIEHUNGEN. Um die gewünschte Tabelle hinzuzufügen, wählen Sie sie aus und klicken auf HINZUFÜGEN. Wiederholen Sie diesen Vorgang für jede Tabelle, die Sie benötigen. Um mehrere Tabellen auf einmal zu markieren, können Sie bei gedrückter (ª)Taste mehrere untereinanderstehende Tabellennamen oder bei gedrückter (Strg)-Taste mehrere nicht aufeinanderfolgende Namen auswählen. Schließen Sie das Dialogfeld, wenn Sie fertig sind. 4. Klicken Sie auf ein Feld einer Tabelle und ziehen Sie es bei gedrückter Maustaste auf das passende Feld einer anderen Tabelle. Daraufhin erscheint das in Abbildung 3.2 gezeigte Dialogfeld BEZIEHUNGEN BEARBEITEN.
Abbildung 3.2: Das Dialogfeld Beziehungen bearbeiten ermöglicht Ihnen das Betrachten und Verändern der Beziehungen zwischen den Tabellen in einer Datenbank
5. Legen Sie mit Hilfe der entsprechenden Kontrollkästchen fest, ob Sie eine Verknüpfung mit referentieller Integrität wünschen und ob Aktualisierungen an die verknüpften Detailfelder weitergegeben und verknüpfte Detaildatensätze mitgelöscht werden sollen. Weitere Informationen zu diesen Themen finden Sie im Abschnitt »Für referentielle Integrität sorgen«. 6. Klicken Sie auf ERSTELLEN.
94
Kapitel 3: Beziehungen: Ihr Schlüssel zur Datensicherheit
3.2.2
Richtlinien für das Einrichten von Beziehungen
Wenn Sie Beziehungen einrichten, müssen Sie sich an einige wichtige Dinge erinnern oder Sie geraten in Schwierigkeiten.
Es ist wichtig, das Zusammenwirken des BEZIEHUNGEN-Fensters und der tatsächlichen Beziehungen zu verstehen, die Sie in der Datenbank eingerichtet haben. Das Fenster ermöglicht es uns, die vorhandenen Beziehungen zu betrachten und zu verändern. Wenn Sie Beziehungen einrichten, tritt die tatsächliche Beziehung in dem Moment in Kraft, in dem Sie auf ERSTELLEN klicken. Sie können Tabellen aus dem Dialogfeld löschen, indem Sie sie auswählen und (Entf) drücken. Die Beziehungen bleiben jedoch bestehen. Wie Sie eine Beziehung aufheben können, wird im Abschnitt »Eine bestehende Beziehung verändern« erklärt. Das BEZIEHUNGEN-Fenster stellt die eingerichteten Beziehungen schematisch dar. Wenn Sie das Layout des Fensters durch das Verschieben, Hinzufügen oder Löschen von Tabellen verändern, werden Sie aufgefordert, die Änderungen beim Schließen des Fensters zu speichern. Access fragt nicht, ob Sie Änderungen an den Beziehungen speichern wollen. Es fragt nur, ob es deren Darstellung im Fenster sichern soll.
Wenn Sie Tabellen zum BEZIEHUNGEN-Fenster hinzufügen, kann es passieren, dass Sie eine Tabelle unbeabsichtigt mehrmals hinzufügen. Dies kann geschehen, wenn sich die Tabelle, die Sie gerade erneut einfügen, hinter dem Dialogfeld TABELLE ANZEIGEN oder außerhalb des angezeigten Bereichs befindet. Wenn das der Fall ist, wird diese Tabelle mehrfach mit verschiedenen Aliasnamen angezeigt. Sie müssen die überzähligen Tabellen löschen.
Sie können mit dem Dialogfeld TABELLE ANZEIGEN auch Abfragen zu dem BEZIEHUNGEN-Fenster hinzufügen. Obwohl diese Möglichkeit selten angewendet wird, kann dies sinnvoll sein, wenn Sie regelmäßig dieselben Abfragen in andere Abfragen einfügen und eine permanente Beziehung zwischen ihnen einrichten wollen.
Wenn Sie Tabellen aus dem BEZIEHUNGEN-Fenster entfernen (die Beziehungen werden dadurch nicht gelöscht) und wieder alle Beziehungen sehen wollen, klicken Sie auf das Symbol ALLE BEZIEHUNGEN ANZEIGEN in der Symbolleiste oder wählen den entsprechenden Befehl aus dem Menü BEZIEHUNGEN.
Um eine Beziehung zu löschen, klicken Sie auf die Verbindungslinie und drücken (Entf).
Erstellen Sie eine neue Datenbank, und fügen Sie eine neue Tabelle mit dem Namen tblCustomers für Kunden, eine Tabelle tblOrders für Bestellungen und eine Tabelle tblOrderDetails für Bestelldetails hinzu. Jede Tabelle sollte die folgenden Felder aufweisen:
Beziehungen einrichten
95
tblCustomers:
CustomerID (Kundennummer), CompanyName (Firmenname), Address (Adresse), City (Stadt), State (Land), ZipCode (PLZ)
tblOrders:
OrderID
(Bestellnummer), CustomerID (Kundennummer), OrderDate (Bestelldatum), ShipVia (Vertriebsweg)
tblOrderDetails: OrderID (Bestellnummer), LineNumber (Position), ItemID (Artikelnummer), Quantity (Menge), Price (Preis)
1. Definieren Sie in der Tabelle tblCustomers das Feld CustomerID (Kundennummer) als Primärschlüssel. Setzen Sie die Feldgröße auf 5. Den anderen Feldern brauchen Sie keine Eigenschaften zuzuweisen. 2. Setzen Sie in der Tabelle tblOrders das Feld OrderID (Bestellnummer) auf AutoWert und machen Sie es zum Primärschlüssel. Geben Sie dem Feld CustomerID (Kundennummer) die Länge 5 und setzen Sie das Feld OrderDate (Bestelldatum) auf Datum/Uhrzeit. 3. Setzen Sie in der Tabelle tblOrderDetails das Feld OrderID (Bestellnummer) auf ZAHL und geben Sie als Größe Long Integer ein. Verfahren Sie mit den Feldern LineNumber (Position), ItemID (Artikelnummer) und Quantity (Menge) genauso. Der Primärschlüssel soll aus einer Kombination aus dem Feld OrderID (Bestellnummer) und dem Feld LineNumber (Position) bestehen. Das Feld Price (Preis) bekommt den Typ Währung. 4. Um das BEZIEHUNGEN-Fenster zu öffnen, wechseln Sie zum Datenbankfenster und klicken in der Symbolleiste auf BEZIEHUNGEN. Wählen Sie im Dialogfeld TABELLE ANZEIGEN die Tabelle tblOrders, halten Sie die (Umschalt)-Taste gedrückt und klicken Sie auf die Tabelle tblCustomers. Klicken Sie anschließend auf HINZUFÜGEN. Alle drei Tabellen sollten jetzt im Dialogfeld BEZIEHUNGEN erscheinen. Schließen Sie das Dialogfeld. Klicken Sie in der Tabelle tblCustomers auf das Feld CustomerID (Kundennummer) und ziehen Sie es bei gedrückter Maustaste auf das Feld CustomerID in der Tabelle tblOrders. Wenn das Fenster BEZIEHUNGEN erscheint, klicken Sie auf ERSTELLEN. Wiederholen Sie diesen Vorgang, indem Sie das Feld OrderID (Bestellnummer) von der Tabelle tblOrders zur Tabelle tblOrderDetails ziehen. Sie finden dieses und die anderen Beispiele aus diesem Kapitel in der Datei Chap3TryIt.MDB auf der beiliegenden CD-ROM.
96
Kapitel 3: Beziehungen: Ihr Schlüssel zur Datensicherheit
3.2.3
Eine bestehende Beziehung verändern
Das Bearbeiten einer Beziehung ist einfach. Access gibt Ihnen die Möglichkeit, eine bestehende Beziehung zu bearbeiten oder ihr Wesen zu verändern. Um eine Beziehung zwischen zwei Tabellen endgültig zu entfernen, gehen Sie wie folgt vor: 1. Wechseln Sie zum Datenbankfenster und klicken Sie in der Symbolleiste auf BEZIEHUNGEN. 2. Klicken Sie auf die Verbindungslinie zweier Tabellen, deren Beziehung Sie löschen möchten. 3. Klicken Sie auf LÖSCHEN und bestätigen Sie die folgende Sicherheitsabfrage mit JA. In den meisten Fällen werden Sie eine Beziehung nicht löschen, sondern bearbeiten wollen. Um dies zu tun, beachten Sie die folgenden vier Schritte: 1. Wechseln Sie zum Datenbankfenster und klicken Sie in der Symbolleiste auf BEZIEHUNGEN. 2. Klicken Sie auf die Verbindungslinie zweier Tabellen, deren Beziehung Sie verändern möchten. 3. Führen Sie die gewünschten Änderungen durch. 4. Klicken Sie auf OK. Es gelten alle normalen Regeln für das Erstellen von Beziehungen.
3.3
Für referentielle Integrität sorgen
Wie Sie sehen, ist das Erstellen einer Beziehung sehr einfach. Die richtige Art von Beziehung zu finden, ist schon schwieriger. Wenn Sie eine neue Beziehung zwischen zwei Tabellen erstellen, trifft Access ein paar Entscheidungen aufgrund vordefinierter Faktoren:
Eine 1:n-Beziehung wird erstellt, wenn eines der beteiligten Felder ein Primärschlüssel ist oder einen eindeutigen Index hat.
Eine 1:1-Beziehung wird erstellt, wenn beide beteiligten Felder Primärschlüssel sind oder eindeutige Indizes haben.
Eine unbestimmte Beziehung wird erstellt, wenn keines der beteiligten Felder ein Primärschlüssel ist oder einen eindeutigen Index hat. In diesem Fall kann keine referentielle Integrität hergestellt werden. Referentielle Integrität besteht aus einer Reihe von Regeln, die von der Jet-Engine verwendet werden und sicherstellen sollen, dass Beziehungen zwischen Tabellen richtig gehandhabt werden. Am wichtigsten dabei ist, dass referentielle Integrität das Auftreten von verwaisten Datensätzen auf der n-Seite einer 1:n-Beziehung verhindert. Wenn Sie zum Beispiel eine solche Beziehung zwischen einer Kunden- und
Für referentielle Integrität sorgen
97
einer Bestellungentabelle erstellt haben, muss jede Bestellung einem bestimmten Kunden zugeordnet sein. Bevor Sie für referentielle Integrität zwischen zwei Tabellen sorgen, müssen die folgenden Bedingungen erfüllt sein:
Das beteiligte Feld auf der 1-Seite muss ein Primärschlüssel sein oder einen eindeutigen Index haben.
Die verbundenen Felder müssen denselben Datentyp aufweisen. (Ein AutoWert kann allerdings mit einem Long Integer verbunden werden.) Textfelder müssen dieselbe Länge und Zahlenfelder dieselbe Größe (z.B. Long Integer) haben.
Beide Tabellen müssen zur selben Access-Datenbank gehören. Beide Tabellen müssen im Access-Dateiformat (.mdb) abgespeichert sein. (Sie können keine externen Tabellen aus anderen Quellen verwenden.)
Die Datenbank, die beide Tabellen umfasst, muss geöffnet sein. Die vorhandenen Daten der beiden Tabellen dürfen keine der Regeln für referentielle Integrität verletzen. Obwohl zu Beziehungen gehörende Textfelder nicht die gleiche Größe haben müssen, ist es empfehlenswert, ihnen die gleiche Größe zu geben. Ansonsten gehen sie zu Lasten der Geschwindigkeit und können unvorhersehbare Fehler beim Erstellen von Abfragen zur Folge haben, die sich auf beide Tabellen beziehen. Nachdem referentielle Integrität zwischen zwei Tabellen eingerichtet wurde, gelten die folgenden Regeln:
Sie können keinen Wert in den Fremdschlüssel der angebundenen Tabelle eingeben, den es nicht im Primärschlüssel der Haupttabelle gibt. Zum Beispiel können Sie in der Bestellungentabelle keine Kundennummer eingeben, die es in der Kundentabelle nicht gibt.
Sie können keinen Datensatz in der Haupttabelle löschen, wenn ihm zugehörige Datensätze in der angebundenen Tabelle existieren. Zum Beispiel können Sie keinen Kunden aus der Kundentabelle löschen, solange es mit ihm verbundene Datensätze in der Bestellungentabelle gibt (Datensätze mit der gleichen Kundennummer).
Sie können keine Werte im Primärschlüssel auf der 1-Seite einer Beziehung ändern, zu denen entsprechende Datensätze in der angebundenen gehören. Zum Beispiel können Sie in der Kundentabelle keine Kundennummern ändern, wenn entsprechende Bestellungen in der Bestellungentabelle vorhanden sind. Wenn eine dieser Regeln verletzt wird und Sie referentielle Integrität zwischen zwei Tabellen eingerichtet haben, erscheint die in Abbildung 3.3 gezeigte Fehlermeldung.
98
Kapitel 3: Beziehungen: Ihr Schlüssel zur Datensicherheit
Abbildung 3.3: Eine Fehlermeldung beim Versuch, eine Bestellung für einen Kunden hinzuzufügen, den es überhaupt nicht gibt
Access unterbindet standardmäßig das Löschen von Datensätzen mit zugehörigen untergeordneten Datensätzen sowie das Ändern eines Primärschlüsselwerts dieser Datensätze. Sie können diese Einschränkungen außer Kraft setzen, indem Sie die beiden Kontrollkästchen im Dialogfeld BEZIEHUNGEN benutzen, die beim Erstellen und Bearbeiten von Beziehungen erscheinen. 1. Wechseln Sie zum Datenbankfenster und öffnen Sie das Fenster BEZIEHUNGEN, indem Sie auf das zugehörige Symbol in der Symbolleiste klicken. Doppelklicken Sie die Verbindungslinie zwischen den Tabellen tblCustomers und tblOrders. Aktivieren Sie das Kontrollkästchen MIT REFERENTIELLER INTEGRITÄT. Klicken Sie auf OK. Wiederholen Sie den Vorgang für die Beziehung zwischen den Tabellen tblOrders und tblOrderDetails. 2. Öffnen Sie die Tabelle tblCustomers und fügen Sie einige Datensätze hinzu. Beachten Sie die Werte im Feld CustomerID. Fügen Sie ein paar neue Datensätze in die Tabelle tblOrders ein, für die in tblCustomers Einträge mit denselben CustomerID-Werten vorhanden sind. Versuchen Sie jetzt, tblOrders eine Bestellung hinzuzufügen, die einen in tblCustomers nicht vorhandenen CustomerID-Wert enthält. Sie sollten daraufhin eine Fehlermeldung erhalten. 3. Versuchen Sie, einen Datensatz aus tblCustomers zu löschen, dem keine Bestellungen zugeordnet sind. Sie sollten zwar eine Warnmeldung erhalten, den Vorgang jedoch fortführen dürfen. Versuchen Sie nun, einen Kunden zu löschen, zu dem Bestellungen vorhanden sind. Sie werden es nicht dürfen. Der Versuch, die entsprechende Kundennummer (CustomerID) zu ändern, sollte ebenfalls fehlschlagen.
3.3.1
Aktualisierungsweitergabe an Detailfeld
Die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD steht nur zur Verfügung, wenn zwischen zwei Tabellen referentielle Integrität eingerichtet wurde. Wenn Sie diese Option aktiviert haben, ist es dem Benutzer nicht verboten, die Werte im Primärschlüssel auf der 1-Seite einer Beziehung zu ändern. Stattdessen werden die Änderungen, die auf der 1-Seite eines Feldes, das zwei Tabellen verbindet, vorgenommen werden, auf das Fremdschlüsselfeld auf der n-Seite übertragen.
Für referentielle Integrität sorgen
99
Es ist nicht nötig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD zu aktivieren, wenn es sich bei dem zugehörigen Feld auf der 1-Seite um ein AutoWert-Feld handelt. Felder dieses Datentyps können nicht geändert werden. Die Aktualisierungsweitergabe an das Detailfeld wirkt sich daher auf solche Felder nicht aus.
Es passiert sehr leicht, dass Sie in Ihr System versehentlich eine Sicherheitslücke einbauen. Wenn Sie eine 1:n-Beziehung erstellen und vergessen, die Eigenschaft Eingabe erforderlich des Fremdschlüsselfeldes auf Ja zu setzen, ermöglichen Sie das Erstellen von verwaisten Datensätzen. Abbildung 3.4 zeigt ein solches Beispiel. In der Tabelle tblOrders wurde eine Bestellung ohne Kundennummer eingegeben. Dieser Datensatz ist verwaist, da kein Datensatz in der Tabelle tblCustomers einen Nullwert als Kundennummer hat. Sie können dieses Problem beheben, indem Sie die oben genannte Eigenschaft des Fremdschlüsselfeldes auf JA setzen.
Abbildung 3.4: Ein einzelner Datensatz mit einem Nullwert im Fremdschlüsselfeld
3.3.2
Löschweitergabe an Detaildatensatz
Die Option LÖSCHWEITERGABE AN DETAILDATENSATZ steht nur zur Verfügung, wenn zwischen zwei Tabellen referentielle Integrität eingerichtet wurde. Wenn diese Option aktiviert ist, kann der Benutzer sogar dann Datensätze auf der 1-Seite einer Beziehung löschen, wenn auf der n-Seite zugehörige Datensätze vorhanden sind. Ein Kunde kann also zum Beispiel auch dann gelöscht werden, wenn zu ihm Bestellungen gehören. Die referentielle Integrität wird aufrechterhalten, da Access automatisch alle entsprechenden Datensätze in der Detailtabelle mitlöscht.
100
Kapitel 3: Beziehungen: Ihr Schlüssel zur Datensicherheit
Wenn Sie versuchen, einen Datensatz auf der 1-Seite einer 1:n-Beziehung zu löschen, der keine abhängigen Datensätze auf der anderen Seite besitzt, sollten Sie die in Abbildung 3.5 gezeigte Warnmeldung bekommen. Falls Sie allerdings einen Datensatz aus der Tabelle auf der 1-Seite löschen wollen, zu dem Datensätze aus der Detailtabelle gehören, werden Sie gewarnt, dass Sie sowohl den Datensatz aus der Haupttabelle als auch die verwandten Datensätze aus der Detailtabelle löschen werden (siehe Abbildung 3.6). Abbildung 3.5: Eine Nachricht, die erscheint, wenn der Benutzer versucht, einen übergeordneten Datensatz ohne die zu ihm gehörenden untergeordneten Datensätze zu löschen Abbildung 3.6: Eine Nachricht, die erscheint, wenn der Benutzer versucht, einen übergeordneten Datensatz mit den zu ihm gehörenden untergeordneten Datensätzen zu löschen
Die Löschweitergabe an Detailfelder ist nicht immer geeignet. Sie ist ein hervorragendes Hilfsmittel, aber Sie sollten sie vorsichtig einsetzen. Obwohl es üblich ist, Löschvorgänge von einer Tabelle mit Bestellungen an eine Bestelldetailtabelle weiterzugeben, ist es meistens wenig sinnvoll, mit einem Kunden alle zu ihm gehörenden Bestellungen zu löschen. Sie würden sonst vielleicht wichtige statistische Bestellinformationen verlieren, wenn Sie einen Kunden löschen. Der Verlust solcher Daten könnte zum Beispiel Ihre Gewinn- und Verluststatistik verfälschen. Es empfiehlt sich daher, das Löschen eines Kunden nicht zu gestatten und ihn stattdessen als inaktiv zu markieren. Wenn Sie andererseits eine Bestellung löschen, die storniert worden ist, wollen Sie wahrscheinlich die entsprechenden Bestelldetails ebenfalls löschen. In diesem Fall ist die Löschweitergabe an Detaildatensätze sinnvoll. Sie müssen in jeder Situation die richtige, auf ihre Bedürfnisse abgestimmte, Entscheidung treffen. Es ist wichtig, alle möglichen Auswirkungen einer solchen Feststellung abzuwägen, bevor Sie eine Entscheidung treffen.
Vorteile von Beziehungen
101
1. Ändern Sie die Beziehung zwischen den Tabellen tblCustomers und tblOrders, indem Sie das Kontrollkästchen AKTUALISIERUNGSWEITERGABE AN DETAILFELD aktivieren. Bearbeiten Sie die Beziehung zwischen tblOrders und tblOrderDetails durch Aktivieren des Kontrollkästchens LÖSCHWEITERGABE AN DETAILDATENSATZ. Es ist nicht nötig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELDER auszuwählen, da das Feld OrderID in tblOrders ein AutoWert-Feld ist. 2. Versuchen Sie, einen Kunden zu löschen, zu dem Bestellungen gehören. Sie werden es nicht dürfen, da Sie die LÖSCHWEITERGABE AN DETAILDATENSÄTZE nicht aktiviert haben. Ändern Sie nun in tblCustomers die Kundennummer eines Kunden, zu dem Bestellungen vorhanden sind. Dies wird funktionieren. Öffnen Sie jetzt die Tabelle mit den Bestellungen (tblOrders) und suchen Sie die zu diesem Kunden gehörenden Bestellungen. Deren Kundennummern sollten entsprechend der Änderung in der Haupttabelle aktualisiert worden sein. 3. Fügen Sie der Tabelle tblOrderDetails einige Bestelldetails hinzu. Versuchen Sie eine Bestellung zu löschen, zu der es Bestelldetails gibt. Sie werden eine Warnung erhalten, aber es wird funktionieren.
3.4
Vorteile von Beziehungen
Der wichtigste Vorteil von Beziehungen ist die von ihnen gebotene Datensicherheit. Ohne Beziehungen können Benutzer wahllos Datensätze in Detailtabellen einfügen, ohne die benötigten Informationen in die Haupttabelle einzugeben. Wenn Sie referentielle Integrität eingerichtet haben, können Sie die Aktualisierungsweitergabe an Detailfelder und die Löschweitergabe an Detaildatensätze veranlassen. Dies spart Ihnen eine Menge Programmcode für das Aufrechthalten der Datensicherheit in Ihrem System. Bei den meisten mit Beziehungen arbeitenden Datenbanksystemen ist es erforderlich, selbst den Programmcode zu schreiben, um untergeordnete Datensätze zu löschen, wenn der Primärdatensatz gelöscht wird, oder um den Fremdschlüssel der untergeordneten Datensätze zu aktualisieren, wenn der Primärschlüssel in der Haupttabelle geändert wurde. Durch das Aktivieren von AKTUALISIERUNGSWEITERGABE AN DETAILFELD und LÖSCHWEITERGABE AN DETAILDATENSATZ sparen Sie sich das Programmieren dieser gemeinhin üblichen Funktionen völlig. Beziehungen werden automatisch in Ihre Abfragen übernommen. Das bedeutet, dass jedesmal, wenn Sie eine neue Abfrage erstellen, die Beziehungen der enthaltenen Tabellen automatisch auf der Grundlage der im BEZIEHUNGEN-Fenster eingerichteten Beziehungen erstellt werden. Ferner werden die Beziehungen zwischen den enthaltenen Tabellen auch bei der Erstellung eines Formulars oder eines Berichts beachtet. Wenn Sie in einem Datenblatt oder in einem Formular Daten ändern oder löschen wollen, werden die Regeln der referentiellen Integrität angewandt – sogar wenn die Beziehung nach dem Formular erstellt wurde.
102
Kapitel 3: Beziehungen: Ihr Schlüssel zur Datensicherheit
3.5
Indizes und Beziehungen
Ein Feld, das zwei Tabellen verbindet, muss auf der 1-Seite einer 1:n-Beziehung ein Primärschlüssel sein oder einen eindeutigen Index haben, um referentielle Integrität zu ermöglichen. Wenn der Index auf der 1-Seite nicht eindeutig ist, gibt es keine Möglichkeit, festzustellen, zu welchem Primärdatensatz ein angehängter Datensatz gehört. In Access 2000 ist es nicht nötig, einen Index auf der n-Seite einer Beziehung einzurichten. Access wird für Sie einen internen Index erstellen. Falls Sie selbst einen Index auf der n-Seite einer Beziehung erstellen, stellen Sie sicher, dass Sie die Option DUPLIKATE MÖGLICH aktiviert haben. Ansonsten haben Sie eine 1:1- anstelle einer 1:n-Beziehung erstellt.
3.5.1
Für die Praxis
Beziehungen zwischen den Tabellen des Zeit- und Abrechnungssystems einrichten An dieser Stelle werden Sie die nötigen Beziehungen zwischen den Tabellen unserer Beispieldatenbank (für das EDV-Consulting-Unternehmen) erstellen. Wenn Sie dies selbst machen wollen, öffnen Sie die Datenbank, die Sie in Kapitel 2 erstellt haben.
tblClients (Kundentabelle) und tblProjekts (Projekttabelle): Diese beiden Tabellen müssen durch eine auf dem Feld ClientID (Kundennummer) basierende 1:nBeziehung verbunden werden. Erzeugen Sie referentielle Integrität, um sicherzustellen, dass keine Projekte für nicht vorhandene Kunden hinzugefügt werden. Es ist nicht notwendig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD zu aktivieren, da das Feld ClientID (Kundennummer), das die Tabellen verbindet, in tblClients ein AutoWert-Feld ist. Sie wollen keine Löschweitergabe an Detaildatensätze einrichten, da Sie beim Löschen eines Kunden keine Rechnungsinformationen ändern wollen. Statt dessen verhindern Sie das Löschen von Kunden mit zugehörigen Projekten durch das Festlegen von referentieller Integrität zwischen den beiden Tabellen.
tblProjects und tblPayments (Bezahlungstabelle): Diese beiden Tabellen müssen durch eine auf dem Feld ProjectID (Projektnummer) basierende 1:n-Beziehung verbunden werden. Erzeugen Sie referentielle Integrität, um sicherzustellen, dass keine Zahlungen für nicht vorhandene Projekte hinzugefügt werden. Es ist nicht notwendig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD zu aktivieren, da das Feld ProjectID, das die Tabellen verbindet, in tblProjects ein AUTOWERT-Feld ist. Sie wollen keine Löschweitergabe an Detaildatensätze einrichten, da Sie beim Löschen eines Projekts keine Zahlungsinformationen ändern möchten. Statt dessen verhindern Sie das Löschen von Projekten mit zugehörigen Zahlungen durch das Einrichten von referentieller Integrität zwischen den beiden Tabellen.
Indizes und Beziehungen
103
tblProjects und tblTimeCardHours (Arbeitszeittabelle): Diese beiden Tabellen müssen durch eine auf dem Feld ProjectID basierende 1:n-Beziehung verbunden werden. Erzeugen Sie referentielle Integrität, um sicherzustellen, dass keine Zeiten für nicht vorhandene Projekte hinzugefügt werden. Es ist nicht notwendig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD zu aktivieren, da das Feld ProjectID, das die Tabellen verbindet, in tblProjects ein AutoWert-Feld ist. Aktivieren Sie die Löschweitergabe an Detaildatensätze für jedes gelöschte Projekt, damit die dazugehörigen Zeiten mitgelöscht werden.
tblProjects und tblTimeCardExpenses (Spesentabelle): Diese beiden Tabellen müssen durch eine auf dem Feld ProjectID basierende 1:n-Beziehung verbunden werden. Erzeugen Sie referentielle Integrität, um sicherzustellen, dass keine Spesen für nicht vorhandene Projekte hinzugefügt werden. Es ist nicht notwendig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD zu aktivieren, da das Feld ProjectID, das die Tabellen verbindet, in tblProjects ein AutoWert-Feld ist. Aktivieren Sie die Löschweitergabe an Detaildatensätze, damit mit Projekten auch die zugehörigen Spesen gelöscht werden.
tblEmployees (Mitarbeitertabelle) und tblTimeCards (Stechuhrkartentabelle): Diese beiden Tabellen müssen durch eine auf dem Feld EmployeeID (Mitarbeiternummer) basierende 1:n-Beziehung verbunden werden. Erzeugen Sie referentielle Integrität, um sicherzustellen, dass keine Stechuhrkarten für nicht vorhandene Mitarbeiter hinzugefügt werden. Es ist nicht notwendig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD zu aktivieren, da das Feld EmployeeID, das die Tabellen verbindet, in tblEmployees (Mitarbeitertabelle) ein AutoWert-Feld ist. Die Option LÖSCHWEITERGABE AN DETAILDATENSATZ möchten Sie nicht einrichten, da Sie beim Löschen eines Mitarbeiters nicht alle Stechuhrkarten des Mitarbeiters mitlöschen wollen.
tblEmployees und tblProjects: Diese beiden Tabellen müssen durch eine auf dem Feld EmployeeID basierende 1:n-Beziehung verbunden werden. Erzeugen Sie referentielle Integrität, um sicherzustellen, dass keine Projekte für nicht vorhandene Mitarbeiter hinzugefügt werden. Es ist nicht notwendig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD zu aktivieren, da das Feld EmployeeID, das die Tabellen verbindet, in tblEmployees ein AutoWert-Feld ist. Sie wollen keine Löschweitergabe an Detaildatensätze einrichten, da Sie sonst mit einem Mitarbeiter auch alle Projekte des Mitarbeiters löschen würden, was natürlich nicht erwünscht ist.
tblTimeCards und tblTimeCardHours: Diese beiden Tabellen müssen durch eine auf dem Feld TimeCardID (Stechuhrkartennummer) basierende 1:n-Beziehung verbunden werden. Erzeugen Sie referentielle Integrität, um sicherzustellen, dass keine Zeiten für nicht vorhandene Karten hinzugefügt werden. Es ist nicht notwendig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD zu aktivieren, da das Feld TimeCardID, das die Tabellen verbindet, in tblTimeCards ein AutoWert-
104
Kapitel 3: Beziehungen: Ihr Schlüssel zur Datensicherheit
Feld ist. In diesem Fall ist es erforderlich, die Löschweitergabe an Detaildatensätze einzurichten, da Sie mit einer Stechuhrkarte alle zu dieser Karte gehörenden Zeiten löschen wollen.
tblTimeCards und tblTimeCardExpenses: Diese beiden Tabellen müssen durch eine auf dem Feld TimeCardID basierende 1:n-Beziehung verbunden werden. Erzeugen Sie referentielle Integrität, um sicherzustellen, dass keine Spesen für nicht vorhandene Karten hinzugefügt werden. Es ist nicht notwendig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD zu aktivieren, da das Feld TimeCardID, das die Tabellen verbindet, in tblTimeCards ein AutoWert-Feld ist. Sie wollen auch in diesem Fall die Löschweitergabe an Detaildatensätze einrichten, da Sie mit einer Stechuhrkarte auch alle zu dieser Karte gehörenden Spesen löschen wollen.
tblExpenseCodes (Tabelle mit Spesencodes) und tblTimeCardExpenses: Diese beiden Tabellen müssen durch eine auf dem Feld ExpenseCodeID (Spesencodenummer) basierende 1:n-Beziehung verbunden werden. Erzeugen Sie referentielle Integrität, um sicherzustellen, dass in der Spesentabelle keine Spesen hinzugefügt werden, die es gar nicht gibt. Es ist nicht notwendig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD zu aktivieren, da das Feld ExpenseCodeID, das die Tabellen verbindet, in tblExpenseCodes ein AutoWert-Feld ist. Eine Löschweitergabe an Detaildatensätze ist nicht in Ihrem Sinne, da mit dem Spesencode nicht gleichzeitig die Spesen gelöscht werden sollten.
tblWorkCodes (Tätigkeitstabelle) und tblTimeCardHours: Diese beiden Tabellen müssen durch eine auf dem Feld WorkCodeID (Tätigkeitsnummer) basierende 1:nBeziehung verbunden werden. Erzeugen Sie referentielle Integrität, um sicherzustellen, dass keine Arbeitsstunden für nicht vorhandene Tätigkeiten hinzugefügt werden. Es ist nicht notwendig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD zu aktivieren, da das Feld WorkCodeID, das die Tabellen verbindet, in tblWorkCodes ein AutoWert-Feld ist. Sie möchten keine Löschweitergabe an Detaildatensätze einrichten, da Sie beim Löschen einer Tätigkeit die dazugehörigen Arbeitszeiten behalten wollen.
tblPaymentMethods (Zahlungsmethodentabelle) und tblPayments: Diese beiden Tabellen müssen durch eine auf dem Feld PaymentMethodID (Zahlungsmethodennummer) basierende 1:n-Beziehung verbunden werden. Erzeugen Sie referentielle Integrität, um sicherzustellen, dass keine Zahlungen mit nicht vorhandenen Zahlungsmethoden hinzugefügt werden. Es ist nicht notwendig, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD zu aktivieren, da das Feld PaymentMethodID, das die Tabellen verbindet, in tblPaymentMethods ein AutoWert-Feld ist. Löschweitergabe an Detaildatensätze ist nicht notwendig, da Sie mit einer Zahlungsmethode nicht auch die dazugehörigen Zahlungen löschen wollen.
Was jeder Entwickler über Abfragen wissen sollte
Kapitel
Hier lesen Sie:
Was Sie über Abfragen wissen sollten Ihr Abfrage-Ergebnis sortieren Ihre Abfrage mit Hilfe von Kriterien verbessern In Kriterien mit Datumsangaben arbeiten Abfrage-Ergebnisse aktualisieren Berechnete Felder erstellen Der Ausdrucks-Generator Daten mit Hilfe von Funktionen zusammenfassen Nullwerte und Abfrage-Ergebnisse Ihre Abfragen mit Hilfe von Feld-, Feldlisten- und Abfrage-Eigenschaften verbessern
4.1
Was ist eine Abfrage und wann wird sie eingesetzt?
Eine »Auswahlabfrage« ist eine gespeicherte Frage zu den in Ihren Tabellen abgelegten Daten. Auswahlabfragen sind die Grundlage für vieles, was Sie in Access machen. Sie liegen den meisten Formularen und Berichten zugrunde und ermöglichen es Ihnen, die Daten anzuzeigen, die Sie gerade benötigen. Mit einer einfachen Auswahlabfrage bestimmen Sie die Tabellen und Felder, deren Daten Sie sehen wollen. Zusätzlich können Sie mit Hilfe von Kriterien die Menge der angezeigten Daten reduzieren. Eine Auswahlabfrage ist eine sehr einfache Abfrage einer oder mehrerer Tabellen. Sie stellt Ihre Daten nur dar, lässt sie jedoch unverändert. Fortgeschrittene Auswahlabfragen können zum Zusammenfassen von Daten, Speichern von berech-
106
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
neten Werten oder Erstellen von Kreuztabellen benutzt werden. Ferner gibt es Aktionsabfragen, mit denen Sie die Daten in den Tabellen auf der Grundlage vorher festgelegter Bedingungen hinzufügen, ändern oder löschen können. Dieses Kapitel befasst sich mit den Auswahlabfragen. Die anderen Abfragetypen werden in Kapitel 11 beschrieben.
4.2
Alles, was Sie über Abfragen wissen sollten
Das Erstellen einer Abfrage ist einfach, da Microsoft uns mit einer benutzerfreundlichen Schnittstelle gesegnet hat, die uns unter anderem die Möglichkeit zum Ziehen und Ablegen bietet. Es gibt in Access 2000 drei Methoden, um eine neue Abfrage zu beginnen. Sie können in der Objektliste des Datenbankfensters das Symbol ABFRAGEN auswählen und dann das Symbol ERSTELLT EINE NEUE ABFRAGE IN DER ENTWURFSANSICHT oder ERSTELLT EINE NEUE ABFRAGE UNTER VERWENDUNG DES ASSISTENTEN doppelklicken (siehe Abbildung 4.1). Die zweite Möglichkeit besteht darin, in der Objektliste des Datenbankfensters das Symbol ABFRAGEN anzuklicken und dann die Schaltfläche NEU zu betätigen. Daraufhin erscheint das Dialogfeld NEUE ABFRAGE, in dem Sie auswählen können, ob Sie Ihre neue Abfrage in der Entwurfsansicht oder mit einem der Assistenten erstellen wollen (siehe Abbildung 4.2). Der Auswahlabfrage-Assistent führt Sie durch die notwendigen Schritte zum Erstellen einer Auswahlabfrage. Mit den anderen Assistenten können Sie die folgenden Arten von Abfragen erzeugen: Kreuztabellenabfrage, Abfrage zur Duplikatsuche und Abfrage zur Inkonsistenzsuche.
Abbildung 4.1: Wählen Sie das Abfragesymbol aus der Objektliste aus, um eine Abfrage entweder in der Entwurfsansicht oder mit Hilfe eines Assistenten zu erstellen
Alles, was Sie über Abfragen wissen sollten
107
Abbildung 4.2: Verwenden Sie das Dialogfeld Neue Abfrage, um für die zu erstellende Abfrage einen Assistenten auszuwählen, oder klicken Sie auf die Schaltfläche Entwurf zum Erstellen einer Abfrage von Grund auf
4.2.1
Tabellen zu Ihren Abfragen hinzufügen
Wenn Sie statt der Assistenten die Entwurfsansicht wählen, wird das Dialogfeld TABELLE ANZEIGEN angezeigt (siehe Abbildung 4.3). Hier können Sie die Tabellen und Abfragen auswählen, auf deren Daten Sie zugreifen wollen. Für Access spielt es keine Rolle, ob Sie Tabellen oder Abfragen als Grundlage für Ihre Abfrage auswählen. Sie können eine Tabelle oder Abfrage in Ihre Abfrage aufnehmen, indem Sie auf ihren Namen doppelklicken oder sie auswählen und auf HINZUFÜGEN klicken. Sie können auch mehrere Tabellen auswählen, indem sie mit gedrückter (ª)-Taste mehrere untereinander stehende oder mit gedrückter (Strg)-Taste mehrere getrennt aufgeführte Namen anklicken. Wenn Sie die hinzuzufügenden Tabellen und Abfragen markiert haben, klicken Sie auf HINZUFÜGEN und dann auf SCHLIESSEN. Auf diese Weise kommen Sie zu dem in Abbildung 4.4 gezeigten Abfrage-Entwurfsfenster. Eine Alternative zu der eben beschriebenen Methode besteht darin, aus der Objektliste im Datenbankfenster zunächst den Eintrag TABELLEN auszuwählen. Dann wählen Sie die Tabelle aus, auf deren Daten sich die Abfrage beziehen soll. Wenn die Tabelle markiert ist, wählen Sie in der Symbolleiste die Option ABFRAGE aus dem Listenfeld NEUE OBJEKTE oder ABFRAGE aus dem Menü EINFÜGEN. Dies ist eine effiziente Methode, um auf nur einer Tabelle basierende Abfragen zu erstellen, da das Fenster TABELLE ANZEIGEN übersprungen wird.
4.2.2
Felder zu Ihrer Abfrage hinzufügen
Jetzt können Sie Felder auswählen, die Sie Ihrer Abfrage hinzufügen wollen. Die in Abbildung 4.4 gezeigte Abfrage basiert auf der Tabelle tblClients aus der Datenbank CHAP4.MDB, die Sie auf der CD-ROM finden. Beachten Sie, dass das Abfrage-Entwurfsfenster zweigeteilt ist. In der oberen Hälfte sind die Ihrer Abfrage zu Grunde
108
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Abbildung 4.3: Durch Auswählen der Entwurfsansicht gelangen Sie in das Dialogfeld Tabelle anzeigen, das Ihnen die Möglichkeit gibt, die Tabellen und Abfragen festzulegen, auf denen Ihre Abfrage basiert
Abbildung 4.4: Das AbfrageEntwurfsfenster ist ein einfach zu benutzendes (und zu erlernendes) Raster für den Abfrage-Entwurf
liegenden Tabellen und Abfragen dargestellt und die untere Hälfte enthält die Felder, welche die Abfrage ausgeben wird. Sie können dem Entwurf Ihrer Abfrage ein Feld auf verschiedene Arten hinzufügen: 1. Doppelklicken Sie auf den Namen des hinzuzufügenden Feldes. 2. Klicken Sie auf ein Feld einer oben angezeigten Tabelle und ziehen Sie es in das unten dargestellte Raster. 3. Wählen Sie mehrere Felder mit der (ª)-Taste (für untereinander stehende Felder) bzw. mit der (Strg)-Taste (für einzelne Felder) aus. Sie können auch mit einem Doppelklick auf die Titelleiste einer Tabelle sämtliche Felder auswählen. Anschließend ziehen Sie alle Felder in das Abfrageraster.
Alles, was Sie über Abfragen wissen sollten
109
Sie können das Sternchen doppelklicken, um alle Felder einer Tabelle in das Abfrage-Ergebnis aufzunehmen. Obwohl dies sehr bequem ist, da Änderungen in der Tabellenstruktur auf diese Weise in die Abfrage übernommen werden, hat diese Methode auch Nachteile. Durch die Verwendung des Sternchens werden alle Felder in die Abfrage übernommen – egal ob sie benötigt werden oder nicht. Dies kann Leistungsengpässe in LAN-, WAN- oder Client-Server-Anwendungen zur Folge haben.
Öffnen Sie die in Access enthaltene Beispieldatenbank Nordwind. Wenn Sie das Startfenster umgehen wollen, halten Sie beim Laden die (ª)-Taste gedrückt. Wählen Sie dann das Symbol ABFRAGEN und klicken Sie auf NEU. Wählen Sie im Dialogfeld NEUE ABFRAGE den Eintrag ENTWURFSANSICHT. Fügen Sie der Abfrage die Kundentabelle hinzu. Mit den folgenden Schritten können Sie anschließend die Felder Kunden-Code, Firma, Kontaktperson, Position, Land und Telefon der Tabelle Kunden auswählen. 1. Klicken Sie auf das Feld Kunden-Code. 2. Halten Sie die (ª)-Taste gedrückt und klicken Sie auf das Feld Position. Dadurch werden die Felder Kunden-Code, Firma, Kontaktperson und Position markiert. 3. Laufen Sie in der Feldliste mit der vertikalen Bildlaufleiste nach unten, bis das Feld Land erscheint. 4. Klicken Sie es bei gedrückter (Strg)-Taste an. 5. Halten Sie die (Strg)-Taste weiter fest und klicken Sie auf das Feld Telefon. Jetzt sollten alle sechs Felder markiert sein. Ziehen Sie alle Felder aus der Tabelle in das Raster im unteren Fensterbereich. Alle sechs Felder sollten dort erscheinen. Mit der horizontalen Bildlaufleiste können Sie eventuell verborgene Felder auf der rechten Seite erreichen. Der einfachste Weg, eine Abfrage zu starten, besteht darin, auf das Symbol AUSFÜHREN in der Symbolleiste zu klicken. (Dieses sieht wie ein Ausrufezeichen aus.) Sie können dazu auch die Schaltfläche ANSICHT anklicken, doch funktioniert diese nur bei Auswahl-, und nicht bei Aktionsabfragen. Diese Schaltfläche besitzt bei Aktionsabfragen eine spezielle Bedeutung, die in Kapitel 11 erläutert wird. Das Anklicken von AUSFÜHREN ist einfacher, da es unabhängig vom Typ Ihrer Abfrage funktioniert. Nach dem Öffnen einer Abfrage erscheint ein Datenblatt, das nur die von Ihnen ausgewählten Felder enthält. Um zur Entwurfsansicht zurückzukehren, klicken Sie erneut auf ANSICHT.
110
4.2.3
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Ein Feld aus Ihrem Abfrageraster entfernen
Um ein Feld aus Ihrem Abfrageraster zu entfernen, folgen Sie diesen Schritten: 1. Suchen Sie das zu löschende Feld. 2. Klicken Sie auf den dünnen grauen Balken (Spaltenmarkierer) direkt über dem Namen des Feldes. Die gesamte Spalte des Abfragerasters wird schwarz markiert (siehe Abbildung 4.5).
Abbildung 4.5: Ein Feld aus Ihrem Abfrageraster entfernen
3. Drücken Sie die (Entf)-Taste oder wählen Sie LÖSCHEN aus dem Menü BEARBEITEN. Nehmen wir an, Sie wollen das Feld Land aus Ihrer Abfrage löschen. Rollen Sie dazu mit der horizontalen Bildlaufleiste nach rechts, bis Sie das Feld im Abfrageraster sehen können. 1. Klicken Sie auf den Spaltenmarkierer direkt über dem Feld. Die ganze Spalte sollte schwarz werden und der Mauszeiger wird zu einem nach unten zeigenden Pfeil. 2. Drücken Sie die (Entf)-Taste, um das Feld Land zu entfernen.
4.2.4
Ein Feld in eine bestehende Abfrage einfügen
Wie Sie ein Feld in eine bestehende Abfrage einfügen, hängt von der Position ab, an der Sie es platzieren wollen. Wenn Sie es an die vorhandenen Felder anfügen möchten, ist es am einfachsten, auf den Namen des hinzuzufügenden Feldes doppelzuklicken. Wollen Sie es zwischen bestehenden Feldern einfügen, klicken Sie es an und ziehen es auf das Feld rechts neben der ihm zugedachten Position.
Alles, was Sie über Abfragen wissen sollten
111
Klicken Sie auf das Feld Land und ziehen Sie es auf das Feld Telefon, um es zwischen den Feldern Position und Telefon einzufügen. Auf diese Weise erscheint das Feld an der richtigen Stelle. Starten Sie die Abfrage mit dem Symbol AUSFÜHREN.
4.2.5
Ein Feld an eine andere Position im Abfrageraster verschieben
Obwohl der Benutzer eine Spalte in der Datenblattansicht einer Abfrage verschieben kann, ist es manchmal vorteilhaft, die Position eines Feldes dauerhaft zu verändern, entweder um die Abfrage benutzerfreundlicher zu machen oder, was wesentlich wichtiger ist, weil Sie die Abfrage als Grundlage für ein Formular oder einen Bericht nehmen wollen. Die Reihenfolge der Felder in der Abfrage wird die standardmäßige Feldreihenfolge für alle Formulare und Berichte, die Sie mit Hilfe von Assistenten erstellen. Sie können sich selbst viel Zeit sparen, indem Sie die Abfragen umsichtig aufbauen. Beachten Sie die folgenden Schritte, um eine einzelne Spalte zu verschieben: 1. Um eine Spalte in der Entwurfsansicht einer Abfrage zu markieren, klicken Sie auf den Spaltenmarkierer (den Balken direkt über dem Feld). 2. Klicken Sie ein zweites Mal auf die ausgewählte Spalte und ziehen Sie sie auf ihre neue Position im Abfrageraster. Wenn Sie mehr als eine Spalte verschieben wollen, folgen Sie diesen Schritten: 1. Bewegen Sie den Mauszeiger auf den ersten Spaltenmarkierer und ziehen Sie ihn anschließend mit gehaltener linker Maustaste über die zu verschiebenden Felder. 2. Klicken Sie ein zweites Mal auf eine der ausgewählten Spalten und ziehen Sie sie auf ihre neue Position im Abfrageraster. Verschieben Sie die Felder Kontaktperson und Position so, dass Sie vor dem Feld Firma stehen. Klicken Sie auf den Spaltenmarkierer des Feldes Kontaktperson und ziehen Sie den Mauszeiger auf den Spaltenmarkierer des Feldes Position. Beide Spalten sollten nun ausgewählt sein. Klicken Sie erneut auf einen der Spaltenmarkierer und ziehen Sie, bis die dicke schwarze Linie links neben das Feld Firma
springt.
Das Verschieben einer Spalte in der Datenblattansicht ändert nicht ihren Entwurf. Wenn Sie eine Spalte in der Datenblattansicht verschoben haben, wirken sich spätere Änderungen der Reihenfolge im Entwurf nicht mehr auf die Datenblattansicht aus. Mit anderen Worten: Die Entwurfs- und die Datenblattansicht sind danach nicht mehr synchronisiert, so dass Sie beide per Hand ordnen müssen. Dies bringt in den meisten
112
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Fällen Vorteile. Wie Sie später lernen werden, muss das Feld Land in der Entwurfsansicht links vom Feld Firma stehen, wenn Sie zum Beispiel erst nach dem Feld Land und dann nach dem Feld Firma sortieren wollen. Wenn Sie bei der Ausgabe Firma vor Land stehen haben wollen, können Sie diese Änderung in der Datenblattansicht vornehmen. Durch diese getrennte Verwaltung der Reihenfolgen können Sie leicht beiden Ansprüchen gerecht werden.
4.2.6
Ihre Abfrage speichern und benennen
Sie können Ihre Abfrage jederzeit mit dem Symbol SPEICHERN aus der Symbolleiste abspeichern. Handelt es sich um eine neue Abfrage, werden Sie aufgefordert, einen Namen einzugeben. Für Abfragenamen sollten Sie mit dem Kürzel qry (Query) oder abf (Abfrage) beginnen, damit Sie sie später leicht wiedererkennen können. Das Interessante hierbei ist, dass Sie nicht das Ergebnis einer Abfrage, sondern nur ihre Definition speichern. Öffnen Sie die Entwurfsansicht Ihrer Abfrage. Klicken Sie in der Symbolleiste auf SPEICHERN. Wenn Sie nach einem Namen gefragt werden, nennen Sie die Abfrage qryKunden.
4.3
Ihr Abfrage-Ergebnis sortieren
Wenn Sie eine neue Abfrage öffnen, werden Sie feststellen, dass diese keine bestimmte Sortierung aufweist. Normalerweise wollen Sie sie jedoch sortieren. Dazu wird die Zeile SORTIERUNG des Abfragerasters benutzt. Die folgenden Schritte zeigen, wie eine Abfrage sortiert wird: 1. Klicken Sie im Abfrageraster in der Spalte auf die Zeile SORTIERUNG, die Sie sortieren wollen (siehe Abbildung 4.6).
Abbildung 4.6: Die Sortierreihenfolge des AbfrageErgebnisses ändern
Ihre Abfrage mit Hilfe von Kriterien verbessern
113
2. Benutzen Sie die Auswahlliste, um festzulegen, ob Sie eine auf- oder eine absteigende Sortierung wünschen. Die folgenden Schritte sortieren Ihre Abfrage in aufsteigender Reihenfolge nach dem Feld Position: 1. Klicken Sie auf die Zeile SORTIERUNG in der Spalte Position im Abfrageraster. 2. Öffnen Sie die Auswahlliste der Sortierrichtungen. 3. Wählen Sie Aufsteigend. 4. Starten Sie die Abfrage und überprüfen Sie, ob sie nach der Position sortiert ist. 5. Klicken Sie in der Symbolleiste auf ANSICHT, um zur Entwurfsansicht zurückzukehren.
4.3.1
Nach mehreren Feldern sortieren
Oftmals wollen Sie eine Tabelle nach mehr als einem Feld sortieren. Die Spalten, nach denen sortiert werden soll, müssen im Abfrageraster von links nach rechts angeordnet sein. Die Spalte mit der höchsten Sortierpriorität muss ganz links stehen, die anderen jeweils rechts daneben. Wenn Sie bei der Ausgabe eine andere Reihenfolge der Spalten wünschen, müssen Sie sie in der Datenblattansicht manuell verschieben, nachdem Sie die Abfrage ausgeführt haben. 1. Wählen Sie das Feld Land mit dem Spaltenmarkierer. 2. Wenn Sie es markiert haben, ziehen Sie es mit der Maus auf die Position links vom Feld Position. Dabei sollte dort eine dicke schwarze Linie erscheinen. 3. Lassen Sie die Maustaste los. 4. Legen Sie für das Feld Land eine aufsteigende Sortierung fest. 5. Starten Sie die Abfrage. Die Datensätze sollten nach Ländern und innerhalb eines Landes nach Titeln geo3rdnet sein.
4.4
Ihre Abfrage mit Hilfe von Kriterien verbessern
Sie haben bis jetzt gelernt, wie Sie für Ihre Abfrage bestimmte Felder auswählen und Sortierungen festlegen können. Eine der wichtigsten Funktionen von Abfragen besteht darin, die ausgegebene Datenmenge durch Auswahlkriterien zu verkleinern. Access gibt Ihnen die Möglichkeit, verschiedene Bedingungen in verschiedenen Feldern zu kombinieren. Für die Bedingungen stehen Ihnen Operatoren zur Verfügung, deren Bedeutungen in der folgenden Tabelle beschrieben sind:
114
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Operator
Bedeutung
Beispiel
Ergebnis
=
Gleich
="Vertrieb"
Findet nur die Datensätze mit dem Feldinhalt »Vertrieb«
<
Kleiner als
<100
Findet alle Datensätze mit einem Wert kleiner als 100 in diesem Feld
<=
Kleiner oder gleich
<=100
Findet alle Datensätze mit dem Wert 100 oder einem kleineren Wert in diesem Feld
>
Größer als
>100
Findet alle Datensätze mit einem Wert größer als 100 in diesem Feld
>=
Größer oder gleich
>=100
Findet alle Datensätze mit dem Wert 100 oder einem größeren Wert in diesem Feld
<>
Ungleich
<>"Vertrieb"
Findet alle Datensätze mit einem anderen Wert als »Vertrieb« in diesem Feld
And (Und)
Beide Bedingungen müssen erfüllt sein
Wird dadurch erstellt, Findet alle Datensätze, die beide dass in mehreren Fel- Bedingungen erfüllen dern derselben Zeile des Abfragerasters Kriterien angegeben werden
Or (Oder)
Eine der Bedin- "CA" or "NY" or "UT" gungen muss wahr sein
Findet alle Datensätze, die den Wert CA, NY oder UT in diesem Feld aufweisen
Like (Wie)
Vergleicht eine Like "Vertrieb*" Zeichenkette mit einem Muster
Findet alle Datensätze, bei denen der Inhalt des Feldes mit »Vertrieb« beginnt
Between (Zwischen)
Findet einen Bereich von Werten
Between 5 and 10
Findet alle Datensätze mit Werten von 5 bis 10 (einschließlich)
In
Wie or
In ("CA","NY","UT")
Findet alle Datensätze, die den Wert »CA«, »NY« oder »UT« in diesem Feld aufweisen
Tabelle 4.1: Access-Operatoren und ihre Bedeutung
115
Ihre Abfrage mit Hilfe von Kriterien verbessern
Operator
Bedeutung
Beispiel
Ergebnis
Not (Nicht)
Wie Ungleich
Not "Vertrieb"
Findet alle Datensätze mit einem anderen Wert als »Vertrieb« in diesem Feld
Is Null (Ist Null)
Findet Leerfelder
Is Null
Findet alle Datensätze, bei denen nichts in diesem Feld steht
Is not Null (Ist nicht Null)
Findet alle nicht Is Not Null leeren Felder
Findet alle Datensätze, bei denen etwas in diesem Feld steht
Tabelle 4.1: Access-Operatoren und ihre Bedeutung (Forts.)
Kriterien, die in zwei Felder der gleichen Zeile eingegeben wurden, werden mit Und verknüpft. Das bedeutet, es müssen beide Bedingungen erfüllt sein, damit der Datensatz in das Abfrage-Ergebnis aufgenommen wird. Einträge in verschiedenen Zeilen gelten als mit Oder verknüpft, d.h. es muss nur eine dieser Bedingungen erfüllt sein, damit der Datensatz im Abfrage-Ergebnis erscheint. Betrachten Sie das Beispiel in Abbildung 4.7. Diese Abfrage gibt alle Datensätze aus, die im Feld Position mit »Marketing« oder »Inhaber« beginnen, egal welche Kunden-Codes diese haben. Zusätzlich werden alle die Datensätze ausgegeben, deren Wert im Feld Position mit »Vertrieb« beginnt und deren Kundennummer zwischen den Buchstaben M und R liegt (einschließlich).
Abbildung 4.7: Einer Abfrage UND- und ODERBedingungen hinzufügen
Erstellen Sie eine Abfrage, um alle Vertriebsagenten in Brasilien und Frankreich zu finden. Die Kriterien sollten wie in Abbildung 4.8 aussehen.
116
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
1. Beachten Sie, dass das Kriterium für das Land "Brasilien" oder "Frankreich" ist, da Sie die Vertriebsagenten aus beiden Ländern ausgeben wollen. Das Kriterium lautet für die Position »Vertriebsagent«. Da beide Kriterien in der gleichen Zeile des Abfragerasters stehen, müssen sie auch beide erfüllt sein, damit der Datensatz ausgegeben wird. Das bedeutet, der Kunde muss Vertriebsagent sein und aus Brasilien oder Frankreich kommen. 2. Ändern Sie die Abfrage so, dass sie alle Kunden ausgibt, deren Position mit »Vertrieb« beginnt. Versuchen Sie, das Kriterium für die Position in "Vertrieb" zu ändern. Sie werden feststellen, dass die Ausgabe leer bleibt, da keine Position nur aus »Vertrieb« besteht. Sie müssen "Wie Vertrieb*" eingeben. Jetzt erst werden Vertriebsagenten, Vertriebsmanager, Vertriebsmitarbeiter und so weiter angezeigt. Allerdings wäre es auf diese Weise noch nicht möglich, eine Position wie »Stellvertretender Vertriebsagent« ausfindig zu machen. Gäbe es diese Position in der Nordwind-Datenbank, müssten Sie als Kriterium Wie "*Vertrieb*" eingeben, um die entsprechenden Datensätze anzuzeigen.
Abbildung 4.8: Die Kriterien zum Auswählen von Vertriebsagenten, deren Heimatland entweder Brasilien oder Frankreich ist
4.5
In Kriterien mit Datumsangaben arbeiten
Access gibt Ihnen die Möglichkeit, Datumsfunktionen und Ausdrücke in Ihren Abfragekriterien zu verwenden. Mit solchen Kriterien können Sie alle Datensätze eines bestimmten Monats, eines bestimmten Tags eines Zeitraumes bestimmen. Tabelle 4.2 zeigt einige Beispiele.
In Kriterien mit Datumsangaben arbeiten
117
Ausdruck
Bedeutung
Beispiel
Ergebnis
Date() bzw. Datum()
Aktuelles Datum
Date()
Alle Datensätze mit dem aktuellen Datum in diesem Feld
Day(Date) bzw. Tag(Datum)
Der Tag des Datums
Day([Bestelldatum])=1
Alle Datensätze mit Bestelldatum am Ersten eines Monats
Month(Date) bzw. Monat(Datum)
Der Monat des Datums
Month([Bestelldatum])=1
Alle Datensätze mit Bestelldatum im Januar
Year(Date) bzw. Jahr(Datum)
Das Jahr des Datums
Year([Bestelldatum])=1999
Alle Datensätze mit Bestelldatum im Jahr 1999
Weekday(Date) bzw. Wochentag(Datum)
Der Wochentag des Datums
Weekday([Bestelldatum])=2
Alle Datensätze mit Bestelldatum an einem Montag
Between #1/1/98# and #12/31/98#
Alle Datensätze mit Bestelldatum im Jahr 1998
Between Date and Date Eine Zeitspanne bzw. Zwischen Datum und Datum DatePart(Interval, Date) bzw. DatTeil (Intervall; Datum)
Ein bestimmter Teil eines Datums
DatePart("q";[Bestel Alle Datensätze mit ldatum])=2 Bestelldatum im zwei-
ten Quartal
Tabelle 4.2: Beispiele für Datumsangaben in Kriterien
Die Funktion Wochentag(Datum; [ErsterWochentag]) greift auf die Ländereinstellung Ihres Systems zu und bestimmt, welchen Wochentag Sie als Wochenbeginn festgelegt haben. Benutzen Sie die Funktion Wochentag( ) ohne das optionale Argument ErsterWochentag, wird standardmäßig der Sonntag als Wochenbeginn betrachtet. Setzen Sie beim Funktionsaufruf den Wert 0 für das Argument ErsterWochentag, wird der Wochenbeginn Ihrer Systemeinstellung verwendet. Mit den Werten 1 bis 7 können Sie den Wochenbeginn auch beliebig setzen (siehe Online-Hilfe zu Wochentag ()). Abbildung 4.9 zeigt Datumsfunktionen im Einsatz. Beachten Sie, dass DatTeil("q",[Bestelldatum]) als Ausdruck und der Wert 2 als Kriterium eingegeben ist. Ebenso stellt Jahr([Bestelldatum]) den Ausdruck und die Zahl 1995 ein Kriterium dar. Diese Abfrage wird folglich alle Datensätze ausgeben, deren Bestelldatum im zweiten Quartal 1995 liegt.
118
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Abbildung 4.9: Die Funktionen DatTeil() bzw. DatePart() und Jahr() bzw. Year() in einer Abfrage verwenden
4.6
Abfrage-Ergebnisse aktualisieren
Falls Sie es noch nicht wissen: Abfrage-Ergebnisse können normalerweise aktualisiert werden. Das bedeutet, dass mit den Daten in einem Abfrage-Ergebnis auch die Daten der zu Grunde liegenden Tabellen geändert werden. Erstellen Sie eine Abfrage auf der Tabelle Kunden. Ziehen Sie die Felder Kunden-Code, Firma, Straße, Ort und Region in das Abfrageraster und führen Sie die Abfrage aus. Nehmen Sie nun an den Daten eines Kunden eine Änderung vor und merken Sie sich seinen Kunden-Code. Verlassen Sie diesen Datensatz, damit er gespeichert wird. Schließen Sie jetzt die Abfrage und öffnen Sie die Tabelle Kunden. Sie werden sehen, dass die Änderung, die Sie in der Abfrage vorgenommen haben, in der Tabelle gespeichert worden ist. Dies ist der Fall, weil das Ergebnis einer Abfrage eine dynamische Datensatzgruppe ist, die mit den Daten der Originaltabelle verbunden bleibt. Dabei ist es egal, ob Sie auf einem Einzelplatzrechner oder im Netzwerk arbeiten. Es ist wichtig, dass Sie verstehen, wie Abfrage-Ergebnisse aktualisiert werden. Ansonsten könnten Sie versehentlich die Daten in Ihren Tabellen ändern, ohne es zu merken. Wie Abfragen aktualisiert werden, denen mehrere Tabellen zu Grunde liegen, wird später in diesem Kapitel in den Abschnitten » Potentielle Schwierigkeiten bei Abfragen, die auf mehreren Tabellen basieren« und »Automatische Anpassung bei Abfragen, die auf mehreren Tabellen basieren« erklärt.
Abfragen auf der Grundlage mehrerer Tabellen erstellen
4.7
119
Abfragen auf der Grundlage mehrerer Tabellen erstellen
Wenn Sie Ihre Daten auf mehrere Tabellen aufgeteilt haben, wollen Sie sie natürlich auch wieder zusammenfügen. Mit Access-Abfragen ist das glücklicherweise sehr einfach. Die Abfrage in Abbildung 4.10 verbindet die Tabellen Kunden, Bestellungen und Bestelldetails. Sie enthält Felder von jeder dieser drei Tabellen. Beachten Sie, dass die Felder Kunden-Code und Firma aus der Tabelle Kunden, die Felder Bestellnummer und Bestelldatum aus der Tabelle Bestellungen und die Felder Einzelpreis und Anzahl aus der Tabelle Bestelldetails stammen. Wenn Sie die Abfrage ausführen, sehen Sie das in Abbildung 4.11 gezeigte Ergebnis. Beachten Sie, dass im AbfrageErgebnis für jeden Datensatz aus der Tabelle Bestelldetails ein Datensatz vorhanden ist. Mit anderen Worten, es gibt 2155 Datensätze in der Tabelle Bestelldetails, und genauso viele Datensätze liefert auch diese Abfrage. Mit einer solchen auf mehrere Tabellen zugreifenden Abfrage können Sie die Daten aus der Tabelle Bestelldetails zusammen mit Daten der zugehörigen Tabellen sehen.
Abbildung 4.10: Eine Abfrage, welche die Tabellen Kunden, Bestellungen und Bestelldetails vereint
Abbildung 4.11: Die Ergebnisse der Abfrage mehrerer Tabellen
120
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Erstellen Sie eine Abfrage, die wie das eben gezeigte Beispiel Daten aus den Tabellen Kunden, Bestellungen und Bestelldetails enthält. Mit den folgenden Schritten können Sie eine solche Abfrage aufbauen: 1. Wählen Sie im Datenbankfenster die Registerkarte ABFRAGEN. 2. Klicken Sie auf NEU. 3. Wählen Sie Entwurfsansicht. 4. Klicken Sie im Dialogfeld TABELLE ANZEIGEN bei gedrückter (Strg)-Taste auf die Tabellen Kunden, Bestellungen und Bestelldetails, um sie auszuwählen. Klicken Sie anschließend auf Hinzufügen. 5. Schließen Sie das Dialogfeld. 6. Möglicherweise sind einige in der Abfrage enthaltene Tabellen nicht zu sehen. Benutzen Sie in diesem Fall die vertikale Bildlaufleiste, um alle Tabellen sichtbar zu machen. Beachten Sie die Verbindungslinien zwischen den Tabellen. Diese entsprechen den Beziehungen, die im Fenster BEZIEHUNGEN eingerichtet wurden. 7. Wählen Sie aus den Tabellen die folgenden Felder aus: Kunden: Land, Ort Bestellungen: Bestelldatum Bestelldetails: Einzelpreis, Anzahl
8. Sortieren Sie die Abfrage nach dem Land und in zweiter Instanz nach dem Ort. Wenn Sie fertig sind, sollte Ihr Entwurf wie in Abbildung 4.12 aussehen. 9. Führen Sie die Abfrage aus. Sie werden Daten aus allen drei Tabellen im Abfrage-Ergebnis vorfinden. Um eine Tabelle aus einer Abfrage zu entfernen, reicht es, die Tabelle im oberen Teil des Entwurfsfensters anzuklicken und die (Entf)-Taste zu drücken. Sie können jederzeit Tabellen zu einer Abfrage hinzufügen, indem Sie in der Symbolleiste auf das Symbol TABELLE ANZEIGEN klicken. Sie können auch das Datenbankfenster anklicken und dann von dort aus Tabellen direkt in den oberen Teil des Abfrage-Entwurfsfensters ziehen.
121
Abfragen auf der Grundlage mehrerer Tabellen erstellen
Abbildung 4.12: Der AbfrageEntwurf aus dem Beispiel
4.7.1
Potentielle Schwierigkeiten bei Abfragen, die auf mehreren Tabellen beruhen
Bei Abfragen, die auf mehreren Tabellen basieren, müssen Sie auf ein paar potentielle Schwierigkeiten Acht geben. Dies betrifft das Aktualisieren und die Frage, welche Datensätze im Abfrage-Ergebnis stehen. Sie werden sich erinnern, dass einige Felder in einer solchen Abfrage nicht geändert werden können. Wenn Sie referentielle Integrität zwischen zwei Tabellen eingerichtet, die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD jedoch nicht ausgewählt haben, kann das verknüpfte Feld auf der 1-Seite einer 1:n-Beziehung nicht geändert werden. Gleiches gilt für das entsprechende Feld auf der n-Seite einer Beziehung, wenn die Daten auf der 1-Seite bereits geändert wurden. Wichtiger ist jedoch, welche Felder geändert werden können. Die Auswirkungen davon können überraschend sein. Wenn Sie ein Feld auf der 1-Seite einer Beziehung ändern, müssen Sie die Tragweite dieser Änderung bedenken. Sie verändern nicht nur den Datensatz auf der 1-Seite der Beziehung, sondern auch die ihm zugehörigen Datensätze auf der n-Seite. Abbildung 4.13 zeigt ein Beispiel für eine solche Änderung. Sie stellt die oben beschriebene Abfrage mit den Tabellen Kunden, Bestellungen und Bestelldetails dar. Ich habe in einem Datensatz des Abfrage-Ergebnisses »Alfreds Futterkiste« in »Waldos Futterkiste« geändert. Sie erwarten wahrscheinlich, dass der Name nur in diesem Bestelldetail geändert wird. Nachdem ich nun die (¼)-Taste gedrückt habe, um den Datensatz zu verlassen, wurden alle Datensätze mit der Firma »Alfreds Futterkiste« aktualisiert (siehe Abbildung 4.14). Dies passiert, weil alle Bestellungen von Alfreds Futterkiste diese Information aus einem Datensatz der Tabelle Kunden mit dem Kunden-Code »ALFKI« beziehen.
122
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Abbildung 4.13: Ändern eines Datensatzes auf der 1-Seite einer 1:n-Beziehung; von der Aktualisierung des Firmennamens sind alle Datensätze mit demselben Kunden-Code betroffen
Abbildung 4.14: Ändern eines Datensatzes auf der 1-Seite einer 1:n-Beziehung; beachten Sie, dass das Feld Firma für alle Datensätze aktualisiert wurde, deren Feld Kunden-Code den Eintrag ALFKI aufweist
Versuchen Sie doch einmal, den Eintrag im Feld Ort eines der Datensätze zu ändern. Sie werden merken, dass außer diesem auch noch andere Datensätze geändert werden, da das Feld Ort aus der Tabelle auf der 1-Seite der 1:n-Beziehung stammt. Wenn Sie die Werte in den Feldern Ort und Land aller Bestellungen und Bestelldetails eines Kunden betrachten, kommen diese Werte aus einem einzigen Datensatz auf der 1-Seite. Dasselbe gilt für das Feld Bestelldatum. Dieses steht auch auf der 1-Seite einer 1:n-Beziehung. Das einzige Feld in dem Abfrage-Ergebnis, das nicht geändert werden kann, ist Gesamtpreis, da es ein berechnetes Feld ist. Probieren Sie weiter, Daten im Abfrage-Ergebnis zu verändern und prüfen Sie, welche Datensätze der Originaltabellen dadurch geändert werden.
Abfragen auf der Grundlage mehrerer Tabellen erstellen
123
Die zweite Schwierigkeit mit Abfragen, die auf mehreren Tabellen basieren, besteht darin zu erkennen, welche Datensätze das Ergebnis bilden. Sie haben bis jetzt nur gelernt, innere Verknüpfungen zu erstellen. Innere Verknüpfungen werden ausführlich in Kapitel 11 behandelt, doch Sie sollten verstehen, dass die Abfrage nur solche Kunden und Bestellungen ausgibt, zu denen Bestellungen bzw. Bestelldetails vorhanden sind. Das bedeutet, dass nicht alle Kunden und Bestellungen aufgelistet sind. In Kapitel 11 werden Sie lernen, eine Abfrage zu erstellen, mit der Sie alle Kunden ausgeben können, egal ob für sie Bestellungen vorliegen oder nicht. Ebenso werden Sie dann ausschließlich die Kunden ohne Bestellungen auflisten können.
4.7.2
Automatische Anpassung bei Abfragen, die auf mehreren Tabellen beruhen
Die automatische Anpassung steht Ihnen in Access standardmäßig zur Verfügung. Wenn Sie Werte in Schlüsselfelder auf der n-Seite einer 1:n-Beziehung eingeben, passen sich die anderen Werte automatisch der übergeordneten Tabelle an. Die meisten Datenbankentwickler bezeichnen dies als »erzwungene referentielle Integrität«. Ein Wert in einem Fremdschlüssel muss zuerst auf der 1-Seite vorhanden sein, bevor er auf der n-Seite eingegeben werden kann. Wie Sie sich vorstellen können, ist es nicht wünschenswert, dass die Möglichkeit besteht, Bestellungen für nicht vorhandene Kunden einzugeben. Zum Beispiel basiert die Abfrage in Abbildung 4.15 auf den Tabellen Kunden und Bestellungen. Die in der Abfrage enthaltenen Felder sind (in dieser Reihenfolge) das Feld Kunden-Code aus Bestellungen, die Felder Firma, Straße und Ort aus der Tabelle Kunden sowie die Felder Bestellnummer und Bestelldatum erneut aus der Tabelle Bestellungen. Wenn im Abfrage-Ergebnis nun der Kunden-Code einer Bestellung geändert wird, aktualisiert Access die Felder Firma, Straße und Ort sofort mit den zu dem neuen Kunden-Code gehörenden Werten aus der Tabelle Kunden. Abbildung 4.16 zeigt, wie diese Werte für Alfreds Futterkiste im Abfrage-Ergebnis dargestellt werden. In Abbildung 4.17 wurden die Felder Firma und Straße mit der Änderung des Kunden-Codes automatisch aktualisiert. Lassen Sie sich von dem Kombinationsfeld für die Auswahl eines Kunden nicht verwirren. Seine Verwendung innerhalb der Abfrage resultiert aus der automatischen Suchfunktion von Access. Mehr über diese Funktion erfahren Sie in Kapitel 2. Tatsächlich wurde der Kunden-Code einer bestimmten Bestellung in der Abfrage geändert. Wenn Sie einen neuen Datensatz einfügen, werden die Kundeninformationen in dem Moment automatisch ergänzt, in dem Sie den Kunden-Code der neuen Bestellung auswählen.
124
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Abbildung 4.15: Diese Abfrage veranschaulicht die Verwendung der automatischen Anpassung in einer Abfrage mit mehreren Tabellen
Abbildung 4.16: Das AbfrageErgebnis vor der Auswahl eines anderen KundenCodes Abbildung 4.17: Das Ergebnis einer automatischen Überprüfung nach dem Ändern eines Kunden-Codes; die Informationen auf der 1-Seite der Beziehung werden »angepasst«, um Angaben zum entsprechenden Kunden zu machen
Berechnete Felder erstellen
4.8
125
Berechnete Felder erstellen
Eine der Regeln für den optimalen Umgang mit Datenbanken besagt, dass Ergebnisse von Berechnungen nicht in ihr gespeichert sein sollten. Sie können die Ergebnisse von Berechnungen erhalten, indem Sie diese Berechnungen in Abfragen einbauen, und Sie können diese Ergebnisse mit Formularen und Berichten darstellen, die auf die entsprechenden Abfragen zugreifen. Des Weiteren haben Sie die Möglichkeit, den Formularen und Berichten mit den gewünschten Berechnungen Steuerelemente hinzuzufügen. Dies verbessert in manchen Fällen die Leistungsfähigkeit. (Dieses Thema wird in Kapitel 15 eingehender behandelt.) Die Spalten eines Abfrage-Ergebnisses können das Ergebnis jedes gültigen Ausdrucks beinhalten, einschließlich des Ergebnisses einer benutzerdefinierten Funktion. Dadurch werden Abfragen sehr vielseitig. Sie könnten zum Beispiel den folgenden Ausdruck eingeben: Links([Vorname],1) & "." " Links([Nachname],1) & "."
Dieser Ausdruck liefert jeweils den ersten Buchstaben des Vor- und Nachnamens gefolgt von einem Punkt. Ein noch einfacherer Ausdruck wäre folgender: [Einzelpreis]*[Anzahl]
Dieser Ausdruck berechnet einfach das Produkt aus den Werten der Felder Einzelpreis und Anzahl. In beiden Fällen würde Access dem Ergebnis automatisch einen Namen geben. Das Ergebnis der Berechnung, welche die jeweils ersten Buchstaben eines Namensteils ausgibt, wird in Abbildung 4.18 gezeigt. Beachten Sie, dass der Ausdruck in der Abbildung einen Namen bekommen hat. Um einen Ausdruck zu benennen, wie zum Beispiel mit der Bezeichnung Initialen, müssen Sie ihn wie folgt eingeben: Initialen: Links([Vorname],1) & "." " Links([Nachname],1) & "."
Abbildung 4.18: Das Ergebnis des Ausdrucks Initialen: Links([Vorname],1) & ».« & Links([Nachname,1] & ».« in der Abfrage
126
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Der Text vor dem Doppelpunkt ist der Name des Ausdrucks – in diesem Fall »Initialen«. Wenn Sie selbst keinen Namen angeben, verwendet Access die Bezeichnung »Ausdruck1«. 1. Führen Sie im Abfrageraster einen Bildlauf nach rechts durch, bis Sie eine leere Spalte sehen. 2. Klicken Sie in die Zeile Feld der neuen Spalte. 3. Geben Sie Gesamtpreis: Einzelpreis*Anzahl ein. Um die Eingabe an dieser Stelle etwas zu vereinfachen, drücken Sie die Tastenkombination (ª)+(F2) (Zoom). Daraufhin erscheint das in Abbildung 4.19 gezeigte Dialogfeld ZOOM. (Access fügt das Leerzeichen hinter dem Doppelpunkt und die eckigen Klammern um die Feldnamen automatisch hinzu, wenn Sie sie weglassen.) 4. Klicken Sie auf OK, um das Fenster ZOOM zu schließen. 5. Führen Sie die Abfrage aus. Das Produkt aus Einzelpreis und Anzahl, der Gesamtpreis, sollte, wie in Abbildung 4.20 gezeigt, in der Spalte rechts außen erscheinen.
Abbildung 4.19: Das Feld mit Hilfe der Zoom-Funktion (ª)+(F2) vergrößern
Sie können in der Zeile Feld des Abfragerasters jeden gültigen Ausdruck eingeben. In einem solchen Ausdruck enthaltene Feldnamen werden automatisch in eckige Klammern gesetzt, sofern sie keine Leerzeichen enthalten. Ist dies der Fall, müssen Sie den Feldnamen selbst in eckige Klammern setzen, da die Abfrage sonst nicht richtig funktionieren würde. Dies ist einer von vielen Gründen, warum Feld- und Tabellennamen keine Leerzeichen enthalten sollten.
Der Ausdrucks-Generator
127
Abbildung 4.20: Das Ergebnis der Gesamtpreisberechnung
4.9
Der Ausdrucks-Generator
Der Ausdrucks-Generator ist eine große Hilfe beim Erstellen von Ausdrücken in Abfragen und an vielen anderen Stellen in Access. Um seine Hilfe in Anspruch zu nehmen, klicken Sie in die Zeile Feld des Abfragerasters und dann in der Symbolleiste auf AUFBAUEN (siehe Abbildung 4.21). Beachten Sie, dass der AusdrucksGenerator in drei Spalten unterteilt ist. Die erste Spalte zeigt die Objekte Ihrer Datenbank. Nachdem Sie ein Objekt ausgewählt haben, können Sie in der mittleren und rechten Spalte das Element anklicken, das Sie in Ihrem Ausdruck benutzen wollen.
Abbildung 4.21: Der Ausdrucks-Generator erleichtert das Erstellen von Ausdrücken in Ihrer Abfrage
128
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Im in Abbildung 4.22 gezeigten Beispiel wurde in der linken Spalte das Objekt Funktionen ausgewählt. Dieses Objekt enthält Auflistungen der eingebauten und der benutzerdefinierten Funktionen. In diesem Beispiel wurde das Objekt Funktionen mit der Untergruppe Eingebaute Funktionen ausgewählt. In der mittleren Spalte wurde Datum/Uhrzeit markiert. Daraufhin wurden in der rechten Spalte alle Datums- und Uhrzeitfunktionen aufgelistet. Wenn Sie nun eine bestimmte Funktion doppelklicken, in diesem Fall die Funktion DatTeil, erscheinen die Funktion und ihre Parameter im Textfenster des Ausdruck-Generators. Diese Funktion besitzt vier Parameter: Intervall, Datum, ErsterWochentag und ErsteWoche. Wenn Sie wissen, welche Parameter Sie eingeben müssen, können Sie die Platzhalter einfach durch Ihre Werte ersetzen. Wenn Sie weitere Informationen brauchen, können Sie Hilfe zu jeder einzelnen Funktion erhalten und mehr über die Parameter erfahren. In Abbildung 4.23 wurden zwei Parameter eingegeben: das Intervall und der Name des zu analysierenden Feldes. Wenn Sie auf OK klicken, wird der so erstellte Ausdruck in Ihr Abfrageraster übernommen.
Abbildung 4.22: Der Ausdrucks-Generator mit ausgewählter und in das Ausdrucksfeld eingefügter DatTeil-Funktion
4.10
Daten mit Hilfe von Abfragen zusammenfassen
Sie können numerische Daten mit Hilfe von Abfragen auf einfache Weise zusammenfassen. Eine zusammenfassende Abfrage ermöglicht Ihnen die Berechnung der Summe, des Mittelwerts, der Anzahl, des Minimums, des Maximums und anderer zusammenfassender Größen für die Daten in Ihrem Abfrage-Ergebnis. Eine solche Abfrage lässt Sie einen Wert für alle Datensätze im Abfrage-Ergebnis berechnen oder berechnete Ergebnisse beliebig gruppieren. Zum Beispiel können Sie den gesamten Umsatz für alle Datensätze bestimmen, wie es in Abbildung 4.24 gezeigt wird, oder Sie geben den Gesamtumsatz für jede Stadt sortiert nach Ländern aus (siehe Abbil-
Daten mit Hilfe von Abfragen zusammenfassen
129
Abbildung 4.23: Eine vom Ausdrucks-Generator eingefügte Funktion mit den durch geeignete Werte aktualisierten Parametern
dung 4.25). Eine andere Möglichkeit besteht darin, den Mittelwert, den kleinsten oder den größten Bestellwert aller Kunden in den USA zu ermitteln. Die Möglichkeiten sind grenzenlos.
Abbildung 4.24: Gesamtumsatz für jeden Datensatz im AbfrageErgebnis
Um eine solche Abfrage zu erstellen, gehen Sie wie folgt vor: 1. Fügen Sie dem Abfrageraster die Felder oder Ausdrücke hinzu, die Sie aufsummieren möchten. Es ist wichtig, die Felder in der Reihenfolge einzufügen, in der Sie gruppiert werden sollen. Abbildung 4.26 zeigt eine Abfrage, die zuerst nach Ländern und dann nach Orten gruppiert ist. 2. Klicken Sie in der Symbolleiste auf FUNKTIONEN oder wählen Sie FUNKTIONEN aus dem Menü ANSICHT, um dem Abfrageraster eine Zeile für Funktionen hinzuzufügen. Die Voreinstellung in der neuen Zeile lautet für jedes Feld Gruppierung.
130
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Abbildung 4.25: Gesamtumsatz nach Land und Stadt
3. Klicken Sie im Abfrageraster auf die Zeile Funktionen. 4. Öffnen Sie das Kombinationsfeld, um die gewünschte Berechnungsart zu wählen. 5. Lassen Sie den Eintrag Gruppierung in der Zeile Funktionen für jedes Feld stehen, nach dem Sie die Abfrage gruppieren wollen (siehe Abbildung 4.26). Beachten Sie dabei die richtige Reihenfolge. Wenn Sie die Datensätze zum Beispiel nach Ländern und innerhalb eines Landes nach Kontaktpersonen gruppieren wollen, müssen Sie das Feld Land links vom Feld Kontaktperson platzieren. Wollen Sie allerdings die Umsätze der einzelnen Kontaktpersonen jeweils gruppiert nach Ländern ausgeben, müssen Sie die Felder in umgekehrter Reihenfolge anordnen.
Abbildung 4.26: Den Funktionstyp für die Funktionszeile aus einer Liste auswählen
6. Fügen Sie der Abfrage ggf. Kriterien hinzu. Abbildung 4.27 zeigt eine Abfrage, welche die Summe, den Mittelwert, das Maximum und die Anzahl aller Bestellungen geordnet nach Ländern und Städten errechnet. Die nächste Abbildung stellt ihr Ergebnis dar. Wie Sie sehen, liefert diese Abfrage wertvolle Informationen.
131
Daten mit Hilfe von Abfragen zusammenfassen
Abbildung 4.27: Eine Abfrage, welche die Summe, den Mittelwert, das Maximum und die Anzahl der Verkäufe nach Land und Stadt bestimmt
Abbildung 4.28: Das Ergebnis einer Abfrage mit vielen zusammenfassenden Funktionen
Wenn Sie diese Abfrage abspeichern und wieder öffnen, werden Sie feststellen, dass Access einige Änderungen an ihr vorgenommen hat. Das Feld Funktionen in der Summenspalte wurde in Ausdruck geändert, und in der ersten Zeile steht: Gesamtumsatz: Summe([Einzelpreis]*[Anzahl])
Das gleiche trifft auf die Spalte Mittelwert zu. Hier steht unter Feld Folgendes: Durchschnittsumsatz: Mittelwert ([Einzelpreis]*[Anzahl])
Access nimmt diese Änderungen immer vor, wenn Sie eine zusammenfassende Funktion für mehr als ein Feld der zu Grunde liegenden Tabellen verwenden. Sie können den Ausdruck auf beide Weisen eingeben, Access speichert und bewertet den Ausdruck wie angemerkt.
132
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Ändern Sie die Abfrage dahingehend, dass sie den Gesamtumsatz pro Land, Stadt und Bestelldatum anzeigt. Bevor Sie die Abfrage ausführen, speichern Sie sie als qryBestellstatistik ab und schließen sie. Wechseln Sie im Datenbankfenster zu den Abfragen und klicken Sie einmal auf qryBestellstatistik und dann nacheinander auf KOPIEREN und EINFÜGEN in der Symbolleiste. Access wird Sie nach einem Namen für die neue Abfrage fragen. Geben Sie qryBestellsumme ein, und bestätigen Sie dies. Markieren Sie diese Abfrage und betätigen Sie die Schaltfläche ENTWURF. Löschen Sie die Felder Einzelpreis und Anzahl aus dem Abfrage-Entwurf. Um die Abfrage nun zu einer Funktionsabfrage zu machen, folgen Sie diesen sechs Schritten: 1. Klicken Sie in der Symbolleiste auf FUNKTIONEN. Dadurch erscheint eine zusätzliche Zeile im Abfrageraster, die für jede Spalte den Wert Gruppierung enthält. 2. In den Feldern Land, Ort und Bestelldatum können Sie den Wert Gruppierung stehen lassen. Klicken Sie im Feld Gesamtumsatz, dem berechneten Feld, auf die Zeile Funktionen, um eine Auswahlliste zu öffnen (siehe Abbildung 4.26). Wählen Sie Summe. 3. Starten Sie die Abfrage. Das Ergebnis sollte nach Ländern, Orten und Bestelldaten geordnet sein und eine Summe für jede eindeutige Kombination dieser drei Felder enthalten. 4. Kehren Sie zur Entwurfsansicht zurück und löschen Sie das Feld Bestelldatum. 5. Führen Sie die Abfrage erneut aus. Jetzt erhalten Sie die Summen geordnet nach Ländern und Orten. 6. Ändern Sie die Funktion in Mittelwert. Nun berechnet die Abfrage jeweils den Mittelwert für alle Bestellungen jeder eindeutigen Kombination aus Land und Ort. Machen Sie die Änderung rückgängig und speichern Sie die Abfrage. Wie Sie sehen, sind zusammenfassende Abfragen sowohl leistungsfähig als auch flexibel. Zwar besteht keine Möglichkeit, ihre Ergebnisse zu bearbeiten, doch können Sie diesen Abfragetyp benutzen, um gleichzeitig die Summe, den Mittelwert, das Minimum, das Maximum und die Anzahl der Gesamtumsätze zu betrachten. Es bedarf lediglich eines Mausklicks, um festzulegen, ob diese nach dem Land, Land und Stadt usw. gruppiert werden sollen.
4.11
Felder aus der Ausgabe ausschließen
Unter gewissen Umständen benötigen Sie für Ihre Abfrage eine Spalte, die Sie nicht mit ins Abfrage-Ergebnis aufnehmen wollen. Dies ist oft der Fall, wenn eine Spalte nur für die Kriterien benötigt wird. Abbildung 4.29 zeigt ein solches Beispiel. Die dargestellte Abfrage würde die Summe, den Mittelwert und das Maximum aller Bestellungen geordnet nach Ländern und Bestelldaten ausgeben. Sie wollen jedoch
Nullwerte und Abfrage-Ergebnisse
133
nur zwischen den Ländern differenzieren und das Bestelldatum lediglich als Kriterium benutzen. Um dies zu erreichen, müssen Sie die Zeile Funktionen auf Bedingung setzen, wie es in Abbildung 4.30 gezeigt ist. Spalten, in denen die Funktion Bedingung verwendet wird, erscheinen nicht im Ergebnis. Sie können das schon im Entwurf daran erkennen, dass das Kontrollkästchen in der Zeile Anzeigen nicht markiert ist.
Abbildung 4.29: Eine Abfrage mit Kriterien für das Bestelldatum vor dem Ausschließen von Feldern aus der Abfrageausgabe
Abbildung 4.30: Die Funktionszeile des Feldes Bestelldatum ist auf Bedingung gesetzt, was das Feld aus dem Abfrage-Ergebnis ausschließt
4.12
Nullwerte und Abfrage-Ergebnisse
Nullwerte in Tabellen können Abfrage-Ergebnisse merklich beeinflussen. Ein Nullwert ist nicht das gleiche wie eine Null oder eine leere Zeichenfolge. In ein Feld mit dem Wert Null wurde bis jetzt noch kein Wert eingegeben. Wie schon in Kapitel 2 erwähnt, können Sie eine leere Zeichenfolge durch zwei Anführungszeichen eingeben.
134
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Nullwerte können die Ergebnisse von Abfragen, die auf mehreren Tabellen beruhen, Tabellen mit zusammenfassenden Funktionen (Zusammenfassungsabfragen) und Tabellen mit berechneten Feldern beeinflussen. Wenn Sie eine Abfrage mit mehreren Tabellen erstellen, werden auf der n-Seite standardmäßig nur die Datensätze berücksichtigt, die keinen Nullwert im Fremdschlüsselfeld enthalten. Dies gehört mit zu den Schwierigkeiten bei solchen Abfragen, über die wir in diesem Kapitel schon gesprochen haben. Abfragen mit zusammenfassenden Funktionen werden auf die gleiche Weise beeinflusst. Nur die Datensätze, die in dem zusammenzufassenden Feld keinen Nullwert haben, werden berücksichtigt. Wenn Sie zum Beispiel einmal die genaue Anzahl von Datensätzen bestimmen wollen, verwenden Sie am besten den Primärschlüssel oder ein ähnliches Feld, das definitionsgemäß keine Nullwerte enthalten kann. Das schwerwiegendste Problem mit Nullwerten tritt auf, wenn ein solcher Wert in einer Berechnung verwendet werden soll. Wenn ein Nullwert in einer Berechnung mit numerischen Operatoren (+, –, /, *...) auftritt, ist das Ergebnis automatisch wieder ein Nullwert. Abbildung 4.31 zeigt eine Abfrage mit einer solchen Berechnung. Die Werte in den Felder Parts und Labor werden addiert. Da für diese Felder kein Standardwert vorgegeben wurde, enthalten Sie einen Nullwert, bis in sie ein Wert eingegeben wird. Die Abfrage liefert das in Abbildung 4.32 gezeigte Ergebnis. Beachten Sie, dass alle Datensätze, die in einem der beiden aufzuaddierenden Felder einen Nullwert aufweisen, über keinen Ergebniswert verfügen.
Abbildung 4.31: Die Entwurfsansicht einer Abfrage, welche im AbfrageErgebnis Nullwerte enthält
Die Lösung für dieses Problem besteht darin, einen Ausdruck zu erstellen, der mögliche Nullwerte in Nullen ändert. Ein solcher Ausdruck könnte wie folgt aussehen: TotalCost: NZ([Parts]+NZ[Labor])
Nullwerte und Abfrage-Ergebnisse
135
Abbildung 4.32: Das Ergebnis einer Abfrage, die Nullwerte veranschaulicht
Die Funktion NZ erkennt Nullwerte in den beiden Feldern und ersetzt sie durch Nullen, die in der Berechnung verwendet werden können. Abbildung 4.33 zeigt das Ergebnis der so geänderten Abfrage.
Abbildung 4.33: Die Abfrage mit einem Ausdruck, der Nullwerte beseitigt
136
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Nullwerte können Ihnen große Schwierigkeiten bereiten, wenn sie in Abfragen vorkommen, auf denen andere Abfragen basieren – in diesem Fall tritt ein Schneeballeffekt auf. Ein solcher Fehler kann leicht übersehen werden, wodurch Sie falsche Ergebnisse bekommen. Mit der Funktion IsNull() werden Sie dieses Problem in den Griff bekommen. Mit dieser Funktion können Sie Nullwerte erkennen, um sie dann durch Nullen oder leere Zeichenfolgen zu ersetzen. Seien Sie hierbei jedoch vorsichtig, da dieser Schritt andere Teile Ihrer Abfrage beeinträchtigen könnte, die diesen Wert für eine andere Berechnung verwenden. Achten Sie auch darauf, Funktionen immer möglichst weit oben im Abfragebaum einzusetzen, da sie am unteren Ende eingesetzt die Geschwindigkeit Ihrer Abfrage stark beeinträchtigen. Ein »Abfragebaum« entsteht dadurch, dass Sie Abfragen auf der Grundlage anderer Abfragen erstellen. Kriterien oben zu platzieren bedeutet, sie in der höchsten (direkt auf die Tabellendaten zugreifenden) Abfrage einzusetzen.
4.13
Ihre Abfragen mit Hilfe von Feld-, Feldlistenund Abfrage-Eigenschaften verbessern
Mit den Eigenschaften von Feldern und Abfragen können Sie das Verhalten und das Erscheinungsbild der Spalten einer Abfrage und der Abfrage selbst bestimmen. Dazu gehen Sie wie folgt vor: 1. Klicken Sie im Entwurfsfenster zur Auswahl eines Feldes in das Feld, zur Auswahl einer Feldliste in die Feldliste und zur Auswahl der Abfrage an eine Stelle außerhalb eines Feldes oder der Feldliste. 2. Klicken Sie in der Symbolleiste auf EIGENSCHAFTEN. 3. Verändern Sie die gewünschten Eigenschaften.
4.13.1
Feldeigenschaften: Das Verhalten eines Feldes ändern
Die Eigenschaften eines Feldes in einer Abfrage umfassen eine Beschreibung, das Format, das Eingabeformat und die Beschriftung der Spalte. Die Beschreibung wird zur Dokumentation und zum Festlegen des Textes benutzt, der in der Statuszeile erscheint, wenn der Benutzer im Anfrage-Ergebnis in die Spalte klickt. Die Eigenschaft Format entspricht der gleichnamigen Eigenschaft eines Tabellenfeldes und ist für die Anzeige der Felder im Abfrage-Ergebnis zuständig. Das Eingabeformat steuert, wie bei einer Tabelle, wie der Benutzer im Abfrage-Ergebnis Daten eingibt oder verändert. Die Eigenschaft Beschriftung legt wie die entsprechende Eigenschaft eines Feldes auch die Beschriftung für die Spalte in der Datenblattansicht und die Standardbezeichnung für Formulare und Berichte fest. Sie fragen sich jetzt vielleicht, was mit den zu den Tabellen gehörenden Eigenschaften in einer Abfrage passiert. Wie verhält sich zum Beispiel die Beschriftung eines Feldes in einer Abfrage in Bezug auf die in der Tabelle festgelegte Eigenschaft dessel-
137
Ihre Abfragen verbessern
ben Feldes? Alle Eigenschaften werden aus der Tabelle automatisch in die Abfrage übernommen. Sie können sie dort natürlich überschreiben. Alle Objekte, die auf einer Abfrage basieren (andere Abfragen, Formulare, Berichte), greifen auf die Eigenschaften dieser Abfrage und nicht auf die der ursprünglichen Tabelle zurück. Beim Eingabeformat ist zu beachten, dass das Eingabeformat der Abfrage nicht im Widerspruch zur Tabelleneigenschaft stehen darf. Die Abfrage-Eigenschaft darf die Eigenschaft der Tabelle zwar einschränken, das Überschreiben ist jedoch nicht zulässig. Wenn zwischen beiden Eigenschaften ein Widerspruch besteht, wird der Benutzer in die Tabelle keine Daten ausgeben können.
4.13.2
Feldlisteneigenschaften: Die Eigenschaften der Feldliste ändern
Feldlisteneigenschaften dienen der Angabe von Attributen für jede der in der Abfrage benutzten Tabellen. Die beiden Eigenschaften sind Alias und Quelle. Die Eigenschaft Alias wird zumeist dann genutzt, wenn eine Tabelle in einer Abfrage mehrmals verwendet wird. Dies ist zum Beispiel bei Eigenverknüpfungen der Fall, die in Kapitel 11 behandelt werden. Die Eigenschaft Quelle wird benutzt, um die Schnittstellenadresse oder den Namen einer anderen Datenbank zu speichern, wenn Sie mit externen Tabellen arbeiten, die nicht mit der aktuellen Datenbank verbunden sind.
4.13.3
Abfrage-Eigenschaften: Das Verhalten der Gesamtabfrage ändern
Microsoft stellt Ihnen viele Eigenschaften zur Verfügung, mit denen Sie das Verhalten der gesamten Abfrage beeinflussen können (siehe Abbildung 4.34). Einige dieser Eigenschaften werden hier besprochen, auf die anderen wird anwendungsbezogen an verschiedenen Stellen dieses Buches eingegangen.
Abbildung 4.34: Abfrage-Eigenschaften, die das Verhalten einer gegebenen Abfrage beeinträchtigen
138
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Mit der Eigenschaft Beschreibung können Sie dokumentieren, was die Abfrage macht. Die Eigenschaft Spitzenwerte legt fest, wie viele der Datensätze mit den höchsten Werten angezeigt werden. Sie können eine absolute Zahl von anzuzeigenden Datensätzen oder einen Prozentwert angeben. Wenn Sie Alle Felder ausgeben auf Ja setzen, werden alle Spalten in der Abfrage ausgegeben, egal ob ihr Kontrollkästchen in der Zeile Anzeigen auf Ja oder Nein gesetzt ist. Die Eigenschaften Keine Duplikate und Eindeutige Datensätze bestimmen, ob nur Datensätze mit einem eindeutigen Wert oder insgesamt eindeutige Datensätze angezeigt werden. Diese Eigenschaften werden in Kapitel 11 näher beschrieben. Mit der Eigenschaft Recordsettyp legen Sie fest, ob in der Abfrage Änderungen vorgenommen werden können, die sich auf die zu Grunde liegende Tabelle auswirken. Standardmäßig steht der Recordsettyp auf Dynaset, wodurch Änderungen auch in die Quelldaten übernommen werden. Die Eigenschaft Ausführungsberechtigungen gehört zum Thema Sicherheit und wird in Kapitel 34 beschrieben. Die Eigenschaften Quelldatenbank, Quellverbindung, ODBCWartezeit und Max Datensätze sind für den Client-Server-Betrieb relevant und werden in Kapitel 19 besprochen. Datensätze sperren betrifft Mehrbenutzeranwendungen und wird in Kapitel 17 näher beschrieben. Die Eigenschaft Unterdatenblattname ermöglicht es Ihnen, eine andere Tabelle oder Abfrage anzugeben, die als von der Abfrage abhängiges Datenblatt mit ihr automatisch geöffnet wird. Nachdem Sie diese Eigenschaft gesetzt haben, können Sie die Eigenschaften Verknüpfen von und Verknüpfen nach verwenden, um die Felder der unter- oder übergeordneten Tabellen oder Abfragen festzulegen, über welche die Abfrage mit ihrem Unterdatenblatt verknüpft wird. Schließlich können Sie mit den Eigenschaften Unterdatenblatthöhe und Unterdatenblatt erweitert vorgeben, welche Höhe das abhängige Datenblatt maximal haben darf und ob es automatisch in einer erweiterten Form erscheinen soll.
4.14
Parameterabfragen, wenn die Kriterien beim Entwurf noch nicht bekannt sind
Es kann vorkommen, dass weder Sie noch der zukünftige Benutzer zum Zeitpunkt des Entwurfs die Abfrageparameter kennen. Parameterabfragen geben Ihnen die Möglichkeit, die Kriterien zur Laufzeit einzugeben, so dass Sie die Abfrage nicht immer ändern müssen, wenn Sie andere Kriterien verwenden möchten. Wenn Sie zum Beispiel einem Benutzer die Möglichkeit geben wollen, beim Start einer Abfrage einen Zeitraum festzulegen, der als Kriterium benutzt werden soll, können Sie das wie in Abbildung 4.35 gezeigt realisieren. Die folgende Bedingung stellt das Kriterium für das Feld Bestelldatum dar: Zwischen [Startdatum eingeben] und [Enddatum eingeben]
139
Parameterabfragen, wenn die Kriterien beim Entwurf noch nicht bekannt sind
Abbildung 4.35: Diese Parameterabfrage fordert die Eingabe eines Start- und eines Enddatums
Dieses Kriterium hat das Erscheinen von zwei Dialogfeldern beim Start der Abfrage zur Folge. Das erste fordert den Benutzer auf, das Startdatum einzugeben, und verwendet dabei den Text in den eckigen Klammern (siehe Abbildung 4.36). Das zweite Dialogfeld fordert den Benutzer schließlich auf, das einzugeben, was im zweiten Klammerpaar angegeben ist. Die Eingaben des Benutzers werden als Kriterium für die Abfrage benutzt.
Abbildung 4.36: Dieses Dialogfeld erscheint beim Ausführen der Parameterabfrage
Fügen Sie der Abfrage qryKundenBestellübersicht einen Parameter hinzu, so dass Sie nur Zusammenfassungen zu einem bestimmten Wertebereich angezeigt bekommen. Gehen Sie zu den Kriterien des Feldes Gesamtpreis und geben Sie den folgenden Ausdruck ein: Zwischen [Bitte Startwert eingeben] und [Bitte Höchstwert eingeben]
Diese Zeile erlaubt es Ihnen, alle Datensätze mit einem Gesamtpreis innerhalb des festgelegten Wertebereichs zu sehen. Der eingeklammerte Text wird zur Laufzeit der Abfrage durch die eingegebenen Werte ersetzt. Um sicherzustellen, dass Access Ihre Werte in den Parametern richtig interpretiert, müssen Sie die Parameter vorher definieren. Wählen Sie den Befehl PARAMETER aus
140
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
dem Menü ABFRAGEN, um das Fenster ABFRAGEPARAMETER zu öffnen. Sie können auch mit der rechten Maustaste in den grauen Bereich der oberen Hälfte des Abfrage-Entwurfsfensters klicken und PARAMETER aus dem erscheinenden Kontextmenü auswählen. Der Text in den Klammern muss in der Spalte PARAMETER des Dialogfeldes stehen. In der Spalte FELDDATENTYP müssen Sie den Datentyp der einzugebenden Parameterwerte festlegen. Abbildung 4.37 zeigt ein Beispiel für fertig definierte Parameter.
Abbildung 4.37: Dieses ausgefüllte Dialogfeld Abfrageparameter deklariert zwei Datumsparameter
Sie können beliebig viele Parameter für beliebig viele Felder festlegen und das Hinzufügen von Parametern funktioniert genauso wie das Hinzufügen von Kriterien. Die Abfrage in Abbildung 4.38 besitzt Parameter für die Felder Position, Einstellung und Ort in der Tabelle Personal der Nordwind-Datenbank. Beachten Sie, dass alle Kriterien in derselben Zeile stehen. Die Datensätze müssen also alle über Parameter eingegebenen Kriterien erfüllen, um angezeigt zu werden. Das Kriterium für die Spalte Position lautet [Bitte Position eingeben]. Das bedeutet, dass die Datensätze in der Ergebnismenge beim Ausführen der Abfrage die eingegebene Position enthalten müssen. Für das Feld Einstellung gilt das Kriterium >=[Bitte Startdatum der Einstellung eingeben]. Nur Datensätze mit einem Einstellungsdatum, das nach dem eingegebenen kommt oder ihm entspricht, erfüllen diese Bedingung. Das letzte Kriterium im Feld Ort, [Bitte Ort eingeben], lässt nur Datensätze mit dem gewünschten Ort zu. Ein Abfragekriterium kann auch das Ergebnis einer Funktion sein. Diese Möglichkeit wird Ihnen in Kapitel 11 eröffnet. Parameterabfragen bieten eine überwältigende Flexibilität. Der Benutzer kann zur Laufzeit ein Kriterium seiner Wahl eingeben. Der Ausdruck im Dialogfeld Abfrageparameter muss genau mit dem Text in den eckigen Klammern übereinstimmen; anderenfalls verlangt Access zusätzliche Eingaben.
Parameterabfragen, wenn die Kriterien beim Entwurf noch nicht bekannt sind
141
Abbildung 4.38: Das AbfrageEntwurfsfenster mit einer Abfrage, die Parameter für drei Felder enthält
Sie können zwar so viele Parameter definieren, wie Sie wollen, zu viele Abfragen können dem Benutzer jedoch schnell lästig werden. Es ist wesentlich benutzerfreundlicher, ein Formular zur Eingabe der Parameterwerte zu erstellen. Wie Sie dabei verfahren, wird in Kapitel 10 beschrieben.
4.14.1
Für die Praxis
Abfragen erstellen, die von der Consulting-Firma im Zeit- und Abrechnungssystem benötigt werden Erzeugen Sie eine Abfrage, die auf der Tabelle tblTimeCardHours basiert und die Gesamtrechnungssumme eines Projekts in einem bestimmten Zeitraum ausgibt. Der Entwurf der Abfrage ist in Abbildung 4.39 zu sehen. Wie Sie der Abbildung entnehmen können, handelt es sich bei der Abfrage um eine Zusammenstellung, welche die Daten nach Projekten gruppiert und den folgenden Ausdruck verwendet: BillAmount: Summe[BillableHours]*[BillingRate]
Das Feld DateWorked (geleistete Arbeitstage) wird als Bedingung genutzt und enthält den Ausdruck: Zwischen [Enter Start Date] und [Enter End Date]
Abbildung 4.39: Der Entwurf der Abfrage qryBillAmountByProject
142
Kapitel 4: Was jeder Entwickler über Abfragen wissen sollte
Die beiden Parameter werden in dem in Abbildung 4.40 dargestellten Dialogfeld ABFRAGEPARAMETER definiert. Speichern Sie die Abfrage als qryBillAmountByProject.
Abbildung 4.40: Das Parameterfenster für qryBillAmountByProject
Die zweite Abfrage greift auf die Tabellen tblClients (Kundentabelle), tblProjects (Projekttabelle) und erneut auf tblTimeCardHours zu und gibt die Gesamtrechnungssumme in einem einzugebenden Zeitraum für jeden einzelnen Kunden aus. Die Abfrage, deren Entwurf in Abbildung 4.41 zu sehen ist, wird nach dem Feld CompanyName (Firmenname) aus tblClients gruppiert und mit folgendem Ausdruck summiert: BillAmount: Summe[BillableHours]*[BillingRate]
Wie in der ersten Abfrage wird das Feld DateWorked als Kriterium benutzt und die Parameter sind wieder im Fenster ABFRAGEPAREMETER definiert. Diese Abfragen finden Sie auf der beiliegenden CD-ROM in einer Datenbank namens CHAP4.MDB. Sie werden noch viele Abfragen zum Zeit- und Abrechnungssystem des Consulting-Unternehmens hinzufügen.
Abbildung 4.41: Der Entwurf der Abfrage qryBillAmountByClient
Was jeder Entwickler über Formulare wissen sollte
Kapitel
Hier lesen Sie:
Wie Sie Formulare verwenden Der Formularaufbau Der Formular-Assistent Zum Formularentwicklungsfenster Geeignete Steuerelemente Ein Steuerelement ersetzen Über bedingte Formatierung Formulareigenschaften Steuerelementeigenschaften Gebundene, ungebundene, berechnete Steuerelemente Formulare über Ausdrücke erweitern Die Befehlsschaltflächen-Assistenten Formulare auf Basis mehrerer Tabellen Formulare auf Abfragen aufsetzen Access-Formulare und das Internet
5.1
Verwendungen für Formulare
Entwickler glauben oft, dass Formulare ausschließlich der Dateneingabe dienen. Tatsächlich können Sie Formulare in Access 2000 aber für viele Zwecke verwenden:
Dateneingabe – Anzeige und Änderung von Daten Programmablauf – Navigieren durch die Anwendung
144
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Benutzerdefinierte Dialogfelder – Nachrichten an den Benutzer ausgeben Informationen drucken – Ausdrucke von Dateneingabe-Informationen erstellen Am weitesten verbreitet ist wahrscheinlich der Gebrauch von Access-Formularen zum Anzeigen und Bearbeiten bestehender oder zum Eingeben neuer Daten. Glücklicherweise unterstützt Access viele Funktionen, mit denen Sie Formulare erstellen können, die Ihren Benutzern die Dateneingabe erleichtern. Access macht es auch einfach für Sie, Formulare zu entwerfen, mit denen Ihre Benutzer Daten ansehen und bearbeiten, nur ansehen, aber nicht bearbeiten oder ausschließlich neue Daten eingeben können. Man kommt nicht unbedingt sofort darauf, dass ein Access-Formular zum Navigieren durch die Anwendung dienen kann, aber die Möglichkeiten dazu sind sehr ausgeprägt. Abbildung 5.1 zeigt ein Formular, das mit dem Übersichts-Manager in Access 2000 erstellt wurde, und Abbildung 5.2 eine benutzerdefinierte Übersicht. Obwohl der Übersichts-Manager den Entwurf von Übersichts-Formularen sehr vereinfacht, werden Sie feststellen, dass jede Art von Übersicht problemlos zu erstellen ist. Sie können sehr kreativ sein, indem Sie Übersichts-Formulare entwerfen, die ebenso zweckmäßig wie ansprechend sind. Übersichts-Formulare werden detailliert in Kapitel 9 behandelt.
Abbildung 5.1: Ein Formular, das mit dem Übersichts-Manager erstellt wurde
Sie können Access auch verwenden, um benutzerdefinierte Dialogfelder zu erstellen, die Informationen anzeigen oder der Dateneingabe dienen. Das benutzerdefinierte Dialogfeld in Abbildung 5.3 dient der Eingabe der Parameter für einen Bericht. Der Benutzer oder die Benutzerin muss die erforderlichen Informationen eingeben, bevor er oder sie fortfahren kann.
Verwendungen für Formulare
145
Abbildung 5.2: Eine benutzerdefinierte Übersicht mit Kurzhinweisen und Bitmaps
Abbildung 5.3: Ein benutzerdefiniertes Dialogfeld, mit dessen Hilfe der Benutzer einen Datumsbereich für einen Bericht festlegen kann
Eine weitere Stärke von Access liegt in seiner Fähigkeit zum Erzeugen professionell aussehender Druckausgaben. Bei vielen anderen Produkten ist es schwierig, ein Dateneingabeformular auszudrucken – manchmal muss das gesamte Formular für einen Bericht umgestaltet werden. In Access ist das Drucken eines Formulars Sache eines einfachen Schaltflächendrucks, verbunden mit etwas Code. Sie haben die Wahl, einen Bericht zu erstellen, der die eingegebenen Informationen anzeigt, oder das Formular selbst zu drucken. Access bietet viele Arten von Formularen. Sie können in einem Formular einen Datensatz zur Zeit anzeigen oder den Benutzer mehrere gleichzeitig sehen lassen. Formulare können gebunden angezeigt werden, was bedeutet, dass der Benutzer antworten und das Formular schließen muss, bevor er weiterarbeiten kann, oder so erscheinen, dass der Benutzer sich nach Belieben durch die offenen Formulare bewegen kann. Bitte merken Sie sich, dass es viele Nutzungsmöglichkeiten und Arten von Formularen gibt. Sie werden sie in diesem Kapitel, in Kapitel 9 und im gesamten Buch näher kennen lernen. Wenn Sie dieses Kapitel lesen, denken Sie daran, dass die Gestaltung Ihrer Formulare lediglich durch Ihre Vorstellungskraft eingeschränkt ist.
146
5.2
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Aufbau eines Formulars
Access-Formulare bestehen aus wenigen unterschiedlichen Abschnitten. Jeder hat seine Funktion und Verhaltensweise. Die drei Hauptabschnitte eines Access-Formulars sind:
Kopf Detailbereich Fuß Der Detailbereich eines Formulars ist der Hauptabschnitt – er wird gebraucht, um die Daten aus der Tabelle oder der Abfrage darzustellen, die dem Formular zu Grunde liegt. Sie werden sehen, dass der Detailbereich viele verschiedene Formen annehmen kann. Er ist ziemlich flexibel und robust. Die Kopf- und Fußabschnitte eines Formulars zeigen Informationen, die nicht von Datensatz zu Datensatz wechseln. Befehlsschaltflächen, die das Formular steuern, wie zum Beipiel eine, die den Benutzer alle Projekte eines bestimmten Kunden sehen lässt, werden oft im Kopf- oder Fußbereich eines Formulars angeordnet. Steuerelemente können auch benutzt werden, um den Benutzer durch die zum Formular gehörenden Datensätze wandern zu lassen. Im Beispiel in Abbildung 5.4 kann der Benutzer aus einer gültigen Kundenliste auswählen. Nachdem ein Kunde aus dem Kombinationsfeld ausgewählt wurde, wird dem Benutzer der entsprechende Datensatz angezeigt.
Abbildung 5.4: Datensatzsteuerung mit Hilfe eines Kombinationsfeldes im Formularkopf
Ein neues Formular erstellen
5.3
147
Ein neues Formular erstellen
Sie können Formulare auf unterschiedliche Arten erstellen. Der gebräuchlichste Weg ist die Auswahl des Formularsymbols aus der Objektliste im Datenbankfenster. Sie können dann die Option ERSTELLT EIN FORMULAR IN DER ENTWURFSANSICHT oder ERSTELLT EIN FORMULAR UNTER VERWENDUNG DES ASSISTENTEN auswählen. Ein anderer Weg zum Erzeugen eines Formulars besteht darin, in der Objektliste auf FORMULARE und dann auf die Befehlsschaltfläche NEU zu klicken. Wenn Sie ein Formular mit dieser Methode erstellen, erscheint das Dialogfeld NEUES FORMULAR. Dieses Dialogfeld erlaubt Ihnen die Auswahl aus der ganzen Vielfalt der Möglichkeiten, die es gibt, um neue Formulare zu erstellen (siehe Abbildung 5.5). Formulare können über die Entwurfsansicht oder mit Hilfe eines der sechs Assistenten erstellt werden. Die Assistenten werden im Folgenden kurz vorgestellt, anschließend wird das Erstellen eines neuen Formulars beschrieben. Selbst die erfahrensten Entwickler benutzen den Formular-Assistenten für gewisse Aufgaben.
Abbildung 5.5: Im Dialogfeld Neues Formular können Sie die Tabelle oder Abfrage festlegen, die dem Formular zu Grunde liegen soll, und die Methode zum Erstellen des Formulars auswählen
5.3.1
Ein Formular mit dem Formular-Assistenten erstellen
Wenn Sie ein Formular mit dem Formular-Assistenten erstellen wollen, wählen Sie in der Formularliste, die Sie durch Anklicken von FORMULARE in der Symbolleiste erreichen, das Symbol ERSTELLT EIN FORMULAR UNTER VERWENDUNG DES ASSISTENTEN oder im Dialogfeld NEUES FORMULAR die Option FORMULAR-ASSISTENT und klicken dann auf OK. Der erste Schritt des Formular-Assistenten fragt Sie nach dem Namen der Tabelle oder Abfrage, die Sie als Grundlage des Formulars verwenden wollen. Egal, ob Sie ein Formular mit dem Formular-Assistenten oder in der Entwurfsansicht erstellen möchten, es ist grundsätzlich besser, ein Formular auf einer Abfrage aufzubauen. Das Verwenden einer Abfrage als Grundlage für ein Formular bietet schnellere Zugriffe (außer wenn Ihr Formular alle Felder und alle Datensätze erfordert), erlaubt größere Flexibilität und lässt es zu, dass Sie das Formular auf der Grundlage mehrerer Tabellen erstellen.
148
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Abbildung 5.6 zeigt das aufklappbare Listenfeld TABELLEN/ABFRAGEN. Sie können sehen, dass alle Tabellen aufgeführt sind, gefolgt von allen Abfragen. Nachdem Sie eine Tabelle oder Abfrage ausgewählt haben, werden die zugehörigen Felder im Listenfeld links angezeigt (siehe Abbildung 5.7). Um die Felder auszuwählen, die Sie im Formular verwenden wollen, doppelklicken Sie auf den Namen des Feldes oder auf das Feld und anschließend auf die Schaltfläche >. In dem Beispiel in Abbildung 5.7 wurden mehrere Felder aus der Abfrage qryClients ausgewählt.
Abbildung 5.6: Eine Liste mit Tabellen und Abfragen, die zur Benutzung im FormularAssistenten zur Verfügung steht
Abbildung 5.7: Ausgewählte Felder aus der Abfrage qryClients
Ein neues Formular erstellen
149
Nachdem Sie die gewünschten Felder ausgewählt haben, klicken Sie auf WEITER. Der zweite Schritt des Formular-Assistenten erlaubt Ihnen, das gewünschte Layout für Ihr Formular anzugeben. Sie können zwischen EINSPALTIG, TABELLARISCH, DATENBLATT oder IN BLÖCKEN wählen, doch die gebräuchlichste Wahl ist EINSPALTIG. Klicken Sie auf WEITER, nachdem Sie ein Formularlayout ausgewählt haben. Im dritten Schritt des Formular-Assistenten können Sie eines von mehreren vordefinierten Formaten für Ihr Formular auswählen (siehe Abbildung 5.8). Zwar können alle Eigenschaften, die durch den Formular-Assistenten festgelegt worden sind, nach dem Erstellen des Formulars in der Entwurfsansicht geändert werden, aber um Zeit zu sparen, ist es am besten, das richtige Format jetzt auszuwählen. Klicken Sie auf WEITER, nachdem Sie sich für ein Format entschieden haben.
Abbildung 5.8: Ein Formularformat auswählen
Im letzten Schritt des Formular-Assistenten geben Sie einen Titel für Ihr Formular an. (Wenn Sie den Standardwert stehen lassen, bekommt das Formular denselben Namen wie die zu Grunde liegende Tabelle oder Abfrage, was zu Verwirrung führen kann.) Unglücklicherweise wird der Titel des Formulars gleichzeitig auch sein Name. Geben Sie deshalb den Text ein, den Sie als Namen des Formulars verwenden wollen. Wenn Sie der standardmäßigen Namensvergabe folgen wollen, sollten Sie den Namen des Formulars mit der Bezeichnung »frm« beginnen. Vielleicht haben Sie Bedenken hinsichtlich der Änderung des Titels in der Entwurfsansicht des Formulars. In diesem Schritt des Formular-Assistenten können Sie entscheiden, ob Sie das Ergebnis Ihrer Arbeit sehen oder das Formular in der Entwurfsansicht öffnen wollen. Es ist meistens am besten, das Ergebnis zu betrachten und den Formularentwurf zu bearbeiten, nachdem Sie einen Blick auf die Arbeit des Formular-Assistenten geworfen haben.
150
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Ein anderer Weg, um den Formular-Assistenten zu starten, besteht darin, in der Objektliste auf das TABELLEN- oder ABFRAGEN-Symbol und anschließend auf die Tabelle oder Abfrage zu klicken, die dem Formular zu Grunde liegen soll. Wählen Sie im aufklappbaren Listenfeld NEUES OBJEKT die Option FORMULAR, um das Dialogfeld NEUES FORMULAR zu öffnen. Wählen Sie dort FORMULAR-ASSISTENT. In diesem Fall brauchen Sie nicht das Listenfeld TABELLEN/ABFRAGEN zu benutzen, um eine Tabelle oder Abfrage auszuwählen. Die Tabelle oder Abfrage, die Sie vor Aufruf des Formular-Assistenten ausgewählt hatten, wird automatisch verwendet.
5.3.2
Ein Formular in der Entwurfsansicht erstellen
Auch wenn die Formular-Assistenten leistungsfähig und nützlich sind, werden Sie es dennoch in vielen Fällen bevorzugen, ein Formular von Grund auf zu entwerfen, insbesondere wenn Sie ein Formular erstellen, das nicht mit Daten verknüpft ist. Um ein Formular ohne den Assistenten zu erstellen, klicken Sie in der Objektliste auf FORMULAR. Doppelklicken Sie das Symbol ERSTELLT EIN FORMULAR IN DER ENTWURFSANSICHT oder klicken Sie die Schaltfläche NEU, um das Dialogfeld NEUES FORMULAR zu öffnen, und wählen Sie dort ENTWURFSANSICHT (die Standardauswahl). Falls Sie NEU geklickt haben, um das Dialogfeld NEUES FORMULAR zu öffnen, und Ihr Formular an Daten gebunden ist, wählen Sie aus dem Listenfeld im Dialogfeld NEUES FORMULAR die zu Grunde liegende Tabelle oder Abfrage aus. Klicken Sie auf OK, um in das Formularentwurfsfenster zu gelangen (siehe Abbildung 5.9).
Abbildung 5.9: Benutzen Sie das Formularentwurfsfenster, um ein Formular zu erstellen und anzupassen
Mit dem Formularentwurfsfenster umgehen
5.4
151
Mit dem Formularentwurfsfenster umgehen
Das Formularentwurfsfenster wird benutzt, um ein Formular zu erstellen und anzupassen. Mit diesem Fenster können Sie Objekte zu einem Formular hinzufügen und sie über das Eigenschaftenfenster anpassen. Microsoft hat viele Formular- und Steuerelementeigenschaften definiert. Wenn Sie diese Eigenschaften beherrschen, können Sie das Erscheinungsbild und die Funktionalität Ihrer Formulare maßschneidern.
5.4.1
Die Werkzeuge des Formularentwurfsfensters
Auch der beste Entwickler braucht die richtigen Werkzeuge für seine Arbeit. Glücklicherweise gibt Microsoft Ihnen Werkzeuge an die Hand, mit denen Sie ebenso ansprechende wie zweckmäßige Formulare erstellen können. Das Formularentwurfsfenster beinhaltet eine Symbolleiste, eine Toolbox und das Formular, das Sie gerade entwerfen. Weitere Werkzeuge sind verfügbar, um Ihnen bei der Entwurfsarbeit zu helfen, einschließlich der Feldliste und des Eigenschaftenfensters. Standardmäßig erscheinen zwei Symbolleisten, wenn Sie sich in der Entwurfsansicht eines Formulars befinden: die Symbolleiste FORMULARENTWURF und FORMATIERUNG. Die Symbolleiste FORMULARENTWURF besitzt Schaltflächen zum Sichern, Drucken, Kopieren, Ausschneiden, Einfügen und Durchführen anderer Standardaufgaben innerhalb des Formulars. Außerdem beinhaltet sie Schaltflächen, die es Ihnen erlauben, die verschiedenen Entwurfsfenster (wie z.B. die Toolbox) ein- und auszublenden. Die Symbolleiste FORMATIERUNG besitzt Schaltflächen für die grafische Bearbeitung der Eigenschaften und Objekte des Formulars. Sie können die Schrift, die Schriftgröße und die Farbe ausgewählter Objekte auf dem Formular verändern. Die Symbolleiste FORMATIERUNG bietet Ihnen außerdem die Möglichkeit, Text mit den Formaten Fett, Unterstrichen und Kursiv zu versehen, die Ausrichtung zu ändern und ausgewählten Objekten Spezialeffekte hinzuzufügen. Die benötigten Werkzeuge ein- und ausblenden Es stehen Ihnen mehrere Felder zur Verfügung, die Ihnen beim Formularentwurf helfen, wenn Sie sich in der Entwurfsansicht befinden. In Abhängigkeit davon, ob Sie einen hochauflösenden Monitor besitzen, finden Sie es möglicherweise lästig, wenn alle Fenster gleichzeitig geöffnet sind. Tatsächlich macht das Formular bei einer niedrigen Bildschirmauflösung und vielen geöffneten Fenstern eher den Eindruck, als wäre es unter all den Fenstern begraben. Dies ist der Grund, weshalb Microsoft dafür gesorgt hat, dass Sie jedes Fensters ein- und ausblenden können. Die Symbolleiste FORMULARENTWURF enthält Schaltflächen für die Feldliste, die Toolbox und das Eigenschaftenfenster, die eben diesem Zweck dienen. Das erste Anklicken öffnet das jeweilige Fenster, das zweite schließt es. Abbildung 5.10 zeigt ein Formular, bei dem die Feldliste, die Toolbox und das Eigenschaftenfenster geöffnet sind. Obwohl die Größe jedes Fensters nach Belieben einstellbar ist (und die Toolbox an der Ecke eines Fenster festgemacht werden kann), ist
152
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
die Entwurfsumgebung auf diesem niedrig auflösenden Bildschirm mit all diesen offenen Fenstern völlig überfrachtet. Einer der Tricks beim Arbeiten mit Access besteht darin zu wissen, wann es sinnvoll ist, jede Werkzeugsammlung verfügbar zu haben. Das Ziel besteht darin, möglichst oft das richtige Fenster zur richtigen Zeit offen zu haben. Die Feldliste, die Toolbox und das Eigenschaftenfenster können durch Betätigen der Umschaltflächen in der Symbolleiste, über die Schaltfläche SCHLIESSEN jedes Fensters oder über das Menü ANSICHT ausgeblendet werden.
Abbildung 5.10: Formularentwurf mit angezeigten Entwurfsfenstern
5.4.2
Dem Formular Felder hinzufügen
Felder können einem Formular ganz einfach mit Hilfe der Feldliste hinzugefügt werden, welche alle Felder enthält, die zur Datenquelle des Formulars gehören. So ist z.B. die Datenquelle des Formulars in Abbildung 5.10 die Abfrage qryClients. In der Feldliste werden die Felder aufgeführt, die Bestandteil der Abfrage sind. Zwei Schritte sind nötig, um ein Feld zu einem Formular hinzuzufügen: 1. Stellen Sie sicher, dass die Feldliste sichtbar ist. Klicken Sie andernfalls auf die Schaltfläche FELDLISTE in der Symbolleiste. 2. Finden Sie das Feld, das Sie zu dem Formular hinzufügen wollen, klicken Sie es an und ziehen Sie es von der Feldliste an die Stelle im Formular, wo es erscheinen soll. Der gewählte Platz wird die obere linke Ecke des Textfeldes und die zugehörige Bezeichnung erscheint links davon.
Mit dem Formularentwurfsfenster umgehen
153
Ein Steuerelement ist ein Objekt, das Sie zu einem Formular oder einem Bericht hinzufügen können. Steuerelemente sind u.a. Textfelder, Kombinationsfelder, Listenfelder und Auswahlfelder. Um mehrere Felder gleichzeitig zu einem Formular hinzuzufügen, können Sie mehrere Felder aus der Feldliste auswählen. Drücken Sie die (Strg)-Taste, um Felder auszuwählen, die nicht aufeinander folgen, oder die (ª)-Taste zur Auswahl von aufeinander folgenden Feldern. Halten Sie beispielsweise die (Strg)-Taste gedrückt und klicken Sie auf drei nicht aufeinander folgende Felder. Jedes Feld wird markiert. Klicken Sie nun auf ein Feld, halten Sie die (ª)-Taste gedrückt und klicken Sie auf ein anderes Feld. Dadurch werden alle Felder dazwischen ausgewählt. Wenn Sie alle Felder auswählen wollen, doppelklicken Sie auf die Kopfzeile der Feldliste. Klicken Sie dann auf irgendeines der markierten Felder und ziehen Sie es auf das Formular, woraufhin alle markierten Felder auf einmal zum Formular hinzugefügt werden.
5.4.3
Formularobjekte auswählen, verschieben, ausrichten und in der Größe verändern
Sie sollten einige wichtige Kniffe kennenlernen, wenn Sie Formularobjekte auswählen, verschieben, ausrichten oder ihre Größe festlegen. Diese Kniffe werden Ihnen Stunden von Frustration und verschwendeter Zeit ersparen. Formularobjekte auswählen Der einfachste Weg, ein einzelnes Objekt auszuwählen, besteht darin, es anzuklicken. Nachdem das Objekt ausgewählt ist, können Sie es verschieben und zum Beispiel seine Größe oder seine Eigenschaften bearbeiten. Das Auswählen mehrerer Objekte ist etwas schwieriger und kann auf verschiedene Arten erfolgen. Welche Methode am sinnvollsten ist, ergibt sich aus der jeweiligen Situation. Um mehrere Objekte auszuwählen, können Sie die (ª)-Taste drücken und jedes auszuwählende Objekt anklicken. Jedes ausgewählte Objekt wird von Anfassern umgeben, die anzeigen, dass es ausgewählt ist. Abbildung 5.11 zeigt ein Formular mit vier ausgewählten Objekten. Es ist wichtig zu wissen, welche Objekte tatsächlich ausgewählt sind. In diesem Fall sind dies das Textfeld ClientID, das Text- und Bezeichnungsfeld Address sowie die Bezeichnung CompanyName, während das Bezeichnungsfeld ClientID und das Textfeld CompanyName nicht ausgewählt sind. Wenn Sie die Abbildung genau betrachten, werden Sie feststellen, dass die ausgewählten Objekte vollständig von Anfassern umgeben sind. Das Bezeichnungsfeld ClientID und das Textfeld CompanyName haben einfache Anfasser, weil sie zu ausgewählten Objekten gehören. Wenn Sie irgendeine Eigenschaft der ausgewählten Objekte ändern, werden diese beiden Felder dadurch nicht beeinträchtigt.
154
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Abbildung 5.11: Objekte auf einem Formular auswählen
Sie können Objekte auch mit Hilfe eines Rahmens auswählen, sofern sie auf dem Formular benachbart liegen. Bewegen Sie den Mauszeiger zu einer leeren Stelle auf dem Formular (nicht über ein Objekt), klicken Sie und ziehen Sie dann den Rahmen auf. Sie können nun eine feine Linie um die Objekte sehen, die Ihr Rahmen umgibt. Wenn Sie loslassen, werden alle Objekte innerhalb des Rahmens ausgewählt, auch wenn sie nur teilweise eingekreist waren. Wenn Sie für irgendein Objekt die Auswahl aufheben wollen, halten Sie die (ª)-Taste gedrückt und klicken auf das Objekt, für das Sie die Auswahl aufheben möchten. Einer der elegantesten Wege, mehrere Objekte auszuwählen, ist der Gebrauch der waagerechten und senkrechten Lineale, die an den Rändern des Formularentwurfsfensters zu sehen sind. Klicken und ziehen Sie innerhalb des Lineals. Wenn Sie innerhalb des senkrechten Lineals klicken und die Maus bewegen, erscheinen zwei senkrechte Linien, die den Auswahlbereich anzeigen. Wenn Sie die Maustaste loslassen, werden alle Objekte innerhalb der Linien ausgewählt. Genau wie beim Auswählen von Objekten mit Hilfe eines Rahmens können Sie die Auswahl für einzelne Objekte aufheben, indem Sie die (ª)-Taste gedrückt halten und das entsprechende Objekt anklicken. Objekte verschieben Um ein einzelnes Steuerelement zusammen mit seinem Bezeichnungsfeld zu verschieben, brauchen Sie es nicht vorher auszuwählen. Bewegen Sie Ihre Maus über das Objekt, klicken Sie es an und ziehen Sie. Es erscheint ein Umriss, der die neue Position des Objekts anzeigt. Wenn das Objekt an der gewünschten Stelle ist, lassen Sie die Maustaste los. Das Bezeichnungsfeld bewegt sich zusammen mit dem zugehörigen Steuerelement. Um mehrere Objekte gleichzeitig zu verschieben, müssen Sie die zu verschiebenden Objekte erst auswählen. Benutzen Sie dazu eine der im vorigen Abschnitt beschrie-
Mit dem Formularentwurfsfenster umgehen
155
benen Methoden. Bewegen Sie Ihre Maus über irgendeines der ausgewählten Objekte, klicken und ziehen Sie. Es erscheint ein Umriss, der die neuen Positionen der Objekte anzeigt. Wenn die Objekte an der gewünschten Stelle sind, lassen Sie die Maustaste los. Eine besondere Technik ist nötig, wenn Sie ein Steuerelement unabhängig von seinem zugehörigen Bezeichnungsfeld verschieben wollen. Wenn Sie ein Steuerelement anklicken, z.B. ein Textfeld, und die Maus über die Begrenzung dieses Steuerelements bewegen, erscheint ein Symbol in Form einer Hand mit fünf aufwärts zeigenden Fingern. Wenn Sie das Objekt nun anklicken und ziehen, werden Steuerelement und zugehöriges Bezeichnungsfeld als Einheit verschoben, wobei ihre Beziehung zueinander erhalten bleibt. Wenn Sie den Mauszeiger über den größeren Anfasser in der oberen linken Ecke des Objekts bewegen, erscheint er als Hand, bei der nur der Zeigefinger aufwärts zeigt. Wenn Sie jetzt klicken und ziehen, wird das Steuerelement unabhängig von seinem Bezeichnungsfeld verschoben und die Beziehung dieser Felder zueinander ändert sich. Objekte aneinander ausrichten Access macht es einfach, Objekte auszurichten. Abbildung 5.12 zeigt einige nicht ausgerichtete Objekte. Beachten Sie, dass die gebundenen Bezeichnungsfelder dreier Objekte ausgewählt sind. Wenn Sie diese Bezeichnungsfelder ausrichten, bleiben die Steuerelemente (in diesem Fall Textfelder) an ihren ursprünglichen Positionen. Wenn Sie die Textfelder ebenfalls auswählen, werden diese versuchen, sich an den Bezeichnungsfeldern auszurichten. Weil Access keine Überlappung von Objekten zulässt, enden die Textfelder unmittelbar neben ihren Bezeichnungsfeldern. Zum linksbündigen Ausrichten beliebiger Objekte (auch solcher unterschiedlicher Art) wählen Sie die gewünschten Objekte aus und klicken AUF FORMAT|AUSRICHTEN|LINKSBÜNDIG oder Sie klicken mit der rechten Maustaste auf die Objekte und wählen AUSRICHTEN|LINKSBÜNDIG. Die ausgewählten Objekte werden daraufhin ausgerichtet (siehe Abbildung 5.13). Sie können die linke, rechte, obere oder untere Kante aller Objekte auf einem Formular ausrichten. Es ist nützlich, die Entwurfswerkzeuge, die Sie üblicherweise benutzen, zur Symbolleiste hinzuzufügen.
Verwechseln Sie nicht den Menübefehl FORMAT|AUSRICHTEN mit den Ausrichtungswerkzeugen in der Symbolleiste FORMATIERUNG. FORMAT|AUSRICHTEN richtet Objekte aneinander aus, während die Werkzeuge in der Symbolleiste den Text eines Objekts innerhalb seiner Begrenzung ausrichten.
156
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Abbildung 5.12: Das Formular vor dem Ausrichten der Objekte
Abbildung 5.13: Das Formular nach dem Ausrichten der Objekte
Am Raster ausrichten Die Funktion AM RASTER AUSRICHTEN entscheidet darüber, ob sich Objekte an den Rasterlinien auf dem Formular ausrichten, wenn Sie sie verschieben oder ihre Größe anpassen. Sie finden diese Funktion im Menü FORMAT. Wenn Sie die Funktion deaktivieren, können Sie die Objekte ohne Rücksicht auf die Rasterlinien verschieben. Ich bevorzuge es, das Merkmal AM RASTER AUSRICHTEN ständig eingeschaltet zu lassen. Um diese Funktion gegebenenfalls vorübergehend auszuschalten, benutze ich einen besonderen Trick – lassen Sie die (Strg)-Taste gedrückt, wenn Sie Objekte anklicken und verschieben. Das Merkmal AM RASTER AUSRICHTEN wird ignoriert.
Mit dem Formularentwurfsfenster umgehen
157
Fortgeschrittene Techniken zur Änderung der Objektgröße Genauso wie es verschiedene Möglichkeiten gibt, Objekte zu verschieben, gibt es auch mehrere Wege zum Ändern der Objektgröße. Wenn ein Objekt ausgewählt ist, kann jeder Anfasser außer dem in der oberen linken Ecke des Objekts zum Ändern der Größe benutzt werden. Die Anfasser oben und unten am Objekt erlauben die Änderung der Höhe und die links und rechts die der Breite. Mit den Anfassern in der oberen rechten, unteren rechten und unteren linken Ecke können Sie Höhe und Breite gleichzeitig anpassen. Zum Ändern der Objektgröße bewegen Sie den Mauszeiger auf einen der Anfasser, klicken und ziehen. Sie können mehrere Objekte auswählen und ihre Größe auf einmal anpassen. Jedes der ausgewählten Objekte wächst oder schrumpft um den gleichen Betrag, wobei ihr Größenverhältnis erhalten bleibt. Access bietet mehrere leistungsstarke Möglichkeiten, die Größe mehrerer Objekte anzupassen. Diese finden Sie unter FORMAT|GRÖSSE :
An Textgröße: Passt die Objektgröße an den Text im Objekt an Am Raster: Passt die Objektgröße an die nächstgelegenen Rasterlinien an Am Höchsten: Passt die Objektgröße an die Höhe des höchsten ausgewählten Objekts an
Am Niedrigsten: Passt die Objektgröße an die Höhe des niedrigsten ausgewählten Objekts an
Am Breitesten: Passt die Objektgröße an die Breite des breitesten ausgewählten Objekts an
Am Schmalsten: Passt die Objektgröße an die Breite des schmalsten ausgewählten Objekts an Etwas verwirrend ist dabei die Option FORMAT|GRÖSSE|AN TEXTGRÖSSE. Tatsächlich wird die Größe des Textfeldes nicht perfekt an die Größe des darin enthaltenen Textes angepasst, denn in einer Umgebung mit proportionalen Schriften ist es unmöglich, ein Textfeld an den größten denkbaren Eintrag anzugleichen. Im Allgemeinen können Sie aber Textfelder mit einer vernünftigen Höhe und Breite ausstatten. Verwenden Sie die Eigenschaft FELDGRÖSSE, um den eingebbaren Text zu begrenzen. Wenn die Eingabe für den zugewiesenen Platz zu groß ist, kann der Benutzer den zusätzlichen Text per Bildlauf betrachten. Wie der nächste Tipp zeigt, ist FORMAT|GRÖSSE|AN TEXTGRÖSSE EHER FÜR BEZEICHNUNGS- ALS FÜR TEXTFELDER GEEIGNET. Um die Größe eines BEZEICHNUNGSFELDES schnell an seinen Text anzupassen, wählen Sie es aus und doppelklicken auf einen der Anfasser mit Ausnahme desjenigen in der oberen linken Ecke.
158
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Den Objektabstand steuern Access bietet Ihnen ausgezeichnete Werkzeuge, um die Objekte auf Ihrem Formular in gleichmäßigem Abstand voneinander anzuordnen. Um den vertikalen Abstand zwischen ausgewählten Objekten anzugleichen, wählen Sie FORMAT|VERTIKALER ABSTAND|ANGLEICHEN. In Abbildung 5.15 sehen Sie das Ergebnis der Anwendung dieses Befehls auf die ausgewählten Objekte aus Abbildung 5.14.
Abbildung 5.14: Das Formular vor dem Verändern des vertikalen Abstands
Der horizontale Abstand zwischen Objekten kann ausgeglichen werden durch FORABSTAND|ANGLEICHEN. Verwandte Befehle sind FORMAT|VERTIKALER ABSTAND|VERGRÖSSERN (oder VERKLEINERN) und FORMAT|HORIZONTALER ABSTAND|VERGRÖSSERN (oder VERKLEINERN). Diese Befehle erhalten die Beziehung zwischen Objekten, während deren Abstand im gleichen Verhältnis vergrößert oder verkleinert wird. MAT|HORIZONTALER
5.4.4
Die Aktivierreihenfolge der Objekte bearbeiten
Die Aktivierreihenfolge der Objekte auf einem Formular hängt von der Reihenfolge ab, in der Sie die Objekte zum Formular hinzufügen. Diese Reihenfolge ist für den Benutzer aber nicht immer sinnvoll. Es kann erforderlich sein, die Aktivierreihenfolge der Objekte auf dem Formular zu verändern. Hierzu wählen Sie ANSICHT|AKTIVIERREIHENFOLGE, um das Dialogfeld REIHENFOLGE zu öffnen (siehe Abbildung 5.16). Dieses Dialogfeld bietet zwei Möglichkeiten. Benutzen Sie die Schaltfläche AUTOMATISCH, damit Access die Aktivierreihenfolge entsprechend der Anordnung der Objekte in einem Abschnitt des Formulars festlegt. Wenn Sie jedoch die Aktivierreihenfolge der Objekte anpassen wollen, klicken Sie auf die jeweilige graue Schaltfläche links neben dem Objektnamen im Feld DEFINIERTE REIHENFOLGE und ziehen das Objekt an die gewünschte Stelle.
159
Das geeignete Steuerelement auswählen
Abbildung 5.15: Das Formular nach dem Verändern des vertikalen Abstands
Sie müssen die Aktivierreihenfolge der Objekte für jeden Abschnitt des Formulars getrennt festlegen. Hierzu wählen Sie den entsprechenden Abschnitt aus dem Dialogfeld REIHENFOLGE und die Aktivierreihenfolge der Objekte für den Abschnitt. Wenn Ihr Formular keinen Kopf oder Fuß besitzt, sind die Abschnitte FORMULARKOPF und FORMULARFUß nicht verfügbar.
Abbildung 5.16: Verwenden Sie das Dialogfeld Reihenfolge, um die Aktivierreihenfolge der Objekte in jedem Abschnitt eines Formulars auszuwählen
5.5
Das geeignete Steuerelement auswählen
Windows-Programmierung im Allgemeinen und Access-Programmierung im Besonderen sind nicht einfach auf das Schreiben von Code begrenzt. Der Erfolg Ihrer Anwendung steht und fällt mit Ihrem Geschick zur Gestaltung einer benutzerfreundlichen Schnittstelle. Access und die Windows-Programmierumgebung bieten eine
160
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Vielzahl von Steuerelementen, von denen jedes eine bestimmte Situation abdeckt. In den folgenden Abschnitten wird jedes Steuerelement vorgestellt und erläutert, wann und wie es benutzt werden sollte.
5.5.1
Bezeichnungen
Mit Bezeichnungen werden Ihren Benutzern Informationen angezeigt. Wenn Sie Steuerelemente wie Textfelder, Kombinationsfelder usw. zu Ihrem Formular hinzufügen, werden automatisch zugehörige Bezeichnungsfelder erzeugt, die nach Belieben verändert oder gelöscht werden können. Ihre standardmäßige Beschriftung hängt von der Beschriftungseigenschaft des Feldes ab, das dem entsprechenden Steuerelement zugrundeliegt. Wenn nichts in die Beschriftungseigenschaft des Feldes eingegeben wurde, wird der Feldname als Beschriftung des Bezeichnungsfeldes verwendet. Das Werkzeug BEZEICHNUNG, das Sie in der Toolbox finden, kann benutzt werden, um beliebigen Text zum Formular hinzuzufügen. Klicken Sie dazu erst auf das Werkzeug BEZEICHNUNG, dann auf das Bezeichnungsfeld und ziehen Sie das Steuerelement anschließend an die gewünschte Stelle auf dem Formular. Bezeichnungsfelder werden oft benutzt, um ein Formular zu beschreiben oder dem Benutzer eine Gebrauchsanweisung zu geben. Bezeichnungsfelder können hinsichtlich Schriftart, Größe, Farbe usw. angepasst werden. Entwickler können VBA-Code verwenden, um die Eigenschaften von Bezeichnungsfeldern zur Laufzeit zu verändern. Benutzer haben diese Möglichkeit hingegen nicht. Manchmal geht die Verbindung eines Bezeichnungsfeldes zu seinem Textfeld verloren. Das bedeutet, dass das Bezeichnungsfeld nicht mehr gemeinsam mit dem zugehörigen Textfeld verschoben, in der Größe verändert und ausgewählt wird. Um diese Verbindung wiederherzustellen, schneiden Sie das Bezeichnungsfeld aus (Strg)+(x), klicken das Textfeld an und drücken (Strg)+(v) zum Einfügen. Wenn Sie absichtlich die Verbindung zwischen Bezeichnungsfeld und zugehörigem Steuerelement lösen wollen, schneiden Sie es einfach aus und fügen es wieder in das Formular ein, ohne das Steuerelement auszuwählen, zu dem es gehört hat. Damit können Sie z.B. das Steuerelement verbergen, ohne das Bezeichnungsfeld mit auszublenden.
5.5.2
Textfelder
Textfelder werden benutzt, um Informationen vom Benutzer entgegenzunehmen. Gebundene Textfelder zeigen und empfangen Informationen, die in einer Tabelle gespeichert werden, ungebundene Textfelder dagegen sammeln Informationen vom Benutzer, die sich nicht auf ein bestimmtes Feld in einem bestimmten Datensatz beziehen. Ein Textfeld kann beispielsweise verwendet werden, um die Parameter für einen Bericht vom Benutzer abzufragen.
Das geeignete Steuerelement auswählen
161
Textfelder werden automatisch zu einem Formular hinzugefügt, wenn Sie ein Feld aus der Feldliste anklicken, auf das Formular ziehen und das Anzeigesteuerelement für dieses Feld auf Textfeld gesetzt ist. Das Anzeigesteuerelement ist das standardmäßige Steuerelement für ein Objekt und wird beim Entwurf der zu Grunde liegenden Tabelle festgelegt. Ein anderer Weg, um ein Textfeld hinzuzufügen, besteht darin, das Werkzeug TEXTFELD aus der Toolbox auszuwählen, indem Sie auf das Textfeld klicken und es auf das Formular ziehen. Dieser Vorgang erzeugt ein ungebundenes Textfeld. Wenn Sie das Textfeld mit Daten verbinden wollen, müssen Sie die Eigenschaft STEUERELEMENTINHALT setzen.
5.5.3
Kombinationsfelder
Access bietet mehrere einfache Möglichkeiten, ein Kombinationsfeld zu einem Formular hinzuzufügen. Wenn die Eigenschaft STEUERELEMENT ANZEIGEN eines Feldes auf KOMBINATIONSFELD gesetzt worden ist, wird beim Hinzufügen eines Feldes automatisch ein Kombinationsfeld auf dem Formular erzeugt. Dieses kennt automatisch seine Datenquelle sowie andere wichtige Eigenschaften. Wenn die Eigenschaft STEUERELEMENT ANZEIGEN eines Feldes nicht auf KOMBINATIONSFELD gesetzt ist, führt der einfachste Weg zum Erzeugen eines Kombinationsfeldes auf dem Formular über den Steuerelement-Assistenten. Der SteuerelementAssistent unterstützt Sie beim Hinzufügen von Kombinationsfeldern, Listenfeldern, Optionsgruppen und Unterformularen zu Ihrem Formular. Die Benutzung des Assistenten spart Zeit und Kraft, obwohl alle Eigenschaften, die durch den Kombinationsfeld-Assistenten gesetzt werden, manuell verändert werden können. Soll der Kombinationsfeld-Assistent gestartet werden, wenn Sie ein Kombinationsfeld zum Formular hinzufügen, stellen Sie sicher, dass das Werkzeug STEUERELEMENT-ASSISTENTEN in der Toolbox angeklickt (eingeschaltet) worden ist, bevor Sie das Kombinationsfeld hinzufügen. Um ein Kombinationsfeld zu einem Formular hinzuzufügen, wählen Sie das Werkzeug KOMBINATIONSFELD in der Toolbox, klicken es an und ziehen das Kombinationsfeld dann auf das Formular. Dadurch wird der Kombinationsfeld-Assistent gestartet, dessen erster Schritt in Abbildung 5.17 dargestellt wird. Sie werden gefragt, ob das Kombinationsfeld die Werte aus einer Tabelle oder Abfrage verwenden soll, ob Sie die Werte lieber selbst eingeben möchten oder ob das Kombinationsfeld benutzt werden soll, um einen bestimmten Datensatz zu suchen. Nehmen Sie die erste Möglichkeit, wenn Ihr Kombinationsfeld Daten verwenden soll, die in einem Feld gespeichert sind, wie zum Beispiel das Bundesland, in dem ein bestimmter Kunde wohnt. Ich benutze selten, wenn überhaupt, die zweite Möglichkeit, bei der man die Werte für das Kombinationsfeld eingeben muss, weil damit ein erhöhter Pflegeaufwand verbunden ist. Jedesmal, wenn Sie einen Eintrag zum Kombinationsfeld hinzufügen wollen, müssen Sie die gesamte Anwendung verändern. Die dritte und letzte Möglichkeit ist optimal, wenn das Kombinationsfeld zum Finden bestimmter Datensätze benutzt werden soll. So kann ein Kombinationsfeld beispiels-
162
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
weise in den Formularkopf eingebaut werden, um eine Liste von Kunden anzuzeigen, wodurch nach der Auswahl eines Kunden der entsprechende Datensatz angezeigt wird. Diese Möglichkeit gibt es allerdings nur, wenn das Formular mit einer Datenquelle verbunden ist.
Abbildung 5.17: Der erste Schritt im Kombinationsfeld-Assistenten: die Datenquelle auswählen
Im zweiten Schritt des Kombinationsfeld-Assistenten wählen Sie eine Tabelle oder Abfrage, um das Kombinationsfeld mit Leben zu füllen. Durch Auswahl einer Abfrage bekommen Sie eine höhere Verarbeitungsgeschwindigkeit. Der dritte Schritt des Kombinationsfeld-Assistenten erlaubt Ihnen die Auswahl der Felder, die in Ihrem Kombinationsfeld auftauchen sollen (siehe Abbildung 5.18.) Das Kombinationsfeld, das im Beispiel erstellt wird, wird benutzt, um den Kunden zu einem bestimmten Projekt zu suchen. Obwohl das Feld CompanyName das einzige Feld ist, das im Kombinationsfeld sichtbar sein soll, wurden sowohl CompanyName als auch ClientID ausgewählt, weil ClientID ein notwendiges Element des Kombinationsfeldes ist. Nach der Auswahl eines Firmennamens im Kombinationsfeld wird die zugehörige Kundennummer im Feld ClientID der Tabelle tblProjects gespeichert. Im vierten Schritt des Kombinationsfeld-Assistenten bestimmen Sie die Breite jedes Feldes im Kombinationsfeld. Beachten Sie in Abbildung 5.19, dass Access das Ausblenden des Schlüsselfelds ClientID vorschlägt, damit der Benutzer eine aussagekräftige Beschreibung sieht, während Access den entsprechenden Schlüsselwert in den Datensatz schreibt. Im fünften Schritt des Kombinationsfeld-Assistenten bestimmen Sie, ob sich Access die ausgewählten Werte einfach merken oder sie in einem bestimmten Feld einer Tabelle speichern soll. In dem Beispiel in Abbildung 5.20 wird der aus dem Kombinationsfeld ausgewählte Wert im Feld ClientID in der Tabelle tblProjects gespeichert.
Das geeignete Steuerelement auswählen
163
Abbildung 5.18: Der dritte Schritt im Kombinationsfeld-Assistenten: Felder auswählen
Abbildung 5.19: Der vierte Schritt im Kombinationsfeld-Assistenten: Spaltenbreiten festlegen
Der sechste und letzte Schritt des Kombinationsfeld-Assistenten fragt nach dem Text, der als Bezeichnung für das Kombinationsfeld dienen soll. Die Schaltfläche FERTIG STELLEN vollendet den Vorgang, erstellt das Kombinationsfeld und füllt alle seine Eigenschaften mit den entsprechenden Werten. Obwohl der Kombinationsfeld-Assistent ein hilfreiches Werkzeug ist, muss man wissen, welche Eigenschaften er vergibt. Abbildung 5.21 zeigt das Eigenschaftenfenster für ein Kombinationsfeld. Viele dieser Eigenschaften werden in anderen Kapiteln behandelt, aber lesen Sie jetzt ein wenig darüber, welche Eigenschaften vom Kombinationsfeld-Assistenten festgelegt werden.
164
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Abbildung 5.20: Der fünfte Schritt im Kombinationsfeld-Assistenten: angeben, wo der ausgewählte Wert gespeichert werden wird
Die Eigenschaft STEUERELEMENTINHALT gibt das Feld an, in dem die ausgewählte Eingabe gespeichert wird. In Abbildung 5.21 ist dies das Feld ClientID der Tabelle tblProjects. Die Eigenschaft HERKUNFTSTYP bestimmt, ob die Quelle des Kombinationsfeldes eine Tabelle/Abfrage, eine Werteliste oder eine Feldliste ist. In dem Beispiel hat HERKUNFTSTYP den Wert TABELLE/ABFRAGE. Die DATENSATZHERKUNFT ist der Name der aktuellen Tabelle oder Abfrage, die benutzt wird, um das Kombinationsfeld mit Leben zu füllen. In dem Beispiel ist die Datensatzherkunft tblClients. Die Eigenschaft SPALTENANZAHL legt fest, wie viele Spalten das Kombinationsfeld enthält, und die Eigenschaft SPALTENBREITEN gibt die Breite jeder Spalte an. In dem Beispiel ist die Breite der ersten Spalte null, wodurch die Spalte unsichtbar wird. Die Eigenschaft GEBUNDENE SPALTE schließlich gibt an, welche Spalte im Kombinationsfeld verwendet wird, um Daten der Quelle zu speichern. In dem Beispiel ist das Spalte 1. Kombinationsfelder sind sehr leistungsfähige Steuerelemente, aber Sie müssen viel darüber wissen, um ihre Möglichkeiten auszuschöpfen. Die weiteren Möglichkeiten von Kombinationsfeldern finden Sie in Kapitel 9.
5.5.4
Listenfelder
Listenfelder ähneln Kombinationsfeldern, aber es gibt drei große Unterschiede:
Sie brauchen mehr Platz auf dem Bildschirm. Sie lassen nur eine Auswahl aus der angezeigten Liste zu, d.h., Sie können in einem Listenfeld keine neuen Werte eingeben (was bei einem Kombinationsfeld möglich ist).
Sie können die Auswahl mehrerer Werte zulassen.
Das geeignete Steuerelement auswählen
165
Abbildung 5.21: Eigenschaften eines Kombinationsfeldes, die zeigen, dass das Feld ClientID als Quelle für das Kombinationsfeld Combo5 ausgewählt worden ist
Sie können die Eigenschaft STEUERELEMENT ANZEIGEN eines Feldes nicht nur auf KOMBINATIONSFELD, sondern auch auf LISTENFELD setzen. Wenn Sie dies tun, wird dem Formular beim Ablegen eines Feldes auf ihm automatisch ein Listenfeld hinzugefügt. Der Listenfeld-Assistent ähnelt dem Kombinationsfeld-Assistenten sehr. Nach dem Durchlaufen des Listenfeld-Assistenten sind die betroffenen Listenfeldeigenschaften die gleichen wie die Kombinationsfeldeigenschaften. Weitere Techniken zum Umgang mit Listenfeldern finden Sie in Kapitel 9.
5.5.5
Kontrollkästchen
Kontrollkästchen werden benutzt, wenn Sie dem Benutzer nur die Eingabe eines von zwei Werten erlauben wollen. Die Werte können auf JA/NEIN, WAHR/FALSCH oder EIN/AUS beschränkt werden. Sie können einem Formular auf verschiedene Arten Kontrollkästchen hinzufügen: 1. Setzen Sie die Eigenschaft STEUERELEMENT ANZEIGEN des zu Grunde liegenden Feldes auf KONTROLLKÄSTCHEN, klicken Sie dann auf das Feld in der Feldliste und ziehen Sie es auf das Formular. 2. Klicken Sie auf das Werkzeug KONTROLLKÄSTCHEN in der Toolbox, klicken Sie dann auf das Feld in der Feldliste und ziehen Sie es auf das Formular. Diese Methode fügt dem Formular ein Kontrollkästchen hinzu, auch wenn die Eigenschaft STEUERELEMENT ANZEIGEN des zu Grunde liegenden Feldes nicht auf KONTROLLKÄSTCHEN gesetzt ist. 3. Klicken Sie auf das Werkzeug KONTROLLKÄSTCHEN in der Toolbox und klicken Sie dann auf die gewünschte Position, um dem Formular ein Kontrollkästchen
166
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
hinzuzufügen. Dieses Kontrollkästchen ist ungebunden. Um es mit Daten zu verbinden, müssen Sie die Eigenschaft Steuerelementinhalt festlegen. Sie können die Eigenschaft DREIFACHER STATUS eines Kontrollkästchens verwenden, um einen dritten Wert, NULL, zuzulassen.
5.5.6
Optionsfelder
Optionsfelder können alleine oder als Teil einer Optionsgruppe verwendet werden. Ein Optionsfeld alleine kann zum Anzeigen eines Wahr/Falsch-Wertes benutzt werden, aber das ist nicht der Sinn von Optionsfeldern. Für diesen Zweck sind Kontrollkästchen vorgesehen. Als Teil einer Optionsgruppe zwingen Optionsfelder den Benutzer dazu, zwischen einer Reihe sich gegenseitig ausschließender Optionen auszuwählen, wie zum Beispiel zwischen American Express, MasterCard, Visa oder Discover im Falle einer Kreditkarte. Dieser Gebrauch von Optionsfeldern wird im Abschnitt »Optionsfelder« behandelt.
5.5.7
Umschaltflächen
Genau wie Optionsfelder können Umschaltflächen alleine oder als Teil einer Optionsgruppe benutzt werden. Eine Umschaltfläche kann selbst einen Wahr/FalschWert anzeigen, aber dies ist nicht der normale Gebrauch. Stattdessen werden Umschaltflächen üblicherweise als Teil einer Optionsgruppe eingesetzt, wie im nächsten Abschnitt erläutert wird.
5.5.8
Optionsgruppen
Optionsgruppen erlauben dem Benutzer, aus einer sich gegenseitig ausschließenden Reihe von Optionen auszuwählen. Sie können Kontrollkästchen, Umschaltflächen oder Optionsfelder enthalten, aber der gebräuchlichste Inhalt einer Optionsgruppe sind Optionsfelder. Der einfachste Weg, eine Optionsgruppe zu einem Formular hinzuzufügen, ist die Benutzung des Optionsgruppen-Assistenten. Damit der Optionsgruppen-Assistent startet, muss die Schaltfläche STEUERELEMENT-ASSISTENTEN in der Toolbox aktiviert sein. Klicken Sie in der Toolbox auf OPTIONSGRUPPE und ziehen Sie die Optionsgruppe dann im Formular auf. Im ersten Schritt des Optionsgruppen-Assistenten, gezeigt in Abbildung 5.22, geben Sie den Text zu jedem Element der Optionsgruppe ein. Im zweiten Schritt wählen Sie anschließend die Standardauswahl für die Optionsgruppe. Diese Vorgaben werden wirksam, wenn der Tabelle, die dem Formular zugrunde liegt, ein neuer Datensatz hinzugefügt wird. Im dritten Schritt wählen Sie zu jedem Optionsfeld Werte aus
Das geeignete Steuerelement auswählen
167
(siehe Abbildung 5.23). Der Datensatz speichert dann nicht den zu jedem Optionsfeld angezeigten Text, sondern den entsprechenden numerischen Wert. Im Beispiel in Abbildung 5.23 wird bei Auswahl der Option CHECK die Zahl 2 gespeichert. Der vierte Schritt des Optionsgruppen-Assistenten fragt, ob Sie die Werte für die Optionsgruppe für eine spätere Verwendung aufbewahren wollen oder ob die Werte in einem Feld gespeichert werden sollen. In Abbildung 5.24 wird der Wert der Optionsgruppe zum Beispiel im Feld PaymentMethodID gespeichert. Im fünften Schritt des Optionsgruppen-Assistenten können Sie aus einer Vielfalt von Stilen für die Optionsgruppen-Schaltflächen auswählen, einschließlich Optionsfeldern, Kontrollkästchen und Umschaltflächen. Ferner können Sie zwischen Effekten für Ihre Schaltflächen wählen, wie graviert, flach, erhöht, schattiert oder vertieft. Der Assistent gibt Ihnen eine Voransicht jeder Möglichkeit. Der sechste und letzte Schritt des Optionsgruppen-Assistenten erlaubt Ihnen das Hinzufügen einer entsprechenden Beschriftung zu der Optionsgruppe. Die vollständige Gruppe von Options-Schaltflächen sehen Sie in Abbildung 5.25.
Abbildung 5.22: Der erste Schritt im Optionsgruppen-Assistenten: zu Optionen Text hinzufügen
Abbildung 5.23: Der dritte Schritt im Optionsgruppen-Assistenten: Optionswerte auswählen
168
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Abbildung 5.24: Der vierte Schritt im Optionsgruppen-Assistenten: die Gruppe mit Daten verbinden
Abbildung 5.25: Das Resultat der Ausführung des OptionsgruppenAssistenten
Sie sollten wissen, dass der Optionsgruppen-Assistent die Eigenschaften des Rahmens, der Optionsfelder innerhalb des Rahmens und der Bezeichnungen, die mit den Optionsfeldern verbunden sind, festlegt. Die Eigenschaften des Rahmens werden in Abbildung 5.26 gezeigt. Der Steuerelementinhalt des Rahmens und die Standardauswahl der Optionsgruppe werden durch den Optionsgruppen-Assistenten vergeben. Jedes einzelne Optionsfeld erhält dann einen Wert und die Beschriftung der zugehörigen Bezeichnung wird vergeben.
Ein Steuerelement durch ein anderes ersetzen
169
Abbildung 5.26: Ein Optionsgruppenrahmen mit den Eigenschaften der ausgewählten Schaltfläche
5.6
Ein Steuerelement durch ein anderes ersetzen
Beim ersten Entwurf eines Formulars fällt Ihnen vielleicht nicht unbedingt für jedes Feld das richtige Steuerelement ein oder Sie denken, das ideale Steuerelement gefunden zu haben, nur um später feststellen zu müssen, dass Ihre Wahl den Vorstellungen des Benutzers nicht so ganz gefällt. In Access ist es einfach, ein Steuerelement durch ein anderes zu ersetzen. Sie können z.B. ein Listenfeld in ein Kombinationsfeld umwandeln.
5.6.1
Ein Textfeld in ein Kombinationsfeld verwandeln
Eine der häufigsten Arten der Umwandlung ist die vom Textfeld in ein Kombinationsfeld. Hierzu klicken Sie mit der rechten Taste auf das Textfeld, wählen Sie ÄNDERN IN und suchen dann das Steuerelement aus, in das Sie das Textfeld verwandeln wollen. Die verfügbaren Steuerelemente hängen von der Art des umzuwandelnden Steuerelements ab. Ein Textfeld kann beispielsweise in ein Bezeichnungsfeld, Listenfeld oder Kombinationsfeld verwandelt werden (siehe Abbildung 5.27). Nach dem Verwandeln eines Textfeldes in ein Kombinationsfeld bearbeiten Sie die entsprechenden Steuerelementeigenschaften. Dabei müssen die Eigenschaften DATENSATZHERKUNFT, GEBUNDENE SPALTE, SPALTENANZAHL und SPALTENBREITEN festgelegt werden. Für die Datensatzherkunft müssen Sie eine Tabelle oder Abfrage angeben. Wenn Sie eine Tabelle auswählen und auf die Schaltfläche mit den drei Punkten klicken, werden Sie gefragt, ob Sie eine Abfrage für diese Tabelle erstellen möchten. Nachdem Sie JA ausgewählt haben, können Sie eine Abfrage erstellen, die nur die Felder im Kombinationsfeld enthält. Anschließend können Sie auswählen, ob die Daten in der zugrunde liegenden Tabelle über eine gebundene Spalte
170
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Abbildung 5.27: Ein Textfeld in ein anderes Steuerelement verwandeln
gespeichert werden sollen. So könnte beispielsweise der Benutzer den Namen eines Projekts auswählen, für das eine Zahlung erfolgen soll, aber statt des Namens wird die ProjectID in der Tabelle tblPayments gespeichert. Setzen Sie die Spaltenanzahl auf die Anzahl der Spalten, die in der zugrunde liegenden Abfrage ausgewählt worden sind; die Spaltenbreite kann danach so verändert werden, dass die Schlüsselspalte verborgen ist.
5.6.2
Kombinationsfeld in Listenfeld
Das Ändern eines Kombinationsfeldes in ein Listenfeld ist ein wesentlich einfacherer Vorgang als das Verwandeln eines Textfeldes in ein Kombinationsfeld oder in ein Listenfeld, weil Kombinationsfelder und Listenfelder sehr viele gemeinsame Eigenschaften haben. Zum Verwandeln eines Kombinationsfeldes in ein Listenfeld klicken Sie einfach mit der rechten Taste auf das Kombinationsfeld und wählen ÄNDERN IN|LISTENFELD.
5.7
Bedingte Formatierung
Neu in Access 2000 ist die bedingte Formatierung, mit deren Hilfe Daten in Abhängigkeit von bestimmten Kriterien unterschiedlich angezeigt werden können. Um Daten mit bedingter Formatierung anzuzeigen, folgen Sie diesen Schritten: 1. Wählen Sie das Steuerelement, das Sie bedingt formatieren wollen. 2. Wählen Sie FORMAT|BEDINGTE FORMATIERUNG. Daraufhin erscheint das Dialogfeld BEDINGTE FORMATIERUNG.
Welche Formulareigenschaften stehen zur Verfügung?
171
3. Wählen Sie FELDWERT IST, AUSDRUCK IST oder FELD HAT FOKUS aus dem ersten Kombinationsfeld aus. 4. Wählen Sie im zweiten Kombinationsfeld den entsprechenden Operator aus. 5. Geben Sie in den Textfeldern rechts die Werte ein, gegen die Sie prüfen möchten. 6. Wählen Sie die Formatierung aus (fett, kursiv, Hintergrundfarbe usw.), die bei erfüllter Bedingung angewendet werden soll. 7. Klicken Sie auf HINZUFÜGEN, um weitere Formate hinzuzufügen. 8. Klicken Sie auf OK, um die bedingte Formatierung durchzuführen.
5.8
Welche Formulareigenschaften stehen zur Verfügung und warum sollten sie benutzt werden?
Formulare haben viele Eigenschaften, die ihr Aussehen und Verhalten beeinflussen. Die Eigenschaften fallen unter die folgenden Kategorien: FORMAT, DATEN, EREIGNIS und ANDERE. Zum Anzeigen der Eigenschaften eines Formulars müssen Sie es auswählen: 1. Klicken Sie auf die Schaltfläche zur Formularauswahl (die schmale graue Schaltfläche am Schnittpunkt der waagerechten und senkrechten Lineale). 2. Wählen Sie BEARBEITEN|FORMULAR AUSWÄHLEN.
5.8.1
Das Eigenschaftenfenster
Zum Anzeigen der Eigenschaften klicken Sie nach dem Auswählen des Formulars auf die Schaltfläche EIGENSCHAFTEN in der Symbolleiste. Das Eigenschaftenfenster, zu sehen in Abbildung 5.28, enthält fünf Registerkarten: FORMAT, DATEN, EREIGNISSE, ANDERE und ALLE. Viele Entwickler sehen gerne alle Eigenschaften auf einmal, jedoch besitzt ein Formular davon insgesamt 81! Der nach Kategorien getrennte Aufruf ist viel übersichtlicher als sich alle 81 Eigenschaften auf einmal anzusehen. Die Kategorie FORMAT enthält die physischen Attribute des Formulars, die das Erscheinungsbild des Formulars beeinflussen (z.B. die Hintergrundfarbe). Die Kategorie DATEN umfasst alle Eigenschaften, die sich auf die Daten beziehen, mit denen das Formular verbunden ist, wie beispielsweise die dem Formular zu Grunde liegende Datenquelle. Die Kategorie EREIGNISSE fasst alle Windows-Ereignisse zusammen, auf die ein Formular reagieren kann. Sie können beispielsweise Code schreiben, der nach dem Laden des Formulars, der Aktivierung, dem Anzeigen des nächsten Datensatzes usw. ausgeführt wird. Die Kategorie ANDERE enthält schließlich die Eigenschaften, die nicht in eine der übrigen drei Kategorien hineinpassen.
172
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Abbildung 5.28: Die Formateigenschaften eines Formulars
5.8.2
Wichtige Formulareigenschaften
Wie bereits erwähnt, besitzen Formulare 81 Eigenschaften, von denen 32 EREIGNISEigenschaften sind, die in Kapitel 9 behandelt werden. Der folgende Abschnitt behandelt die Eigenschaften der Kategorien FORMAT, DATEN und ANDERE. Formateigenschaften eines Formulars Die Formateigenschaften eines Formulars beeinflussen sein Erscheinungsbild. Formulare verfügen über 26 Formateigenschaften: Beschriftung: Die Eigenschaft BESCHRIFTUNG legt den Text fest, der in der Titelzeile des Formulars erscheint. Diese Eigenschaft kann zur Laufzeit verändert werden. Sie können beispielsweise den Benutzernamen oder den Namen des Kunden, für den eine Rechnung geschrieben wird, hier einblenden. Standardansicht: Die Eigenschaft STANDARDANSICHT bietet die Auswahl zwischen drei Möglichkeiten:
EINZELNES FORMULAR: Es kann nur ein Datensatz zurzeit angesehen werden. ENDLOSFORMULAR: So viele Datensätze, wie in das Formularfenster passen, werden gleichzeitig angezeigt, jeder als Detailabschnitt eines einzelnen Formulars.
DATENBLATT: Zeigt die Datensätze in einer ähnlichen Form wie eine Kalkulationstabelle an, wobei die Zeilen Datensätzen und die Spalten Feldern entsprechen. Die ausgewählte Einstellung wird die Standardansicht des Formulars.
Welche Formulareigenschaften stehen zur Verfügung?
173
Zugelassene Ansichten: Die Eigenschaft ZUGELASSENE ANSICHTEN legt fest, ob der Benutzer zwischen Formular- und Datenblattansicht hin- und herwechseln darf. In der Standardansicht wurde die standardmäßige Ansicht vorgegeben, ZUGELASSENE ANSICHTEN dagegen legt fest, ob der Benutzer die Standardansicht verlassen darf. Bildlaufleisten: Die Eigenschaft BILDLAUFLEISTEN legt fest, ob Bildlaufleisten erscheinen sollen, wenn die Objekte auf dem Formular nicht ins Formularfenster passen. Mögliche Optionen sind IN BEIDEN RICHTUNGEN, NUR VERTIKAL, NUR horizontal oder NEIN. Datensatzmarkierer: Ein Datensatzmarkierer ist der graue Balken links neben einem Datensatz in der Formularansicht oder das graue Feld links neben jedem Datensatz in der Datenblattansicht. Er wird gebraucht, um einen Datensatz auszuwählen, der kopiert oder gelöscht werden soll. Die Eigenschaft DATENSATZMARKIERER legt fest, ob Datensatzmarkierer vorhanden sind. Wenn Sie dem Benutzer ein benutzerdefiniertes Menü an die Hand geben, können Sie den Datensatzmarkierer entfernen, so dass der Benutzer Datensätze nur kopieren oder löschen kann, wenn Ihre Anwendung um diese Fähigkeiten erweitert wurde. Navigationsschaltflächen: Navigationsschaltflächen sind die Steuerelemente, die im Fuß des Formulars erscheinen und dem Benutzer erlauben, sich innerhalb des Formulars von Datensatz zu Datensatz zu bewegen. Die Eigenschaft NAVIGATIONSSCHALTFLÄCHEN legt fest, ob die Navigationsschaltflächen sichtbar sind. Für Dialogformulare sollten Sie diese Eigenschaft auf Nein setzen, genauso wie dies für reine Dateneingabeformulare sinnvoll sein kann, und Sie können eigene Symbolleisten oder Befehlsschaltflächen einfügen, welche die normalen Möglichkeiten erweitern oder einschränken. Beispielsweise könnte es erforderlich sein, dem Benutzer in einer Client-Server-Umgebung die Möglichkeit zu verweigern, zum ersten oder letzten Datensatz zu springen, weil das in einer derartigen Umgebung sehr viel Zeit kosten kann. Trennlinien: Die Eigenschaft TRENNLINIEN zeigt an, ob zwischen den Datensätzen eine Trennungslinie erscheinen soll, wenn die Standardansicht des Formulars auf ENDLOSFORMULAR gesetzt wird. Größe anpassen: Diese Eigenschaft legt fest, ob die Größe des Formulars automatisch an die Darstellung eines vollständigen Datensatzes angepasst wird. Automatisch Zentrieren: Diese Eigenschaft legt fest, ob das Formular beim Öffnen automatisch im Anwendungsfenster zentriert wird. Rahmenart: Diese Eigenschaft ist viel umfassender als ihr Name vermuten lässt. Die Rahmenart kann die Werte KEINE, DÜNN, VERÄNDERBAR und DIALOG annehmen. Bei Begrüßungsbildschirmen wird die Rahmenart oft auf KEINE gesetzt, wodurch das Formular keine Begrenzung bekommt. Eine dünne Begrenzung ist nicht in der Größe veränderbar, was bedeutet, dass der Befehl GRÖSSE ÄNDERN im Systemmenü
174
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
des Formulars nicht verfügbar ist. Diese Einstellung stellt eine gute Wahl für Formulare dar, die auch dann noch im Vordergrund bleiben, wenn andere Formulare den Fokus erhalten. Eine veränderbare Begrenzung ist der Standard für die meisten Formulare. Hier enthält das Kontextmenü des Steuerelements alle Standardoptionen. Ein Dialograhmen ähnelt einer dünnen Begrenzung. Ein Formular mit dieser Rahmenart kann nicht maximiert, minimiert oder in der Größe verändert werden. Wenn die Begrenzung des Formulars auf DIALOG gesetzt ist, sind die Optionen MAXIMIEREN, MINIMIEREN und GRÖSSE ÄNDERN nicht im Systemmenü des Formulars verfügbar. Zum Erstellen benutzerdefinierter Dialogfelder wird oft die Rahmenart DIALOG zusammen mit den Eigenschaften POPUP und GEBUNDEN verwendet. Mit Systemmenüfeld: Die Eigenschaft MIT SYSTEMMENÜFELD legt fest, ob ein Formular ein Systemmenüfeld hat. Verwenden Sie diese Option sparsam. Eine Ihrer Verantwortlichkeiten als Access-Programmierer besteht darin, Ihre Anwendung an die Windows-Standards anzulehnen. Wenn Sie sich die Windows-Programme ansehen, mit denen Sie arbeiten, werden Sie nur sehr wenige Formulare ohne Systemmenüfeld finden. Sie können daraus ableiten, wie Ihre eigenen Anwendungen aussehen sollten. MinMaxSchaltflächen: Die Eigenschaft MINMAXSCHALTFLÄCHEN gibt an, ob das Formular Schaltflächen zum Minimieren und Maximieren besitzt. Die Möglichkeiten sind KEINE VORHANDEN, MIN, MAX, und BEIDE. Wenn Sie eine oder beide Schaltflächen entfernen, stehen die entsprechenden Optionen auch nicht mehr im Systemmenüfeld. Die Eigenschaft MINMAXSCHALTFLÄCHEN wird bei Formularen mit der Rahmenart KEINE oder DIALOG ignoriert. Genau wie die Eigenschaft MIT Systemmenüfeld verwende ich diese Eigenschaft selten. Damit meine Anwendungen dem Windows-Standard entsprechen, wähle ich vielmehr die passende Rahmenart und lasse deren vorgegebene Attribute stehen. Schließen-Schaltfläche: Diese Eigenschaft legt fest, ob der Benutzer das Formular über das Systemmenü oder durch Doppelklicken auf das Systemmenüsymbol schließen kann. Wenn Sie diese Eigenschaft auf Nein setzen, müssen Sie dem Benutzer eine andere Möglichkeit zum Schließen des Formulars bieten. Ansonsten könnte es passieren, dass der Benutzer seinen Computer neu starten muss, um Ihre Anwendung zu schließen. Direkthilfe Schaltfläche: Diese Eigenschaft legt fest, ob Sie die Schaltfläche DIREKTHILFE in die Titelleiste einfügen wollen. Diese Vorgehensweise funktioniert nur, wenn die Min-Max-Eigenschaft auf NEIN gesetzt ist. Wenn die Eigenschaft SCHALTFLÄCHE DIREKTHILFE auf JA gesetzt ist, kann der Benutzer zuerst auf die DIREKTHILFE-Schaltfläche und dann auf ein Objekt auf dem Formular klicken, um die Hilfe für dieses Objekt anzuzeigen. Wenn für das ausgewählte Objekt keine eigene Hilfe existiert, wird die Hilfe für das Formular oder ggf. die Microsoft AccessHilfe angezeigt.
Welche Formulareigenschaften stehen zur Verfügung?
175
Breite: Die Eigenschaft BREITE gibt die Breite des Formulars an. Diese Option wird meistens durch Anklicken und Ziehen des Formulars auf die gewünschte Größe gesetzt. Sie können diese Eigenschaft aber auch von Hand festlegen, wenn Sie wollen, dass mehrere Formulare exakt die gleiche Größe haben. Bild, Bildtyp, Bildgrößenmodus, Bildausrichtung und Bildnebeneinander: Die Eigenschaft BILD lässt Sie die Attribute einer Bitmap auswählen und anpassen, die als Hintergrund für das Formular verwendet wird. Raster X, Raster Y: Diese Eigenschaften können benutzt werden, um den Abstand der horizontalen und vertikalen Linien festzulegen, die in der Entwurfsansicht auf dem Formular erscheinen. Durch das Festlegen dieser Eigenschaften haben Sie Einfluss darauf, wie präzise Ihre Objekte auf dem Formular positioniert werden, wenn die Option AM RASTER AUSRICHTEN aktiv ist. Drucklayout: Diese Eigenschaft gibt an, ob Bildschirm- oder Druckerschriftarten auf dem Formular verwendet werden. Wenn Sie das Formular lieber für den Druck optimieren wollen als für die Anzeige, sollten Sie diese Eigenschaft auf JA setzen. Unterdatenblatthöhe: Die Unterdatenblatthöhe legt die maximale Höhe für ein Unterdatenblatt fest. Unterdatenblatt erweitert: Diese Eigenschaft legt fest, ob ein Unterdatenblatt anfänglich im erweiterten Format angezeigt wird. Besitzt die Eigenschaft den Wert NEIN, erscheint das Unterdatenblatt anfänglich in einem minimierten und sonst in einem erweiterten Format. Palettenherkunft: Die Eigenschaft PALETTENHERKUNFT legt die Quelle für die Auswahl der Farben eines Formulars fest. Dateneigenschaften eines Formulars Die Dateneigenschaften eines Formulars steuern die Datenquelle des Formulars, welche Art von Tätigkeiten der Benutzer mit den Daten im Formular durchführen kann und wie die Daten im Formular in einer Mehrbenutzerumgebung gesperrt werden. Ein Formular besitzt zehn Dateneigenschaften. Datenherkunft: Die Eigenschaft DATENHERKUNFT bezeichnet die Tabelle, gespeicherte Abfrage oder SQL-Anweisung, auf der die Datensätze des Formulars aufgebaut sind. Nach der Auswahl einer Datenherkunft für ein Formular können seine Steuerelemente mit den Feldern in dieser Datenquelle verbunden werden. Das Feldlistenfenster steht erst zur Verfügung, nachdem die Datenherkunft des Formulars festgelegt worden ist.
176
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Die Datenherkunft eines Formulars kann zur Laufzeit geändert werden. Infolgedessen können Sie generische, wiederverwendbare Formulare für viele Situationen erstellen. Filter: Die Eigenschaft Filter lädt automatisch einen gespeicherten Filter zusammen mit dem Formular. Ich ziehe es vor, ein Formular auf einer Abfrage aufzubauen, welche die Darstellung der Daten auf dem Formular einschränkt. Der Abfrage können zur Laufzeit Parameter übergeben werden, um zu steuern, welche Daten angezeigt werden. Sortiert nach: Diese Eigenschaft legt die Reihenfolge der Datensätze im Formular fest und kann zur Laufzeit verändert werden, um die Datensätze unterschiedlich sortiert anzuzeigen. Filter zulassen: Diese Eigenschaft entscheidet darüber, ob Datensätze zur Laufzeit gefiltert werden können. Wird sie auf NEIN gesetzt, werden sämtliche Filteroptionen für den Benutzer deaktiviert. Bearbeitungen, Löschen, Anfügen zulassen: Mit diesen Eigenschaften bestimmen Sie, ob der Benutzer im Formular Datensätze bearbeiten, löschen oder hinzufügen kann. Diese Optionen ersetzen jedoch nicht die Zugriffsberechtigungen, die für die dem Formular zugrunde liegenden Tabellen oder Abfragen eingerichtet worden sind. Das Thema Datensicherheit wird in den Kapiteln 33 und 34 behandelt. Daten eingeben: Die Eigenschaft DATEN EINGEBEN legt fest, ob Ihr Benutzer in einem Formular ausschließlich Daten hinzufügen kann. Setzen Sie diese Eigenschaft auf JA, wenn Ihre Benutzer bestehende Datensätze weder ansehen noch bearbeiten, sondern nur neue Datensätze erfassen sollen. Recordsettyp: Die Eigenschaft RECORDSETTYP eröffnet drei Optionen: DYNASET, Dynaset (INKONSISTENTE AKTUALISIERUNGEN) und SNAPSHOT. Jede dieser Möglich-
keiten besitzt unterschiedliche Leistungsmerkmale und Bearbeitungsmöglichkeiten. Durch Angabe der Option DYNASET wird der Datensatz vollständig aktualisierbar, außer wenn er oder einzelne seiner Felder aus anderen Gründen nicht geändert werden können. Ein Beispiel hierfür ist ein Formular, das auf einer Abfrage mit einer 1:n-Beziehung aufbaut. Das Verknüpfungsfeld auf der Einserseite der Beziehung kann nur geändert werden, wenn das Merkmal AKTUALISIERUNGSWEITERGABE AN Detailfeld gesetzt ist. Die Option DYNASET (INKONSISTENTE AKTUALISIERUNGEN) erlaubt das Bearbeiten aller Tabellen und gebundenen Daten. Dies kann inkonsistente Änderungen von Daten in den an der Abfrage beteiligten Tabellen zur Folge haben. Die Option SNAPSHOT erlaubt keinerlei Aktualisierungen. Datensätze sperren: Diese Eigenschaft legt den Sperrmechanismus fest, der auf die Daten der dem Formular zu Grunde liegenden Datensätze angewendet wird. Es stehen drei Optionen zur Verfügung. Die Option KEINE SPERRUNGEN – der am wenigsten einschränkende Sperrmechanismus – realisiert ein »optimistisches Sperren«, das
Welche Formulareigenschaften stehen zur Verfügung?
177
heißt, Access versucht nicht, den Datensatz zu sperren, bis der Benutzer ihn verlässt. Diese Option kann zu Konflikten führen, wenn zwei Benutzer gleichzeitig denselben Datensatz bearbeiten wollen. Die Option ALLE DATENSÄTZE sperrt sämtliche Datensätze, die dem Formular zugrunde liegen, solange dieses geöffnet ist. Dies ist die am meisten einschränkende Option und sollte nur benutzt werden, wenn der Benutzer des Formulars sicherstellen muss, dass andere Benutzer diese Datensätze nur ansehen, aber nicht bearbeiten dürfen. Die Option BEARBEITETER DATENSATZ sperrt einen 2 KB großen Bereich mit Datensätzen, sobald der Benutzer beginnt, die Daten im Formular zu bearbeiten. Diese Option realisiert ein »pessimistisches Sperren«. Auch wenn sie Konflikte dadurch verhindert, dass zwei Benutzer nicht gleichzeitig denselben Datensatz verändern können, kann sie zu Sperrkonflikten führen. Diese drei Sperrmechanismen werden detailliert in Kapitel 17 behandelt. Andere Eigenschaften eines Formulars Popup: Die Eigenschaft POPUP gibt an, ob das Formular immer im Vordergrund angezeigt wird. Sie wird für benutzerdefinierte Dialogfelder oft zusammen mit der Eigenschaft GEBUNDEN auf JA gesetzt. Gebunden: Die Eigenschaft GEBUNDEN gibt an, ob einem Formular der Fokus entzogen werden kann, während es geöffnet ist. Besitzt die Eigenschaft den Wert JA, muss das Formular geschlossen werden, bevor der Benutzer mit der Anwendung weiterarbeiten kann. Wie bereits erwähnt, wird diese Eigenschaft gemeinsam mit der Eigenschaft POPUP in benutzerdefinierten Dialogfeldern verwendet. Zyklus: Die Eigenschaft ZYKLUS steuert das Verhalten der Tabulatortaste im Formular. Die Optionen sind ALLE DATENSÄTZE, AKTUELLER DATENSATZ und AKTUELLE SEITE. Wenn die Eigenschaft ZYKLUS auf ALLE DATENSÄTZE gesetzt ist, gelangt der Benutzer oder die Benutzerin zum nächsten Datensatz, wenn er oder sie auf dem letzten Steuerelement des Formulars die Tabulatortaste drückt. Beim Wert AKTUELLER DATENSATZ gelangt der Benutzer vom letzten Steuerelement auf dem Formular zum ersten Steuerelement im selben Datensatz. Die Option AKTUELLE Seite, die es nur für mehrseitige Formulare gibt, legt fest, dass der Benutzer durch Drücken der Tabulatortaste vom letzten Steuerelement auf der Seite zum ersten Steuerelement auf derselben Seite gelangt. Alle drei Optionen werden durch die Tabulatorreihenfolge der Objekte auf dem Formular beeinflusst. Menüleiste: Die Eigenschaft MENÜLEISTE bestimmt, welche Menüleiste dem Formular zugeordnet wird. Die Menüleiste, die in Access 2000 manchmal auch als Befehlsleiste bezeichnet wird, wird im Dialogfeld ANPASSEN erstellt, in das man aus dem Ansichtsmenü durch Auswahl von SYMBOLLEISTE|ANPASSEN gelangt. Menüs werden in Kapitel 9 behandelt. Symbolleiste: Die Eigenschaft Symbolleiste bestimmt, welche Symbolleiste dem Formular zugeordnet wird. Die Symbolleiste, die in Access 2000 ebenfalls manchmal als »Befehlsleiste« bezeichnet wird, wird im Dialogfeld ANPASSEN erstellt. Die ausge-
178
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
wählte Symbolleiste wird immer dann angezeigt, wenn das Formular den Fokus hat. Symbolleisten werden in Kapitel 9 behandelt. Kontextmenü, Kontextmenüleiste: Die Eigenschaft KONTEXTMENÜ gibt an, ob ein Kontextmenü angezeigt wird, wenn der Benutzer mit der rechten Maustaste auf ein Objekt auf dem Formular klickt. Mit der Eigenschaft KONTEXTMENÜLEISTE können Sie einem Objekt auf dem Formular oder dem Formular selbst ein benutzerdefiniertes Kontextmenü zuweisen. Genau wie die Standardmenüleiste wird auch die Kontextmenüleiste im Dialogfeld ANPASSEN erstellt, in das man aus dem Ansichtsmenü durch Auswahl von SYMBOLLEISTE|ANPASSEN gelangt. Kontextmenüs werden in Kapitel 9 behandelt. Schneller Laserdruck: Die Eigenschaft SCHNELLER LASERDRUCK legt fest, ob Linien und Rechtecke zusammen mit dem Formular gedruckt werden. Wenn diese Eigenschaft auf JA gesetzt wird, werden Sie feststellen, dass die Ausgabe des Formulars auf einem Laserdrucker erheblich beschleunigt wird. Hilfedatei, Hilfekontext-ID: Mit den Eigenschaften HILFEDATEI und HILFEKONweisen Sie dem Formular eine bestimmte Hilfedatei und Stichworte zu.
TEXT-ID
Marke: Die Eigenschaft MARKE ist eine zusätzliche Eigenschaft, in der beliebige Informationen über das Formular gespeichert werden können. Diese Eigenschaft wird oft zur Laufzeit gesetzt und abgefragt, um notwendige Informationen über das Formular zu speichern. Beispielsweise könnte man einem Satz von Formularen, die gemeinsam aus dem Speicher entfernt werden sollen, eine Marke hinzufügen. Enthält Modul: Die Eigenschaft ENTHÄLT MODUL bestimmt, ob das Formular ein Klassenmodul enthält. Wenn zu Ihrem Formular kein Code gehört, können Ladezeit, Ausführungsgeschwindigkeit und Datenbankgröße erheblich reduziert werden, indem diese Eigenschaft auf NEIN gesetzt wird. Entwurfsänderungen zulassen: Die Eigenschaft ENTWURFSÄNDERUNGEN ZULASbestimmt, ob der Formularentwurf beim Betrachten geändert werden kann. Wenn diese Eigenschaft auf ALLE ANSICHTEN gesetzt ist, steht das Eigenschaftenfenster auch in der Formularansicht zur Verfügung und Änderungen an den Formulareigenschaften innerhalb der Formularansicht bleiben erhalten, wenn das Formular gespeichert wird. SEN
Welche Steuerelementeigenschaften stehen zur Verfügung?
5.9
179
Welche Steuerelementeigenschaften stehen zur Verfügung und warum sollten sie benutzt werden?
Es hängt von der Art des Steuerelements ab, welche Steuerelementeigenschaften verfügbar sind. Die gebräuchlicheren Eigenschaften werden in diesem Abschnitt behandelt, während die übrigen überall im Buch erläutert werden, sobald sie für bestimmte Dinge wichtig sind.
5.9.1
Formateigenschaften eines Steuerelements
Format: Die Eigenschaft FORMAT eines Steuerelements bestimmt, wie die Daten im Steuerelement angezeigt werden. Das Steuerelement erbt sein Format automatisch von seiner zu Grunde liegenden Datenquelle. Diese Eigenschaft wird in drei Situationen genutzt:
wenn die Eigenschaft FORMAT für das zu Grunde liegende Feld nicht gesetzt ist wenn Sie das Feldformat überschreiben wollen wenn Sie einem ungebundenen Steuerelement ein Format geben wollen Sie können aus einer Vielfalt vordefinierter Werte für das Format eines Steuerelements auswählen oder eigene Formate erstellen. Ich verändere diese Eigenschaft oft zur Laufzeit, um das Format eines Steuerelements abhängig von einer bestimmten Bedingung zu verändern. Beispielsweise ist das Format für eine Visa-Kartennummer ein anderes als das für eine ATM-Kartennummer. Dezimalstellenanzeige: Die Eigenschaft DEZIMALSTELLENANZEIGE bestimmt darüber, wie viele Dezimalstellen im Steuerelement erscheinen sollen. Diese Eigenschaft wird zusammen mit der Eigenschaft FORMAT benutzt, um das Erscheinungsbild des Steuerelements festzulegen. Beschriftung: Die Eigenschaft BESCHRIFTUNG wird benutzt, um dem Benutzer hilfreiche Informationen anzuzeigen. Sie steht allerdings nur für Bezeichnungen, Befehlsschaltflächen und Umschaltflächen zur Verfügung. Hyperlink-Adresse: Die Eigenschaft HYPERLINK-ADRESSE ist nur für Befehlsschaltflächen, Bilder und ungebundene Bezeichnungen verfügbar. Sie enthält den UNCPfad (Pfad zu einer Datei) oder URL (Adresse einer Webseite), der mit dem Steuerelement verbunden ist. Wenn das Formular aktiv ist und der Mauszeiger über das Steuerelement bewegt wird, zeigt ein Klick auf das Steuerelement die angegebene Datei oder Webseite an. Hyperlink-Unteradresse: Wie die Eigenschaft HYPERLINK-ADRESSE ist auch die Eigenschaft HYPERLINK-UNTERADRESSE nur für Befehlsschaltflächen, Bilder und ungebundene Bezeichnungen verfügbar. Die Hyperlink-Unteradresse ist eine Zei-
180
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
chenfolge, die auf eine Stelle in dem Dokument verweist, das in der Eigenschaft HYPERLINK-ADRESSE angegeben wurde. Sichtbar: Die Eigenschaft SICHTBAR bestimmt, ob ein Steuerelement sichtbar ist. Diese Eigenschaft kann abhängig von bestimmten Umständen zur Laufzeit umgeschaltet werden. Beispielsweise könnte eine Frage auf dem Formular nur für Datensätze zutreffen, in denen das Geschlechtsmerkmal auf weiblich gesetzt ist. Andernfalls sollte die Frage nicht sichtbar sein. Anzeigen: Die Eigenschaft ANZEIGEN wird benutzt, wenn Sie bestimmte Steuerelemente nur auf dem Bildschirm oder nur auf dem Drucker ausgeben wollen. Die drei Optionen lauten IMMER, NUR BEIM DRUCKEN oder NUR AM BILDSCHIRM. Ein Beispiel für den Gebrauch der Eigenschaft ANZEIGEN ist eine Bezeichnung mit Anweisungen, die nur auf dem Bildschirm, aber nicht auf dem Ausdruck, erscheinen sollen. Bildlaufleisten: Die Eigenschaft BILDLAUFLEISTEN bestimmt, ob Bildlaufleisten erscheinen, wenn die Daten im Steuerelement nicht in die Ausdehnung des Steuerelements hineinpassen. Die Optionen lauten KEINE und VERTIKAL. Ich setze die Eigenschaft BILDLAUFLEISTEN oft auf VERTIKAL, wenn das Steuerelement Daten aus einem Memofeld anzeigen soll. Die Bildlaufleisten erleichtern es dem Benutzer, mit einer großen Datenmenge in einem Memofeld umzugehen. Vergrößerbar, Verkleinerbar: Die Eigenschaften VERGRÖSSERBAR und VERKLEINERBAR beziehen sich nur auf den Ausdruck des Formulars. Die Eigenschaft VERKLEINERBAR kommt dann zur Anwendung, wenn keine Daten in das Steuerelement eingegeben worden sind. Wurde diese Eigenschaft auf JA gesetzt, wird ein Steuerelement ohne Daten weggelassen, so dass keine Leerzeilen gedruckt werden. Links, Oben, Breite, Höhe: Diese Eigenschaften legen die Position und Größe des Steuerelements fest. Hintergrundart, Hintergrundfarbe: Die Eigenschaft HINTERGRUNDART kann auf NORMAL oder TRANSPARENT gesetzt sein. Beim Wert TRANSPARENT sieht man die Hintergrundfarbe des Formulars durch das Steuerelement hindurch. Dies ist oftmals die bevorzugte Einstellung für eine Optionsgruppe. Die Eigenschaft HINTERGRUNDFARBE bestimmt die Hintergrundfarbe (im Gegensatz zur Textfarbe) für das Steuerelement. Ist die Hintergrundart eines Steuerelements auf TRANSPARENT gesetzt, wird seine Hintergrundfarbe ignoriert. Spezialeffekt: Die Eigenschaft SPEZIALEFFEKT fügt 3-D-Effekte zum Steuerelement hinzu. Die Optionen für diese Eigenschaft sind FLACH, ERHÖHT, VERTIEFT, GRAVIERT, SCHATTIERT und UNTERSTRICHEN. Jeder dieser Effekte gibt dem Steuerelement ein anderes Aussehen.
Welche Steuerelementeigenschaften stehen zur Verfügung?
181
Rahmenart, -farbe, breite: Diese Eigenschaften betreffen Aussehen, Farbe und Breite des Rahmens eines Steuerelements. Die Optionen für RAHMENART sind TRANSPARENT, DURCHGEZOGEN, STRICHLINIEN, KURZE STRICHLINIEN, PUNKTE, WENIGE PUNKTE , STRICHLINIE PUNKT und STRICHLINIE PUNKT PUNKT. Die Eigenschaft RAHMENFARBE bestimmt die Farbe des Rahmens und kann aus einer Vielzahl von Farben ausgewählt werden. Die Eigenschaft RAHMENBREITE kann auf eine von verschiedenen Punktgrößen festgelegt werden. Ist die Rahmenart eines Steuerelements auf TRANSPARENT gesetzt, wird seine Rahmenfarbe ignoriert. Textfarbe, Schriftart, Schriftgrad, Schriftbreite, Kursiv, Unterstrichen: Diese Eigenschaften steuern das Erscheinungsbild von Text in einem Steuerelement. Wie ihre Namen vermuten lassen, erlauben sie die Auswahl von Farbe, Schriftart, Größe und Dicke für den Text und legen fest, ob der Text kursiv oder unterstrichen erscheint. Diese Eigenschaften können als Antwort auf ein Laufzeitereignis verändert werden. Zum Beispiel kann sich die Textfarbe eines Steuerelements ändern, wenn der Wert darin einen bestimmten Betrag übersteigt. Die Auswahlmöglichkeiten für die Schriftbreite übersteigen in der Regel die Fähigkeiten der meisten Schriftarten und Drucker – normalerweise haben Sie nur die Wahl zwischen normal und fett, welchen Wert Sie auch auswählen. Textausrichtung: Die Eigenschaft TEXTAUSRICHTUNG wird oft mit der Steuerelementausrichtung verwechselt. Die Eigenschaft TEXTAUSRICHTUNG bestimmt, wie die Daten innerhalb des Steuerelements ausgerichtet werden. Linker Rand, Oberer Rand, Rechter Rand, Unterer Rand: Diese Eigenschaften geben an, wie weit der Text vom linken, oberen, rechten und unteren Rand des Steuerelements entfernt ist. Sie sind besonders nützlich bei großen Steuerelementen wie Textfeldern, denen Memofelder zugrunde liegen. Zeilenabstand: Die Eigenschaft ZEILENABSTAND definiert den Abstand der Zeilen in einem mehrzeiligen Steuerelement. Diese Eigenschaft kommt am häufigsten bei Textfeldern zum Einsatz, denen Memofelder zugrunde liegen. Ist Hyperlink: Wenn diese Eigenschaft auf JA gesetzt ist, werden die Daten im Steuerelement als Hyperlink formatiert. Wenn die Daten im Steuerelement eine gültige Verknüpfung enthalten (z.B. http:\\microsoft.com), werden die Daten als Hyperlink funktionieren.
5.9.2
Dateneigenschaften eines Formulars
Steuerelementinhalt : Die Eigenschaft STEUERELEMENTINHALT bestimmt, welches Feld aus einer Datenquelle dem Steuerelement zu Grunde liegt. Eine Quelle kann auch jeder gültige Access-Ausdruck sein.
182
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Eingabeformat: Die Eigenschaften FORMAT und DEZIMALSTELLENANZEIGE beeinflussen das Erscheinungsbild des Steuerelements, während die Eigenschaft EINGABEFORMAT vorgibt, welche Daten in das Steuerelement eingegeben werden können. Falls vorhanden, wird das Eingabeformat des Feldes, das dem Steuerelement zugrunde liegt, automatisch an das Steuerelement vererbt. Wurde kein Eingabeformat als Feldeigenschaft definiert, kann das Eingabeformat direkt im Formular eingegeben werden. Andernfalls kann das Eingabeformat des Steuerelements die Eingabemöglichkeiten weiter einschränken. Wenn die Eigenschaften FORMAT und EINGABEFORMAT eines Steuerelements unterschiedlich sind, bestimmt der Wert von FORMAT die Anzeige der Daten im Steuerelement so lange, bis das Steuerelement den Fokus erhält. Wenn das Steuerelement den Fokus hat, gilt das EINGABEFORMAT. Standardwert: Die Eigenschaft STANDARDWERT eines Steuerelements bestimmt, welcher Wert neuen Datensätzen zugeordnet wird, die im Formular eingegeben werden. Diese Eigenschaft kann innerhalb der Feldeigenschaften gesetzt werden. Ein Standardwert, der an ein Feld vergeben wird, wird automatisch an das Formular vererbt. Der Standardwert für das Steuerelement überschreibt den eines Feldes. Gültigkeitsregel, Gültigkeitsmeldung: Die Gültigkeitsregel und die Gültigkeitsmeldung für ein Steuerelement haben die gleiche Wirkung wie für ein Feld. Auf dem Niveau der Datenbank-Engine gelten zwingende Gültigkeitsregeln, weshalb die Gültigkeitsregel für ein Steuerelement nicht derjenigen des zugehörigen Feldes widersprechen darf. Andernfalls kann der Benutzer keine Daten in das Steuerelement eingeben. Aktiviert: Die Eigenschaft Aktiviert bestimmt, ob ein Steuerelement den Fokus bekommen darf. Beim Wert NEIN erscheint das Steuerelement abgeblendet. Gesperrt: Die Eigenschaft GESPERRT legt fest, ob die Daten im Steuerelement verändert werden können. Wenn die Eigenschaft GESPERRT auf JA gesetzt ist, kann das Steuerelement den Fokus erhalten, aber nicht bearbeitet werden. Die Eigenschaften AKTIVIERT und GESPERRT eines Steuerelements stehen in Wechselwirkung zueinander. Tabelle 5.1 verdeutlicht diesen Zusammenhang.
Welche Steuerelementeigenschaften stehen zur Verfügung?
Aktiviert
Gesperrt
Wirkung
ja
ja
Das Steuerelement kann den Fokus bekommen und seine Daten können kopiert, aber nicht geändert werden.
ja
nein
Das Steuerelement kann den Fokus bekommen und seine Daten können geändert werden.
nein
ja
Das Steuerelement kann keinen Fokus bekommen.
nein
nein
Das Steuerelement kann keinen Fokus bekommen, seine Daten erscheinen abgeblendet.
183
Tabelle 5.1: Wie aktivierte und gesperrte Eigenschaften zusammenhängen
Filter anwenden: Die Eigenschaft FILTER ANWENDEN zeigt an, ob die Werte, die einem gebundenen Textfeld zugewiesen sind, im Fenster FORMULARBASIERTER FILTER erscheinen sollen.
5.9.3
Andere Eigenschaften eines Formulars
Name: Die Eigenschaft NAME erlaubt Ihnen, das Steuerelement zu benennen. Dieser Name dient zum Ansprechen des Steuerelements im Code und taucht in verschiedenen aufklappbaren Listen auf, die alle Steuerelemente eines Formulars anzeigen. Es ist wichtig, dass Ihre Steuerelemente einen Namen haben, denn benannte Steuerelemente verbessern die Lesbarkeit Ihres Codes und erleichtern die Arbeit mit Access-Formularen und anderen Objekten. Die Regeln zur Namensvergabe für Steuerelemente werden im Anhang abgehandelt. Statusleistentext: Die Eigenschaft STATUSLEISTENTEXT gibt den Text an, der in der Statusleiste erscheint, wenn das Steuerelement den Fokus erhält. Das Setzen dieser Eigenschaft überschreibt die Eigenschaft BESCHREIBUNG, die im Tabellenentwurf vorhanden sein kann. Eingabetasten-Verhalten: Die Eigenschaft EINGABETASTEN-VERHALTEN bestimmt, ob die Eingabetaste die Einfügemarke zum nächsten Steuerelement springen lässt oder im aktuellen Steuerelement eine neue Zeile einfügt. Letzteres wird oft bei Textfeldern angewandt, die den Inhalt von Memofeldern anzeigen. AutoKorrektur zulassen: Die Eigenschaft AUTOKORREKTUR ZULASSEN legt fest, ob im Steuerelement die AutoKorrektur verfügbar ist. Die AutoKorrektur berichtigt automatisch häufige Schreibfehler. Vertikal: Die Eigenschaft VERTIKAL steuert, ob der Text im Steuerelement horizontal oder vertikal angezeigt wird. Die Vorgabe lautet NEIN bzw. horizontal. Wenn VERTIKAL ausgewählt ist, wird der Text im Steuerelement um 90° gedreht.
184
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Automatisch weiter: Ist die Eigenschaft AUTOMATISCH WEITER auf JA gesetzt, springt die Einfügemarke automatisch zum nächsten Steuerelement, wenn das letzte Zeichen eines Eingabeformats eingegeben worden ist. Manche Benutzer mögen diese Option, andere finden sie lästig, besonders wenn es aus manchen Feldern nur mit der Tabulatortaste weitergeht und aus anderen nicht. Standard: Die Eigenschaft STANDARD bezieht sich auf eine Befehlsschaltfläche oder ein ActiveX-Steuerelement und bestimmt, ob das Steuerelement die Standardschaltfläche auf dem Formular darstellt. Abbrechen: Die Eigenschaft ABBRECHEN bezieht sich auf eine Befehlsschaltfläche oder ein ActiveX-Steuerelement und gibt an, dass der Code des Steuerelements ausgeführt werden soll, wenn das Formular aktiv ist und die Esc-Taste gedrückt wird. Makro Wiederholen: Die Eigenschaft MAKRO WIEDERHOLEN bestimmt, ob eine Prozedur oder ein Makro wiederholt ausgeführt werden sollen, solange die Befehlsschaltfläche gedrückt ist. Statusleistentext: Die Eigenschaft STATUSLEISTENTEXT bestimmt die Meldung, die in der Statusleiste erscheint, wenn das Steuerelement den Fokus hat. In Reihenfolge: Die Eigenschaft IN REIHENFOLGE legt fest, ob die Tabulatortaste benutzt werden kann, um zu einem Steuerelement zu gelangen. Diese Eigenschaft sollte für Steuerelemente, deren Werte selten verändert werden, auf NEIN gesetzt werden. Wird das Steuerelement doch einmal gebraucht, kann der Benutzer es anklicken. Reihenfolgenposition: Die Eigenschaft REIHENFOLGENPOSITION legt den Platz in der Tabulatorreihenfolge für das Steuerelement fest. Im Allgemeinen setze ich die Eigenschaft REIHENFOLGENPOSITION über ANSICHT|AKTIVIERREIHENFOLGE, statt den Wert direkt in der Eigenschaft REIHENFOLGENPOSITION des Steuerelements einzutragen. Kontextmenüleiste: Die Kontextmenüleiste ordnet einem Steuerelement ein bestimmtes Menü zu. Die Menüleiste erscheint, wenn der Benutzer mit der rechten Maustaste auf das Steuerelement klickt. SteuerelementTipp-Text: Die Eigenschaft STEUERELEMENTTIPP-TEXT legt den Kurzhinweis für das Steuerelement fest. Der Kurzhinweis erscheint automatisch, sobald der Benutzer den Mauszeiger über das Steuerelement bewegt und einen Moment dort lässt. HilfekontextID: Die Eigenschaft HILFEKONTEXTID bestimmt die Hilfsanzeige, die dem Steuerelement zugeordnet ist. Marke: Die Eigenschaft MARKE ist eine zusätzliche Eigenschaft, in der beliebige Informationen über ein Steuerelement gespeichert werden können und die zur Laufzeit gelesen und geändert werden kann.
Gebundene, ungebundene und berechnete Steuerelemente
5.10
185
Gebundene, ungebundene und berechnete Steuerelemente
Es gibt wichtige Unterschiede zwischen gebundenen und ungebundenen Steuerelementen. »Ungebundene Steuerelemente« zeigen Informationen an oder empfangen Informationen vom Benutzer, die nicht in der Datenbank gespeichert werden sollen. Hier einige Beispiele für ungebundene Steuerelemente:
Ein Bezeichnungsfeld, das dem Benutzer Anweisungen gibt Ein Logo, das auf dem Formular angezeigt wird Ein Kombinations- oder Textfeld auf dem Formular, in das der Benutzer Parameter für einen Bericht eingeben kann
Ein Rechteck, das auf das Formular gebracht wird, um mehrere Steuerelemente logisch zu gruppieren »Gebundene Steuerelemente« werden benutzt, um Informationen anzuzeigen und zu bearbeiten, die in einer Datenbanktabelle gespeichert sind. Ein gebundenes Steuerelement erscheint automatisch in dem Formular, das in seiner Eigenschaft STEUERELEMENT ANZEIGEN angegeben wurde, und das Steuerelement erbt automatisch viele der Attribute von dem Feld, an das es gebunden ist. Die Eigenschaft STEUERELEMENT ANZEIGEN wird im Tabellenentwurf festgelegt und bestimmt, welcher Art das gebundene Steuerelement ist, das zu einem Formular oder Bericht hinzugefügt wird. Ein »berechnetes Steuerelement« ist eine besondere Art von Steuerelement, das die Ergebnisse einer Berechnung anzeigt. Die Daten in einem berechneten Steuerelement können vom Benutzer nicht verändert werden. Der Wert des Steuerelements ändert sich automatisch, wenn sich die Werte des Ausdrucks ändern, der ihn berechnet. Beispielsweise ändert sich die Gesamtsumme, wenn der Preis oder die Menge verändert wird.
5.11
Formulare mit Hilfe von Ausdrücken erweitern
Wie im vorigen Abschnitt erwähnt, kann ein Steuerelement jeden beliebigen Ausdruck als Datensatzherkunft verwenden. Soll ein Ausdruck als Datenquelle des Steuerelements dienen, muss dem Ausdruck ein Gleichheitszeichen vorangestellt werden. Die Datenquelle kann von Hand eingegeben werden oder Sie benutzen den Ausdrucks-Generator, um den Vorgang zu vereinfachen.
186
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Um einen Ausdruck zur Datenquelle eines Steuerelements hinzuzufügen, beginnen Sie mit dem Hinzufügen eines ungebundenes Steuerelements zum Formular. Um den Ausdrucks-Generator zu starten, klicken Sie auf die Eigenschaft DATENSATZHERKUNFT des Formulars und anschließend auf die Schaltfläche mit den drei Punkten. Dies bringt Sie ins Dialogfeld AUSDRUCKS-GENERATOR (siehe Abbildung 5.29.) Im Listenfeld links wählen Sie die Art des Objekts aus, das Sie im Ausdruck verwenden wollen. Das mittlere und rechte Listenfeld lässt Sie die Elemente festlegen, die Sie in Ihren Ausdruck einfügen wollen. Der Ausdrucks-Generator ist sinnvoll, wenn Ihnen die jeweilige für den Ausdruck erforderliche Syntax nicht vertraut ist. Ein Ausdruck kann auch direkt in das Textfeld des Steuerelementinhalts eingegeben werden. Um den Ausdruck leichter betrachten zu können, steht Ihnen die ZoomFunktion zur Verfügung (Umschalt+F2). Das Dialogfeld ZOOM für den Steuerelementinhalt sehen Sie in Abbildung 5.30. Der dort dargestellte Ausdruck berechnet die Auszahlungssumme. Wenn die Auszahlungssumme größer oder gleich 1000 ist, wird die Meldung »Big Hitter« und sonst nichts angezeigt.
Abbildung 5.29: Der Ausdrucks-Generator hilft Ihnen beim Hinzufügen eines Ausdrucks als Datenquelle für ein Steuerelement
Abbildung 5.30: Das Dialogfeld ZOOM für eine Steuerelementquelle
Die Befehlsschaltflächen-Assistenten: Programmierung ohne Eingabe
5.12
187
Die Befehlsschaltflächen-Assistenten: Programmierung ohne Eingabe
Mit dem Befehlsschaltflächen-Assistenten können Sie Ihren Formularen schnell und einfach Funktionalität hinzufügen. Der Assistent schreibt den Code für 33 häufig erforderliche Aufgaben aus den Bereichen Datensatznavigation, Datensatzoperationen, Formularoperationen, Berichtsoperationen, Anwendung und Diverse. Der Befehlsschaltflächen-Assistent wird automatisch aufgerufen, wenn Sie eine Befehlsschaltfläche hinzufügen und gleichzeitig die Schaltfläche STEUERELEMENT-ASSISTENTEN aktiviert ist. Den ersten Schritt des Befehlsschaltflächen-Assistenten sehen Sie in Abbildung 5.31. Hier geben Sie die Art der Aktivität und die besonderen Aktionen an, welche die Befehlsschaltfläche durchführen soll. Die folgenden Schritte des Assistenten unterscheiden sich in Abhängigkeit von der ausgewählten Kategorie und Aktion.
Abbildung 5.31: Der erste Schritt des BefehlsschaltflächenAssistenten
Abbildung 5.32 zeigt, wie der zweite Schritt des Befehlsschaltflächen-Assistenten aussieht, wenn im ersten Schritt die Kategorie FORMULAROPERATIONEN und FORMULAR ÖFFNEN ausgewählt wurden. Beachten Sie, dass dieser Schritt fragt, welches Formular Sie öffnen wollen. Nachdem Sie ein Formular ausgewählt und WEITER angeklickt haben, werden Sie gefragt, ob Access das Formular öffnen und bestimmte Daten zum Anzeigen suchen soll, oder ob Sie möchten, dass das Formular geöffnet wird und alle Datensätze angezeigt werden. Wenn Sie angeben, dass nur bestimmte Datensätze angezeigt werden sollen, erscheint das Dialogfeld aus Abbildung 5.33. Dieses fordert Sie auf, Felder auszuwählen, die eine Beziehung zwischen den beiden Formularen herstellen. Im nächsten Schritt des Assistenten wählen Sie einen Text oder ein Bild für die Befehlsschaltfläche aus. Der letzte Schritt des Assistenten fragt Sie nach dem Namen für die Befehlsschaltfläche.
188
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Abbildung 5.32: Der Befehlsschaltflächen-Assistent erwartet die Auswahl des Namens eines zu öffnenden Formulars
Abbildung 5.33: Der Befehlsschaltflächen-Assistent erwartet die Auswahl der Felder mit Bezug auf jedes Formular
Am Befehlsschaltflächen-Assistenten überrascht am meisten, wie unterschiedlich er in Abhängigkeit von den ausgewählten Merkmalen funktioniert. Er gestattet das Hinzufügen komplizierterer Funktionalitäten zu Ihrer Anwendung, ohne dass Sie eine einzige Zeile Code schreiben müssen. Den Code, der für das eben genannte Beispiel generiert wurde, sehen Sie in Abbildung 5.34; er wird viel verständlicher, wenn Sie die nächsten Kapitel gelesen haben. Der Vorteil des vom BefehlsschaltflächenAssistenten generierten Codes ist, dass er vollständig verändert werden kann, nachdem er geschrieben wurde. Access nimmt Ihnen also einiges an Routinearbeit ab und liefert ein Ergebnis, das Sie ganz an Ihre Vorstellungen anpassen können.
189
Formulare auf der Grundlage mehrerer Tabellen
Abbildung 5.34: Der vom BefehlsschaltflächenAssistenten erzeugte Code
5.13
Formulare auf der Grundlage mehrerer Tabellen
Viele Formulare sind auf mehreren Tabellen aufgebaut. Beispielsweise wird ein Formular, das oben einen Kunden und darunter dessen Aufträge zeigt, als 1:n-Formular betrachtet. Formulare können auch auf einer Abfrage basieren, die mehrere Tabellen verknüpft. Anstatt in solch einem Formular eine 1:n-Beziehung zu sehen, werden die beiden Tabellen als eine angezeigt, wobei jeder Datensatz auf der Mehrfachseite der Beziehung mit seinen übergeordneten Daten erscheint.
5.13.1
1:n-Formulare erstellen
Es gibt verschiedene Möglichkeiten, 1:n-Formulare zu erstellen. Wie bei vielen anderen Arten von Formularen können Sie sich von einem Assistenten helfen lassen oder das Formular eigenhändig entwerfen. Weil alle Methoden der Formularerstellung für Benutzer und Entwickler gleichermaßen nützlich sind, werden in diesem Abschnitt die verfügbaren Optionen behandelt. Ein 1:n-Formular mit Hilfe des Formular-Assistenten erstellen Das Erstellen eines 1:n-Formulars mit Hilfe des Formular-Assistenten ist ein einfacher Vorgang, der zehn Schritte umfasst:
190
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
1. Klicken Sie in der Objektliste auf FORMULAR und doppelklicken Sie dann auf ERSTELLT EIN FORMULAR UNTER VERWENDUNG DES ASSISTENTEN. 2. Wählen Sie aus dem aufklappbaren Listenfeld TABELLEN/ABFRAGEN die Tabelle oder Abfrage aus, die auf der 1-Seite der Beziehung erscheinen soll. 3. Wählen Sie die Felder aus, die Sie von der 1-Seite der Beziehung aus verwenden wollen. 4. Wählen Sie aus dem aufklappbaren Listenfeld TABELLEN/ABFRAGEN die Tabelle oder Abfrage aus, die auf der Mehrfachseite der Beziehung erscheinen soll. 5. Wählen Sie die Felder aus, die Sie von der Mehrfachseite der Beziehung aus verwenden wollen. 6. Klicken Sie auf WEITER. 7. Entscheiden Sie, ob das übergeordnete Formular mit Unterformularen oder ob die untergeordneten Formulare als verknüpfte Formulare erscheinen sollen (siehe Abbildung 5.35). Klicken Sie auf WEITER.
Abbildung 5.35: Der Formular-Assistent beim Erstellen eines 1:nFormulars
8. Wenn Sie die Option FORMULAR MIT UNTERFORMULAR(EN) auswählen, müssen Sie angeben, ob das Unterformular in tabellarischer Form oder als Datenblatt erscheinen soll. Diese Option ist nicht verfügbar, wenn im siebten Schritt VERKNÜPFTE FORMULARE ausgewählt wurde. Klicken Sie auf WEITER. 9. Wählen Sie ein Format für das Formular aus und klicken Sie auf WEITER. 10. Geben Sie dem Formular und dem Unterformular einen Namen und klicken Sie auf FERTIG STELLEN.
191
Formulare auf der Grundlage mehrerer Tabellen
Das Ergebnis ist ein Hauptformular, das ein Unterformular enthält. Ein Beispiel sehen Sie in Abbildung 5.36
Abbildung 5.36: Das Ergebnis des Erstellens eines 1:n-Formulars mit dem FormularAssistenten
Ein 1:n-Formular mit Hilfe des Unterformular/Unterbericht-Assistenten erstellen Ein 1:n-Formular kann auch durch Erstellen des übergeordneten Formulars und anschließendes Hinzufügen eines Unterformular/-berichts-Steuerelements aus der Toolbox geschaffen werden. Wenn Sie den Unterformular/Unterberichts-Assistenten benutzen wollen, überzeugen Sie sich davon, dass das Werkzeug STEUERELEMENT-ASSISTENTEN ausgewählt ist, bevor Sie das Unterformular/-berichts-Steuerelement zum Hauptformular hinzufügen. Danach folgen sechs Schritte: 1. Klicken Sie auf das Steuerelement UNTERFORMULAR/-BERICHT. 2. Klicken Sie auf die Stelle des Hauptformulars, an der Sie das Unterformular einfügen möchten. Dadurch wird der Unterformular-Assistent aufgerufen. 3. Entscheiden Sie, ob Sie ein bestehendes Formular als Unterformular verwenden oder ein neues Unterformular auf einer Tabelle oder Abfrage aufbauen wollen. 4. Wenn Sie TABELLEN/ABFRAGEN auswählen, fragt der nächste Schritt des Unterformular-Assistenten nach der Tabelle/Abfrage und den Feldern, die Sie daraus verwenden wollen (siehe Abbildung 5.37). Wählen Sie die Felder aus und klicken Sie auf WEITER. 5. Der nächste Schritt des Unterformular-Assistenten fragt Sie nach der Beziehung zwischen den Feldern der beiden Formulare. Sie können die vorgeschlagene Beziehung auswählen oder eine eigene definieren (siehe Abbildung 5.38). 6. Benennen Sie das Unterformular und klicken Sie auf FERTIG STELLEN. Das entstandene Formular sollte so ähnlich aussehen wie ein Formular, das mit dem Formular-Assistenten erstellt worden ist. Das Erstellen eines 1:n-Formulars auf diese Art stellt einfach nur eine Alternative zum Formular-Assistenten dar.
192
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Abbildung 5.37: Felder zum Einbinden in das Unterformular auswählen
Abbildung 5.38: Die Beziehung zwischen dem Haupt- und dem Unterformular definieren
Ein anderer Weg zum Hinzufügen eines Unterformulars zu einem Hauptformular besteht darin, ein Formular im Datenbankfenster anzuklicken und auf das Hauptformular zu ziehen. Access versucht anschließend, die Beziehung zwischen den beiden Formularen herauszufinden.
Formulare auf Abfragen aufsetzen
5.13.2
193
Unterformulare
Nachdem ein Unterformular hinzugefügt worden ist, müssen Sie verstehen, wie man damit arbeitet. Machen Sie sich zunächst mit den folgenden Eigenschaften eines Unterformular-Steuerelements vertraut: Herkunftsobjekt: Der Name des Formulars, der im Steuerelement angezeigt wird Verknüpfen von: Die Felder des Unterformulars, die dieses mit dem Hauptformular verknüpfen Verknüpfen nach: Die Felder des Hauptformulars, durch die das Unterformular mit diesem verknüpft wird Ebenso sollten Sie verstehen, wie Unterformulare geändert werden. Eine Möglichkeit besteht darin, das Unterformular wie jedes andere Formular zu öffnen. Nach dem Schließen und Sichern des Formulars erscheinen alle Änderungen dann automatisch im Hauptformular. Die andere Möglichkeit ist, das Unterformular aus dem Hauptformular heraus zu bearbeiten. Bei geöffnetem Hauptformular sieht man auch das Unterformular. Alle Änderungen, die innerhalb des Hauptformulars am Entwurf des Unterformulars durchgeführt werden, sind dauerhaft. Die Standardansicht des Unterformulars ist DATENBLATT oder ENDLOSFORMULAR, je nachdem, wie Sie das Unterformular unter Verwendung welcher Optionen hinzugefügt haben. Wenn Sie die Standardansicht verändern wollen, bearbeiten Sie einfach die Standardansicht des Unterformulars. Wenn ein Unterformular in der Datenblattansicht gezeigt wird, ist die Reihenfolge der Felder im Unterformular völlig unabhängig von dem Datenblatt, das im Hauptformular erscheint. Die Reihenfolge der Spalten hängt ausschließlich von der Aktivierreihenfolge der Felder im Unterformular ab. Sie müssen daher die Aktivierreihenfolge der Felder im Unterformular bearbeiten, um die Reihenfolge der Felder im Datenblatt zu verändern.
5.14
Formulare auf Abfragen aufsetzen
Eine Strategie der Formularerstellung ist das Aufsetzen auf Abfragen, wodurch Sie grundsätzlich eine optimale Geschwindigkeit und eine hohe Flexibilität erzielen. Anstatt alle Felder und Datensätze über das Netzwerk zu senden, übertragen Sie nur diejenigen, die wirklich gebraucht werden. Die Vorteile dieser Strategie werden erheblich deutlicher, wenn Sie in einer Client-Server-Umgebung tätig sind, in der die Abfrage auf dem Server abgearbeitet wird. Auch in einer Umgebung, in der die Daten im Access-Dateiformat (.MDB) auf einem Datei-Server gespeichert werden, kann ein Formular, das auf einer Abfrage basiert, die Vorteile der Indizierung und der Spei-
194
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
cherverwaltung von Access besser ausnutzen. Durch das Aufsetzen des Formulars auf einer Abfrage haben Sie zudem eine bessere Kontrolle darüber, welche Datensätze in das Formular aufgenommen werden und in welcher Reihenfolge sie erscheinen. Außerdem können Sie ein Formular auch auf einer 1:n-Verknüpfung aufbauen, wobei Haupt- und Detailinformationen wie ein Datensatz dargestellt werden. Beachten Sie, dass in Abbildung 5.39 die Kunden- und Projektinformationen auf dem Formular so erscheinen, als wären sie ein Datensatz.
Abbildung 5.39: Ein Formular auf der Grundlage einer 1:nAbfrage
5.14.1
Eingebettete SQL-Anweisungen und gespeicherte Abfragen im Vergleich
In früheren Access-Versionen boten gespeicherte Abfragen eine bessere Leistung als eingebettete SQL-Anweisungen. Der Grund dafür liegt darin, dass Access beim Speichern einer Abfrage diese kompiliert und einen Abfrageplan generiert, der Informationen über das Optimieren der Abfrage hinsichtlich Datenmenge und verfügbarer Indizes enthält. Wenn in früheren Access-Versionen ein Formular auf einer eingebetteten SQL-Anweisung aufgebaut war, wurde die SQL-Anweisung bei jedem Öffnen des Formulars erneut kompiliert und optimiert. In Access 2000 werden eingebettete SQL-Anweisungen jedoch genauso kompiliert wie gespeicherte Abfragen. Vielleicht fragen Sie sich jetzt, ob es in Access 2000 besser ist, eine Abfrage auf einer gespeicherten Abfrage oder auf einer SQL-Anweisung aufzubauen. Ich bevorzuge Folgendes: Habe ich vor, dieselbe oder eine vergleichbare Abfrage zusammen mit mehreren Formularen und Berichten zu verwenden, erstelle ich eine Abfrage und baue die Formulare und Berichte darauf auf. Dadurch muss ich die Abfrage nicht doppelt und dreifach erstellen. Brauche ich dagegen eine Abfrage, die nur in einem Formular vorkommt, baue ich sie als eingebettete SQL-Anweisung auf. Dadurch spare ich in der Datenbank den Platz, den eine Abfrage nun einmal einnimmt.
Access-Formulare und das Internet
195
Ein Abfrageplan kann manchmal ungenau sein, weil er die Abfrage anhand der Datenmenge in den Tabellen optimiert, die dem Formular zugrundeliegen. Unterliegt die Datenmenge in diesen Tabellen starken Schwankungen, muss der Abfrageplan neu erstellt werden. Dies kann durch Öffnen, Ausführen und Speichern der Abfrage oder durch Komprimieren der Datenbank geschehen.
5.15
Access-Formulare und das Internet
Microsoft hat die Entwicklung Internet-fähiger Anwendungen vereinfacht, indem Hyperlinks zu Formularen hinzugefügt und Access-Formulare als HTML oder im Microsoft-IIS-Format (Version 1 oder 2) gespeichert werden können. Diese Möglichkeiten werden in den folgenden Abschnitten behandelt.
5.15.1
Einem Formular einen Hyperlink hinzufügen
Hyperlinks können zu ungebundenen Bezeichnungsfeldern (Bezeichnungsfelder, die nicht mit einem Textfeld oder einem anderen Objekt verbunden sind), Schaltflächen und Bild-Steuerelementen hinzugefügt werden. Sind sie vorhanden, kann der Benutzer zu einem Dokument (UNC) oder einer Homepage (URL) springen, indem er einfach das Steuerelement mit dem Hyperlink anklickt. Zum Hinzufügen eines Hyperlinks zu einem Bezeichnungsfeld, einer Schaltfläche oder einem Bild-Steuerelement gehen Sie folgendermaßen vor: 1. Klicken Sie das Steuerelement an, um es auszuwählen. 2. Sehen Sie sich die Steuerelementeigenschaften an. 3. Wählen Sie die Registerkarte FORMAT des Eigenschaftenfensters. 4. Klicken Sie auf die Eigenschaft HYPERLINK-ADRESSE. 5. Klicken Sie auf die Erstellen-Schaltfläche (die drei Punkte), um das Dialogfeld HYPERLINK EINFÜGEN zu öffnen (siehe Abbildung 5.40). 6. Haben Sie unter LINK ZU die Schaltfläche DATEI ODER WEBSEITE ausgewählt, können Sie einen Dateipfad oder einen URL im Textfeld eingeben oder auf DATEI bzw. WEBSEITE klicken, um eine Datei oder URL zu suchen. Sie können auch Hyperlinks auf zuletzt verwendete Dateien, betrachtete Webseiten oder eingefügte Verknüpfungen erzeugen. Wenn Sie unter LINK ZU die Schaltfläche AKTUELLE DATENBANK auswählen, können Sie eine Verknüpfung zu einem Objekt in der aktuellen Datenbank erstellen (siehe Abbildung 5.41). Wählen Sie NEUE SEITE ERSTELLEN, um eine neue Datenzugriffsseite zu erstellen, oder wählen Sie E-MAIL-ADRESSE aus, um eine Verknüpfung zu einer E-Mail-Adresse zu definieren.
196
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Abbildung 5.40: Mit Hilfe des Dialogfelds Hyperlink einfügen eine Verknüpfung zu einer Datei oder einem URL einrichten
Abbildung 5.41: Innerhalb einer Access-Datenbank einen Ort für einen Hyperlink festlegen
7. Klicken Sie auf OK, um den Vorgang abzuschließen. Der Inhalt des Textfeldes DATEITYP ODER WEBSEITE wird zur Hyperlink-Adresse und der Objektname wird zur Hyperlink-Unteradresse (siehe Abbildung 5.42). Das Verwenden einer Hyperlink-Adresse zum Öffnen eines Objekts in einer Access-Datenbank anstelle des Klick-Ereignisses BEIM KLICKEN der Schaltfläche und VBA-Code erlaubt es Ihnen, das Klassenmodul des Formulars zu entfernen (vorausgesetzt, dies ist die einzige Prozedur, die Sie für das Formular benötigen) und damit die Leistung des Formulars zu optimieren.
Access-Formulare und das Internet
197
Abbildung 5.42: Für ein Bezeichnungssteuerelement definierte HyperlinkAdresse und -Subadresse
5.15.2
Ein Formular als HTML speichern
Formulare können auf zwei Arten als HTML-Dokumente gespeichert werden. Die erste Methode sieht vor, das Formular als HTML zu speichern, indem Sie DATEI|EXPORTIEREN auswählen. (Sie können das Formular auch im Datenbankfenster mit der rechten Maustaste anklicken und EXPORTIEREN auswählen.) Dies ruft das Dialogfeld EXPORTIEREN VON FORMULAR auf. Wählen Sie HTML-DOKUMENTE (*.HTML;*.HTM) aus dem aufklappbaren Listenfeld DATEITYP aus. Geben Sie einen Dateinamen für das HTML-Dokument ein. Wenn nach dem Sichern des HTML-Dokuments der standardmäßige Browser des Systems geladen werden soll, klicken Sie auf AUTOSTART. Klicken Sie danach auf SPEICHERN. Es erscheint das Dialogfeld HTML-AUSGABEOPTIONEN. Klicken Sie ggf. auf DURCHSUCHEN, um eine HTML-Vorlage zu finden. Klicken Sie anschließend auf OK, um das Dialogfeld HTML-AUSGABEOPTIONEN zu schließen. Nur das Datenblatt, das dem Formular zugeordnet ist, wird als HTML gespeichert, das Format des Formulars selbst dagegen nicht. Die andere Methode besteht in der Auswahl von DATEI|SPEICHERN UNTER. Wählen Sie in diesem Fall DATENZUGRIFFSSEITE aus dem aufklappbaren Listenfeld ALS. Weitergehende Informationen finden Sie in Kapitel 32.
198
5.15.3
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Ein Formular für den Internet Information Server oder als Active Server Pages speichern
Formulare können auch für den Microsoft Internet Information Server (Version 1 oder 2) oder als Active Server Pages gespeichert werden. Beide Möglichkeiten erstellen dynamische Formulare. Im Falle des Microsoft IIS werden die .HTX- und .IDCDateien benutzt, um eine .HTM-Datei mit den aktuellen Daten aufzubauen. Die .IDCDatei enthält Informationen über die Datenquelle einschließlich des Datenquellennamens, des Benutzernamens, des Passwortes und der Abfrage, welche die Datensatzherkunft des erstellten Formulars zurückgibt. Die .HTX-Datei ist eine HTMLDatei, die Code enthält, welcher angibt, wo die zurückgegebenen Daten eingefügt werden sollen. Mit Hilfe von Active Server Pages erstellt der Microsoft Information Server ebenfalls eine .HTM-Datei mit den aktuellen Daten. Diese und andere Punkte zum Erstellen von Access-Anwendungen für das Internet werden detaillierter in Kapitel 31 behandelt.
5.15.4
Für die Praxis
Formulare für Ihre Anwendung entwerfen Das Zeit- und Abrechnungssystem erfordert verschiedene Formulare. Die wichtigeren werden in diesem Abschnitt entworfen und sind auf der CD-ROM in der Datei CHAP5.MDB enthalten.
Die Formulare, die in diesem Abschnitt erstellt werden, sind recht komplex. Wenn Sie es vorziehen, können Sie die vollständigen Formulare aus CHAP5.MDB benutzen, anstatt sie selbst aufzubauen.
5.15.5
Das Kundenformular entwerfen
Abbildung 5.43 zeigt das Formular frmClients, ein 1:n-Formular mit einem Unterformular namens fsubClients. Das Hauptformular baut auf der Abfrage qryClients auf, während dem Unterformular die Abfrage qryClientsSub zugrunde liegt. Der Formularfuß enthält drei Schaltflächen. Die Schaltfläche VIEW PROJECTS öffnet das Formular frmProjects mit einer Where-Bedingung, wobei nur die Projekte gezeigt werden, die zum Kunden auf dem Hauptformular gehören. Die Schaltfläche VIEW PAYMENTS öffnet das Formular frmPayments für die Projekte, die im Unterformular fsubClients ausgewählt worden sind. Anstatt in der Anweisung OpenForm eine WhereBedingung zu benutzen, werden die Kriterien in der Abfrage gesetzt, die dem Formu-
Access-Formulare und das Internet
199
Abbildung 5.43: Das frmClientsFormular zeigt alle Projekte, die mit einem ausgewählten Kunden in Zusammenhang stehen
lar frmPayment zu Grunde liegt. Das Formular frmTimeCards wird ohne Rücksicht auf den ausgewählten Kunden geöffnet, wenn man auf die Schaltfläche VIEWTIMECARDS klickt. Man kann hier unabhängig vom Kunden Zeitkarten für jedes Projekt eingeben. Das Formular kann auch mit einem Hyperlink geöffnet werden. Werfen Sie jetzt einen Blick auf die Schritte, die erforderlich sind, um eine Schaltfläche hinzuzufügen, wie z.B. die Schaltfläche VIEW PROJECTS. Zu diesem Zweck können Sie vom Schaltflächen-Assistenten Gebrauch machen. Wählen Sie im Assistenten die Kategorie FORMULAROPERATIONEN und als Aktion FORMULAR ÖFFNEN. Überzeugen Sie sich davon, dass Sie das Formular frmProjects mit einer WhereBedingung öffnen, indem Sie im dritten Schritt des Befehlsschaltflächen-Assistenten die Option DAS FORMULAR ÖFFEN UND BESTIMMTE DATEN SUCHEN UND ANZEIGEN auswählen. Nennen Sie die Schaltfläche cmdProjects. Es muss noch eine wichtige Zeile zu dem Stück Code hinzugefügt werden, das der Schaltflächen-Assistent geschrieben hat. Hierzu klicken Sie auf die Schaltfläche, deren Code Sie bearbeiten wollen, während Sie sich in der Entwurfsansicht für frmClients befinden. Betrachten Sie die Ereigniseigenschaften der Schaltfläche und klicken Sie dann die Schaltfläche mit den drei Punkten rechts vom Ereignis BEIM KLICKEN für die Schaltfläche an. Fügen Sie die folgende Zeile Code vor der Zeile stDocNAme = "frmProjects" ein: DoCmd.RunCommand acCmdSaveRecord
Diese Code-Zeile sichert den aktuellen Kundendatensatz, bevor eines der anderen Formulare geöffnet wird. Die vollständige Routine könnte zum Beispiel folgendermaßen aussehen: Sub cmdProjects_Click() On Error GoTo Err_cmdProjects_Click
200
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Dim stDocName As String Dim stLinkCriteria As String DoCmd.RunCommand acCmdSaveRecord stDocName = "frmProjects" stLinkCriteria = "[ClientID]=" & Me.[txtClientID] DoCmd.OpenForm stDocName, , , stLinkCriteria Exit_cmdProjects_Click: Exit Sub Err_cmdProjects_Click: MsgBox Err.Description Resume Exit_cmdProjects_Click End Sub
Nennen Sie die beiden anderen Schaltflächen cmdPayments und cmdTimeCards. Legen Sie die Eigenschaft HYPERLINK-ADRESSE für jede Schaltfläche so fest, dass sie auf die aktuelle Datenbank zeigt. Setzen Sie die Eigenschaft HYPERLINK-UNTERADRESSE von cmdPayments so, dass sie das Formular frmPayments öffnet, und geben Sie die Eigenschaft HYPERLINK-UNTERADRESSE von cmdTimeCards so an, dass das Formular frmTimeCards geöffnet wird.
5.15.6
Das Zeitkartenformular entwerfen
Das Formular frmTimeCards basiert auf der Abfrage qryTimeCards und enthält zwei Unterformulare (siehe Abbildung 5.44). Das erste Unterformular heißt fsubTimeCards und das zweite fsubTimeCardsExpenses. Das Unterformular fsubTimeCards baut auf der Abfrage qrySubTimeCards auf und enthält ein berechnetes Steuerelement im Formularfuß. Dieses Steuerelement heißt txtTotalHoursWorked und enthält den Ausdruck =Summe(BillableHours), der die Summe der abrechenbaren Stunden im Unterformular ermittelt. Das Unterformular fsubTimeCardsExpenses basiert auf der Abfrage qrySubTimeCardsExpenses und umfasst ebenfalls ein berechnetes Steuerelement im Formularfuß. Das Steuerelement heißt txtTotalExpenses und enthält den Ausdruck =Summe(ExpenseAmount), der die Summe der Ausgaben im Unterformular ermittelt. Der Fuß des Formulars frmTimeCards enthält zwei Steuerelemente: txtTotalBillableHours und txtTotalExpenses, wobei das Steuerelemente txtTotalBillableHours den folgenden Ausdruck einschließt: =[fsubTimeCards].[Formular]![txtTotalHoursWorked]
Access-Formulare und das Internet
201
Abbildung 5.44: Das frmTimeCards-Formular zeigt alle Arbeitszeiten und Ausgaben für einen bestimmten Mitarbeiter
Dieser Ausdruck übernimmt das Ergebnis der Berechnung des Steuerelements txtTotalHoursWorked auf dem Unterformular fsubTimeCards. Das Steuerelement txtTotalExpenses umfasst den folgenden Ausdruck: =[fsubTimeCardsExpenses].[Formular]![txtTotalExpenses]
Dieser Ausdruck weist das Ergebnis der Berechnung des Steuerelements txtTotalExpenses auf dem Unterformular fsubTimeCardsExpenses zu.
5.15.7
Das Zahlungenformular entwerfen
Das Formular frmPayments basiert auf der Abfrage qryPayments, welche das folgende Kriterium für die ProjectID (Projektnummer) enthält: [Formulare]![frmClients]![fsubClients].[Formular]![ProjectID]
Dieses Kriterium betrachtet das Feld ProjectID aus dem Unterformular fsubClients, das Teil des Formulars frmClients ist, und stellt sicher, dass Sie nur Zahlungen sehen, die mit dem ausgewählten Projekt zusammenhängen. Das Formular frmPayments sehen Sie in Abbildung 5.45. Das Textfeld ProjectName enthält diesen Ausdruck: [Formulare]![frmClients]![fsubClients].[Formular]![txtProject Name]
Dieser Ausdruck zeigt den Projektnamen aus dem Unterformular fsubClients auf dem Formular frmClients an.
202
5.15.8
Kapitel 5: Was jeder Entwickler über Formulare wissen sollte
Das Projektformular entwerfen
Das Formular frmProjects ist komplexer als die anderen: es enthält zwei Unterformulare, von denen eines über dem anderen liegt. Die Schaltfläche View Expenses ist ein Umschalter, der den Benutzer sowohl Ausgaben als auch Stunden sehen lässt (siehe Abbildung 5.46)
Abbildung 5.45: Das frmPayments-Formular dient der Eingabe von Zahlungen in Zusammenhang mit einem bestimmten Projekt
Abbildung 5.46: Das frmProjects-Formular erlaubt dem Benutzer das Betrachten der Ausgaben und Zeiten, die für ein bestimmtes Projekt angefallen sind
Das Formular frmProjects beruht auf der Abfrage qryProjects, die den folgenden Ausdruck als Kriterium für die CientID hat: [Formulare]![frmClients]![txtClientID]
Dieser Ausdruck bedeutet, dass nur Projekte angezeigt werden, bei denen die ClientID im Formular frmClients dargestellt wird. Die beiden Unterformulare sind fsubProjects und fsubProjectExpenses. Der Code, der ihre Sichtbarkeit umschaltet, wird in Kapitel 8 behandelt. Das Formular fsubProjects basiert auf qrySubProjects und das Formular fsubProjectExpenses auf qrySubProjectExpenses. Das Formular frmProjects enthält ebenso wie die beiden Unterformulare verschiedene berechnete Steuerelemente.
Access-Formulare und das Internet
5.15.9
203
Was noch vor uns liegt
Die in diesem Beispiel erstellte Anwendung ist dem Zeit- und Abrechnungssystem nachgebildet, das vom Datenbank-Assistenten erstellt wurde. Sie werden diese Anwendung von Grund auf selbst aufbauen und so alles über ihre Bestandteile lernen. Außerdem werden Sie dieser Anwendung bedeutend mehr Funktionalität hinzufügen. Am Ende wird Ihre Anwendung weit leistungsfähiger sein als die Anwendung, die der Datenbank-Assistent erstellt hat.
Was jeder Entwickler über Berichte wissen sollte
Kapitel
Hier lesen Sie:
Berichtstypen Einen neuen Bericht erstellen Das Berichtsentwurfsfenster Das geeignete Steuerelement auswählen Welche Berichtseigenschaften stehen zur Verfügung und warum sollten sie benutzt werden?
Welche Steuerelementeigenschaften stehen zur Verfügung und warum sollten sie benutzt werden?
Berichte auf der Grundlage mehrerer Tabellen Sortierreihenfolge und Gruppierung Durch Aufsetzen der Berichte auf gespeicherte Abfragen die Geschwindigkeit und die Wiederverwendbarkeit verbessern
Access-Berichte und das Internet
6.1
Berichtstypen
Der Berichts-Generator von Microsoft Access ist sehr leistungsfähig und bietet eine Vielzahl von Möglichkeiten. Es gibt viele verschiedene Berichtstypen in Access 2000:
Detailberichte zusammenfassende Berichte Kreuztabellenberichte Berichte mit Grafiken und Diagrammen
206
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Berichte mit Formularen Berichte mit Etiketten Berichte mit einer beliebigen Kombination dieser Elemente
6.1.1
Detailberichte
Ein Detailbericht liefert einen Eintrag für jeden im Bericht enthaltenen Datensatz. Wie Sie in Abbildung 6.1 sehen können, gibt es in der Tabelle Bestellungen im Zeitraum 1995-96 für jede Bestellung einen Eintrag. Die Detailangaben des Berichts sind nach Ländern und innerhalb der Länder nach Verkaufsberatern gruppiert. Zusätzlich werden Zwischensummen für die Verkaufsberater und Länder angegeben. Am Ende des Berichts erscheint die Endsumme für alle Datensätze in diesem Bericht. Der Bericht basiert auf einer Parameterabfrage, welche die im Bericht anzuzeigenden Daten nach Kriterien begrenzt, die der Benutzer zur Laufzeit vorgibt.
Abbildung 6.1: Ein Beispiel für einen Detailbericht
6.1.2
Zusammenfassende Berichte
Ein zusammenfassender Bericht gibt Ihnen eine Zusammenfassung für alle Datensätze, die im Bericht enthalten sind. In Abbildung 6.2 werden nur die Gesamtumsätze je Quartal und Jahr im Bericht angezeigt. Die zu Grunde liegenden Datensätze, aus denen diese Zusammenfassung resultiert, erscheinen in diesem Bericht nicht. Der Bericht basiert auf einer Abfrage, welche die Nettoumsätze nach der BESTELLNR zusammenfasst. Der Bericht selbst enthält in seinem Detailbereich keine Steuerelemente. Sämtliche Steuerelemente befinden sich in den Kopf- und Fußbereichen
Berichtstypen
207
von Gruppen, die sich auf das Quartal und das Jahr des Lieferdatums beziehen. Da im Detailbereich des Berichts keine Steuerelemente zu finden sind, druckt Access nur die Zusammenfassung.
Abbildung 6.2: Ein Beispiel für einen zusammenfassenden Bericht
6.1.3
Kreuztabellenberichte
Kreuztabellenberichte zeigen zusammengefasste Daten an, die nach einer Datenmenge auf der linken Seite des Berichts und einer anderen Menge im oberen Teil gruppiert sind. Der Bericht in Abbildung 6.3 zeigt Umsätze je Produkt und Mitarbeiter. Der Bericht basiert auf einer Kreuztabellenabfrage und wurde mit etwas Programmierung erstellt. Das Programm ist erforderlich, weil bei jedem Ausführen des Berichts unter Umständen eine andere Anzahl von Mitarbeitern in den Spalten des Berichts dargestellt werden muss. Mit anderen Worten: die Anzahl der benötigten Spalten kann von Bericht zu Bericht variieren. Dieser Bericht sowie die erforderlichen Verfahren, um ihn zu erstellen, werden in Kapitel 10 erklärt.
6.1.4
Berichte mit Grafiken und Diagrammen
Auch wenn der Satz »Ein Bild sagt mehr als tausend Worte« ein Klischee ist, so ist er dennoch wahr – Untersuchungen zeigen, dass man sich Daten besser merkt, wenn sie in einem Bild anstatt als Zahlen angezeigt werden. Glücklicherweise macht Access das Einfügen von Grafiken und Diagrammen recht einfach. Wie in Abbildung 6.4 zu sehen ist, kann ein Bericht entworfen werden, der Zahlen und Diagramme
208
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Abbildung 6.3: Ein Beispiel für einen Kreuztabellenbericht
verbindet. Der Bericht in Abbildung 6.4 zeigt die Umsätze pro Produkt sowohl als Zahlen als auch in Form eines Balkendiagramms. Der Hauptbericht ist nach Produktkategorien gruppiert und enthält einen Unterbericht, der auf einer Abfrage basiert, welche die Umsätze nach den Feldern KATEGORIE-NR, KATEGORIENAME und ARTIKELNAME für einen bestimmten Datenbereich zusammenfasst. Das Diagramm summiert die Artikelumsätze nach dem Artikelnamen, um die Informationen grafisch darzustellen.
Abbildung 6.4: Ein Beispiel für einen Bericht mit einem Diagramm
Berichtstypen
6.1.5
209
Berichte mit Formularen
Benutzer brauchen häufig einen Bericht, der wie ein gedrucktes Formular aussieht. Der Berichts-Generator von Access mit seinen vielen grafischen Hilfsmitteln erlaubt Ihnen das schnelle Erstellen von Berichten, die selbst das eleganteste Eingabeformular nachahmen. Der Bericht in Abbildung 6.5 erstellt eine Rechnung für einen Kunden und basiert auf einer Abfrage, die Informationen aus den Tabellen Kunden, Bestellungen, Bestelldetails, Artikel, Personal und Versandtermin herauszieht. Die Berichtseigenschaft Filter ist so gesetzt, dass die im Bericht auftauchenden Daten auf die letzten sechs Datensätze in der Tabelle Bestellungen begrenzt werden. Die Verwendung von Grafiken, Farben, Schriften, Schattierungen und anderen besonderen Effekten gibt dem Formular ein professionelles Aussehen.
Abbildung 6.5: Ein Beispiel für einen Bericht, der ein Formular enthält
6.1.6
Berichte mit Etiketten
Das Erstellen von Adressetiketten erfolgt in Access 2000 einfach mit Hilfe des Etiketten-Assistenten. Adressetiketten sind lediglich eine besondere Art von Berichten, bei denen die Seiteneinrichtung die Anzahl der Etiketten pro Seite sowie die Größe jedes Etiketts festlegt. Ein Beispiel für einen mit dem Etiketten-Assistenten erstellten Adressetikettenbericht sehen Sie in Abbildung 6.6. Dieser Bericht basiert auf der Tabelle Kunden, hätte aber auch ebenso einfach auf einer Abfrage aufbauen können, welche die erzeugten Adressetiketten einschränkt.
210
6.2
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Aufbau eines Berichts
Berichte können sich aus vielen Teilen zusammensetzen, die als »Abschnitte« des Berichts bezeichnet werden. Ein neuer Bericht besteht automatisch aus den folgenden drei Abschnitten, die in Abbildung 6.7 zu sehen sind:
Seitenkopf Detailbereich Seitenfuß
Abbildung 6.6: Ein Beispiel für einen Bericht mit Adressetiketten
Abbildung 6.7: Abschnitte eines Berichts
Einen neuen Bericht erstellen
211
Der Detailbereich ist der wichtigste Abschnitt eines Berichts. Er wird benutzt, um die Daten der zu Grunde liegenden Tabelle oder einer Abfrage darzustellen. Bestimmte Berichte wie zum Beispiel zusammenfassende Berichte besitzen einen leeren Detailbereich. Dafür enthalten zusammenfassende Berichte Daten in Gruppenköpfen und -füßen (wird am Ende dieses Abschnitts genauer erläutert). Der Seitenkopf ist der Teil, der automatisch am Anfang jeder Seite des Berichts gedruckt wird. Er enthält oftmals Informationen wie etwa den Titel des Berichts. Der Seitenfuß wird automatisch am Ende jeder Seite des Berichts ausgedruckt und enthält üblicherweise Informationen wie beispielsweise die Seitenzahl und das Datum. Jeder Bericht kann nur einen Seitenkopf und einen Seitenfuß haben. Zusätzlich zu den drei Abschnitten, die jedem Bericht automatisch hinzugefügt werden, können Berichte die folgenden Abschnitte enthalten:
Berichtskopf Berichtsfuß Gruppenköpfe Gruppenfüße Ein Berichtskopf ist ein Abschnitt, der nur einmal am Anfang des Berichts gedruckt wird, während der Berichtsfuß am Ende des Berichts erscheint. Jeder Access-Bericht kann nur einen Berichtskopf und einen Berichtsfuß besitzen. Der Berichtskopf wird oft genutzt, um ein Deckblatt für den Bericht zu erstellen. Er kann Bilder und andere Effekte enthalten, so dass er ein professionelles Aussehen erhält. Der Berichtsfuß wird in der Regel für Endsummen genutzt, kann aber auch andere zusammenfassende Informationen enthalten. Zusätzlich zu den Kopf- und Fußbereichen des Berichts und der Seiten kann ein Access-Bericht bis zu 10 Gruppenköpfe und -füße aufweisen. Berichtsgruppen trennen Daten logisch und physisch. Der Gruppenkopf wird vor den Detaildaten der Gruppe und der Gruppenfuß danach ausgegeben. Sie könnten zum Beispiel Kundenumsätze nach Land und Stadt gruppieren, wobei der Name des Landes oder der Stadt für jede relevante Datensatzgruppe mit ausgegeben wird. Wenn Sie die Umsätze für jedes Land und jede Stadt addieren wollen, können Sie die Länder- und Städtenamen in die Gruppenköpfe und die Summen in die entsprechenden Gruppenfüße einfügen.
6.3
Einen neuen Bericht erstellen
Sie können einen neuen Bericht auf mehrere Arten erstellen – die gebräuchlichste ist es, im Datenbankfenster aus der Objektliste den Eintrag BERICHTE zu wählen und dann auf ERSTELLT EINEN NEUEN BERICHT UNTER VERWENDUNG DES ASSISTENTEN doppelzuklicken. Wenn Sie es vorziehen, können Sie auch auf NEU klicken, um das
212
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Dialogfeld NEUER BERICHT zu öffnen (siehe Abbildung 6.8). Hier können Sie aus vielen verfügbaren Möglichkeiten zur Erstellung eines Berichts auswählen. Berichte können über die Entwurfsansicht von Grund auf oder mit der Hilfe von fünf Assistenten neu erstellt werden. Drei der Assistenten helfen Ihnen bei der Erstellung von Standardberichten, einer erstellt Berichte mit Diagrammen und der andere automatisiert das Erstellen von Adressetiketten. Die Berichts-Assistenten sind so leistungsfähig, dass ich einen von ihnen für fast jeden meiner Berichte benutze, um das erste Fundament zu legen.
Abbildung 6.8: Im Dialogfeld Neuer Bericht können Sie zwischen der Entwurfsansicht und einem von fünf Assistenten wählen
6.3.1
Einen Bericht mit Hilfe des Berichts-Assistenten erstellen
Um einen Bericht mit Hilfe des Berichts-Assistenten zu erstellen, klicken Sie in der Objektliste einmal auf BERICHTE und dann doppelt auf ERSTELLT EINEN BERICHT UNTER VERWENDUNG DES ASSISTENTEN. Dies startet den Berichts-Assistenten. Der erste Schritt besteht nun darin, die Tabelle oder die Abfrage auszuwählen, welche die Daten für den Bericht bereitstellt. Ich bevorzuge es, meine Berichte auf Abfragen aufzubauen. Das verbessert im Allgemeinen die Geschwindigkeit, da es die kleinstmögliche Datenmenge liefert. In einer Client-Server-Umgebung ist dies besonders wichtig, da die Abfrage meistens auf dem Server ausgeführt wird und nur die Resultate über das Netzwerk übertragen werden. Berichte auf Abfragen aufzubauen, verbessert auch Ihre Möglichkeiten, Berichten verschiedene Kriterien zugrundezulegen. Nachdem Sie die Tabelle oder Abfrage ausgewählt haben, können Sie die Felder auswählen, die Sie in den Bericht aufnehmen wollen. Die in der ausgewählten Tabelle oder Abfrage enthaltenen Felder werden im Listenfeld auf der linken Seite angezeigt. Um Felder zum Bericht hinzuzufügen, doppelklicken Sie auf den Namen des hinzuzufügenden Feldes oder klicken einmal auf den Feldnamen und dann auf die Schaltfläche >. Im Beispiel in Abbildung 6.9 wurden sechs Felder der Tabelle tblClients ausgewählt.
Einen neuen Bericht erstellen
213
Abbildung 6.9: Der erste Schritt im Berichts-Assistenten: Tabellen-/Feldauswahl
Nachdem Sie die Tabelle oder Abfrage sowie die gewünschten Felder ausgewählt haben, klicken Sie auf WEITER. Sie werden nun aufgefordert, Gruppierungsebenen hinzuzufügen, die den Bericht um Berichtsgruppierungen erweitern. Fügen Sie Gruppierungsebenen hinzu, wenn Sie Datenreihen optisch trennen oder im Bericht zusammenfassende Berechnungen (Zwischensummen) auftauchen müssen. Berichtsgruppierungen werden später in diesem Kapitel behandelt. Wenn Ihr Bericht keine Gruppierungen benötigt, klicken Sie auf WEITER. Im dritten Schritt des Berichts-Assistenten wählen Sie die Sortierreihenfolge für Ihren Bericht aus. Da die Sortierung einer zu Grunde liegenden Abfrage von der für den Bericht bestimmten Sortierreihenfolge ersetzt wird, ist es eine gute Idee, eine Sortierreihenfolge für den Bericht festzulegen. Sie können mit Hilfe des Assistenten bis zu vier Sortierebenen vorgeben. Im Beispiel in Abbildung 6.10 wird der Bericht nach dem Feld ClientID sortiert. Nachdem Sie die Felder, nach denen Sie sortieren wollen, ausgewählt haben, klicken Sie auf WEITER. Im vierten Schritt des Berichts-Assistenten entscheiden Sie sich für das Layout und die Seitenausrichtung. Die Layoutmöglichkeiten variieren in Abhängigkeit davon, was in den vorherigen Schritten des Assistenten ausgewählt worden ist. Die Seitenausrichtung kann Hoch- oder Querformat sein. Dieser Schritt des Berichts-Assistenten lässt Sie außerdem festlegen, ob Access die Breite jedes Feldes automatisch so festlegt, dass jeweils alle Felder auf eine Seite passen. Nachdem Sie Access diese Informationen gegeben haben, klicken Sie auf WEITER. Der fünfte Schritt des Berichts-Assistenten betrifft die Auswahl eines Berichtsformates. Die Auswahlmöglichkeiten sind FETT, FORMAL, GESCHÄFTLICH, INFORMELL, KOMPAKT und WEICHES GRAU. Sie können jeden Stil in einer Vorschau betrachten,
214
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Abbildung 6.10: Der dritte Schritt im Berichts-Assistenten: Berichtsdaten sortieren
bevor Sie sich entscheiden. Jedes vom Berichts-Assistenten angewandte Formatattribut sowie alle anderen auf diese Weise definierten Berichtseigenschaften können nach der Fertigstellung des Berichts jederzeit in der Entwurfsansicht verändert werden. Klicken Sie nach dem Auswählen des Formats auf WEITER. Der letzte Schritt des Berichts-Assistenten fragt Sie nach dem Titel für den Bericht. Dieser Titel wird sowohl als Name als auch als Überschrift für den Bericht benutzt. Ich wähle für gewöhnlich den von Access vorgeschlagenen Berichtsnamen und ändere den Titel, wenn der Berichts-Assistent fertig ist. Sie haben dann immer noch die Möglichkeit, sich eine Berichtsvorschau anzusehen oder den Berichtsentwurf anzupassen. Wenn Sie sich dafür entscheiden, den Entwurf doch noch zu verändern, werden Sie in die Entwurfsansicht versetzt (siehe Abbildung 6.11). Eine Vorschau des Berichts kann zu jeder Zeit aufgerufen werden.
Abbildung 6.11: Entwurfsansicht eines fertiggestellten Berichts
Das Berichtsentwurfsfenster
215
Sie können den Berichts-Assistenten auch starten, indem Sie aus der Objektleiste im Datenbankfenster TABELLEN oder ABFRAGEN auswählen und dann auf die Tabelle oder Abfrage klicken, die dem Bericht zugrunde liegen soll. Benutzen Sie dann das aufklappbare Listenfeld NEUES OBJEKT auf der Symbolleiste, um dort den Eintrag BERICHT auszuwählen. Im Dialogfeld NEUER BERICHT wählen Sie nun die Option BERICHTS-ASSISTENT. Es ist nicht erforderlich, das Listenfeld zur Tabellen-/Abfrageauswahl zu benutzen, um eine Tabelle oder Abfrage auszuwählen, da diejenige, die Sie vor dem Aufrufen des Assistenten markiert hatten, automatisch für Sie ausgewählt wird.
6.3.2
Einen Bericht in der Entwurfsansicht erstellen
Obwohl Sie normalerweise bei dem Großteil Ihrer Berichte mit den Berichts-Assistenten anfangen, sollten Sie verstehen, wie man einen neuen Bericht in der Entwurfsansicht erstellt. Um einen Bericht zu erstellen, ohne einen Assistenten zu verwenden, klicken Sie in der Objektliste auf das Symbol BERICHTE und dann doppelt auf ERSTELLT EINEN BERICHT IN DER ENTWURFSANSICHT. Sie gelangen dadurch in das Berichtsentwurfsfenster. Anschließend müssen Sie als Datensatzquelle des Berichts die Tabelle oder Abfrage festlegen, auf welcher der Bericht basieren soll. Ein anderer Weg, um in der Entwurfsansicht einen Bericht zu erstellen, besteht darin, in der Objektliste das Symbol BERICHTE auszuwählen und dann auf NEU zu klicken. Dies öffnet ebenfalls das Dialogfeld NEUER BERICHT. Klicken Sie nun auf ENTWURFSANSICHT, benutzen Sie das aufklappbare Listenfeld, um die Tabelle oder Abfrage auszuwählen, auf welcher der Bericht beruhen soll, und klicken Sie dann auf OK. Sie gelangen wiederum in das Berichtsentwurfsfenster.
6.4
Das Berichtsentwurfsfenster
Das Berichtsentwurfsfenster wird benutzt, um einen Bericht zu erstellen und ihn zu verändern. Mit diesem Fenster können Sie Objekte zu dem Bericht hinzufügen sowie deren Eigenschaften ändern. Microsoft stellt zahlreiche Eigenschaften für Berichte, Berichtsgruppierungen und Steuerelemente bereit. Sie können Berichte mit vielfältigem Aussehen und unterschiedlicher Funktionalität erstellen, indem Sie diese Eigenschaften verändern.
6.4.1
Die Werkzeuge für den Berichtsentwurf
Um Ihnen beim Entwerfen von Berichten zu helfen, stehen verschiedene Werkzeuge für den Berichtsentwurf zur Verfügung. Darunter befinden sich das EIGENSCHAFTENFENSTER, die TOOLBOX, die FELDLISTE und das GRUPPIERUNGSFENSTER. Zwei Symbolleisten sind dazu da, das Entwickeln und Anpassen Ihrer Berichte zu vereinfachen: die Symbolleiste BERICHTSENTWURF und die Symbolleiste FORMATIERUNG. Die Symbolleiste BERICHTSENTWURF bietet Werkzeuge, um Ihren Bericht abzuspei-
216
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
chern, anzusehen und auszudrucken sowie um Berichtsobjekte auszuschneiden, zu kopieren und einzufügen. Die Symbolleiste FORMAT soll Ihnen helfen, das Aussehen Ihres Berichts anzupassen. Sie enthält Werkzeuge, um die Schriftart, Schriftgröße, Schriftausrichtung, Farbe, Schattierung und sonstige Attribute der Berichtsobjekte anzupassen. Die TOOLBOX, die FELDLISTE sowie die Fenster EIGENSCHAFTEN, SORTIEREN und GRUPPIEREN sind alle als ein- und ausblendbar entworfen. Das bedeutet, dass die Schaltflächen auf der Symbolleiste BERICHTSENWURF diese nützlichen Fenster abwechselnd verstecken oder anzeigen. Wenn Sie einen hochauflösenden Monitor besitzen, werden Sie wahrscheinlich alle Fenster stets geöffnet haben. Wenn Sie hingegen einen niedrigauflösenden Monitor Ihr Eigen nennen, sollten Sie ausprobieren, wann Sie welches Fenster geöffnet haben müssen, um effektiv zu arbeiten.
6.4.2
Dem Bericht Felder hinzufügen
Am leichtesten können Felder hinzugefügt werden, indem man die FELDLISTE benutzt. Wenn die FELDLISTE geöffnet ist, klicken Sie einfach auf ein Feld und ziehen es auf den gewünschten Abschnitt. Wie bei Formularen können mehrere Felder gleichzeitig hinzugefügt werden. Benutzen Sie die (Strg)-Taste, um nicht aneinander grenzende Felder auszuwählen, die (ª)-Taste, um benachbarte Felder auszuwählen, oder doppelklicken Sie auf die Titelleiste der Feldliste, um alle Felder auszuwählen. Dann ziehen Sie die Felder als eine Einheit auf den Bericht. Ein Problem beim Hinzufügen von Feldern zu einem Bericht ist, dass sowohl die Felder als auch die dazugehörigen Bezeichnungen in den gleichen Abschnitt des Berichts gesetzt werden. Das bedeutet, dass beim Ziehen eines Feldes in den Detailbereich sowohl das Feld als auch die dazugehörige Bezeichnung im Detailbereich erscheint. Wenn Sie gerade einen tabellarischen Bericht erstellen, ist das nicht wünschenswert. Sie müssen also die dazugehörigen Bezeichnungen ausschneiden und im Seitenkopfbereich des Berichts einfügen.
6.4.3
Berichtsobjekte auswählen, verschieben, ausrichten und in der Größe verändern
Microsoft Access bietet mehrere Methoden, die Ihnen helfen, Berichtsobjekte auszuwählen, zu verschieben, anzuordnen und in ihrer Größe zu ändern. Die Effektivität der Methoden hängt von der Situation ab. Mit zunehmender Erfahrung werden Sie wissen, wann Sie welche Methode anwenden sollten. Das Auswählen, Verschieben, Anordnen sowie Ändern der Größe eines Berichtsobjekts ähnelt sehr den entsprechenden Methoden für Formularobjekte. Die Methoden werden in diesem Kapitel daher nur kurz beschrieben. Eine detailliertere Erklärung zu jeder Methode erfahren Sie in Kapitel 5.
Das Berichtsentwurfsfenster
217
Berichtsobjekte auswählen Um ein einzelnes Berichtsobjekt auszuwählen, klicken Sie es an. Um das ausgewählte Objekt herum erscheinen daraufhin Anfasser. Nachdem das Objekt ausgewählt wurde, können Sie jedes seiner Merkmale (Eigenschaften) verändern, seine Größe ändern, es bewegen oder ausrichten. Um mehrere Objekte auszuwählen, die man als Einheit handhaben kann, nutzen Sie eine der folgenden Methoden:
Halten Sie die (ª)-Taste gedrückt, während Sie auf die verschiedenen Objekte klicken. Jedes Objekt, auf das Sie klicken, wird der Auswahl hinzugefügt.
Positionieren Sie Ihren Mauszeiger auf einer freien Fläche Ihres Berichts. Klicken und ziehen Sie, um die Objekte, die Sie auswählen wollen, mit einem Auswahlrahmen einzufangen. Wenn Sie die Maus loslassen, werden alle Objekte ausgewählt, die sich zumindest teilweise innerhalb des Rahmens befinden.
Klicken Sie auf das horizontale oder vertikale Lineal und ziehen Sie es. Dabei erscheinen Linien, welche die mögliche Auswahl anzeigen. Wenn Sie die Maustaste loslassen, werden alle Objekte innerhalb der Linien ausgewählt. Stellen Sie sicher, dass Sie verstehen, welche Objekte tatsächlich ausgewählt sind. Angehängte Bezeichnungen können einige Verwirrung auslösen. Abbildung 6.12 zeigt einen Bericht mit vier ausgewählten Objekten: das Bezeichnungsfeld rptClients, das Bezeichnungsfeld Contact First Name, das Textfeld City und das Textfeld ContactFirstName. Das Bezeichnungsfeld City ist nicht ausgewählt. Es ist nur von einem Auswahlanfasser umgeben, da es an das Textfeld City gebunden ist. Wenn Sie die Eigenschaften der ausgewählten Objekte ändern würden, wäre das Bezeichnungsfeld City nicht betroffen. Objekte verschieben Wenn Sie ein einzelnes Steuerelement zusammen mit seiner Bezeichnung verschieben wollen, klicken Sie auf das Objekt und ziehen es an seinen neuen Platz. Das Objekt und die gebundene Bezeichnung bewegen sich als eine Einheit. Um mehrere Objekte zu bewegen, benutzen Sie eine der Methoden, die im vorherigen Abschnitt erklärt worden sind, um die zu bewegenden Objekte auszuwählen. Nachdem Sie die Objekte ausgewählt haben, klicken Sie auf irgendeines von ihnen und ziehen es. Die ausgewählten Objekte und ihre gebundenen Bezeichnungen werden zusammen verschoben. Ein Objekt ohne seine gebundene Bezeichnung zu verschieben, ist etwas kniffliger. Wenn er über dem Mittelpunkt oder der Kante eines ausgewählten Objekts (nicht über den Anfassern zur Größenveränderung) steht, sieht der Mauszeiger wie eine Hand mit allen fünf Fingern nach oben aus. Dies zeigt an, dass das ausgewählte
218
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Objekt und seine gebundene Bezeichnung als Einheit bewegt werden. So bleibt ihre Verbindung bestehen. Wenn Sie hingegen den Mauszeiger direkt über den Auswahlanfasser in der oberen linken Ecke des Objekts stellen, sieht er wie eine Hand mit ausgestrecktem Zeigefinger aus. Dies zeigt an, dass das Objekt und die gebundene Bezeichnung voneinander unabhängig bewegt werden. Sie können nun zum Beispiel die Entfernung zwischen den Objekten ändern.
Abbildung 6.12: Objekte in einem Access-Bericht auswählen
Objekte aneinander ausrichten Um Objekte aneinander auszurichten, müssen Sie diese erst auswählen. Wählen Sie dazu FORMAT AUSRICHTEN und dann LINKS, RECHTS OBEN, UNTEN oder AM RASTER. Die ausgewählten Objekte werden sich anschließend aneinander ausrichten. Achten Sie auf die »Stolperfallen«, wenn Sie Berichtsobjekte ausrichten. Wenn Sie mehrere Textfelder und die dazugehörigen Bezeichnungen ausgewählt haben und dann ausrichten, versucht Access, die linken Seiten der Textfelder und die linken Seiten der Bezeichnungen aneinander auszurichten. Um dieses Problem zu umgehen, müssen Sie die Textfelder separat von den gebundenen Bezeichnungen ausrichten. Während des Ausrichtungsprozesses wird Access nie Objekte überlappen lassen. Wenn die auszurichtenden Objekte nicht zueinander passen, kann Access sie nicht ausrichten. Wenn Sie zum Beispiel versuchen, die Unterkanten mehrerer Objekte horizontal auszurichten und sie nicht in die Breite des Berichts passen, richtet Access nur die Objekte aus, die auf die Linie passen.
Das geeignete Steuerelement auswählen
219
Am Raster ausrichten Die Funktion AM RASTER AUSRICHTEN ist eine Umschaltfläche, die sich im FORMATMenü befindet. WENN AM RASTER AUSRICHTEN ausgewählt ist, rasten alle Objekte, die Sie verschieben oder in der Größe verändern, an den Gitternetzlinien des Berichts ein. Um die Funktion AM RASTER AUSRICHTEN kurzzeitig auszuschalten, halten Sie die (Strg)-Taste gedrückt, während Sie Objekte in der Größe verändern oder bewegen. Fortgeschrittene Techniken zur Änderung der Objektgröße Access bietet viele Techniken, die ihnen helfen, Objektgrößen zu ändern. Ein ausgewähltes Objekt verfügt über acht Größenanfasser, von denen alle außer dem oberen linken genutzt werden können, um die Objektgröße zu ändern. Klicken Sie einfach auf einen der Größenanfasser und ziehen Sie an ihm. Wenn mehrere Objekte ausgewählt sind, wirken sich die Größenänderungen bei allen gleich aus. Auch das Menü FORMAT GRÖSSE kann Ihnen helfen, Objektgrößen zu ändern. Es bietet sechs Optionen: AN TEXTGRÖSSE, AN RASTER, AM HÖCHSTEN, AM NIEDRIGSTEN, AM SCHMALSTEN und AM BREITESTEN. Diese Optionen werden genauer in Kapitel 5 besprochen. Access bietet einen tollen Trick, der hilft, die Größe von Bezeichnungen anzupassen: Doppelklicken Sie einfach auf irgendeinen Größenanfasser und die Objektgröße wird automatisch so festgelegt, dass der enthaltene Text vollständig hineinpasst. Den Objektabstand steuern Access erleichtert Ihnen auch die Steuerung des Objektabstands. Sowohl der horizontale als auch der vertikale Abstand zwischen den ausgewählten Objekten kann angeglichen werden. Wählen Sie zuerst die Objekte und dann FORMAT|HORIZONTALER ABSTAND|ANGLEICHEN oder FORMAT|VERTIKALER ABSTAND|ANGLEICHEN aus. Sie können auch den relativen Abstand zwischen den Objekten erhalten, während Sie den Abstand zwischen ihnen vergrößern oder verkleinern. Um das zu tun, wählen Sie FORMAT|HORIZONTALER / VERTIKALER ABSTAND|VERGRÖSSERN / VERMINDERN.
6.5
Das geeignete Steuerelement auswählen
Berichte enthalten üblicherweise Bezeichnungen, Textfelder, Linien, Rechtecke, Bildelemente sowie gebundene und ungebundene Objektrahmen. Die anderen Steuerelemente werden in der Regel für Berichte genutzt, die wie Formulare aussehen sollen. Die verschiedenen Steuerelemente, die in einen Bericht eingefügt werden können, sowie ihre Anwendungsmöglichkeiten werden in den folgenden Abschnitten behandelt.
220
6.5.1
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Bezeichnungen
Bezeichnungen werden benutzt, um dem Benutzer Informationen anzuzeigen, und kommen in der Regel als Berichts-, Spalten- oder Gruppenüberschriften in Ihrem Bericht zum Einsatz. Obwohl der dargestellte Text zur Laufzeit durch Programme verändert werden kann, können Bezeichnung nicht direkt an die Daten gekoppelt werden. Um eine Bezeichnung zu einem Bericht hinzuzufügen, benutzen Sie das Werkzeug BEZEICHNUNG aus der TOOLBOX. Klicken Sie das Werkzeug an und ziehen Sie die Bezeichnung auf den Bericht.
6.5.2
Textfelder
Textfelder werden benutzt, um Feldinhalte oder das Ergebnis eines Ausdrucks darzustellen, und kommen in allen Abschnitten des Berichts zum Einsatz. Beipielsweise kann ein Textfeld im Seitenkopf einen Ausdruck enthalten, der den Zeitraum anzeigt, der die Grundlage des Berichts darstellt. In einem Gruppenkopf kann ein Textfeld genutzt werden, um die Überschrift für diese Gruppe anzuzeigen. Die Möglichkeiten sind endlos, da das Textfeld jeden gültigen Ausdruck enthalten kann. Um ein Textfeld zu einem Bericht hinzuzufügen, wählen Sie das Werkzeug TEXTaus der TOOLBOX. Klicken und ziehen Sie das Textfeld an seinen Platz im Bericht. Ein Textfeld kann auch eingefügt werden, indem man ein Feld von der FELDLISTE in den Bericht zieht. Dies funktioniert immer dann, wenn die Eigenschaft ANZEIGE des Feldes auf TEXTFELD gesetzt ist.
FELD
6.5.3
Linien
Linien kann man verwenden, um Objekte in einem Bericht optisch voneinander zu trennen. Zum Beispiel kann eine Linie unter einen Abschnitt oder eine Zwischensumme gesetzt werden. Um einem Bericht eine Linie hinzuzufügen, klicken Sie auf das Werkzeug Linie, um es auszuwählen. Dann klicken und ziehen Sie, um die Linie in Ihren Bericht einzufügen. Einmal hinzugefügt, besitzt die Linie mehrere Eigenschaften, die Sie verändern können, um so ihr Aussehen anzupassen. Um sicherzugehen, dass die Linie absolut gerade ist, drücken Sie die (ª)-Taste, während Sie klicken und ziehen, um die Linie zu zeichnen.
6.5.4
Rechtecke
Rechtecke können benutzt werden, um Gegenstände im Bericht optisch zusammenzufassen, die vom Sinn her zusammengehören. Sie können auch angewandt werden, um bestimmte Steuerelemente in Ihrem Bericht herausragen zu lassen. Ich ziehe oft
Das geeignete Steuerelement auswählen
221
Rechtecke um wichtige Zwischen- oder Endsummen herum, bei denen ich sicher gehen möchte, dass der Leser des Berichts sie wahrnimmt. Um einem Bericht ein Rechteck hinzuzufügen, klicken Sie auf das Werkzeug RECHTECK aus der TOOLBOX, um es auszuwählen. Dann klicken und ziehen Sie, um das Rechteck in Ihren Bericht zu setzen. Das Rechteck kann einige Objekte verdecken, die schon in Ihrem Bericht vorhanden sind. Um dieses Problem zu beheben, kann die Eigenschaft Hintergrundfarbe des Rechtecks auf Transparent gesetzt werden. Diese Einstellung ist in Ordnung, solange das Rechteck eine Hintergrundfarbe haben muss. Wenn das so ist, wählen Sie FORMAT|IN DEN HINTERGRUND, um die Objekte so anzuordnen, dass das Rechteck hinter den anderen Objekten des Berichts liegt.
6.5.5
Gebundene Objektfelder
Mit gebundenen Objektfeldern können Sie Daten in OLE-Feldern darstellen, die Objekte aus anderen Anwendungen enthalten wie zum Beispiel Bilder, Tabellenkalkulationen und Textverarbeitungsdokumente. Um ein gebundenes Objektfeld zu einem Bericht hinzuzufügen, klicken Sie auf das Werkzeug GEBUNDENES OBJEKTFELD in der TOOLBOX. Dann ziehen Sie das Feld auf Ihren Bericht. Setzen Sie anschließend die Eigenschaft STEUERELEMENTINHALT des Objekts auf das entsprechende Feld. Sie können ein gebundenes Objektfeld einem Bericht auch hinzufügen, indem Sie ein OLE-Feld aus der Feldliste ziehen und es auf Ihrem Bericht ablegen.
6.5.6
Ungebundene Objektfelder
Ungebundene Objektfelder können benutzt werden, um Logos und andere Bilder zu ihrem Bericht hinzuzufügen. Anders als gebundene Objektfelder sind sie aber nicht an zu Grunde liegende Daten gebunden. Um ein ungebundenes Objektfeld zu Ihrem Bericht hinzuzufügen, klicken Sie auf das Werkzeug OBJEKTFELD in der Toolbox. Ziehen Sie das Objektfeld an seinen Platz in Ihrem Bericht. Dies öffnet, wie Abbildung 6.13 zeigt, das Dialogfeld OBJEKT EINFÜGEN, mit dessen Hilfe Sie ein neues OLE-Objekt erstellen oder ein vorhandenes aus einer Datei einfügen können. Wenn Sie auf AUS DATEI ERSTELLEN klicken, verändert sich das Dialogfeld OBJEKT EINFÜGEN, so dass es aussieht wie in Abbildung 6.14. Klicken Sie auf DURCHSUCHEN und machen Sie die Datei ausfindig, die Sie Ihrem Bericht hinzufügen möchten. Das Dialogfeld OBJEKT EINFÜGEN bietet Ihnen die Möglichkeit, eine Verknüpfung mit dem OLE-Objekt anzulegen oder es einzubetten. Wenn Sie VERKNÜPFEN wählen, wird ein Verweis auf das OLE-Objekt erstellt. In diesem Fall enthält der Bericht lediglich eine Bitmap, während er sich weiterhin auf die Datei auf der Festplatte bezieht. Wenn Sie VERKNÜPFEN nicht aktivie-
222
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
ren, wird das ausgewählte Objekt kopiert und in den Bericht eingebettet. Das Objekt wird zu einem Bestandteil der Access-MDB-Datei und es wird kein Verweis auf das Originalobjekt unterhalten.
Abbildung 6.13: Verwenden Sie das Dialogfeld Objekt einfügen, um ein neues oder vorhandenes Objekt in ein ungebundenes Objektfeld einzufügen
Es ist meistens vorzuziehen, ein Bild-Steuerelement anstelle eines ungebundenen Objektfeldes zu verwenden, wenn gleichbleibende Informationen, wie zum Beispiel ein Logo, dargestellt werden sollen, da das Bild-Steuerelement wesentlich weniger Ressourcen verbraucht als ein ungebundenes Objektfeld. Bild-Steuerelemente werden im nächsten Abschnitt behandelt. Abbildung 6.15 zeigt einen Bericht mit einem Bild-Steuerelement.
Abbildung 6.14: Das Dialogfeld Objekt einfügen mit ausgewählter Option Aus Datei erstellen
6.5.7
Bild-Steuerelemente
Bild-Steuerelemente sind die beste Möglichkeit, um gleichbleibende Bilder wie etwa Logos in einem Bericht darzustellen. Ein ungebundenes Objektfeld kann, nachdem
223
Welche Berichtseigenschaften stehen zur Verfügung?
Abbildung 6.15: Ein Bericht mit einem ungebundenen Objektfeld
es in den Bericht eingefügt wurde, verändert werden. Sie können aber nicht die Anwendung des Objekts öffnen und ein Bild verändern, nachdem es in den Bericht eingefügt wurde. Diese Beschränkung bedeutet allerdings, dass wesentlich weniger Ressourcen benötigt werden, was die Leistung spürbar verbessert.
6.5.8
Andere Steuerelemente
Wie schon vorher in diesem Abschnitt erwähnt, ist es Standard, hauptsächlich Bezeichnungs- und Textfelder in Ihren Berichten zu verwenden. Andere Steuerelemente können aber, wo es sinnvoll ist, hinzugefügt werden. Um andere Steuerelemente einzufügen, klicken Sie das Steuerelement an und ziehen es an die Zielposition in Ihrem Bericht.
6.6
Welche Berichtseigenschaften stehen zur Verfügung und warum sollten sie benutzt werden?
Berichte haben viele verschiedene Eigenschaften, die verändert werden können, um Aussehen und Verhalten des Berichts zu beeinflussen. Wie Formulareigenschaften sind die Berichtseigenschaften in Kategorien unterteilt: FORMAT, DATEN, EREIGNIS und ANDERE. Um die Eigenschaften eines Berichts anzusehen, wählen Sie zuerst den Bericht aus anstatt einen der Abschnitte des Berichts. Dazu gibt es zwei Möglichkeiten:
Klicken Sie auf den Berichtsmarkierer. Dies ist die kleine graue Schaltfläche an der Schnittstelle zwischen horizontalem und vertikalem Lineal.
224
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Wählen Sie BEARBEITEN|BERICHT AUSWÄHLEN. Nachdem ein Bericht ausgewählt wurde, können Sie seine Eigenschaften betrachten und verändern.
6.6.1
Das Eigenschaftenfenster
Nachdem ein Bericht ausgewählt wurde, zeigt das Eigenschaftenfenster alle Eigenschaften, die mit dem Bericht zusammenhängen. Um einen Bericht auszuwählen und das Eigenschaftenfenster gleichzeitig zu öffnen, doppelklicken Sie auf den Berichtsmarkierer. Ein Bericht verfügt in seinem Eigenschaftenfenster über 37 Eigenschaften (es gibt noch weitere Eigenschaften, die nur über Programm-Code erreichbar sind), die in entsprechende Kategorien im Eigenschaftenfenster unterteilt sind. Dreißig der Eigenschaften beziehen sich auf das Format des Berichts, seine Daten und andere Spezialeigenschaften. Die verbleibenden sieben Eigenschaften beziehen sich auf Ereignisse, die auftreten, wenn der Bericht gestartet wird. Die Format-, Daten- und anderen Eigenschaften werden hier behandelt, während die Ereigniseigenschaften Gegenstand von Kapitel 10 sind.
6.6.2
Die Formateigenschaften eines Berichts
Ein Bericht besitzt die folgenden 15 Formateigenschaften, um sein Aussehen zu beeinflussen: Beschriftung: Die Eigenschaft BESCHRIFTUNG ist der Text, der im Fenstertitel erscheint, wenn sich der Benutzer den Bericht ansieht. Sie kann zur Laufzeit verändert werden, um die Titelzeile an eine bestimmte Situation anzupassen. Seitenkopf, Seitenfuß: Die Eigenschaften SEITENKOPF und SEITENFUSS legen fest, auf welchen Seiten diese Abschnitte erscheinen. Die Optionen sind ALLE SEITEN, AUSSER BERICHTSKOPF, AUSSER BERICHTSFUSS UND AUSSER BERICHTSKOPF/-FUSS. Da Sie eventuell nicht möchten, dass der Seitenkopf oder Seitenfuß mit auf die gleichen Seiten wie der Berichtskopf oder Berichtsfuß gedruckt wird, geben Ihnen diese Eigenschaften die Kontrolle darüber, wo diese Abschnitte gedruckt werden. Gruppe zusammenhalten: In Access können Sie eine Datengruppe zusammen auf einer Seite halten, indem Sie die Eigenschaft GRUPPE ZUSAMMENHALTEN benutzen. Die Option PRO SEITE zwingt die Datengruppe, auf einer Seite zu bleiben, während die Option PRO SPALTE dafür sorgt, dass die Datengruppe innerhalb einer Spalte bleibt. Eine »Datengruppe« bezeichnet alle Daten innerhalb einer Berichtsgruppe (wie zum Beispiel alle Kunden in einer Stadt). Breite: Die Eigenschaft BREITE legt fest, wie breit die Abschnitte des Berichts sind. Bild, Bildtyp, Bildgrößenmodus, Bildausrichtung, Bild nebeneinander, Bildseiten: Der Hintergrund eines Berichts kann ein Bild sein. Die Bildeigenschaften legen fest, welches Bild als Hintergrund verwendet wird und welche Eigenschaften auf es angewendet werden.
Welche Berichtseigenschaften stehen zur Verfügung?
225
Raster X/Raster Y: Die Eigenschaften RASTER X und RASTER Y legen die Dichte der Gitternetzlinien im Berichtsentwurfsfenster fest. Drucklayout: Die Eigenschaft DRUCKLAYOUT gibt an, ob Bildschirm- oder Druckerzeichensätze im Bericht benutzt werden. Wenn Sie den Bericht für die Ansicht am Bildschirm optimieren wollen, wählen Sie NEIN, bei beabsichtigter Ausgabe auf den Drucker hingegen JA. Diese Möglichkeit ist nicht so wichtig, wenn Sie TrueType-Schriften benutzen, da TrueType-Schriften auf dem Bildschirm und auf dem Drucker gleich gut ausgegeben werden. Palettenherkunft: Die Eigenschaft PALETTENHERKUNFT legt die Quelle für die für den Bericht auswählbaren Farben fest.
6.6.3
Die Dateneigenschaften eines Berichts
Ein Bericht besitzt die folgenden fünf Dateneigenschaften, die benutzt werden, um Informationen über die dem Bericht zu Grunde liegenden Daten einzugeben. Datenherkunft: Die Eigenschaft DATENHERKUNFT legt die Tabelle oder Abfrage fest, deren Daten dem Bericht zu Grunde liegen und kann zur Laufzeit verändert werden. Deshalb ist es sehr einfach, allgemeine Berichte zu erstellen, die immer wieder andere Datenquellen nutzen. Filter: Die Eigenschaft FILTER erlaubt es Ihnen, den Bericht mit einem speziellen Filter zu öffnen. Ich bevorzuge es normalerweise, den Bericht auf einer Abfrage aufzubauen anstatt einen Filter darauf anzuwenden. Andererseits kann es sinnvoll sein, den Bericht auf einer Abfrage aufzubauen, dann aber unter bestimmten temporären Umständen zur Laufzeit einen Filter anzuwenden und wieder zu entfernen. Filter aktiv: Die Eigenschaft FILTER AKTIV legt fest, ob ein Berichtsfilter angewandt wird. Wenn der Wert dieser Eigenschaft auf NEIN gesetzt ist, wird die Filtereigenschaft ignoriert. Sortiert nach: Die Eigenschaft SORTIERT werden, wenn der Bericht geöffnet wird.
NACH
legt fest, wie die Datensätze sortiert
Sortierung aktiv: Die Eigenschaft SORTIERUNG AKTIV bestimmt, ob die Eigenschaft SORTIERT NACH des Berichts benutzt wird. Wenn der Wert dieser Eigenschaft auf NEIN gesetzt ist, wird die Eigenschaft SORTIERT NACH ignoriert.
6.6.4
Andere Berichtseigenschaften
Ein Bericht verfügt über zehn Eigenschaften, die zur Kategorie ANDERE gehören. Diese Eigenschaften, die im Folgenden vorgestellt werden, erlauben es Ihnen, andere wichtige Aspekte des Berichts vorzugeben. Datensätze sperren: Die Eigenschaft DATENSÄTZE SPERREN legt fest, ob die Tabellen, die benutzt werden, um den Bericht zu erstellen, während der Laufzeit des
226
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Berichts gesperrt werden sollen. Die zwei Werte für diese Eigenschaft sind KEINE SPERRUNGEN und ALLE DATENSÄTZE, wobei KEINE SPERRUNGEN der Standardwert ist. Er bedeutet, dass kein Datensatz in den zu Grunde liegenden Tabellen des Berichts gesperrt wird, solange der Bericht ausgeführt wird. Das kann verheerend sein, wenn komplizierte Berichte gestartet werden. Die Daten im Bericht könnten geändert werden, während der Bericht ausgeführt wird, was die Zahlen für Summen und Prozentanteile ungültig werden ließe. Obwohl die Option ALLE DATENSÄTZE für diese Eigenschaft alle Datensätze in allen Tabellen sperrt, die im Bericht enthalten sind (und somit jegliche Dateneingaben verhindert, solange der Bericht ausgeführt wird), ist dies ein notwendiges Übel, um genaue Berichte zu erstellen. Datumsgruppierung: Die Eigenschaft DATUMSGRUPPIERUNG legt fest, wie die Gruppierung von Datumsangaben in Ihrem Bericht erfolgt. Die Einstellung USSTANDARD bedeutet, dass Access die Standards für die Vereinigten Staaten für Berichtsgruppierungen benutzt. Sonntag ist also der erste Tag der Woche, die erste Woche beginnt am ersten Januar und so weiter. Der Wert SYSTEMEINSTELLUNGEN VERWENDEN bedeutet, dass die Gruppierungen auf den regionalen Ländereinstellungen in der Systemsteuerung basieren statt auf den US-Standards. Menüleiste: Die Eigenschaft MENÜLEISTE gibt Ihnen die Möglichkeit, eine eigene Menüleiste mit dem Bericht zu verknüpfen, die sichtbar wird, wenn der Benutzer sich den Bericht ansieht. Durch Hinzufügen eines eigenen Menüs können Sie beeinflussen, was der Benutzer tun kann, während der Bericht aktiv ist. Symbolleiste: Die Eigenschaft SYMBOLLEISTE erlaubt es Ihnen, eine eigene Symbolleiste mit dem Bericht zu verknüpfen, die sichtbar wird, wenn der Benutzer sich den Bericht ansieht. Kontextmenüleiste: Die Eigenschaft KONTEXTMENÜLEISTE legt fest, welches Kontextmenü mit dem Bericht assoziiert wird, während er sich in der Voransicht befindet. Die Kontextmenüleiste erscheint, wenn der Benutzer mit der rechten Maustaste auf das Vorschaufenster klickt. Schneller Laserdruck: Die Eigenschaft SCHNELLER LASERDRUCK legt fest, ob Linien und Rechtecke durch Buchstabenzeichen ersetzt werden sollen, wenn Sie den Bericht auf einem Laserdrucker ausdrucken. Wenn eine schnelle Druckausgabe Ihr Ziel ist und Sie einen Laserdrucker einsetzen, sollten Sie diese Eigenschaft auf JA setzen. Hilfedatei, Hilfekontext-ID: Mit den Eigenschaften HILFEDATEI, HILFEKONTEXTID können Sie eine Hilfedatei und ein Hilfethema mit Ihrem Bericht verknüpfen. Marke: Die Eigenschaft MARKE ist eine zusätzliche Eigenschaft, um benutzerdefinierte Informationen entweder in der Entwurfsphase oder zur Laufzeit zu speichern. Dies ist die Art von Microsoft Access, Ihnen eine zusätzliche Eigenschaft an die Hand zu geben. Access macht keinen Gebrauch von dieser Eigenschaft. Wenn Sie selbst keinen Nutzen daraus ziehen, wird sie nie benutzt.
Welche Steuerelementeigenschaften stehen zur Verfügung?
227
Enthält Modul: Die Eigenschaft ENTHÄLT MODUL legt fest, ob ein Bericht ein verknüpftes Modul enthält. Wenn kein Programmtext im Bericht enthalten ist, kann das Ausschalten der Klassenmodule sowohl die Leistung verbessern als auch die Größe der Datenbank reduzieren. Ein Bericht ohne ein Klassenmodul wird als »leichtgewichtiges Objekt« angesehen, das schneller geladen und angezeigt wird als ein Objekt mit verknüpftem Klassenmodul. Ein paar der Verhaltensweisen der Eigenschaft ENTHÄLT MODUL verdienen besondere Beachtung. Wenn ein Bericht erstellt wird, lautet der Wert für die Eigenschaft ENTHÄLT MODUL standardmässig NEIN. Access setzt die Eigenschaft ENTHÄLT MODUL automatisch auf JA, wenn Sie versuchen, ein Modul von diesem Bericht aus einzusehen. Wenn Sie die Eigenschaft ENTHÄLT MODUL auf NEIN setzen, löscht Access das Klassenmodul des Objekts und den ganzen Programm-Code, der darin enthalten ist.
6.7
Welche Steuerelementeigenschaften stehen zur Verfügung und warum sollten sie benutzt werden?
Wie Berichte besitzen auch Steuerelemente Eigenschaften. Die meisten Steuerelementeigenschaften können während des Entwurfs und zur Laufzeit geändert werden, was Ihnen gestattet, Ihre Berichte auf einfache Weise flexibel zu machen. So sind zum Beispiel manche Steuerelemente nur dann sichtbar, wenn bestimmte Bedingungen erfüllt sind.
6.7.1
Die Formateigenschaften eines Steuerelements
Sie können verschiedene Formateigenschaften des ausgewählten Objekts verändern, indem Sie die Symbolleiste FORMATIERUNG benutzen. Wenn Sie es bevorzugen, können Sie aber all diese Eigenschaften auch im Eigenschaftenfenster verändern. Format: Die Eigenschaft FORMAT legt fest, wie die Daten im Steuerelement dargestellt werden. Diese Eigenschaft wird automatisch von dem zu Grunde liegenden Feld geerbt. Wenn Sie möchten, dass die Formatierung des Steuerelements von der des zu Grunde liegenden Feldes abweicht, müssen Sie die Eigenschaft FORMAT des Steuerelements ändern. Beschriftung: Die Eigenschaft BESCHRIFTUNG gibt den Text für Bezeichnungsfelder und Befehlsschaltflächen an. Eine Beschriftung ist eine Zeichenfolge, die bis zu 2048 Zeichen enthalten kann. Hyperlink-Adresse: Die Eigenschaft HYPERLINK-ADRESSE ist eine Zeichenfolge, die einen UNC-Pfad (Netzwerkpfad) oder einen URL (Webadresse) darstellt.
228
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Befehlsschaltflächen, Bild-Steuerelemente und Bezeichnungsfelder enthalten alle die Eigenschaft HYPERLINK-ADRESSE. Hyperlink-Unteradresse: Die Eigenschaft HYPERLINK-UNTERADRESSE ist eine Zeichenfolge, welche einen Ort innerhalb des Dokuments darstellt, das in der Eigenschaft HYPERLINK-ADRESSE genannt ist. Befehlsschaltflächen, Bild-Steuerelementes und Bezeichnungsfelder enthalten alle die Eigenschaft HYPERLINK-UNTERADRESSE. Dezimalstellenanzeige: Die Eigenschaft DEZIMALSTELLENANZEIGE definiert die Anzahl der Dezimalstellen für Zahlenwerte. Sichtbar: Die Eigenschaft SICHTBAR legt fest, ob ein Steuerelement sichtbar ist. In vielen Fällen wollen Sie die Sichtbarkeit eines Steuerelements je nach Situation einund ausschalten. Duplikate ausblenden: Die Eigenschaft DUPLIKATE AUSBLENDEN versteckt doppelte Datenwerte im Detailbereich eines Berichts. Doppelte Datenwerte treten auf, wenn ein oder mehrere aufeinander folgende Datensätze in einem Bericht in einem oder mehreren Feldern den gleichen Wert aufweisen. Vergrößerbar, Verkleinerbar: Wenn die Eigenschaft VERGRÖSSERBAR auf JA gesetzt ist, erlaubt sie dem Steuerelement, sich vertikal auszubreiten, um für die ganzen Daten Platz zu schaffen. Die Eigenschaft VERKLEINERBAR entfernt leere Zeilen, wenn im jeweiligen Datensatz in einem Feld keine Daten existieren. Dies kann zum Beispiel sinnvoll sein, wenn Sie in Briefetiketten standardmäßig zwei Zeilen für Adressdaten vorsehen, dies bei einem Datensatz aber nicht ausgenutzt wird und Sie nicht möchten, dass auf dem Etikett eine Leerzeile erscheint. Links, Oben, Breite, Höhe: Diese Eigenschaften bestimmen die Größe und Position des Steuerelements auf dem Bericht. Hintergrundart, Hintergrundfarbe: Die Eigenschaft HINTERGRUNDART kann auf NORMAL oder TRANSPARENT gesetzt werden. Wenn sie auf TRANSPARENT gesetzt ist, scheint die Farbe des Berichts durch das Steuerelement hindurch. Beim Wert NORMAL bestimmt die Eigenschaft HINTERGRUNDFARBE die Farbe des Objekts. Spezialeffekt: Die Eigenschaft SPEZIALEFFEKT fügt dem Steuerelement einen 3-DEffekt hinzu. Rahmenart, Rahmenfarbe, Rahmenbreite: Diese Eigenschaften bestimmen das Erscheinungsbild des Objektrahmens. Textfarbe, Schriftart, Schriftgrad, Schriftbreite, Kursiv, Unterstrichen: Die Rahmeneigenschaften beeinflussen den Rahmen des Objekts. Diese Schrifteigenschaften hingegen bestimmen das Aussehen des Textes im Steuerelement. Textausrichtung: Die Eigenschaft TEXTAUSRICHTUNG bestimmt die Ausrichtung von Text innerhalb des Steuerelements. Sie kann auf LINKSBÜNDIG, ZENTRIERT, RECHTSBÜNDIG oder VERTEILEN gesetzt werden. Beim Wert VERTEILEN wird der Text in Blocksatz dargestellt.
Welche Steuerelementeigenschaften stehen zur Verfügung?
229
Linker Rand, Oberer Rand, Rechter Rand, Unterer Rand: Diese Eigenschaften werden benutzt, um festzulegen, wie weit entfernt von der linken, oberen, rechten und unteren Kante des Steuerelements der Text gedruckt wird. Diese Eigenschaften sind besonders für große Steuerelemente nützlich, die viel Text enthalten, wie zum Beispiel ein Memofeld auf einer Rechnung. Zeilenabstand: Die Eigenschaft ZEILENABSTAND wird benutzt, um den Abstand zwischen den Zeilen des Textes im Steuerelement festzulegen. Ist Hyperlink: Die Eigenschaft IST HYPERLINK wird genutzt, um festzulegen, ob der Text im Steuerelement als Hyperlink dargestellt werden soll. Wenn die Eigenschaft IST HYPERLINK auf JA gesetzt und der Text innerhalb des Steuerelements ein gültiger Link ist, fungiert der Text als Hyperlink. (Das ist nur dann sinnvoll, wenn Sie den Bericht im HTML-Format speichern.)
6.7.2
Die Dateneigenschaften eines Steuerelements
Die Dateneigenschaften eines Steuerelements legen Informationen über die Daten fest, die dem Bericht zu Grunde liegen. Steuerelementinhalt: Die Eigenschaft STEUERELEMENTINHALT legt das Feld in der Datenquelle des Berichts fest, welches das Steuerelement ausfüllt. Ein Steuerelementinhalt kann auch ein gültiger Ausdruck sein. Laufende Summe: Die Eigenschaft LAUFENDE SUMME (die es nur bei Berichten gibt) ist recht leistungsfähig. Sie kann genutzt werden, um Summen über alle Datensätze oder nur für die Datensätze einer Gruppe zu bilden. Sie kann auf NEIN, ÜBER GRUPPE und ÜBER ALLES gesetzt werden. Wenn sie auf ÜBER GRUPPE gesetzt wird, sammelt der Wert im Textfeld die Daten von allen Datensätzen innerhalb der Gruppe, wird aber jedes Mal wieder zurückgesetzt, wenn der Gruppenwert sich ändert. Ein Beispiel hierfür ist ein Bericht, der Einlagenbeträge für jeden Staat anzeigt, wobei eine laufende Summe für alle Einlagen innerhalb des Staates gebildet wird. Jedesmal, wenn der Staat wechselt, wird der Betrag auf Null gesetzt. Wenn die Eigenschaft den Wert ÜBER ALLES aufweist, wird die Summe über den ganzen Bericht weitergebildet.
6.7.3
Die anderen Eigenschaften eines Steuerelements
Die anderen Eigenschaften eines Steuerelements sind solche, die nicht in eine der anderen Kategorien passen. Name: Die Eigenschaft NAME bietet Ihnen einen einfachen und selbstdokumentierenden Weg, um auf das Steuerelement aus einem VBA-Programm und auch aus vielen anderen Situationen heraus zuzugreifen. Sie sollten alle Ihre Steuerelemente benennen. Lesen Sie den Anhang, um genauere Informationen zu erhalten.
230
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Vertikal: Die Eigenschaft VERTIKAL legt fest, ob der Text innerhalb des Steuerelements vertikal dargestellt werden soll. Der Standardwert lautet NEIN. Marke: Wie die Eigenschaft MARKE eines Berichts gibt die Eigenschaft MARKE eines Steuerelements Ihnen einen benutzerdefinierten Eintrag für Ihr Steuerelement. Sie können beliebige zusätzliche Informationen in die Eigenschaft MARKE eintragen. Ein von Entwicklern häufig begangener Fehler besteht darin, Steuerelementen Namen zu geben, die mit Access-Namen in Konflikt treten. Diese Art Fehler ist sehr schwer aufzuspüren. Stellen Sie sicher, dass Sie eindeutige Namen sowohl für Felder als auch für Steuerelemente benutzen. Geben Sie weiterhin niemals einem Steuerelement den gleichen Namen wie einem Feld, das innerhalb seines Ausdrucks auftaucht. Der Ausdruck =ClientName & Titel sollte nicht den Namen »ClientName« bekommen. Das würde eine Fehlermeldung auslösen. Geben Sie einem Steuerelement nicht den gleichen Namen wie seinem Inhalt. Access gibt gebundenen Steuerelementen den gleichen Namen wie deren Felder, Sie müssen diese also umbenennen, um Probleme zu vermeiden. Wenn Sie diese einfachen Warnungen befolgen, werden Sie sich eine Menge Ärger ersparen.
6.8
Seitenumbrüche einfügen
Seitenumbrüche können so gesetzt werden, dass sie vor, innerhalb oder nach einem Abschnitt auftauchen. Die Art und Weise, wie Sie jeden Seitenumbruchtyp setzen, ist recht unterschiedlich. Um einen Seitenumbruch innerhalb eines Abschnitts zu setzen, müssen Sie das Werkzeug SEITENWECHSEL aus der Toolbox benutzen. Klicken Sie auf das Werkzeug SEITENWECHSEL in der Toolbox und dann dort in den Bericht, wo Sie den Seitenumbruch einfügen möchten. Um einen Seitenumbruch vor beziehungsweise nach einem Abschnitt einzufügen, setzen Sie die Eigenschaft NEUE SEITE des Abschnitts auf VOR BEREICH, NACH BEREICH bzw. VOR & NACH. Die Eigenschaft NEUE SEITE gilt für Gruppenköpfe, Gruppenfüße und den Detailbereich des Berichts. Achten Sie darauf, einen Seitenumbruch nicht innerhalb eines Steuerelements des Berichts zu setzen. Der Seitenumbruch wird dann inmitten der Daten des Steuerelements auftauchen.
Gebundene, ungebundene und berechnete Steuerelemente
6.9
231
Gebundene, ungebundene und berechnete Steuerelemente
Drei Arten von Steuerelemente können in einen Bericht eingefügt werden: gebundene, ungebundene und berechnete Steuerelemente. Ungebundene Steuerelemente wie zum Beispiel in den Bericht aufgenommene Logos sind nicht an Daten gebunden, während gebundene Steuerelemente direkt von den Daten innerhalb eines Feldes der zu Grunde liegenden Tabelle oder Abfrage abhängen. Berechnete Steuerelemente enthalten gültige Ausdrücke. Sie können alles enthalten, von einer Seitenzahl bis hin zu ausgeklügelten Finanzkalkulationen. Die meisten komplexen Berichte enthalten eine Kombination aus vielen gebundenen, ungebundenen und berechneten Steuerelementen.
6.10
Berichte mit Hilfe von Ausdrücken erweitern
Berechnete Steuerelemente benutzen Ausdrücke als ihre Steuerelementinhalte. Um ein berechnetes Steuerelement zu erstellen, müssen Sie erst ein ungebundenes Steuerelement zu Ihrem Bericht hinzufügen. Ausdrücke müssen mit einem Gleichheitszeichen (=) beginnen; ein Beispiel für einen Berichtsausdruck ist =Summe([BillableHours]). Dieser Ausdruck addiert, wenn er in den Berichtsfuß gesetzt wird, die Inhalte des Steuerelements BillableHours aller Datensätze im Bericht. Sie können einen Ausdruck aufbauen, indem Sie ihn direkt als Steuerelementinhalt eingeben oder den Ausdrucks-Generator verwenden, der in Kapitel 5 behandelt wird.
6.11
Berichte auf der Grundlage mehrerer Tabellen
Der Großteil Ihrer Berichte wird wahrscheinlich auf mehr als einer Tabelle beruhen. Das ist so, da eine ordentlich strukturierte Datenbank es meistens verlangt, dass Sie die Tabellendaten wieder zusammenführen, um ihrem Benutzer wertvolle Informationen zu geben. Ein Bericht, der die Daten aus Kunden-, Bestellungen-, Bestelldetailund Produkttabellen kombiniert, kann zum Beispiel die folgenden Informationen liefern:
Kundeninformationen: Firmenname und Adresse Bestellinformationen: Bestelldatum und Liefermethode Bestelldetailinformationen: bestellte Menge, Preis Produkttabelle: Produktbeschreibung Ein solcher, mehrere Tabellen verwendender Bericht, kann direkt auf den Tabellen beruhen, deren Daten er anzeigt, oder er kann auf einer Abfrage basieren, welche die Tabellen schon zusammengefügt hat und so eine flache Tabellenstruktur bietet.
232
6.11.1
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
1:n-Berichte erstellen
Sie können 1:n-Berichte erstellen, indem Sie den Berichts-Assistenten benutzen oder den Bericht von Grund auf aufbauen. Unterschiedliche Situationen erfordern verschiedene Vorgehensweisen, von denen einige in den folgenden Abschnitten behandelt werden. Einen 1:n-Bericht mit Hilfe des Berichts-Assistenten erstellen Einen 1:n-Bericht mit Hilfe des Berichts-Assistenten zu erstellen, ist recht einfach. Folgen Sie einfach diesen Schritten: 1. Klicken Sie in der Objektliste auf BERICHTE und doppelklicken Sie dann auf ERSTELLT EINEN BERICHT UNTER VERWENDUNG DES ASSISTENTEN. 2. Benutzen Sie das aufklappbare Listenfeld TABELLEN/ABFRAGEN, um die erste Tabelle oder Abfrage auszuwählen, deren Daten im Bericht erscheinen sollen. 3. Bestimmen Sie die Felder, die Sie aus dieser Tabelle einfügen wollen. 4. Wählen Sie nacheinander alle Tabellen oder Abfragen aus, die Sie in den Bericht einfügen wollen, und markieren Sie die erforderlichen Felder. 5. Klicken Sie auf WEITER, nachdem Sie alle gewünschten Felder aus allen Tabellen und Abfragen für Ihren Bericht ausgewählt haben. Der zweite Schritt des Berichts-Assistenten bietet Ihnen Vorschläge für das Layout Ihrer Daten (siehe Abbildung 6.16). Sie können die Vorschläge von Access annehmen oder eine andere der verfügbaren Layoutmöglichkeiten auswählen. Klicken Sie auf WEITER.
Abbildung 6.16: Der zweite Schritt im Berichts-Assistenten: ein Layout auswählen
Berichte auf der Grundlage mehrerer Tabellen
233
6. Im dritten Schritt des Berichts-Assistenten werden Sie gefragt, ob Sie irgendwelche Gruppierungen hinzufügen möchten. Gruppierungen können benutzt werden, um Daten optisch zu trennen und Zwischensummen zu bilden. Im Beispiel in Abbildung 6.17 wurde der Bericht nach Städten und Firmennamen gruppiert. Nachdem Sie Gruppierungen ausgewählt haben, klicken Sie auf WEITER.
Abbildung 6.17: Der dritte Schritt im Berichts-Assistenten: Gruppierungen auswählen
7. Im nächsten Schritt des Berichts-Assistenten können Sie auswählen, wie Sie die Datensätze im Detailbereich des Berichts sortiert haben möchten (siehe Abbildung 6.18). Dieser Schritt des Assistenten erlaubt es Ihnen auch, zusammenfassende Berechnungen anzugeben, die auf Ihre Daten angewendet werden sollen. Mit Hilfe der Schaltfläche ZUSAMMENFASSUNGSOPTIONEN können Sie sich auch dazu entscheiden, den Prozentwert der gesamten Berechnungen aufzuführen. 8. Im fünften Schritt des Berichts-Assistenten wählen Sie das Layout und die Ausrichtung Ihres Berichts aus. Die Layoutoptionen lauten ABGESTUFT, IN BLÖCKEN, GLIEDERUNG 1, GLIEDERUNG 2, LINKS AUSRICHTEN 1 und LINKS AUSRICHTEN 2. 9. Der sechste Schritt des Berichts-Assistenten lässt Sie aus vordefinierten Formaten für Ihren Bericht auswählen. Die Formate sind FETT, FORMAL, GESCHÄFTLICH, INFORMELL, KOMPAKT und WEICHES GRAU. Sie können sich jedes Format in einer Vorschau ansehen.
234
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Abbildung 6.18: Der vierte Schritt im Berichts-Assistenten: eine Sortierreihenfolge auswählen
Abbildung 6.19: Zusammenfassende Berechnungen hinzufügen
10. Im siebten und letzten Schritt des Berichts-Assistenten legen Sie einen Titel für den Bericht fest. Der Titel wird gleichzeitig auch der Name für den Bericht. Ich wähle einen angemessenen Namen und ändere den Titel, nachdem der Assistent fertig ist. Der letzte Schritt gibt Ihnen auch die Möglichkeit zu entscheiden, ob Sie den fertigen Bericht sofort betrachten oder noch einmal die Entwurfsansicht sehen wollen. Den im vorherigen Beispiel erstellten Bericht sehen Sie in Abbildung 6.20. Beachten Sie, dass der Bericht nach den Feldern ORT und FIRMA sortiert und gruppiert wurde.
Berichte auf der Grundlage mehrerer Tabellen
235
Die Daten des Berichts sind nach den Feldern BESTELLDATUM und ARTIKELGRUPPE innerhalb der FIRMENGRUPPE sortiert.
Abbildung 6.20: Ein fertiggestellter 1:n-Bericht
Diese Methode zum Erstellen von 1:n-Berichten ist bei weitem die einfachste. In der Tat war das Verfahren des Verknüpfens im Hintergrund eine der Hauptverbesserungen in Access für Windows 95. Es wird von den Assistenten genutzt, wenn Sie Felder aus verschiedenen Tabellen auswählen, um zu bestimmen, wie die komplexen Abfragen, die für den Bericht oder das Formular benötigt werden, zu erstellen sind. Dieses Verfahren spart Ihnen viel Zeit und sorgt dafür, dass Sie beim Erstellen eines Berichts von unnötig komplexen Entscheidungen verschont bleiben. Obwohl Sie von dieser Funktion Gebrauch machen sollten, ist es wichtig, dass Sie als Entwickler wissen, was hinter den Kulissen passiert. Die folgenden zwei Abschnitte geben Ihnen dieses notwendige Wissen. Einen Bericht auf der Grundlage einer 1:n-Abfrage erstellen Eine andere beliebte Methode zum Erstellen eines Berichts besteht darin, ihn auf einer 1:n-Abfrage aufzubauen. Ein 1:n-Bericht, der auf diesem Wege entsteht, wird genauso erstellt, als würde er auf den Daten einer einzelnen Tabelle beruhen. Zuerst erstellen Sie die Abfrage, die dem Bericht zu Grunde liegen soll (siehe Abbildung 6.21). Wenn Sie die Abfrage fertig gestellt haben, können Sie diese anstelle all der Tabellen auswählen (wie es im vorhergegangenen Abschnitt gemacht wurde). Nachdem die Abfrage ausgewählt wurde, gehen Sie zum Erstellen des Berichts genauso vor wie im vorangegangenen Beispiel.
236
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Abbildung 6.21: Ein Beispiel für eine Abfrage, die als Grundlage für einen 1:n-Bericht fungiert
Einen 1:n-Bericht mit Hilfe des Unterberichts-Assistenten erstellen Ein 1:n-Bericht kann auch erstellt werden, indem Sie den Hauptbericht erstellen und dann ein Unterbericht-Steuerelement hinzufügen. Diese Methode wird oft benutzt, um Berichte wie etwa Rechnungen zu erstellen, welche die Berichtsdaten in einer 1:n-Beziehung anstatt in einem unstrukturierten Format darstellen (wie in Abbildung 6.20 gezeigt). Wenn Sie den Unterformular/Unterberichts-Assistenten benutzen wollen, müssen Sie sicherstellen, dass das Werkzeug STEUERELEMENT-ASSISTENTEN ausgewählt ist, bevor Sie das Unterformular/Unterbericht-Steuerelement dem Hauptbericht hinzufügen. Gehen Sie dazu wie folgt vor: 1. Klicken Sie die Schaltfläche UNTERFORMULAR/-BERICHT in der Symbolleiste an, um das Werkzeug auszuwählen. 2. Klicken Sie auf die Stelle im Hauptbericht, an der das Steuerelement erscheinen soll. UNTERFORMULAR/UNTERBERICHT-Steuerelemente werden in der Regel in den Detailbereich des Berichts eingefügt. Wenn Sie das UNTERFORMULAR/ UNTERBERICHT-Steuerelement in den Bericht gesetzt haben, wird der UNTERBERICHTS-ASSISTENT aufgerufen. 3. Geben Sie an, ob Sie möchten, dass der Unterbericht auf einem bereits vorhandenen Bericht oder Formular basiert, oder ob Sie einen neuen Unterbericht basierend auf einer Abfrage oder Tabelle erstellen möchten. Klicken Sie auf WEITER. 4. Wenn Sie sich für die zweite Möglichkeit entschieden haben, müssen Sie die Tabelle oder Abfrage auswählen, auf der Ihr Unterbericht basieren soll. Sie können sogar Felder von mehr als einer Tabelle oder Abfrage auswählen. Wenn Sie fertig sind, klicken Sie auf WEITER.
Berichte auf der Grundlage mehrerer Tabellen
237
5. Der nächste Schritt des Unterberichts-Assistenten schlägt eine Beziehung zwischen dem Hauptbericht und dem Unterbericht vor (siehe Abbildung 6.22). Sie können die ausgewählte Beziehung akzeptieren oder eine eigene definieren. Wenn Sie fertig sind, klicken Sie auf WEITER. 6. Der letzte Schritt des Unterberichts-Assistenten fragt Sie nach dem Namen des Unterberichts. Gemäß Konvention sollte der Name mit »rsub« beginnen. Klicken Sie auf FERTIG STELLEN, wenn Sie fertig sind.
Abbildung 6.22: Der UnterberichtsAssistent: die Beziehung festlegen
Wie Sie in Abbildung 6.23 sehen können, wird die 1:n-Beziehung zwischen zwei Tabellen durch diese Art von Bericht klar hervorgehoben. Im Beispiel wird jeder Kunde aufgelistet. Alle Detaildatensätze, welche die Bestellungen von jedem Kunden in der Liste wiedergeben, werden gleich hinter den Kundendaten aufgeführt.
6.11.2
Unterberichte
Wenn ein Unterbericht zu einem Bericht hinzugefügt wurde, ist es wichtig zu verstehen, welche Eigenschaften durch den Unterberichts-Assistenten festgelegt wurden, damit Sie das Steuerelement ggf. ändern können. Sie sollten sich mit einigen Eigenschaften eines Unterberichts vertraut machen: Herkunftsobjekt: Der Name des Berichts oder eines anderen Objekts, das im Steuerelement dargestellt wird Verknüpfen von: Die Felder aus dem Unterbericht, die den Unterbericht mit dem Hauptbericht verknüpfen
238
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Abbildung 6.23: Ein fertiggestellter 1:n-Bericht, der mit dem Unterformular-/Unterberichts-Assistenten erstellt wurde
Verknüpfen nach: Die Felder aus dem Hauptbericht, die den Hauptbericht mit dem Unterbericht verknüpfen Vergrößerbar: Legt fest, ob sich das Steuerelement in vertikaler Richtung vergrößern kann, um den Daten im Unterbericht Platz zu verschaffen Verkleinerbar: Legt fest, ob leere Zeilen entfernt werden sollen, wenn im Unterbericht keine Daten vorhanden sind Sie sollten nicht nur wissen, wie Sie mit den Eigenschaften eines Unterberichts umgehen, sondern Sie sollten den Unterbericht auch aus dem Hauptbericht heraus verändern können. Sie können den Unterbericht immer bearbeiten, indem Sie ihn in der Liste der Berichte im Datenbankfenster auswählen. Um das zu tun, klicken Sie auf den zu modifizierenden Bericht und dann auf ENTWURF. Sie können einen Unterbericht auch verändern, indem Sie seine Objekte direkt im Hauptbericht auswählen.
6.12
Sortierreihenfolge und Gruppierung
Entgegen der Sortierung in Formularen wird die Sortierung der Daten innerhalb eines Berichts nicht von der zu Grunde liegenden Abfrage vererbt. In der Tat beeinflusst die zugrunde liegende Abfrage die Sortierung des Berichts nur dann, wenn keine Sortierung für den Bericht angegeben wurde. Jede Sortierreihenfolge, die in der Abfrage festgelegt wurde, wird komplett von der Sortierreihenfolge des Berichts überschrieben, deren Festlegung im Dialogfeld SORTIEREN UND GRUPPIEREN erfolgt (siehe Abbildung 6.24). Das Sortieren sowie das Gruppieren des Berichts wird von den Optionen beeinflusst, die Sie auswählen, wenn Sie den Berichts-Assistenten ausführen. Das Dialogfeld SORTIEREN UND GRUPPIEREN können Sie benutzen, um Sortier- beziehungsweise Gruppierungsmöglichkeiten für Ihren Bericht hinzuzufü-
239
Sortierreihenfolge und Gruppierung
gen, zu entfernen oder zu verändern. Sortierungen beeinflussen schlicht die Reihenfolge der Datensätze im Bericht. Gruppierungen fügen Gruppenköpfe und -füße zu ihrem Bericht hinzu.
Abbildung 6.24: Das Fenster Sortieren und gruppieren bei einer Gruppierung nach Stadt- und Firmennamen sowie einer Sortierung nach dem Bestelldatum und der Artikelbezeichnung
6.12.1
Eine Sortierreihenfolge und eine Gruppierung hinzufügen
Häufig möchten Sie eine Sortierung oder eine Gruppierung zu einem Bericht hinzufügen. Um das zu tun, folgen Sie diesen vier Schritten: 1. Klicken Sie auf der Symbolleiste BERICHTSENTWURF auf SORTIEREN PIEREN, um das Dialogfeld SORTIEREN UND GRUPPIEREN zu öffnen.
UND GRUP-
2. Klicken Sie auf den Markierer der Zeile, über der Sie die Sortierung oder Gruppierung einfügen möchten. In Abbildung 6.25 wird eine Sortierung oder Gruppierung über der Gruppierung ORT eingefügt. Drücken Sie die (Einfg)-Taste, um eine leere Zeile in das Dialogfeld SORTIEREN UND GRUPPIEREN einzufügen.
Abbildung 6.25: Eine Sortier- oder Gruppierungsstufe einfügen
3. Klicken Sie in das Feld FELD/AUSDRUCK und benutzen Sie die aufklappbare Liste, um das Feld auszuwählen, nach dem Sie sortieren oder gruppieren wollen. 4. Setzen Sie die Eigenschaften, um festzulegen, auf welche Weise sortiert oder gruppiert werden soll (siehe nächster Abschnitt).
240
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Um eine hinzugefügte Sortierung oder Gruppierung wieder zu entfernen, klicken Sie den Markierer der Zeile im Dialogfeld SORTIEREN UND GRUPPIEREN an, die Sie entfernen möchten. Dann drücken Sie die (Entf)-Taste. Sie werden gewarnt, dass alle Steuerelemente in den Gruppenköpfen- und füßen verloren gehen.
6.12.2
Sortier- und Gruppeneigenschaften
Jede Gruppierung in einem Bericht verfügt über Eigenschaften, welche die Attribute der Gruppe festlegen. Jede Gruppe besitzt darüber hinaus fünf Eigenschaften, die angeben, ob das Feld oder der Ausdruck zum Sortieren, Gruppieren oder für beides benutzt wird (siehe Abbildung 6.26). Außerdem können Sie mit Hilfe dieser Eigenschaften Details über die Gruppierungsoptionen festlegen. Die Sortier- und Gruppeneigenschaften sind Folgende: Gruppenkopf: Die Eigenschaft GRUPPENKOPF gibt an, ob die ausgewählte Gruppe einen Kopfbereich enthält. Wenn Sie die Eigenschaft GRUPPENKOPF auf JA setzen, erscheint eine zusätzliche Zeile im Bericht, die Sie nutzen können, um Informationen über die Gruppe anzuzeigen. Wenn Sie zum Beispiel nach Ländern gruppieren, kann der Gruppenkopf benutzt werden, um den Namen des Landes anzuzeigen, das Sie gerade drucken. Wenn die beiden Eigenschaften GRUPPENKOPF und GRUPPENFUSS auf NEIN stehen, wird das Feld nur benutzt, um die Sortierreihenfolge der Datensätze für den Bericht festzulegen.
Abbildung 6.26: Das Fenster Sortieren und Gruppieren mit fünf Sortier- und Gruppeneigenschaften
Gruppenfuß: Die Eigenschaft GRUPPENFUSS gibt an, ob die ausgewählte Gruppe einen Fußbereich enthält. Wenn Sie die Eigenschaft GRUPPENFUSS auf JA setzen, erscheint eine zusätzliche Zeile im Bericht. Der Gruppenfußbereich kann verwendet werden, um zusammenfassende Informationen über die Gruppe darzustellen wie zum Beispiel Zwischensummen. Gruppieren nach: Die Eigenschaft GRUPPIEREN NACH legt das fest, was eine neue Gruppe ausmacht. Sie wird oft in Situationen benutzt, in denen Abteilungsdaten
Sortierreihenfolge und Gruppierung
241
zusammengefasst werden müssen. Anstatt zum Beispiel nach der ganzen Abteilungsnummer zu gruppieren, möchten Sie eventuell nur nach den ersten drei Ziffern Gruppen bilden. Intervall: Die Eigenschaft INTERVALL wird zusammen mit der Eigenschaft GRUPPIEREN NACH benutzt, um einen Intervallwert anzugeben, nach dem Daten gruppiert werden. Wenn zum Beispiel die Eigenschaft GRUPPIEREN NACH für ein Textfeld auf ANFANGSZEICHEN gesetzt ist und das Intervall auf 3 steht, werden die Felddaten nach den ersten drei Buchstaben gruppiert. Zusammenhalter: Die Eigenschaft ZUSAMMENHALTER legt fest, ob Access versucht, die gesamte Gruppe auf einer Seite zusammenzuhalten. Die drei Optionen lauten NEIN, GANZE GRUPPE, und MIT 1. DETAILDATENSATZ. Die Option GANZE GRUPPE bedeutet, dass Access versucht, die ganze Gruppe auf einer Seite zu behalten, was den Gruppenkopf, den Gruppenfuß und den Detailbereich mit einschließt. Die Möglichkeit MIT 1. DETAILDATENSATZ bedeutet, dass Access den Gruppenkopf nur dann auf eine Seite druckt, wenn es auch den ersten Detaildatensatz mit auf die gleiche Seite drucken kann. Wenn Sie die Eigenschaft ZUSAMMENHALTER auf GANZE GRUPPE gesetzt haben und die Gruppe zu groß ist, um auf eine Seite zu passen, ignoriert Access diese Einstellung. Weiterhin ignoriert Access die Eigenschaft ZUSAMMENHALTER, wenn Sie diese auf MIT 1. DETAILDATENSATZ setzen und entweder der Gruppenkopf oder der Detaildatensatz zu groß ist, um auf eine Seite zu passen.
6.12.3
Was sind Gruppenkopf- und -fußeigenschaften und warum sollten sie verwendet werden?
Jeder Gruppenkopf und -fuß hat seine speziellen Eigenschaften, die sein Verhalten festlegen: Neue Seite: Die Eigenschaft NEUE SEITE kann auf KEINE, VOR, NACH und VOR & NACH gesetzt werden. Beim Wert KEINE erscheint kein Seitenwechsel vor oder nach dem Berichtsabschnitt, bei VOR wird ein Seitenwechsel vor und bei NACH hinter dem Berichtsabschnitt eingefügt. Bei Auswahl von VOR & NACH erscheint ein Seitenwechsel sowohl vor dem Berichtsabschnitt als auch danach. Neue Zeile oder Spalte: Die Eigenschaft NEUE ZEILE ODER SPALTE legt fest, ob ein Spaltenwechsel erfolgt, wenn der Berichtsabschnitt gedruckt wird. Diese Eigenschaft gilt nur für mehrspaltige Berichte. Die Auswahlmöglichkeiten sind KEINE, VOR, NACH und VOR & NACH. Wie die Eigenschaft NEUE SEITE bestimmt diese Eigenschaft, ob ein Spaltenwechsel auftritt, bevor und/oder nachdem der Berichtsabschnitt gedruckt wurde, bzw. ob der Berichtsabschnitt überhaupt eine Rolle spielt.
242
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Zusammenhalten: Die Eigenschaft ZUSAMMENHALTEN gibt an, ob Sie möchten, dass Access versucht, den gesamten Berichtsabschnitt zusammen auf eine Seite zu drucken. Wenn diese Eigenschaft auf JA gesetzt ist, druckt Access den Abschnitt auf der nächsten Seite, wenn es den gesamten Abschnitt nicht mehr auf der aktuellen Seite drucken kann. Wenn sie auf NEIN gesetzt ist, druckt Access so viel von dem Abschnitt auf die aktuelle Seite wie möglich und fügt dann einen Seitenumbruch ein. Wenn ein Abschnitt die Seitenlänge überschreitet, beginnt Access den Druck auf einer neuen Seite und fährt mit dem Drucken auf der Folgeseite fort. Sichtbar: Die Eigenschaft SICHTBAR bestimmt, ob der Abschnitt sichtbar ist. Häufig muss ein spezieller Berichtsbereich zur Laufzeit wegen verschiedener Umstände versteckt werden. Das kann leicht erledigt werden, indem man den Wert der Eigenschaft SICHTBAR des Berichtsabschnitts mit einem VBA-Programm verändert, welches auf das FORMAT-Ereignis reagiert. Vergrößerbar, Verkleinerbar: Die Eigenschaft VERGRÖSSERBAR legt fest, ob sich der Abschnitt vertikal ausdehnen soll, um den Daten darin Platz zu verschaffen. Die Eigenschaft VERKLEINERBAR gibt an, ob sie möchten, dass der Abschnitt vertikal schrumpft und so Leerzeilen unterdrückt. Bereich wiederholen: Die Eigenschaft BEREICH WIEDERHOLEN ist sehr nützlich. Mit ihrer Hilfe können Sie festlegen, ob der Gruppenkopf auf jeder nachfolgenden Seite wiederholt wird, wenn der Berichtsabschnitt mehr als eine Seite für den Ausdruck braucht.
6.13
Durch Aufsetzen der Berichte auf gespeicherte Abfragen Geschwindigkeit und Wiederverwendbarkeit verbessern
Normalerweise ist es am besten, Ihren Access-Bericht auf einer Abfrage aufzubauen. Das bietet Ihnen mehrere Vorteile:
Die Abfrage, die dem Bericht zugrunde liegt, kann von anderen Formularen und Berichten genutzt werden.
Kompliziertere Berechnungen brauchen nur noch einmal erstellt zu werden – Sie müssen sie nicht mehr für jeden Bericht (oder jedes Formular) neu erstellen. Mit früheren Versionen von Access wurden Berichte, die auf gespeicherten Abfragen beruhten, schneller geöffnet als Berichte mit eingebetteten SQL-Anweisungen. Das war so, weil Access einen Abfrageplan erstellte, wann immer Sie eine Abfrage entworfen und abgespeichert hatten. Dieser Abfrageplan ist ein Ausführungsplan, der auf der Datenmenge in den Abfragetabellen sowie auf den verfügbaren Indizes in jeder Tabelle beruht. Wenn Sie in den früheren Versionen von Access einen Bericht starteten, der auf einer eingebetteten SQL-Anweisung beruhte, wurde die Abfrage
Access-Berichte und das Internet
243
kompiliert. Dabei wurde der Abfrageplan zur Laufzeit berechnet, was die Ausführung der Abfrage verlangsamte. In Access 2000 werden Abfragepläne für SQLAnweisungen zu dem Zeitpunkt erstellt, an dem das Formular oder der Bericht abgespeichert wird. Abfragepläne werden zusammen mit dem betreffenden Formular oder Bericht gespeichert. Was sind also die Vorteile davon, einen Bericht auf einer gespeicherten Abfrage anstatt auf einer eingebetteten SQL-Anweisung aufzusetzen? Häufig werden Sie mehrere Berichte und Formulare erstellen, die auf den gleichen Informationen beruhen. Eine eingebettete SQL-Anweisung kann nicht von mehreren Datenbankobjekten gemeinsam genutzt werden, sondern Sie müssen die Anweisung zumindest in jedes Formular und in jeden Bericht, das bzw. den Sie erstellen, hineinkopieren. Berichte und Formulare auf Abfragen aufzubauen, löst dieses Problem. Sie erstellen die Abfrage nur einmal und ändern sie später im Fall der Fälle ebenfalls nur einmal. Viele Formulare und Berichte können alle die gleiche Abfrage benutzen (einschließlich ihrer Kriterien, Ausdrücke und so weiter). Berichte enthalten häufig komplexe Ausdrücke. Wenn ein bestimmter Ausdruck nur in einem Bericht verwendet wird, geht nichts verloren, wenn man diesen Ausdruck in eine eingebettete SQL-Anweisung schreibt. Auf der anderen Seite werden jedoch viele komplexe Ausdrücke in mehreren Formularen und Berichten eingesetzt. Durch das Einbinden dieser Ausdrücke in Abfragen, auf denen die Berichte und Formulare aufbauen, brauchen Sie den Ausdruck nur noch einmal zu erstellen. Es ist einfach, eine eingebettete SQL-Anweisung als Abfrage zu speichern. Somit können Sie den BERICHTS-ASSISTENTEN benutzen, um einen Bericht zu erstellen, der mehrere Tabellen verwendet, und Sie können dann die resultierende SQLAnweisung als Abfrage speichern. Wenn der Bericht in der Entwurfsansicht geöffnet ist, öffnen Sie dazu das EIGENSCHAFTENfenster, klicken auf die Registerkarte DATEN und klicken anschließend im Feld DATENHERKUNFT auf die Schaltfläche mit den drei Punkten. Die eingebettete SQL-Anweisung erscheint nun als Abfrage. Wählen Sie DATEI|SPEICHERN ALS BZW. DATEI|EXPORTIEREN, geben Sie einen Namen für die Abfrage ein und klicken Sie jetzt auf OK. Schließen Sie das Abfragefenster; damit geben Sie an, dass Sie die Eigenschaft DATENHERKUNFT neu festlegen. Ihre Abfrage basiert nun auf einer gespeicherten Abfrage anstatt einer eingebetteten SQL-Anweisung.
6.14
Access-Berichte und das Internet
Microsoft hat es durch das Hinzufügen von Hyperlinks und dadurch, dass es Ihnen erlaubt wird, einen Access-Bericht als HTML-Dokument zu speichern, leichter gemacht, Internet-fähige Anwendungen zu entwickeln. Diese Funktionen werden in den folgenden Abschnitten behandelt.
244
6.14.1
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Einem Bericht einen Hyperlink hinzufügen
Hyperlinks können an Berichte in Form von Bezeichnungsfeldern hinzugefügt werden. Sobald Sie einen Hyperlink hinzugefügt haben, fungiert er als direkte Verbindung zu einer UNC- oder URL-Adresse. Um einen Hyperlink zu einem Bericht hinzuzufügen, folgen Sie diesen Schritten: 1. Wenn das Berichtsfenster in der Entwurfsansicht geöffnet ist, fügen Sie ein Bezeichnungsfeld zu dem Bericht hinzu. 2. Setzen Sie die Eigenschaft HYPERLINK-ADRESSE auf den UNC-Pfad oder URL, auf den Sie verweisen möchten. Der einfachste Weg dazu ist es, in das Feld der Eigenschaft HYPERLINK-ADRESSE und dann auf die Schaltfläche mit den drei Punkten zu klicken, um das Dialogfeld HYPERLINK EINFÜGEN zu öffnen. 3. Geben Sie den UNC-Pfad oder URL in das Textfeld DATEITYP ODER WEBSEITE ein. Sie können die Schaltfläche DATEI benutzen, um einen UNC-Pfad zu suchen, oder mit Hilfe der Schaltfläche WEBSEITEN einen URL ausfindig machen. 4. Wenn Sie eine Hyperlink-Unteradresse eingeben wollen, klicken Sie auf TEXTMARKE. Die Hyperlink-Unteradresse kann ein Abschnittsname, eine Foliennummer oder jeder andere bekannte Ort im Dokument sein, das im Textfeld DATEITYP ODER WEBSEITE steht. 5. Klicken Sie auf OK. Die Eigenschaften HYPERLINK-ADRESSE und HYPERLINKUNTERADRESSE enthalten nun die Informationen aus dem Dialogfeld HYPERLINK EINFÜGEN. Die Eigenschaften HYPERLINK-ADRESSE und HYPERLINK-UNTERADRESSE kommen nur dann ins Spiel, wenn ein Bericht als HTML-Dokument gespeichert und in einem Webbrowser, wie zum Beispiel dem Internet Explorer 5.0, angesehen wird. Das Abspeichern eines Berichts als HTML-Dokument wird im folgenden Abschnitt behandelt.
6.14.2
Einen Bericht als HTML speichern
Um einen Bericht als HTML abzuspeichern, wählen Sie DATEI|EXPORTIEREN. Benutzen Sie dann das aufklappbare Listenfeld DATEITYP, um HTML-Dokumente (*.htm, *.html) auszuwählen. Wählen Sie einen Speicherort und einen Namen für die Datei aus und klicken Sie auf SPEICHERN. Das Dokument wird als HTML gespeichert und bekommt den Namen und Ort, den Sie angegeben haben. Aktivieren Sie das Kontrollkästchen AUTOSTART, um den Bericht in Ihrem standardmäßigen Webbrowser anzuzeigen, nachdem das HTML erzeugt wurde.
Access-Berichte und das Internet
6.14.3
245
Für die Praxis
Berichte für Ihre Anwendung erstellen Das Zeit- und Abrechnungssystem benötigt mehrere Berichte, die Sie im Verlaufe dieses Buchs entwerfen werden. Einige der einfacheren werden hier erstellt.
6.14.4
Den Bericht rptClientListing entwerfen
Der Bericht rptClientListing listet alle Kunden in der Tabelle tblClients auf. Der Bericht enthält den Firmennamen, den Kontaktnamen, die Stadt, das Bundesland, die Postleitzahl und die Bürotelefonnummer eines jeden Kunden und ist nach dem Firmennamen sortiert. Der Bericht rptClientListing basiert auf einer Abfrage namens qryClientListing, die in Abbildung 6.27 gezeigt wird. Sie enthält die Felder COMPANYNAME (Firmenname), CITY (Stadt), STATE (Bundesland), OFFICEPHONE (Telefon) und FAX. Die Abfrage enthält zudem noch einen Ausdruck CONTACTNAME, der die Felder CONTACTFIRSTNAME und CONTACTLASTNAME aneinanderhängt. Der Ausdruck sieht so aus: ContactName: [ContactFirstName] & " " & [ContactLastName]
Abbildung 6.27: Die Abfrage qryClientListing – eine Grundlage für den Bericht rptClientListing
Um den Bericht zu erstellen, gehen Sie wie folgt vor: 1. Wählen Sie BERICHTE aus der Objektliste, und doppelklicken Sie auf ERSTELLT EINEN BERICHT UNTER VERWENDUNG DES ASSISTENTEN. 2. Benutzen Sie das Listenfeld TABELLEN/ABFRAGEN, um die Abfrage qryClientListing auszuwählen (siehe Abbildung 6.28). Klicken Sie auf OK. 3. Klicken Sie auf die Schaltfläche >>, um anzugeben, dass Sie alle Felder in der Abfrage in Ihren Bericht einfügen möchten. Klicken Sie auf WEITER. 4. Fügen Sie keine Gruppierungen für den Bericht hinzu. Klicken Sie auf WEITER.
246
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Abbildung 6.28: Die Abfrage qryClientListing auswählen
5. Benutzen Sie das erste aufklappbare Listenfeld, um COMPANYNAME als Sortierfeld auszuwählen (siehe Abbildung 6.29). Klicken Sie auf WEITER.
Abbildung 6.29: Das Feld COMPANYNAME als Sortierreihenfolge festlegen
6. Wählen Sie QUERFORMAT als Seitenausrichtung und klicken Sie auf WEITER. 7. Wählen Sie ein Format für den Bericht aus und klicken Sie auf WEITER. 8. Geben Sie dem fertigen Bericht den Titel rptClientListing. Klicken Sie dann auf FERTIG STELLEN.
Access-Berichte und das Internet
247
9. Der fertig gestellte Bericht sollte so aussehen wie in Abbildung 6.30. Klicken Sie auf ENTWURF, um den Bericht in der Entwurfsansicht zu öffnen. Beachten Sie, wie sowohl der Name als auch der Titel des Berichts rptClientListing lauten. Ändern Sie den Titel des Berichts in Client Listing by Company Name (siehe Abbildung 6.31).
Abbildung 6.30: Eine Voransicht des fertig gestellten Berichts
Abbildung 6.31: Den Berichtstitel ändern
6.14.5
Den Bericht rptTimeSheet entwerfen
Der Bericht rptTimeSheet ist viel komplexer als der Bericht rptClientListing. Er enthält zwei Unterberichte: rsubTimeSheet und rsubTimeSheetExpenses.
248
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Der Bericht rptTimeSheet wird in Abbildung 6.32 gezeigt. Er basiert auf der Abfrage qryTimeSheet (siehe Abbildung 6.33) Diese enthält Felder aus den beiden Tabellen tblTimeCards und tblEmployees.
Abbildung 6.32: Der Bericht rptTimeSheet in der Entwurfsansicht
Abbildung 6.33: Die Abfrage QRYTIMESHEET in der Entwurfsansicht
Der Bericht rptTimeSheet besitzt einen Seitenkopf, der den Titel des Berichts enthält. Der Kopfbereich TimeCardID umfasst die Felder EmployeeName und DateEntered aus der Abfrage qryTimeSheet. Der Detailbereich des Berichts besteht aus den beiden Unterberichten rsubTimeSheet und rsubTimeSheetExpenses. Der Seitenfuß enthält zwei Ausdrücke: einen für das Datum und einen für die Seitenzahl. Sie sehen so aus: =Jetzt() ="Page " & [Seite] & " of " & [Seiten]
Der Bericht rsubTimeSheet basiert auf qrySubTimeSheet. Diese Abfrage enthält die folgenden Felder aus den Tabellen tblProjects und tblTimeCardHours:
249
Access-Berichte und das Internet
TblProjects: ProjectName TblTimeCardsHours: TimeCardID, TimeCardDetailID, DateWorked, WorkDescription, BillableHours, BillingRate und der Ausdruck HourlyBillings: [tblTimeCardHours].[BillingRate]*[BillableHours]
Der Entwurf von rsubTimeSheet wird in Abbildung 6.34 gezeigt. Dieser Unterbericht kann leicht von einem Assistenten erstellt werden. Wählen Sie alle Felder außer TimeCardID und TimeCardDetailID aus der Abfrage qrySubTimeSheets aus. Geben Sie an, dass Ihre Daten nach tblTimeCardHours angezeigt werden sollen. Fügen Sie keine Gruppierungen hinzu und sortieren Sie den Bericht nicht. Wenn Sie mit dem Assistenten fertig sind, ändern Sie den Entwurf des Berichts. Entfernen Sie die Beschriftung aus dem Berichtskopf und verschieben Sie alles aus dem Seitenkopf in den Berichtskopf. Schieben Sie den Seitenkopf zusammen, entfernen Sie alles aus dem Seitenfuß und fügen Sie einen Berichtsfuß mit dem Ausdruck =Summe([HourlyBillings]) hinzu.
Abbildung 6.34: Der Bericht rsubTimeSheet in der Entwurfsansicht
Ändern Sie das Format der Steuerelemente HourlyBillings und TotalHourlyBillings in Währung. Benutzen Sie das Dialogfeld SORTIEREN UND GRUPPIEREN, um nach TimeCardID und TimeCardDetailID zu sortieren. Der Bericht rsubTimeSheetExpenses basiert auf der Abfrage qrySubTimeSheetExpense, welche die folgenden Felder aus den Tabellen tblProjects, tblExpenseCodes und tblTimeCardExpenses enthält. tblProjects: ProjectName tblTimeCardsExpenses: TimeCardID, TimeCardExpenseID, ExpenseDate, ExpenseDescription und ExpenseAmount tblExpenseCodes: ExpenseCode
Der Entwurf von rsubTimeSheetExpenses wird in Abbildung 6.35 gezeigt. Dieser Unterbericht kann leicht von einem Assistenten erstellt werden. Wählen Sie alle Felder der Abfrage qrySubTImeExpense außer TimeCardID und TimeCardExpenseID aus und geben Sie an, dass die Daten nach tblTimeCardExpenses angezeigt werden sollen. Fügen Sie keine Gruppierungen hinzu und sortieren Sie den Bericht auch nicht. Wenn Sie mit dem Assistenten fertig sind, verändern Sie den Entwurf des Berichts.
250
Kapitel 6: Was jeder Entwickler über Berichte wissen sollte
Entfernen Sie die Beschriftung des Berichtskopfs und verschieben Sie alles aus dem Seitenkopf in den Berichtskopf. Schieben Sie den Seitenkopf zusammen, entfernen Sie alles aus dem Seitenfuß und fügen Sie einen Berichtsfuß mit dem Ausdruck =Summe([ExpenseAmount]) hinzu.
Abbildung 6.35: Der Bericht rsubTimeSheetExpenses in der Entwurfsansicht
Ändern Sie das Format der Steuerelemente ExpenseAmount und TotalExpenseAmount in Währung und benutzen Sie das Dialogfeld SORTIEREN UND GRUPPIEREN, um nach TimeCardID und TimeCardExpenseID zu sortieren.
VBA: Eine Einführung
Kapitel Hier lesen Sie:
Was versteht man unter Klassen-, Standard-, Formular- und Berichtsmodulen von Access?
Mit Variablen arbeiten Parameter über- und Werte zurückgeben Vom Modulfenster aus Prozeduren ausführen Das Objekt DoCmd Mit integrierten Funktionen arbeiten Mit Konstanten arbeiten Werkzeuge für den Visual Basic Editor (VBE) Den VBE individuell anpassen
7.1
Was ist VBA?
Visual Basic für Applikationen (VBA) ist die Entwicklungssprache für Microsoft Access 2000, eine konsistente Sprache für die Anwendungsentwicklung in der Office-Suite von Microsoft, zu der jetzt auch Outlook gehört. Der Sprachkern, seine Konstrukte und die Umgebung sind für Microsoft Access 2000, Microsoft Visual Basic, Microsoft Excel, Microsoft Word, Microsoft Outlook (für die Programmierung innerhalb der gesamten Anwendung) und Microsoft Project gleich. Unterschiedlich sind jedoch die integrierten Objekte der einzelnen Anwendungen. Access besitzt beispielsweise ein Objekt CurrentProject, Excel dagegen ein Objekt mit dem Namen Workbook. Die Objekte der einzelnen Anwendungen sind mit bestimmten Eigenschaften (Attributen) und Methoden (Aktionen) (und in einigen Fällen auch mit Ereignissen) verknüpft. In diesem Kapitel bekommen Sie einen Überblick über die Sprache VBA und ihre Konstrukte.
252
Kapitel 7: VBA: Eine Einführung
Anders als Word- oder Excel-Makros sind Access-Makros keine Sub-Prozeduren innerhalb von Modulen, sondern Datenbankobjekte eines eigenen Typs mit einer eigenen Schnittstelle. Deshalb lassen sich Access-Makros nicht zum Erlernen der Programmierung in VBA einsetzen, wie es möglich ist, wenn man ein Word- oder Excel-Makro aufzeichnet und anschließend den dazugehörenden VBA-Code analysiert. Einfache Access-Anwendungen kann man unter Verwendung von Makros schreiben. Das geht zwar für die schnelle Entwicklung von Prototypen und sehr einfache Anwendungen in Ordnung, aber der größte Teil der ernsthaften Entwicklung in Access erfolgt mit VBA. Anders als mit Makros lässt sich mit VBA Folgendes realisieren:
Arbeit mit komplexen logischen Strukturen (Case-Anweisungen, Schleifen usw.) Verwendung von Konstanten und Variablen Nutzung von Funktionen und Aktionen, die in Makros nicht zur Verfügung stehen
Ausführen von Aktionen mit Datensatzgruppen in Form von Schleifen Transaktionsverarbeitung Erstellen von und Arbeit mit Datenbankobjekten per Programm Implementieren einer Fehlerbehandlung Erstellen von Bibliotheken mit benutzerdefinierten Funktionen Aufrufen von Windows-API-Funktionen Ausführen komplexer DDE- und OLE-Automatisierungsbefehle Die Sprache VBA ermöglicht den Einsatz komplexer logischer Strukturen, während Sie mit Makros lediglich die einfache If...Then...Else-Logik verwenden können. VBA bietet Ihnen eine Vielzahl logischer Konstrukte und Schleifen, die weiter hinten in diesem Kapitel behandelt werden. In VBA können Sie außerdem Variablen und Konstanten deklarieren und dann damit arbeiten. Sie können den Variablen einen geeigneten Gültigkeitsbereich zuweisen und sie als Parameter an Unterroutinen und Funktionen übergeben. Wie Sie später sehen werden, bilden Variablen und Konstanten einen integralen Bestandteil aller Access-Anwendungen. Viele wichtige Merkmale der Sprache VBA sind nicht über Makro-Aktionen verfügbar. Wenn Sie versuchen, eine Anwendung ausschließlich mit Makros zu entwickeln, können Sie einen großen Teil der vielfältigen Möglichkeiten von VBA nicht nutzen. Außerdem lassen sich viele der in Makros und Modulen vorhandenen Aktionen mit Hilfe von VBA-Code wesentlich effizienter erledigen.
Was ist VBA?
253
Komplexe Access-Anwendungen verlangen häufig, dass eine Datensatzgruppe durchlaufen und dabei mit jedem Datensatz der Gruppe eine bestimmte Aktion ausgeführt wird. Das ist mit Makros nicht möglich. Mit Hilfe von VBA und ActiveXDatenobjekten lassen sich Daten dagegen hinzufügen, löschen, aktualisieren und bearbeiten. ActiveX-Datenobjekte werden in Kapitel 12 vorgestellt. Bei der Bearbeitung von Datensatzgruppen wollen Sie sicherstellen, dass die gesamte Verarbeitung erfolgreich abgeschlossen ist, bevor die Daten dauerhaft aktualisiert werden. Mit Hilfe der Methoden BeginTrans, CommitTrans und RollbackTrans können Sie gewährleisten, dass die Aktualisierung nur erfolgt, wenn alle Teile einer Transaktion erfolgreich durchgeführt wurden. Transaktionsverarbeitung kann, wenn sie korrekt ausgeführt wird, die Leistung Ihrer Anwendung wesentlich verbessern, weil Daten erst dann auf die Festplatte geschrieben werden, wenn der Prozess abgeschlossen ist. Transaktionsverarbeitung und ihre Vorzüge werden in Kapitel 22 behandelt. Mit Access-Makros kann man Datenbankobjekte zur Laufzeit weder erstellen noch modifizieren. Mit VBA können Sie Datenbanken, Tabellen, Abfragen und weitere Datenbankobjekte anlegen und bestehende Objekte verändern. Für diese Fähigkeit gibt es viele praktische Anwendungen. (Weitere Einzelheiten hierzu finden Sie in Kapitel 12.) Wenn die Benutzer beispielsweise nebenbei Abfragen erstellen können, möchten Sie ihnen vielleicht die Möglichkeit an die Hand geben, Abfragen mit Hilfe eines bereitgestellten Front-End-Formulars zu gestalten und für die spätere Wiederverwendung zu speichern. Mit Access-Makros lässt sich keine Fehlerbehandlung implementieren. Falls während der Ausführung eines Access-Makros mit der Laufzeitversion von Access ein Fehler auftritt, wird der Benutzer aus der Anwendung (und damit aus der AccessLaufzeitversion) katapultiert. Mit Hilfe von Fehlerbehandlungsverfahren können Sie exakt festlegen, was passieren soll, wenn es während der Ausführung Ihrer Anwendung zu einem Fehler kommt. Die Fehlerbehandlung wird in Kapitel 14 eingehender besprochen. Darüber hinaus erleichtert VBA die Zusammenstellung von Code-Bibliotheken mit wiederverwendbaren Funktionen, das Gestalten und Testen komplexer Prozesse und sogar das Schreiben eigener Add-Ins. Selbst wenn Sie nur relativ einfache Anwendungen entwickeln, sollen Sie in der Lage sein, allgemeine Funktionsbibliotheken anzulegen, die sich in all Ihren Access-Anwendungen einsetzen lassen. Das ist bei Verwendung von Makros extrem schwierig, wenn nicht unmöglich. Viele leistungsfähige Funktionen, die VBA nicht bietet, sind als Teil von Windows selbst verfügbar. Als Windows-API (Application Programming Interface) werden die nahezu 1.000 Windows-Funktionen bezeichnet, die Microsoft den Access-Programmierern zur Verfügung stellt. Diese sind nicht über Access-Makros erreichbar; mit Hilfe von VBA-Code lassen sie sich dagegen deklarieren und aufrufen, was sowohl die Leistung als auch die Funktionalität Ihrer Anwendungen erhöht. Das WindowsAPI ist Thema von Kapitel 27.
254
Kapitel 7: VBA: Eine Einführung
DDE (Dynamic Data Exchange) und Automatisierung ermöglichen die Kommunikation zwischen Ihren Access-Anwendungen und anderen Programmen. DDE ist zwar ein älteres Verfahren als die Automatisierung, wird aber immer noch zur Kommunikation mit einigen Anwendungen eingesetzt, die die Automatisierung nicht unterstützen. Mit der Automatisierung werden Automatisierungs-Server-Anwendungen wie Excel und Project und deren Objekte gesteuert. (Alle Microsoft-OfficeAnwendungen sind Automatisierungs-Server.) Die Automatisierung wird in Kapitel 26 dargestellt. Makros können zwar schnelle Lösungen für einfache Probleme bieten, aber ihre Beschränktheit macht VBA zur einzigen echten Möglichkeit für die Entwicklung komplexer Lösungen. Um den Übergang von Makros zu Modulen zu vereinfachen, stellt Microsoft eine Funktion bereit, die Makros in VBA-Module konvertiert.
7.2
Was sind die Klassen-, Standard-, Formularund Berichtsmodule von Access?
VBA-Code wird in Einheiten verfasst, die als Unterroutinen und Funktionen bezeichnet und in Modulen gespeichert werden. Access-Module sind entweder Standard- oder Klassenmodule. Standardmodule werden erstellt, indem man das Modulsymbol im Datenbankfenster auswählt und dann auf NEU klickt. Klassenmodule können selbstständige Objekte sein oder mit einem Formular oder Bericht verknüpft werden. Um ein selbstständiges Klassenmodul anzulegen, wählen Sie im Menü EINFÜGEN den Befehl KLASSENMODUL. Außerdem erstellt Microsoft Access immer, wenn Sie ein Formular oder einen Bericht mit Code hinterlegen, ein Klassenmodul, das mit diesem Formular oder Bericht verknüpft ist und den betreffenden Code enthält. Spezielle Module eines Formulars oder Berichts werden im Allgemeinen als »Formular- und Berichtsklassenmodule« bezeichnet, ihr Code häufig als »Code Behind Forms« (CBF). CBF wird im jeweiligen Formular bzw. Bericht erstellt und abgelegt und von darin auftretenden Ereignissen ausgelöst. Eine »Unterroutine« (Unterprozedur) ist eine Routine, die auf ein Ereignis reagiert oder eine Aktion durchführt. Eine »Ereignisprozedur« ist eine spezielle Art Unterroutine, die automatisch in Reaktion auf ein Ereignis wie zum Beispiel einen Mausklick auf eine Befehlsschaltfläche oder das Laden eines Formulars ausgeführt wird; sie kann keinen Wert zurückgeben. Eine »Funktion« ist eine spezielle Art Routine, weil sie – anders als Unterroutine – einen Wert zurückgeben kann. Wie eine Unterroutine lässt sich auch eine Funktion von einem Ereignis auslösen.
Was sind die Module von Access?
7.2.1
255
Wo entsteht VBA-Code?
Der gesamte VBA-Code wird im Visual Basic Editor geschrieben (auch VBE genannt). Sobald Sie versuchen, auf den Code in einem Standard- oder Klassenmodul zuzugreifen, gelangen Sie in den VBE (zu sehen in Abbildung 7.1). Die VBEUmgebung in Microsoft Access ist jetzt mit den anderen Microsoft-Office-Produkten konsistent. Es handelt sich um ein von Microsoft Access getrenntes Fenster, das über eine Menüleiste, eine Symbolleiste, ein Projektfenster, ein Eigenschaftenfenster, ein Direktfenster, ein Lokalfenster, ein Überwachungsfenster, einen Objektkatalog und ein Code-Fenster verfügt. Die einzelnen Komponenten des VBE werden bei Bedarf in diesem Kapitel und im weiteren Verlauf des Buchs erläutert.
Abbildung 7.1: Der Visual Basic Editor (VBE)
7.2.2
Die Anatomie eines Moduls
Alle Module, sowohl Standard- als auch Klassenmodule, enthalten einen Abschnitt ALLGEMEINE DEKLARATIONEN (siehe Abbildung 7.2). Wie der Name schon sagt, werden dort Variablen und Konstanten deklariert, die für alle Funktionen und Unterroutinen des Moduls sichtbar sein sollen, sowie Optionen festgelegt. Diese Variablen werden als Variablen »auf Modulebene« oder »private« Variablen bezeichnet. Im Abschnitt ALLGEMEINE DEKLARATIONEN eines Moduls können Sie auch öffentliche Variablen deklarieren, die von allen Funktionen und Prozeduren in allen Modulen der Datenbank gesehen und modifiziert werden können.
256
Kapitel 7: VBA: Eine Einführung
Abbildung 7.2: Im Abschnitt Allgemeine Deklarationen eines Moduls werden private und öffentliche Variablen deklariert
Die öffentlichen Variablen von Access 2000 ersetzen die globalen Variablen von Access 2.0. Globale Variablen werden in Access 2000 zwar noch unterstützt, aber es gibt feine Unterschiede zwischen öffentlichen und globalen Variablen; diese werden später noch behandelt. Ein Modul besteht ebenfalls aus benutzerdefinierten Unterroutinen und Funktionen. Abbildung 7.3 zeigt eine Unterroutine mit dem Namen SayHello. Beachten Sie das aufklappbare Listenfeld im linken oberen Teil des Fensters mit dem Titel CHAP7EX – MODUL (CODE), das als Objektliste bezeichnet wird. Unterroutinen und Funktionen sind manchmal mit einem bestimmten Objekt wie zum Beispiel einem Formular oder einem Steuerelement innerhalb eines Formulars verknüpft und dort wird diese Verknüpfung angezeigt. Hier ist unsere Unterroutine SayHello nicht mit einem Objekt verknüpft, weshalb die Objektliste den Eintrag (ALLGEMEIN) ENTHÄLT. Access 2000 besitzt eine Umgebungsoption mit dem Namen VOLLSTÄNDIGE MODULANSICHT, mit deren Hilfe Sie mehrere Unterroutinen und Funktionen eines Moduls gleichzeitig sehen können. Beachten Sie den Unterschied zwischen den Abbildungen 7.3 und 7.4! Im Code-Fenster in Abbildung 7.3 ist jeweils nur eine Unterroutine sichtbar, im Code-Fenster in Abbildung 7.4 sehen Sie dagegen die Auswirkungen der vollständigen Modulansicht – mehrere Unterroutinen sind sichtbar, jeweils durch eine feine horizontale Linie getrennt. In Access 2000 ist die volle Modulansicht standardmäßig eingestellt. Um diese Einstellung zu ändern, wählen Sie im VBE EXTRAS|OPTIONEN, klicken auf die Registerkarte EDITOR und aktivieren den Eintrag STANDARDGEMÄSS GANZES MODUL ANZEIGEN. Wenn Sie vorübergehend in die Prozeduransicht wechseln wollen, klicken Sie auf die Schaltfläche PROZEDURANSICHT in der linken unteren Ecke des Modulfensters; über die Schaltfläche VOLLSTÄNDIGE MODULANSICHT kehren Sie anschließend in die volle Modulansicht zurück.
Was sind die Module von Access?
257
Abbildung 7.3: Ein Beispiel für eine benutzerdefinierte Unterroutine mit dem Namen SayHello
Abbildung 7.4: In der vollständigen Modulansicht können Sie mehrere Prozeduren gleichzeitig sehen
7.2.3
Option Explicit
Option Explicit ist eine Anweisung, die in den Abschnitt ALLGEMEINE DEKLARATIO-
jedes Moduls aufgenommen werden kann, auch in das Klassenmodul eines Formulars oder Berichts. Wenn diese Anweisung eingesetzt wird, müssen alle Variablen innerhalb des Moduls vor der Verwendung deklariert werden, sonst kommt es beim Kompilieren des Moduls zu einer Fehlermeldung, die besagt, dass eine Variable nicht definiert wurde. Wenn der Compiler ohne Option Explicit auf eine nicht deklarierte Variable trifft, behandelt VBA diese einfach als neue Variable und fährt ohne Warnung fort. Auf den ersten Blick scheint es vielleicht besser zu sein, auf die Anweisung Option Explicit zu verzichten, weil sie Compiler-Fehler auslöst, die sonst nicht auftreten würden; richtig ist jedoch das genaue Gegenteil. Sie sollten diese Anweisung in ausnahmslos jedem Modul verwenden. Sehen Sie sich beispielsweise folgenden Code an: NEN
258
Kapitel 7: VBA: Eine Einführung
intAmount = 2 intTotal = intAmont * 2
Das Ziel dieses Codes ist natürlich die Multiplikation des Wertes der Variablen intAmount, in diesem Fall 2, mit 2. Beachten Sie jedoch, dass der Variablenname in der zweiten Zeile falsch geschrieben ist. Wenn Option Explicit nicht aktiv ist, sieht VBA intAmont als neue Variable an und fährt einfach mit der Verarbeitung fort. Die Variable intTotal wird auf 0 anstatt auf 4 gesetzt und es gibt keinen einzigen Hinweis auf den Fehler. Ergebnisse dieser Art lassen sich durch die Verwendung von Option Explicit völlig vermeiden. In Access 2.0 mussten Sie die Anweisung Option Explicit in jedes Modul, jedes Formular und jeden Bericht von Hand einfügen. Seit Access 97 haben Entwickler die Möglichkeit, Access global anzuweisen, die Anweisung Option Explicit in alle neuen Module aufzunehmen. In Access 2000 wählen Sie dazu im VBE EXTRAS|OPTIONEN und klicken auf der Registerkarte EDITOR auf VARIABLENDEKLARATION ERFORDERLICH. Es ist wichtig, die Anweisung Option Explicit in alle Module zu integrieren; deshalb sollten Sie darauf achten, dass diese Option auf True gesetzt ist. Die Standardeinstellung bei der Installation von Microsoft Access 2000 ist False! Option Explicit erspart Ihnen stundenlange Fehlersuche und verhindert, dass »Ihr Pieper losgeht«, nachdem Ihre Anwendung an die Benutzer verteilt wurde. Außer dem Abschnitt ALLGEMEINE DEKLARATIONEN und benutzerdefinierten Prozeduren, Formularen und Berichten enthalten Klassenmodule noch Ereignisprozeduren, die mit einem bestimmten Objekt in einem Formular verknüpft sind. Beachten Sie in Abbildung 7.5, dass die aufklappbare Objektliste den Eintrag cmdHello anzeigt, also den Namen des Objekts, dessen Ereignisroutinen Sie gerade betrachten. Das aufklappbare Listenfeld auf der rechten Seite zeigt alle Ereignisse, die man für eine Befehlsschaltfläche programmieren kann; jedes davon erstellt eine eigene Ereignisroutine. Beim Durchlesen dieses Buches bieten sich viele Gelegenheiten dazu.
7.2.4
Ereignisprozeduren erstellen
Ereignisprozeduren werden automatisch erstellt, wenn Sie Ereignis-Code für ein Objekt schreiben. Die Routine Private Sub cmdHello_Click wird beispielsweise erstellt, wenn Sie Code in den Abschnitt für das in Abbildung 7.5 gezeigte ClickEreignis der Schaltfläche cmdHello einfügen. Um zum Ereignis-Code für ein Objekt zu gelangen, unternehmen Sie Folgendes: 1. Klicken Sie in der Entwurfsansicht auf das Objekt und dann auf die Schaltfläche EIGENSCHAFTEN in der Symbolleiste oder klicken Sie mit der rechten Maustaste auf das Objekt und wählen Sie im Kontextmenü EIGENSCHAFTEN. 2. Klicken Sie auf die Registerkarte EREIGNIS.
259
Was sind die Module von Access?
Abbildung 7.5: Eine Ereignisprozedur für das Click-Ereignis der Befehlsschaltfläche cmdHello
3. Wählen Sie das Ereignis aus, für das Sie Code schreiben wollen (z.B. das Ereignis BEIM KLICKEN). 4. Wählen Sie im aufklappbaren Listenfeld den Eintrag [EREIGNISPROZEDUR] aus. 5. Klicken Sie auf die Schaltfläche mit den drei Punkten, die Sie im Visual Basic Editor (VBE) in den Ereignis-Code für dieses Objekt bringt. Wie am Anfang des Kapitels gesagt wurde, wird der Visual Basic Editor (VBE) in einem eigenen Fenster geöffnet. Er bietet eine mit allen anderen Microsoft-OfficeAnwendungen konsistente Programmierumgebung. Im VBE hinzugefügte Module erscheinen erst im Datenbank-Container, wenn sie im VBE gespeichert wurden.
7.2.5
Funktionen und Unterroutinen erstellen
Sie können auch eigene Prozeduren schreiben, die nicht an ein bestimmtes Objekt oder Ereignis gebunden sind und je nach Art und Ort der Deklaration von einer beliebigen Stelle in Ihrer Anwendung oder von einem bestimmten Code-, Formularoder Berichtsmodul aus aufgerufen werden können. In einem Code-Modul eine benutzerdefinierte Routine erstellen 1. Klicken Sie in der Objektliste im Datenbankfenster auf MODULE. 2. Klicken Sie auf NEU, um ein neues Modul zu erstellen, oder wählen Sie ein vorhandenes Modul aus und klicken Sie auf ENTWURF, um den VBE aufzurufen. 3. Wählen Sie im Aufklappmenü MODUL EINFÜGEN in der Symbolleiste (zweites Symbol von links) oder im Menü EINFÜGEN den Punkt PROZEDUR. Es erscheint das Dialogfeld PROZEDUR HINZUFÜGEN (siehe Abbildung 7.6).
260
Kapitel 7: VBA: Eine Einführung
4. Geben Sie den Namen der Prozedur ein. 5. Wählen Sie als Prozedurtyp Sub, Function oder Property. 6. Um die Prozedur für die gesamte Anwendung verfügbar zu machen, wählen Sie als Gültigkeitsbereich Public; um sie für dieses Modul »privat« zu deklarieren, wählen Sie Private. 7. Geben Sie zum Schluss an, ob alle Variablen der Prozedur statisch sein sollen. (Statische Variablen werden in diesem Kapitel unter »Gültigkeitsbereich und Lebensdauer von Variablen: Variablen mit möglichst geringer Sichtbarkeit wählen« behandelt.) Klicken Sie danach auf OK.
Abbildung 7.6: Im Dialogfeld Prozedur hinzufügen geben Sie Namen, Typ und Gültigkeitsbereich der zu erstellenden Prozedur an
In einem Formular- oder Berichtsklassenmodul eine benutzerdefinierte Routine erstellen 1. Wählen Sie in der Entwurfsansicht eines Formulars oder Berichts im Menü den Eintrag ANSICHT. Beachten Sie das Symbol neben dem Menüpunkt CODE. Dasselbe Symbol finden Sie auch in der Symbolleiste. Sie können den hinter einem Formular oder Bericht liegenden Code einsehen, indem Sie auf das Symbol in der Symbolleiste oder im Menü ANSICHT auf CODE klicken. In beiden Fällen gelangen Sie in den VBE. 2. Wählen Sie im Aufklappmenü MODUL EINFÜGEN in der Symbolleiste (zweites Symbol von links) oder im Menü EINFÜGEN den Punkt PROZEDUR, um das Dialogfeld PROZEDUR HINZUFÜGEN zu öffnen. 3. Geben Sie den Namen der Prozedur ein. 4. Wählen Sie als Prozedurtyp Sub, Function oder Property. 5. Um die Prozedur für die gesamte Anwendung verfügbar zu machen, wählen Sie als Gültigkeitsbereich Public, um sie für dieses Modul »privat« zu deklarieren, Private.
Was sind die Module von Access?
261
6. Geben Sie zum Schluss an, ob alle Variablen der Prozedur statisch sein sollen. (Statische Variablen werden in diesem Kapitel unter »Gültigkeitsbereich und Lebensdauer von Variablen: Variablen mit möglichst geringer Sichtbarkeit wählen« behandelt.) Klicken Sie auf OK, wenn Sie fertig sind. Unabhängig davon, ob Sie eine Prozedur in einem Standard- oder in einem Klassenmodul erstellen, können Sie jetzt den Code für die Prozedur eingeben. Eine hervorragende Abkürzung ist dabei die direkte Eingabe des Namens der neuen Prozedur im Code-Fenster mit vorangestellter Bezeichnung als Unterroutine oder Funktion. Ein Beispiel: Sub Whatever oder Function Whatever. Damit wird eine neue Unterroutine oder Funktion erstellt, sobald Sie (¢) drücken.
7.2.6
Ereignis- und benutzerdefinierte Prozeduren aufrufen
Ereignisprozeduren werden automatisch aufgerufen, wenn ein Ereignis für ein Objekt eintritt. So wird der Code für das Click-Ereignis für eine bestimmte Befehlsschaltfläche ausgeführt, wenn ein Benutzer auf diese Schaltfläche klickt. Die übliche Methode, benutzerdefinierte Prozeduren aufzurufen, ist die Verwendung des Schlüsselworts Call – z.B. Call SayHello. Dieselbe Prozedur lässt sich aber auch ohne die Verwendung des Schlüsselworts aufrufen: SayHello. Die Verwendung des Schlüsselworts Call ist zwar nicht unbedingt erforderlich, macht die Anweisung aber selbstdokumentierend und leichter lesbar. Eine benutzerdefinierte Prozedur lässt sich aus einer Ereignisroutine oder aus einer anderen benutzerdefinierten Routine oder Funktion aufrufen.
7.2.7
Gültigkeitsbereich und Lebensdauer von Prozeduren
Der Gültigkeitsbereich einer Prozedur kann öffentlich oder privat sein. Er legt fest, wie weit sie von anderen Prozeduren aufgerufen werden kann. Außer dem Gültigkeitsbereich kann auch die Positionierung einer Prozedur Funktionalität und Leistung Ihrer Anwendung merklich beeinflussen. Ein weiteres Attribut von Prozeduren betrifft die Lebensdauer der in ihr deklarierten Variablen. Standardmäßig besitzen die in einer Prozedur deklarierten Variablen eine Lebensdauer, d.h. sie haben nur solange einen Wert und eine Bedeutung, wie die Prozedur ausgeführt wird. Wenn die Ausführung abgeschlossen ist, werden die von ihr deklarierten Variablen aus dem Speicher entfernt. Diese Standardlebensdauer kann durch die Verwendung des Schlüsselwortes Static geändert werden.
262
Kapitel 7: VBA: Eine Einführung
Öffentliche Prozeduren Eine öffentliche Prozedur innerhalb eines Code-Moduls lässt sich von jeder Stelle innerhalb der Anwendung aufrufen. In einem Modul deklarierte Prozeduren sind automatisch öffentliche Prozeduren, d.h. Prozeduren, die Sie in ein Code-Modul einfügen, lassen sich von jeder Stelle innerhalb der Anwendung aufrufen, falls Sie nichts Gegenteiliges angeben. Möglicherweise meinen Sie, dass zwei öffentliche Prozeduren nicht denselben Namen tragen können. Dies gilt zwar für frühere Access-Versionen, aber nicht mehr für Access 2000. Wenn zwei öffentliche Prozeduren den Namen gemeinsam haben, muss die aufrufende Prozedur explizit angeben, welche Prozedur gemeint ist. Das wird in folgendem Code-Abschnitt aus dem Klassenmodul von frmHello in der Beispieldatenbank Chap7ex.mdb deutlich: Private Sub cmdSayGoodBye_Click() Call basUtils.SayGoodBye End Sub
Dieser und der gesamte Beispiel-Code dieses Kapitels steht in der Datei Chap7ex.mdb auf der CD mit dem Beispiel-Code. Die Routine SayGoodBye kommt in zwei Access-Code-Modulen vor. Das Präfix basUtils gibt jedoch an, dass sich die auszuführende Routine im Standardmodul mit dem Namen basUtils befindet. In Formular- oder Berichtsklassenmodulen deklarierte Prozeduren sind ebenfalls automatisch öffentlich und lassen sich daher von jeder Stelle innerhalb der Anwendung aufrufen. Die Prozedur cbfIAmPublic (siehe Abbildung 7.7) steht im Formular frmHello, kann aber trotzdem von jeder Stelle innerhalb der Anwendung aufgerufen werden. Die einzige Voraussetzung besteht darin, dass das Formular mit der Prozedur in der Formularansicht geöffnet ist. Die Prozedur cbfIAmPublic kann mit folgender Syntax (die Sie im Standardmodul basHello finden) von jeder Stelle innerhalb der Anwendung aufgerufen werden: Sub CallPublicFormProc() Call Forms.frmHello.cbfIAmPublic End Sub
Obwohl alle Prozeduren (bis auf Ereignisprozeduren) standardmäßig öffentlich sind, sollte das Schlüsselwort Public verwendet werden, um darauf hinzuweisen, dass die Prozedur für alle Unterroutinen und Funktionen in der Datenbank sichtbar ist.
Was sind die Module von Access?
263
Abbildung 7.7: Eine öffentliche Prozedur eines Formulars ist für alle Unterroutinen und Funktionen in der Datenbank sichtbar
Private Prozeduren Wie bereits erwähnt, sind alle benutzerdefinierten Prozeduren automatisch öffentlich. Wenn eine in einem Modul deklarierte Prozedur nur innerhalb des Moduls gültig sein soll, d.h., dass sie nur von Routinen in diesem Modul aufgerufen werden kann, müssen Sie sie explizit als privat deklarieren (siehe Abbildung 7.8).
Abbildung 7.8: Diese private Prozedur ist nur für Unterroutinen und Funktionen im Modul basUtils sichtbar
Die in Abbildung 7.8 gezeigte Prozedur IAmPrivate befindet sich im Standardmodul basUtils. Da sie privat ist, kann sie nur von anderen Routinen in diesem Modul aufgerufen werden. Vorrang des Gültigkeitsbereichs Private Prozeduren haben grundsätzlich Vorrang vor öffentlichen. Wenn eine private Prozedur denselben Namen trägt wie eine öffentliche, wird die private Prozedur ausgeführt, sofern sie von einer Routine in dem Modul aufgerufen wird, in dem sie deklariert wurde. Namenskonflikte zwischen privaten und öffentlichen Prozeduren treten daher nicht auf.
264
Kapitel 7: VBA: Eine Einführung
Entwickler fragen sich oft, wo sie Code unterbringen sollen: in Formular- oder Berichtsklassenmodulen oder in Standardmodulen. Beide Methoden haben Vorund Nachteile. Die Platzierung von Code in Standardmodulen bedeutet, dass sich der Code mühelos von jeder Stelle in der Anwendung aufrufen lässt, ohne dass ein bestimmtes Formular oder ein bestimmter Bericht geladen sein muss. Öffentliche Routinen in Standardmodulen lassen sich auch aus anderen Datenbanken aufrufen. Deshalb eignen sich Standardmodule hervorragend für allgemeine Routinen, die als Teil einer Bibliothek zur Verfügung stehen sollen. Access 2000 lädt Module nur bei Bedarf, was bedeutet, dass Prozeduren nur Platz im Arbeitsspeicher belegen, solange sie verwendet werden. Dies gilt insbesondere, wenn Sie Ihre Module sorgfältig planen (siehe Kapitel 15). Unabhängig davon, wann der Code geladen wird, besteht ein Vorteil der Platzierung von Code hinter Formularen oder Berichten (statt in Modulen) darin, dass das Formular bzw. der Bericht abgeschlossen und deshalb portierbar ist. Sie können das Formular bzw. den Bericht in eine beliebige andere Datenbank importieren und es/er funktioniert immer noch erwartungsgemäß. Dieser objektorientierte Ansatz bedeutet, dass das Formular nichts aus der Außenwelt voraussetzt. Wie Sie sehen können, hat jede der beiden Methoden Vor- und Nachteile. Als allgemeine Regel sollten Sie eine für ein bestimmtes Formular oder einen Bericht spezifische Routine im Formular bzw. Bericht unterbringen, eine weitläufig benutzte Routine jedoch in einem Modul. Statische Prozeduren Wenn eine Prozedur als statisch deklariert wurde, behalten alle in ihr deklarierten Variablen zwischen den einzelnen Aufrufen der Prozedur ihren Wert. Dies stellt eine Alternative zur expliziten Deklaration der einzelnen Variablen als statisch dar. Es folgt ein Beispiel für eine statische Prozedur, das Sie im Modul basVariable finden: Static Sub IncrementThem() Dim intCounter1 As Integer Dim intCounter2 As Integer Dim intCounter3 As Integer intCounter1 = intCounter1 + 1 intCounter2 = intCounter2 + 1 intCounter3 = intCounter3 + 1 MsgBox intCounter1 & " – " & intCounter2 & " – " & intCounter3 End Sub
Normalerweise würde jede Variable in dieser Prozedur bei jedem Start der Prozedur wieder mit 0 initialisiert, d.h., im Meldungsfeld erscheinen nur Einsen, wenn die Prozedur ausgeführt wird. Da die Prozedur aber als statisch deklariert wurde, behalten die Variablen von einem Aufruf zum anderen ihren Wert, d.h., die Werte im Meldungsfeld werden bei jeder Ausführung höher. Dieses Verhalten sollte Ihnen nach der Behandlung der Variablen weiter hinten in diesem Kapitel erheblich klarer werden.
Mit Variablen arbeiten
7.3
265
Mit Variablen arbeiten
Beim Anlegen von VBA-Variablen ist vieles zu bedenken. Die Art, wie Sie eine Variable deklarieren, legt ihren Gültigkeitsbereich, ihre Lebensdauer und noch anderes fest. Die folgenden Punkte werden dazu beitragen, dass Sie die Deklaration von Variablen in VBA besser verstehen.
7.3.1
Variablen deklarieren
Es gibt in VBA verschiedene Methoden, Variablen zu deklarieren: eine standardmäßige und drei weitere. Sie können beispielsweise einfach x=10 deklarieren. Auf diese Art deklarieren Sie die Variablen eigentlich überhaupt nicht, sondern sie werden im Grunde bei der Verwendung deklariert. Diese Methode ist recht gefährlich, da anfällig für Tippfehler und andere Probleme. Wenn Sie sich an die weiter vorn empfohlene Vorgehensweise halten, grundsätzlich die Anweisung Option Explicit zu verwenden, lässt Access die Deklaration von Variablen in dieser Art nicht zu. Sie können genauso gut Dim intCounter eingeben: Die Dim-Anweisung deklariert die Variable. Bei dieser Methode besteht das einzige Problem darin, dass Sie dem Compiler gegenüber den Typ der Variablen nicht deklariert haben und es sich daher um eine Variable des Typs Variant handelt. Ein anderer häufig vorkommender Fehler ist die Deklaration mehrerer Variablen in einer Zeile wie in folgendem Beispiel: Dim intCounter, intAge, intWeight As Integer
In dieser Zeile wird nur die letzte Variable explizit als Variable des Typs Integer deklariert, die anderen jedoch implizit als Variablen des Typs Variant. Wenn Sie vorhaben, mehrere Variablen in einer Zeile zu deklarieren, müssen Sie sicherstellen, dass jede einzeln deklariert wird, wie es im folgenden Beispiel zu sehen ist: Dim intCounter As Integer, intAge As Integer, intWeight As Integer
Die effizienteste und sicherste Methode der Variablendeklaration ist die eindeutige Zuweisung von Typen gegenüber dem Compiler und die Deklaration jeder Variablen in einer eigenen Code-Zeile: Dim intCounter As Integer Dim strName As String
Wie Sie sehen können, werden bei eindeutiger Typzuweisung sowohl der Name der Variablen als auch der Typ der Daten deklariert, welche sie enthalten kann. Das ermöglicht dem Compiler, Fehler wie z.B. das Ablegen einer Zeichenfolge in einer Variablen des Typs Integer abzufangen, bevor das Programm ausgeführt wird. Bei korrekter Implementierung kann diese Methode außerdem die für die Ausführung des Programms benötigten Ressourcen reduzieren, indem es für jede Variable den kleinstmöglichen Datentyp auswählt.
266
Kapitel 7: VBA: Eine Einführung
Variablen des Typs Variant sollten Sie nach Möglichkeit meiden. Sie erfordern nicht nur eine beträchtliche Menge Speicherplatz, sondern sind außerdem langsam, weil sie vom Compiler zur Laufzeit aufgelöst werden müssen. Bestimmte Situationen erfordern jedoch Variant-Variablen. Ein Beispiel dafür ist der Wunsch, dass die Variable zu verschiedenen Zeiten verschiedene Arten von Daten aufnehmen soll, ein anderer Fall der Wunsch, zwischen einer leeren Variablen (einer noch nicht initialisierten) und einer Variablen mit einem Nullwert oder einer Zeichenfolge der Länge null unterscheiden zu können. Darüber hinaus sind Variant-Variablen die einzigen, die den Sonderwert Null enthalten können. Leere Variablen und Null-Werte werden in Kapitel 24 behandelt.
7.3.2
VBA-Datentypen
VBA stellt eine Reihe von Datentypen für Variablen bereit. Tabelle 7.1 enthält eine Liste der verfügbaren Typen, die jeweilige Namenskonvention, die erforderliche Speicherplatzmenge, die Art der aufzunehmenden Daten und die Standardwerte. Datentyp
Beispiel für NamensKonvention
Speicherplatz
Speicherbereich
Standardwert
Byte
bytValue
1 Byte
0 bis 255
0
Boolean
boolAnswer
2 Bytes
True oder False
False
Integer
intCounter
2 Bytes
-32768 bis 32767
0
Long Integer
lngAmount
4 Bytes
-2,147 483 648 bis 2,147 483647
0
Single
sngAmount
4 Bytes
-3.402823E38 bis -1.401298E-45 für negative Werte; 1.401298E-45 bis 3.402823E38 für positive Werte
0
Double
dblValue
8 Bytes
0 1.79769313486231E308 bis 4.94065645841247E-324 für negative Werte; 4.94065645841247E-324 bis 1.79769313486231E308 für positive Werte
Tabelle 7.1: Datentypen und Namenskonventionen
267
Mit Variablen arbeiten
Datentyp
Beispiel für NamensKonvention
Speicherplatz
Speicherbereich
Standardwert
Currency
curSalary
8 Bytes
-922 337 203 685 477.5808 bis 922 337 203 685 477.5807
0
Date
dtmStartDate
8 Bytes
1/1/10 bis 12/31/9999
4 Bytes
beliebiges Objekt
Object Reference objExcel Fixed String
strName
verschieden bis zu 65.526 Zeichen
""
Variable String
strName
verschieden bis ca. 2 Mrd. Zeichen
""
Variant
varData
verschieden Kann alle anderen Datentypen außer Fixed String enthalten
leer
Benutzer-definierter Datentyp
typEmp
verschieden Basiert auf Elementen
Decimal
decTaxAmount
12 Bytes
+/-79 228 162 514 264 337 0 593 543 950 335 ohne Dezimalstellen +/7.922816251426433759354 3950335 mit 28 Dezimalstellen
Tabelle 7.1: Datentypen und Namenskonventionen (Forts.)
7.3.3
Gültigkeitsbereich und Lebensdauer von Variablen: Variablen mit möglichst geringer Sichtbarkeit wählen
Sie haben bereits von den verschiedenen Variablentypen in VBA gehört. Wie Prozeduren besitzen auch Variablen einen Gültigkeitsbereich. Eine Variable kann als lokal, privat (für das Modul) oder öffentlich deklariert werden. Sie sollten versuchen, in Ihrem Code lokale Variablen zu verwenden, weil diese gegen die versehentliche Änderung durch andere Routinen abgeschirmt sind. Variablen besitzen außerdem ein Attribut, das als Lebensdauer bezeichnet wird und häufig die Zeit angibt, während der die Variable tatsächlich existiert, d.h. die Zeitspanne, für die ihr Wert erhalten bleibt. In den folgenden Abschnitten werfen wir einen genaueren Blick darauf, wie Gültigkeitsbereich und Lebensdauer von Variablen festgelegt werden.
268
Kapitel 7: VBA: Eine Einführung
Lokale Variablen Lokale Variablen stehen nur in der Prozedur zur Verfügung, in der sie deklariert wurden. Sehen Sie sich folgendes (nicht in der Datenbank Chap7ex enthaltene) Beispiel an: Private Sub cmdOkay_Click Dim strAnimal As String StrAnimal = "Dog" Call ChangeAnimal Debug.Print strAnimal End Sub
'immer noch Hund
Private Sub ChangeAnimal StrAnimal = "Cat" End Sub
Dieser Code kann sich auf dreierlei Weise verhalten. Wenn Option Explicit wirksam wäre, was bedeutet, dass alle Variablen vor der Verwendung deklariert werden müssten, würde dieser Code zu einem Compiler-Fehler führen. Wenn die Anweisung Option Explicit nicht verwendet würde, würde die Variable strAnimal nur im Kontext der Unterroutine ChangeAnimal in Cat geändert. Wenn die Anweisung Dim strAnimal As String in den Abschnitt DEKLARATIONEN des Moduls verschoben wird, ändert sich der Wert der Variablen in "Cat". Beachten Sie in der oben abgedruckten Ereignisroutine cmdOkayClick die Anweisung Debug.Print. Der Ausdruck, der auf die Anweisung folgt, wird im Direktfenster angezeigt. Dieses Werkzeug hilft Ihnen bei der Fehlerbehebung in Ihren Anwendungen und lässt sich von fast allen Stellen in Ihrer Anwendung aus aufrufen, und zwar am einfachsten mit der Tastenkombination (Strg)(G), mit der Sie in den VBE im Direktfenster gelangen und sich die dort ausgegebenen Ausdrücke ansehen können. Das Direktfenster wird in Kapitel 13 ausführlich erläutert. Statische Variablen: Ein Spezialtyp lokaler Variablen Die folgenden Beispiele veranschaulichen den Unterschied zwischen lokalen und statischen Variablen. Lokale Variablen werden jedesmal neu initialisiert, wenn der Code aufgerufen wird. Die folgende Prozedur lässt sich ausführen, indem Sie das Formular frmScopeAndLifeTime öffnen und auf die Schaltfläche LOCAL AGE klicken. Beachten Sie, dass bei jedem Ausführen der Prozedur im Textfeld txtNewAge die Zahl 1 erscheint. Private Sub cmdLocalAge_Click() Dim intAge As Integer intAge = intAge + 1 Me.txtNewAge = intAge End Sub
Mit Variablen arbeiten
269
Immer wenn dieser Code ausgeführt wird, initialisiert die Dim-Anweisung die Variable intAge mit Null. Das ist ganz anders bei folgendem Code, der die Verwendung einer statischen Variablen veranschaulicht: Private Sub cmdStaticAge_Click() Static sintAge As Integer sintAge = sintAge + 1 Me.txtNewAge = sintAge End Sub
Immer wenn dieser Code ausgeführt wird, wird die Variable sintAge erhöht und dieser Wert bleibt erhalten. Das lässt sich überprüfen, indem Sie das Formular frmScopeAndLifeTime öffnen und auf die Schaltfläche STATIC AGE klicken. Private Variablen Bis jetzt beschränkte sich die Darstellung auf Variablen, die nur innerhalb einer einzigen Prozedur gültig sind. Private Variablen (auf Modulebene) sind für alle Routinen innerhalb des Moduls sichtbar, in dem sie deklariert wurden, nicht jedoch für andere Module. Insofern sind sie für das Modul privat. Sie werden mit Hilfe einer PrivateAnweisung wie der folgenden im Abschnitt ALLGEMEINE DEKLARATIONEN eines Formulars, Berichts oder Access-Moduls deklariert: [Allgemeine Deklarationen] Option Explicit Private mintAge As Integer
Der Wert einer als privat deklarierten Variablen kann von jeder Unterroutine oder Funktion innerhalb des Moduls geändert werden. Die folgende Unterroutine erhöht beispielsweise den Wert der privaten Variablen mintAge um 1. Der Code lässt sich durch Öffnen des Formulars frmScopeAndLifeTime und einen Klick auf die Schaltfläche MODULE AGE ausführen. Private Sub cmdModuleAge_Click() mintAge = mintAge + 1 Me.txtNewAge = mintAge End Sub
Beachten Sie die Namenskonvention, dem Namen der Variablen den Buchstaben m als Präfix voranzustellen, um sie als privat auf Modulebene zu kennzeichnen. Sie sollten Privatdeklarationen nur für Variablen verwenden, die für mehrere Prozeduren desselben Moduls sichtbar sein müssen, und sich zum Ziel setzen, nach Möglichkeit mit lokalen Variablen zu arbeiten, um den Code modular und »kugelsicher« zu gestalten.
270
Kapitel 7: VBA: Eine Einführung
Öffentliche Variablen Auf öffentliche Variablen kann der gesamte VBA-Code Ihrer Anwendung zugreifen. Sie sind normalerweise auf Anmelde-IDs, Umgebungseinstellungen und ähnliche Variablen beschränkt, die für die gesamte Anwendung sichtbar sein müssen. Die Deklaration öffentlicher Variablen kann im Abschnitt ALLGEMEINE DEKLARATIONEN eines Moduls erfolgen und sieht folgendermaßen aus: Option Explicit Public gintAge As Integer
Beachten Sie das Präfix g (ein Relikt der alten globalen Variablen), das richtige Präfix für eine in einem Standardmodul deklarierte öffentliche Variable. Dieser Standard wird verwendet, weil solche Variablen nicht nur für das Modul sichtbar sind, in dem sie deklariert wurden, sondern auch für andere Module. Der folgende Code, der zum Click-Ereignis der Befehlsschaltfläche cmdPublic gehört, setzt die öffentliche Variable gintCounter um 1 herauf. Er lässt sich ausführen, wenn Sie das Formular frmScopeAndLifeTime öffnen und auf die Schaltfläche PUBLIC AGE klicken. Private Sub cmdPublicAge_Click() gintAge = gintAge + 1 Me.txtNewAge = gintAge End Sub
7.4
Kommentare in den Code einfügen
Kommentare, die seit Access 97 farblich gekennzeichnet werden, werden unter Verwendung eines Apostrophs in Module eingefügt. Außerdem kann man das Schlüsselwort Rem verwenden, aber im Allgemeinen wird das Apostroph bevorzugt. Dieses Zeichen lässt sich an den Anfang der Code-Zeile oder an eine beliebige Stelle innerhalb der Zeile setzen. Alles, was darauf folgt, wird als Kommentar angesehen. In Abbildung 7.9 sehen Sie Code mit Kommentaren.
Abbildung 7.9: Code mit Kommentaren, die verdeutlichen, was die Unterroutine macht
Das Zeichen für die Fortsetzung der Zeile
7.5
271
Das Zeichen für die Fortsetzung der Zeile
Access-Basic-Code, wie er in Access 2.0 verwendet wurde, besaß kein Zeichen für die Fortsetzung der Zeile. Deshalb mussten Sie viel mit dem Bildlauf arbeiten und eine Menge Tricks auf Lager haben, um eine fortlaufende Code-Zeile zu simulieren. Mit VBA lösen Access 97 und 2000 das Problem: Das Zeichen für die Fortsetzung der Zeile ist der Unterstrich. Abbildung 7.10 veranschaulicht seine Verwendung.
Abbildung 7.10: Das Zeichen für die Fortsetzung der Zeile wird verwendet, um die Lesbarkeit einer langen Code-Zeile zu verbessern
7.6
Die VBA-Steuerstrukturen
VBA gibt dem Entwickler verschiedene Konstrukte für Schleifen und Entscheidungen an die Hand. Die gebräuchlichsten werden in den folgenden Abschnitten vorgestellt und sind im Formular frmControlStructures zu finden.
7.6.1
If...Then...Else
Das Konstrukt If...Then...Else wertet aus, ob eine Bedingung zutrifft. Im folgenden Beispiel geschieht alles zwischen If und Else, falls die Anweisung als True ausgewertet wird, der Code zwischen Else und End If wird dagegen ausgeführt, wenn sie False ergibt. Der Else-Teil ist optional. Private Sub cmdIfThenElse_Click() If IsNull(Me.txtName) Or IsNull(Me.txtAge) Then MsgBox "Name or Age Is Blank" Else MsgBox "Your Name Is " & Me.txtName _ & "And Your Age Is " & Me.txtAge End If End Sub
272
Kapitel 7: VBA: Eine Einführung
Der Code prüft, ob das Textfeld txtName oder das Textfeld txtAge den Wert Null enthält. Je nach Ergebnis werden unterschiedliche Meldungen ausgegeben. Auch einzeilige If-Anweisungen folgender Art sind zulässig: If IsNull(Me.txtValue) Then MsgBox "You Must Enter a Value"
Dieses Format für eine If-Anweisung ist jedoch nicht zu empfehlen, weil es die Lesbarkeit verringert. Eine andere sinnvolle Form einer If-Anweisung ist die Anweisung ElseIf, mit der Sie eine unbegrenzte Anzahl von Bedingungen in einer If-Anweisung auswerten können. Der folgende Code (der in der Datenbank Chap7Ex nicht enthalten ist) liefert ein Beispiel dafür: Sub MultipleIfs(intNumber As Integer) If intNumber = 1 Then MsgBox "You entered a One" ElseIf intNumber = 2 Then MsgBox "You entered a Two" ElseIf intNumber >= 3 And intNumber <= 10 MsgBox "You entered a Number Between 3 And 10" Else MsgBox "You entered Some Other Number" End If End Sub
Die Bedingungen in einer If-Anweisung werden in der Reihenfolge ausgewertet, in der sie erscheinen. Daher ist es am günstigsten, die wahrscheinlichsten Bedingungen an den Anfang zu setzen. Sobald eine Bedingung zutrifft, wird die Ausführung unmittelbar nach dem End If fortgesetzt. Wenn keine der Bedingungen zutrifft und keine Else-Anweisung vorhanden ist, gilt dasselbe. Bei mehreren Bedingungen ist eine Select Case-Anweisung, wie sie weiter hinten in diesem Kapitel beschrieben wird, fast immer vorzuziehen. Case-Anweisungen machen den Code allgemein leichter les- und pflegbar.
7.6.2
Immediate If (IIf)
Immediate If (IIF) ist eine Variante der If-Anweisung, eigentlich sogar eine integrierte Funktion, die einen von zwei Werten zurückgibt, je nachdem, ob die geprüfte Bedingung wahr oder falsch ist. Ein Beispiel (das Sie nicht in Chap7Ex finden): Function EvalSales(curSales As Currency) As String EvalSales = IIf(curSales >= 100000, "Great Job", "Keep Plugging") End Function
Die VBA-Steuerstrukturen
273
Diese Funktion wertet den Parameter curSales daraufhin aus, ob dessen Wert größer oder gleich 100.000 DM ist. Wenn dies zutrifft, gibt sie die Zeichenfolge "Great Job" zurück, sonst die Zeichenfolge "Keep Plugging". Es wird sowohl der Wahr- als auch der Falsch-Teil der IIf-Anweisung ausgewertet. Daher wird, wenn in einem der beiden Teile des Ausdrucks ein Problem auftritt (z.B. eine Division durch Null), ein Fehler gemeldet. Die Funktion IIf wird am häufigsten in einem berechneten Steuerelement eines Formulars oder Berichts oder zum Erstellen eines neuen Feldes in einer Abfrage eingesetzt. Das wahrscheinlich gebräuchlichste Beispiel stellt ein IIf-Ausdruck dar, der bestimmt, ob der Wert eines Steuerelements Null ist. Falls dies zutrifft, kann der Ausdruck auf Wunsch eine Null bzw. eine leere Zeichenfolge zurückgeben und andernfalls den Wert des Steuerelements. Der folgende Ausdruck wertet zum Beispiel den Wert eines Steuerelements in einem Formular aus: =IIf(IsNull(Forms!frmOrders.txtFreight),0,Forms!frmOrders.txtFreight)
Dieser Ausdruck gibt entweder eine Null oder den Frachtwert im Steuerelement txtFreight aus.
Man kann mit der Funktion IIf zwar auch Null-Werte behandeln, aber dafür ist die integrierte Funktion NZ besser geeignet, welche die IIf-eigenen Schwierigkeiten umgeht.
7.6.3
Bedingtes If: Bedingte Kompilierung
Bedingte Kompilierung ermöglicht Ihnen, Code-Teile in Abhängigkeit von bestimmten Kriterien auszuführen. Diese Möglichkeit ist in einigen Situationen sinnvoll: 1. wenn bestimmte Teile Ihres Codes in der Demo-Version Ihres Programms und andere in der Version für den Verkauf ausgeführt werden sollen; 2. wenn Sie Ihre Anwendung in mehreren Ländern vertreiben und bestimmte Code-Abschnitte nur für einige Länder gelten, für andere aber nicht; 3. wenn bestimmte Teile des Codes nur während des Tests der Anwendung ausgeführt werden sollen. Bedingte Kompilierung wird mit der Direktive #If...Then...#Else durchgeführt, die hier gezeigt wird. Sie finden sie unter der Befehlsschaltfläche CONDITIONAL COMPILATION im Formular frmControlStructures: Private Sub cmdConditionalCompilation_Click() #If LANGUAGE = "Spanish" Then MsgBox "Hola, Que Tal?"
274
Kapitel 7: VBA: Eine Einführung
#Else MsgBox "Hello, How Are You" #End If End Sub
Die Compiler-Konstante, hier Language, kann an zwei Stellen deklariert werden: im Abschnitt ALLGEMEINE DEKLARATIONEN eines Moduls oder im Dialogfeld PROJEKTEIGENSCHAFTEN. Eine im Abschnitt ALLGEMEINE DEKLARATIONEN eines Moduls deklarierte Compiler-Konstante sieht folgendermaßen aus: #Const Language = "Spanish"
Der Nachteil dieser Konstanten besteht darin, dass sie sich nicht als öffentliche Konstante deklarieren lassen. Mit der Direktiven #Const kann man keine öffentlichen Compiler-Konstanten deklarieren, d.h. alle im Abschnitt ALLGEMEINE DEKLARATIONEN eines Moduls deklarierten Compiler-Konstanten können nur in diesem Modul verwendet werden. Der wesentliche Vorteil von Compiler-Konstanten dieser Art besteht darin, dass sie eine Zeichenfolge enthalten können. Die im vorigen Abschnitt deklarierte Konstante Language bekommt beispielsweise den Wert "Spanish". Öffentliche Compiler-Konstanten kann man durch Änderung der Projekteigenschaften deklarieren. Da ihr Gültigkeitsbereich öffentlich ist, kann von jeder beliebigen Stelle in der Anwendung auf Compiler-Konstanten verwiesen werden, die in den Projekteigenschaften deklariert wurden. Ihr wesentlicher Nachteil liegt darin, dass sie nur ganze Zahlen enthalten können. Sie müssten dann zum Beispiel Language = 1 eingeben. Um Compiler-Konstanten mit Hilfe des Dialogfeldes PROJEKTEIGENSCHAFTEN zu definieren, klicken Sie mit der rechten Maustaste im Projektfenster und wählen EIGENSCHAFTEN VON PROJEKT aus; dabei ist PROJEKT der Name des Projekts, an dem Sie arbeiten. Dann können Sie die benötigten Werte in das Textfeld mit der Beschriftung ARGUMENTE FÜR BEDINGTE KOMPILIERUNG eingeben. Es dürfen auch mehrere sein, die durch einen Doppelpunkt getrennt werden, zum Beispiel Language = 1 : Version = 2. Mit der Compiler-Direktive Language = 1 sähe der Code folgendermaßen aus: Sub ConditionalIf() #If Language = 1 Then MsgBox "Hola, Que Tal?" #Else MsgBox "Hello, How Are You?" #EndIf End Sub
Damit dieser Code korrekt ausgeführt wird, müssen Sie die Konstantendeklaration aus dem vorigen Beispiel entfernen.
Beachten Sie, dass die Anweisung ConditionalIf jetzt die Konstante Language daraufhin prüft, ob sie die Ganzzahl 1 ergibt.
Die VBA-Steuerstrukturen
275
Es ist wichtig, dass bedingte Konstanten nicht dasselbe sind wie normale Konstanten oder Variablen mit dem Standardkonstrukt If...Then...Else. Normale Konstanten oder Variablen werden zur Laufzeit ausgewertet, was bei jeder Ausführung Verarbeitungszeit erfordert. Bedingte Konstanten und bedingte If...Then...Else-Anweisungen steuern, welche Code-Abschnitte tatsächlich kompiliert werden. Die gesamte Auflösung findet während der Kompilierung statt – damit entfällt unnötige Verarbeitung zur Laufzeit.
7.6.4
Select Case
Anstelle mehrerer If..Then...Else-Anweisungen ist eine Select Case-Anweisung häufig verständlicher, wie Sie hier sehen. Sie finden diesen Code unter der Schaltfläche SELECT CASE des Formulars frmControlStructures. Private Sub cmdCase_Click() Dim intAge As Integer If IsNull(Me.txtAge) Then intAge = 0 Else intAge = Val(Me.txtAge) End If Select Case intAge Case 0 MsgBox "You Must Enter a Number" Case 1 To 18 MsgBox "You Are Just a Kid" Case 19, 20, 21 MsgBox "You Are Almost an Adult" Case 22 To 40 MsgBox "Good Deal" Case Is > 40 MsgBox "Getting Up There!" Case Else MsgBox "You Entered An Invalid Number" End Select End Sub
Diese Unterroutine konvertiert zunächst mit Hilfe der Funktion NZ eine Null oder einen Leerwert im Steuerelement txtAge in 0; jeder andere Wert wird in intAge gespeichert. Dann wertet die Select Case-Anweisung die Variable intAge aus. Wenn der Wert 0 ist, wird ein Meldungsfeld mit dem Text You Must Enter a Number eingeblendet. Wenn der Wert zwischen 1 und 18 (einschließlich) liegt, enthält das Meldungsfeld die Aussage You Are Just a Kid. Bei Eingabe von 19, 20 oder 21 lautet die Meldung You Are Almost an Adult, bei einem Wert zwischen 22 und 40 (inklusive) Good Deal, und bei einem Wert über 40 heißt sie Getting Up There. Bei anderen Werten erhält der Benutzer die Meldung, dass er eine ungültige Zahl eingegeben hat.
276
7.6.5
Kapitel 7: VBA: Eine Einführung
Schleifen
VBA bietet mehrere Schleifenstrukturen, die in diesem Abschnitt fast alle erläutert werden. Sehen Sie sich folgendes Beispiel an (das Sie unter der Befehlsschaltfläche Do While...Loop des Formulars frmControlStructures finden): Sub cmdDoWhileLoop_Click() Do While Nz(Me!txtAge)< 35 Me.txtAge = Nz(Me!txtAge) + 1 Loop End Sub
In dieser Struktur wird der Code innerhalb der Schleife nicht ausgeführt, wenn der Wert in txtAge größer oder gleich 35 ist. Wenn der Code wenigstens einmal bedingungslos ausgeführt werden soll, müssen Sie folgendes Konstrukt verwenden (das Sie unter der Befehlsschaltfläche Do...Loop While des Formulars frmControlStructures finden): Sub cmdDoLoopWhile_Click() Do Me.txtAge = Nz(Me!txtAge) + 1 Loop While Nz(Me!txtAge) < 35 End Sub
Dieser Code wird einmal ausgeführt, auch wenn txtAge auf 35 gesetzt wurde. Die Do While...Loop-Schleife im vorigen Beispiel wird ausgewertet, bevor der Code ausgeführt wird, und garantiert daher die Ausführung nicht. Die Do...Loop While-Schleife wird erst am Schleifenende ausgewertet und garantiert daher die Ausführung. Alternativen zu Do While...Loop und Do...Loop While stellen die Konstrukte Do Until...Loop und Do...Loop Until dar. Do Until...Loop (zu finden unter der gleichnamigen Befehlsschaltfläche im Formular frmControlStructures) funktioniert folgendermaßen: Sub cmdDoUntil_Click() Do Until Nz(Me!txtAge) = 35 Me.txtAge = Nz(Me!txtAge) + 1 Loop End Sub
Diese Schleife wird solange ausgeführt, bis txtAge den Wert 35 erreicht. Das Konstrukt Do...Loop Until (zu finden unter der gleichnamigen Befehlsschaltfläche im Formular frmControlStructures) stellt eine weitere Variante dar:
Die VBA-Steuerstrukturen
277
Sub cmdLoopUntil_Click() Do Me.txtAge = Nz(Me!txtAge) + 1 Loop Until Nz(Me!txtAge) = 35 End Sub
Wie das Konstrukt Do...Loop While wertet auch Do...Loop Until die Bedingung erst am Schleifenende aus, so dass der Code innerhalb der Schleife garantiert mindestens einmal ausgeführt wird. Eine Schleife lässt sich leicht aus Versehen so schreiben, dass sie endlos weiterläuft, wie Sie in folgendem Beispiel sehen (das Sie nicht in Chap7Ex finden):
Sub EndlessLoop() Dim intCounter As Integer IntCounter As Integer IntCounter = 5 Do Debug.Print intCounter IntCounter = intCounter + 1 Loop until intCounter = 5 End Sub
Dieser Code setzt intCounter auf 5. Die Schleife erhöht intCounter um eins und prüft dann, ob intCounter gleich 5 ist. Wenn dies nicht zutrifft, wird der Code in der Schleife noch einmal ausgeführt. Da die Variable intCounter niemals den Wert 5 annehmen wird (weil sie mit 6 beginnt), wird die Schleife endlos fortgesetzt. Sie müssen sie mit (Strg)+(Pause) verlassen; diese Tastenkombination funktioniert jedoch in der Laufzeitversion von Access nicht.
7.6.6
For...Next
Das Konstrukt For...Next wird verwendet, wenn Sie eine bestimmte Anzahl von Wiederholungen durchführen wollen. Sie finden es unter der gleichnamigen Befehlsschaltfläche im Formular frmControlStructures und es sieht folgendermaßen aus: Sub cmdForNext_Click() Dim intCounter As Integer For intCounter = 1 To 5 Me!txtAge = Nz(Me!txtAge) + 1 Next intCounter End Sub
278
Kapitel 7: VBA: Eine Einführung
Beachten Sie, dass die Variable intCounter selbsterhöhend ist. Sowohl Anfangs- als auch Endwert können Variablen sein. Eine For...Next-Anweisung kann auch eine Schrittweite übernehmen, wie Sie gleich sehen (der Zähler wird bei jedem Schleifendurchlauf um den Wert von Step hochgesetzt): Sub ForNextStep() 'Beachten Sie, dass Sie diesen Code nicht in der Datenbank Chap7ex.mdb finden. Dim intCounter As Integer For intCounter = 1 To 5 Step 2 Me!txtAge = Nz(Me!txtAge) + 1 Next intCounter End Sub
7.6.7
With...End With
Die Anweisung With...End With führt eine Folge von Anweisungen für dasselbe Objekt aus. Ein Beispiel (zu finden unter der gleichnamigen Befehlsschaltfläche im Formular frmControlStructures): Private Sub cmdWithEndWith_Click() With Me.txtAge .BackColor = 16777088 .ForeColor = 16711680 .Value = "Hello World" .FontName = "Arial" End With End Sub
Dieser Code führt vier Operationen am Textfeld txtAge im aktuellen Formular aus, welche die Eigenschaften BackColor, ForeColor, Value und FontName des Textfeldes ändern. Die Anweisung With...End With verfügt über zwei wesentliche Vorzüge. Einer besteht lediglich in geringerem Eingabeaufwand: Sie brauchen nicht für jede Aktion, die ausgeführt werden soll, den Objektnamen zu wiederholen. Der wichtigere betrifft die Leistung: Da nur einmal (und nicht mehrmals) auf das Objekt verwiesen wird, ist die Ausführung effizienter. Die Vorteile fallen noch deutlicher aus, wenn sich das With...End With-Konstrukt innerhalb einer Schleife befindet.
7.6.8
For Each...Next
Die Anweisung For Each...Next führt eine Gruppe von Anweisungen für jedes Element eines Datenfelds oder einer Auflistung aus. Das folgende Beispiel (das Sie unter der gleichnamigen Befehlsschaltfläche im Formular frmControlStructures finden) veranschaulicht die Verwendung dieses leistungsfähigen Konstrukts:
Die VBA-Steuerstrukturen
279
Private Sub cmdForEachNext_Click() Dim ctl As Control For Each ctl In Controls With ctl .ForeColor = 16711680 .FontName = "Arial" .FontSize = 14 End With Next ctl End Sub
Der Code durchläuft die Steuerelemente eines Formulars in Form einer Schleife und ändert dabei die Eigenschaften ForeColor, FontName und BackColor aller Steuerelemente. Wie im vorhergehenden Beispiel wird auch hier das Konstrukt With...End With verwendet, diesmal wie häufig zusammen mit For Each...Next. Es folgt ein Beispiel für das Konstrukt With...End With (zu finden unter der gleichnamigen Befehlsschaltfläche im Formular frmControlStructures): Private sub cmdForEachWith_Click() With Me.txtAge .BackColor = 16777088 .ForeColor = 16711680 .Value = "Hello World" .FontName = "Arial" End With End Sub
Mit diesem Code werden drei Eigenschaften des Steuerelements txtAge geändert: ForeColor, FontName und FontSize. Denken Sie vor der Umsetzung all dieser wertvollen Informationen in die Praxis daran, dass noch keine Fehlerbehandlung in den Code integriert wurde. Wenn eines der Steuerelemente des Beispielformulars keine Eigenschaft namens ForeColor, FontName oder FontSize besitzt, führt die Ausführung zu einem Fehler. In Kapitel 8 lernen Sie, wie man den Typ eines Objekts bestimmt, bevor man einen Befehl für dieses ausführt. Wenn man vor dem Versuch, die Eigenschaften eines Objekts zu ändern, seinen Typ kennt, kann dies zur Vermeidung von Fehlern beitragen.
280
7.7
Kapitel 7: VBA: Eine Einführung
Parameter über- und Werte zurückgeben
Sowohl Unterroutinen als auch Funktionen können Argumente (Parameter) übernehmen, aber nur Funktionen können Werte zurückgeben. Die folgende Unterroutine (die Sie unter der Befehlsschaltfläche PASS PARAMETERS des Formulars frmParametersAndReturnValues finden) übernimmt zwei Parameter, nämlich txtFirstName und txtLastName, und zeigt dann ein Meldungsfeld mit dem ersten Buchstaben der übergebenen Parameter an. Private Sub cmdPassParamters_Click() Call Initials(Nz(Me.txtFirstName), Nz(Me.txtLastName)) End Sub Sub Initials(strFirst As String, strLast As String) 'Diese Prozedur finden Sie, wenn Sie in der Objektliste 'des VBE-Fensters Allgemein auswählen MsgBox "Your Initials Are " & _ Left(strFirst, 1) & _ Left(strLast, 1) End Sub
Beachten Sie, dass der Text in den Steuerelementen txtFirstName und txtLastName des aktuellen Formulars (dargestellt durch das Schlüsselwort Me) an die Unterroutine Initials übergeben wird, wobei die Parameter strFirst und strLast heißen. Das erste Zeichen beider Parameter wird im Meldungsfeld angezeigt. Dieser Code übergibt lediglich Werte und arbeitet dann mit diesen. Das folgende Beispiel (das Sie unter der Befehlsschaltfläche RETURN VALUES des Formulars frmParametersAndReturnValues finden) verwendet eine Funktion, um einen Wert zurückzugeben. Private Sub cmdReturnValues_Click() Dim strInitials As String strInitials = ReturnInit(Me.txtFirstName, Me.txtLastName) MsgBox "Your Initials Are " & strInitials End Sub Function ReturnInit(strFName, strLName As String) As String 'Diese Prozedur finden Sie, wenn Sie in der Objektliste 'des VBE-Fensters Allgemein auswählen ReturnInit = Left$(strFname, 1) & Left(strLName, 1) End Function
Beachten Sie, dass in diesem Beispiel die Funktion ReturnInit aufgerufen wird, welche die in den beiden Textfeldern stehenden Werte als Parameter sendet. Die Funktion setzt ReturnInit (den Funktionsnamen) auf die ersten Zeichen der Zeichenfolgen, gibt damit den Wert an die aufrufende Routine (cmdReturnValues_Click) zurück und setzt strInitials auf den Rückgabewert.
Vom Modulfenster aus Prozeduren ausführen
281
Beachten Sie, dass die Funktion ReturnInit so gestaltet ist, dass sie zwei Zeichenfolgen als Parameter übernimmt. Das ist aus dem Schlüsselwort As String zu entnehmen, das auf jeden Parameter folgt. Außerdem soll die Funktion eine Zeichenfolge zurückgeben, was Sie aus dem Schlüsselwort As String im Anschluss an die Parameterliste (außerhalb der Klammern) erkennen. Wenn Sie nicht explizit festlegen, dass die Funktion einen bestimmten Datentyp zurückgeben soll, gibt sie den Typ Variant zurück.
7.8
Vom Modulfenster aus Prozeduren ausführen
In Access 2000 ist das Testen von Prozeduren vom Modulfenster aus einfach – klicken Sie einfach irgendwo innerhalb der auszuführenden Prozedur und drücken Sie die Taste (F5) oder klicken Sie auf die Schaltfläche SUB/USERFORM AUSFÜHREN in der Symbolleiste. Dann wird die Prozedur, in der Sie sich befinden, genauso ausgeführt, als ob Sie sie per Programm oder mit Hilfe des Direktbereichs im Testfenster aufgerufen hätten.
7.9
Das Objekt DoCmd: Makro-Aktionen durchführen
Die Access-Umgebung ist reich an Objekten mit integrierten Eigenschaften und Methoden. Mit Hilfe von VBA-Code lassen sich die Eigenschaften ändern und die Methoden ausführen. Eines der in Access verfügbaren Objekte heißt DoCmd und wird zur Ausführung von Makro-Aktionen in VBA-Prozeduren eingesetzt. Die MakroAktionen werden dabei als Methoden des Objekts DoCmd behandelt und die Syntax dafür sieht folgendermaßen aus: DoCmd.ActionName [Argumente]
Ein praktisches Beispiel: DoCmd.OpenReport strReportName, acPreview
Die Methode OpenReport ist eine Methode des Objekts DoCmd, die einen Bericht ausführt. Die beiden ersten Parameter, die sie übernimmt, sind der Name des gewünschten Berichts und die Ansicht, in der dieser erscheinen soll (Vorschau-, Normal- oder Entwurfsansicht). Beides sind Argumente der Methode. Zu den meisten Makro-Aktionen gibt es entsprechende Methoden von DoCmd, die Sie in der Hilfe finden (für einige jedoch nicht): AddMenu, MsgBox, RunApp, RunCode, SendKeys, SetValue, StopAllMacros und StopMacro. Dabei ist allein die Methode SendKeys für VBA-Programmierer von Bedeutung. Für die übrigen Makro-Aktionen gibt es entweder im VBA-Code keine Verwendung oder sie lassen sich mit Hilfe von VBA-
282
Kapitel 7: VBA: Eine Einführung
Funktionen oder -Befehlen effizienter ausführen. Die Sprache VBA besitzt zum Beispiel eine Funktion namens MsgBox, die wesentlich leistungsfähiger ist als die MakroEntsprechung. Viele der Methoden von DoCmd besitzen optionale Parameter. Falls Sie kein Argument liefern, wird der Standardwert verwendet. Sie können Kommata als Platzhalter einsetzen, um die Positionen fehlender Argumente zu markieren, wie Sie hier sehen: DoCmd.OpenForm "frmOrders", , ,"[OrderAmount] > 1000"
Die Methode OpenForm des Objekts DoCmd übernimmt sieben Parameter, von denen die letzten sechs optional sind. Im Beispiel werden zwei Parameter explizit genannt. Der erste ist der Name des Formulars, eine notwendige Angabe. Der zweite und der dritte Parameter fehlen, d.h., Sie haben die Standardwerte akzeptiert. Die als Platzhalter verwendeten Kommata sind erforderlich, weil ein weiterer Parameter explizit angegeben ist. Es handelt sich um den vierten, die Where-Bedingung des Formulars: den Datensatz, in dem die Bestellmenge größer als 1.000 ist. Die übrigen Parameter sind nicht genannt, also werden für diese die Standardwerte benutzt. Wenn Sie wollen, können Sie für die Übergabe benannte Parameter verwenden, die später behandelt werden. Diese können die oben genannte Syntax wesentlich vereinfachen, weil die Argumente nicht in einer bestimmten Reihenfolge erscheinen und weil Sie keine Kommata zählen müssen. Die Syntax kann folgendermaßen geändert werden: DoCmd.OpenForm FormName:="frmOrders", WhereCondition:= "[OrderAmount] > 1000"
7.10
Integrierte Funktionen
VBA besitzt eine reichhaltige und umfassende Funktionsbibliothek sowie Werkzeuge, um ihre Benutzung zu erleichtern.
7.10.1
Integrierte Funktionen
Einige der häufiger verwendeten Funktionen und Beispiele werden in den folgenden Abschnitten vorgestellt. Schauen Sie einmal an einem Regentag in die Online-Hilfe oder die »Sprachreferenz von Microsoft Access Visual Basic«, um sich mit den übrigen vertraut zu machen. Die folgenden Beispiele dienen lediglich der Veranschaulichung und sind nicht in der Datenbank Chap7Ex zu finden.
Integrierte Funktionen
283
Format Die Funktion Format formatiert Ausdrücke in der angegebenen Art. Der erste Parameter ist der zu formatierende Ausdruck, der zweite das anzuwendende Format. Ein Beispiel: Sub FormatData() Debug.Print Format$(50, "Currency") 'Gibt $50.00 aus Debug.Print Format$(Now, "Short Date") 'Gibt das aktuelle Datum aus Debug.Print Format$(Now, "DDDD") 'Gibt die verbale Bezeichnung des Tages aus Debug.Print format$(Now, "DDD") 'Gibt den Tag mit drei Zeichen aus Debug.Print Format$(Now, "YYYY") 'Gibt das Jahr vierstellig aus Debug.Print Format$(Now, "WW") 'Gibt die Wochennummer aus End Sub
Instr Die Funktion Instr gibt die Stelle an, an der eine Zeichenfolge innerhalb einer anderen Zeichenfolge anfängt: Sub InstrExample() Debug.Print InStr("Alison Balter", "Balter") 'Gibt 8 zurück Debug.Print InStr("Hello", "l") 'Gibt 3 zurück End Sub
Left Die Funktion Left gibt die angegebene Anzahl Zeichen einer Zeichenfolge von links aus: Sub LeftExample() Debug.Print Left$("Hello World", 7) 'Gibt Hello Windows aus End Sub
Right Die Funktion Right gibt die angegebene Anzahl Zeichen einer Zeichenfolge von rechts aus: Sub RightExample() Debug.Print Right$("Hello World", 7) 'Gibt o World aus End Sub
Mid Die Funktion Mid gibt eine Teilzeichenkette mit der genannten Zeichenzahl aus. Das Beispiel beginnt mit dem vierten Zeichen und gibt fünf Zeichen zurück:
284
Kapitel 7: VBA: Eine Einführung
Sub MidExample() Debug.Print Mid$("Hello World", 4, 5) 'Gibt lo Wo aus End Sub
UCase Die Funktion UCase gibt eine Zeichenfolge vollständig in Großbuchstaben zurück: Sub UCaseExample() Debug.Print UCase$("Hello World") 'Gibt HELLO WORLD aus End Sub
DatePart Die Funktion DatePart gibt den angegebenen Teil des Datums zurück: Sub DatePartExample() Debug.Print DatePart("YYYY", Now) 'Gibt das Jahr aus Debug.Print DatePart("M", Now) 'Gibt die Monatsnummer aus Debug.Print DatePart("Q", Now) 'Gibt die Nummer des Quartals aus Debug.Print DatePart("Y", Now) 'Gibt den Tag im Jahr aus Dbug.Print DatePart("WW", Now) 'Gibt die Wochennummer aus End Sub
DateDiff Die Funktion DateDiff gibt den Abstand zwischen zwei Daten aus: Sub DateDiffExample() Debug.Print DateDiff("d", Now, "12/31/99") ''Tage bis zum 32.12.1999 Debug.Print DateDiff("m", Now, "12/31/99") ''Monate bis zum 31.12.1999 Debug.Print DateDiff("yyyy", Now, "12/31/99") ''Jahre bis zum 31.12.1999 Debug.Print DateDiff("q", Now, "12/31/99) ''Quartale bis zum 31.12.1999 End Sub
DateAdd Die Funktion DateAdd gibt das Ergebnis der Addition einer angegebenen Zeitspanne zu oder ihre Subtraktion von einem Datum aus: Sub DateAddExample() Debug.Print DateAdd("d", 3, Now) 'Heute plus drei Tage
Integrierte Funktionen
Debug.Print 'Heute plus Debug.Print 'Heute plus Debug.Print 'Heute plus Debug.Print 'Heute plus End Sub
7.10.2
285
DateAdd("m", 3, Now) drei Monate DateAdd("yyyy", 3, Now) drei Jahre DateAdd("q", 3, Now) drei Quartale DateAdd("ww", 3, Now) drei Wochen
Funktionen leicht gemacht mit dem Objektkatalog
Mit dem Objektkatalog können Sie sich Elemente der Typbibliothek einer ActiveXKomponente ansehen. Im Klartext: mit dem Objektkatalog können Sie die Methoden, Eigenschaften und Konstanten einer Komponente durchblättern. Außerdem können Sie Informationen kopieren und in Ihren Code einfügen sowie die Parameter einer Methode hinzufügen. Mit folgenden Schritten sehen Sie die verfügbaren Methoden durch, kopieren die gewünschte Methode und fügen sie in Ihren Code ein: 1. Wählen Sie im VBE den Menübefehl ANSICHT|OBJEKTKATALOG (beachten Sie, dass Sie auch ein Symbol in der Symbolleiste finden, das Sie verwenden können) oder öffnen Sie mit (F2) das Fenster OBJEKTKATALOG (siehe Abbildung 7.11).
Abbildung 7.11: Der Objektkatalog mit allen Klassen der Datenbank Chap7Ex und allen Elementen des Moduls basUtils
2. Das Fenster OBJEKTKATALOG ist in horizontaler Richtung in zwei Flächen geteilt. Die Objektliste links oben dient zum Filtern der Elemente, die im unteren Teil
286
Kapitel 7: VBA: Eine Einführung
des Fensters angezeigt werden sollen. Wählen Sie in dieser Objektliste das Projekt bzw. die Bibliothek aus, deren Klassen und Elemente Sie im unteren Teil ansehen wollen. 3. Wählen Sie im unteren Teil des Fensters im linken Listenfeld, in dem Klassenmodule, Vorlagen für neue Objekte, Standardmodule und Module mit Unterroutinen und Funktionen aufgelistet sind, die Klasse aus. 4. Wählen Sie im Listenfeld ELEMENTE VON eine Eigenschaft, eine Methode, ein Ereignis, eine Konstante, eine Funktion oder eine Anweisung der Klasse aus. In Abbildung 7.11 ist im Listenfeld links das Modul basUtils hervorgehoben. Beachten Sie, dass die zu basUtils gehörenden Unterroutinen und Funktionen im Listenfeld rechts erscheinen. 5. Klicken Sie auf die Schaltfläche IN ZWISCHENABLAGE KOPIEREN (die dritte von rechts in der oberen Symbolleiste des Fensters OBJEKTKATALOG), um die Funktion und ihre Parameter in die Zwischenablage zu kopieren, so dass Sie sie leicht in Ihren Code einfügen können. Das Beispiel in Abbildung 7.11 zeigt die Auswahl einer benutzerdefinierten Funktion, die aus einem Modul der Datenbank gewählt wurde, aber Sie können auch eine beliebige integrierte Funktion auswählen. Abbildung 7.12 zeigt ein Beispiel, in dem die Funktion DatePart aus der VBA-Bibliothek gewählt wurde. Der Objektkatalog stellt alle Bibliotheken bereit, auf welche die Datenbank verweist. In den Kapiteln 8 und 26 wird er ausführlicher behandelt.
Abbildung 7.12: Im Objektkatalog ist die VBA-Bibliothek ausgewählt
Mit Konstanten arbeiten
7.11
287
Mit Konstanten arbeiten
Eine »Konstante« ist ein aussagekräftiger Name für eine nichtssagende Zahl oder Zeichenfolge. Konstanten können nur für Werte verwendet werden, die sich zur Laufzeit nicht ändern. Ein Steuer- oder Provisionssatz könnte beispielsweise in Ihrer gesamten Anwendung als Konstante auftreten. In Access gibt es drei Arten von Konstanten:
symbolische Konstanten interne Konstanten systemdefinierte Konstanten Symbolische Konstanten werden mit Hilfe des Schlüsselworts Const angelegt und dienen dazu, die Lesbarkeit Ihres Codes zu verbessern und die Pflege zu erleichtern. Anstatt bei jedem Verweis auf den Steuersatz die Zahl .0875 zu nennen, können Sie die Konstante mccurTaxRate verwenden. Wenn sich der Steuersatz ändert und Sie den Wert in Ihrem Code anpassen müssen, ist dies nur an einer Stelle erforderlich. Außerdem ist die Bezeichnung mccurTaxRate – anders als die Zahl .0875 – selbstdokumentierend. Interne Konstanten sind in Microsoft Access integriert und Teil der Sprache. Als Access-Programmierer können Sie Konstanten, die von Microsoft Access, Visual Basic, DAO und Active Data Objects (ADO) bereitgestellt werden, sowie Konstanten aus allen Objektbibliotheken verwenden, die Sie in Ihrer Anwendung einsetzen. Es gibt nur drei systemdefinierte Konstanten und diese stehen allen Anwendungen auf Ihrem Rechner zur Verfügung: True, False und Null.
7.11.1
Mit symbolischen Konstanten arbeiten
Wie bereits erwähnt, wird eine symbolische Konstante mit Hilfe des Schlüsselworts Const deklariert (in einer Unterroutine oder Funktion oder im Abschnitt ALLGEMEIN eines Formular- oder Berichtsmoduls). Für Konstanten ist in Access 2000 strenge Typzuweisung möglich. Deklaration und Verwendung einer privaten Konstanten würden folgendermaßen aussehen: Private Const TAXRATE As Currency = .0875
Wenn dieser Code im Abschnitt DEKLARATIONEN eines Moduls steht, legt er eine private Konstante namens TAXRATE mit dem Wert .0875 an, die folgendermaßen verwendet wird: Function TotalAmount(curSaleAmount As Currency) TotalAmount = curSaleAmount * TAXRATE End Function
288
Kapitel 7: VBA: Eine Einführung
Diese Routine multipliziert den Wert von curSaleAmount, den sie als Parameter übernimmt, mit der Konstanten TAXRATE und gibt das Ergebnis zurück, indem sie den Funktionsnamen mit dem Produkt der beiden Werte gleichsetzt. Der Vorteil der Konstanten liegt in diesem Beispiel darin, dass der Code besser lesbar ist als die Zeile TotalAmount = curSaleAmount * .0875. Der Gültigkeitsbereich symbolischer Konstanten Genauso wie normale Variablen haben auch benutzerdefinierte Konstanten einen Gültigkeitsbereich. Im vorangegangenen Beispiel haben Sie eine private Konstante angelegt. Mit der folgenden Anweisung wird, wenn sie im Abschnitt DEKLARATIONEN eines Moduls steht, eine öffentliche Konstante erzeugt: Public Const TAXRATE = .0875 As Currency
Da diese Konstante als öffentlich deklariert wurde, können alle Unterroutinen und Funktionen (einschließlich der Ereignisroutinen) in der gesamten Anwendung auf sie zugreifen. Um die Vorzüge einer öffentlichen Konstanten besser zu verstehen, können Sie sich einen Fall denken, in dem viele Funktionen und Unterroutinen auf die Konstante TAXRATE verweisen. Stellen Sie sich vor, was passiert, wenn sich der Steuersatz ändern sollte: ohne Konstante müssten Sie die gesamte Anwendung durchgehen und den alten Steuersatz durch den neuen ersetzen. Da jedoch Ihre öffentliche Konstante nur an einer einzigen Stelle deklariert wurde, können Sie die eine Code-Zeile mit der Konstantendeklaration mühelos ändern. Die Werte von Konstanten lassen sich definitionsgemäß nicht zur Laufzeit ändern. Bei einem solchen Versuch erhalten Sie folgende Fehlermeldung des VBA-Compilers: Assignment to constant not permitted Abbildung 7.13 zeigt dieses Meldungsfeld. Sie können erkennen, dass der Versuch gemacht wurde, den Wert der Konstanten TAXRATE zu ändern, was zu einem Compiler-Fehler führte. Wenn Sie den Wert zur Laufzeit ändern müssen, sollten Sie erwägen, den Wert in einer Tabelle abzulegen, anstatt ihn als Konstante zu deklarieren. Sie können den Wert dann beim Laden der Anwendung in eine Variable einlesen und bei Bedarf ändern. Wenn Sie wollen, können Sie den neuen Wert in die Tabelle zurückschreiben.
7.11.2
Mit internen Konstanten arbeiten
Microsoft Access deklariert eine Reihe interner Konstanten, die sich in Code-, Formular- und Berichtsmodulen verwenden lassen. Da sie von Microsoft Access reserviert wurden, können Sie weder ihre Werte ändern noch ihre Namen erneut verwenden; die Konstanten können jedoch jederzeit ohne Deklaration benutzt werden.
Mit Konstanten arbeiten
289
Sie sollten interne Konstanten in Ihrem Code verwenden, wo immer es möglich ist. Das macht den Code nicht nur leichter lesbar, sondern auch besser auf zukünftige Access-Versionen portierbar. Möglicherweise ändert Microsoft irgendwann den Wert einer Konstanten, aber der Name wird wahrscheinlich nicht geändert werden. Alle internen Konstanten erscheinen im Objektkatalog, der mit einem Klick auf das Werkzeug OBJEKTKATALOG in der Symbolleiste von Visual Basic aktiviert wird. Um die Konstanten anzuzeigen, die zur Access-Bibliothek gehören, wählen Sie in der aufklappbaren Liste PROJEKT/BIBLIOTHEK im Objektkatalog den Eintrag ACCESS. Klicken Sie dann im Listenfeld KLASSEN auf KONSTANTEN, um die Liste der Konstanten im Listenfeld ELEMENTE VON 'KONSTANTEN' auszugeben.
Abbildung 7.13: Der Versuch, den Wert einer Konstanten zu ändern
In der in Abbildung 7.14 gezeigten Liste beginnen alle Konstantennamen mit ac. Alle VBA-Konstanten besitzen das Präfix vb, alle DAO-Konstanten db und alle AccessKonstanten ac. Um sich die Konstanten von Visual Basic anzusehen, wählen Sie im Listenfeld PROJEKT/BIBLIOTHEK den Eintrag VBA und dann in der Klassenliste den Eintrag KONSTANTEN. Wenn das Projekt, mit dem Sie arbeiten, einen Verweis auf die ADO-Bibliothek enthält, können Sie die dazugehörigen Konstanten sehen, indem Sie im Listenfeld PROJEKT/BIBLIOTHEK den Eintrag ADODB wählen. Anschließend klicken Sie auf
. Damit wird eine Liste der ADODB-Konstanten (mit dem Präfix ad) geöffnet.
290
Kapitel 7: VBA: Eine Einführung
Abbildung 7.14: Mit Hilfe des Objektkatalogs interne Konstanten ansehen
7.12
Werkzeuge für die Arbeit im VBE
Wenn Sie die branchenüblichen Tipps und Tricks, von denen viele in diesem Kapitel erläutert werden, effizient nutzen, können Sie viel Zeit sparen. Diese Tricks helfen Ihnen dabei, sich in der Programmierumgebung zu bewegen und Ihren Code schnell und mühelos zu ändern. Dazu gehört die Möglichkeit, problemlos in eine benutzerdefinierte Prozedur zu wechseln, innerhalb von Modulen Stellen zu suchen und zu ersetzen, Hilfe zu VBA-Funktionen und -Befehlen zu finden und das Code-Fenster zu teilen, um zwei Prozeduren gleichzeitig einsehen zu können. Die Entwicklungsumgebungen von Access 97 und Access 2000 sind besser als ihre Vorgänger. Es wurden Fähigkeiten hinzugefügt, die das Programmieren erleichtern und angenehmer gestalten, wie zum Beispiel folgende:
Eigenschaften und Methoden auflisten Konstanten auflisten Direkthilfe zu Befehlen und Funktionen Parameterinformationen Vollenden eines Wortes durch Access Einsehen von Funktionsdefinitionen Alle diese bei der Programmierung hilfreichen Funktionen stehen mit einem Rechtsklick zur Verfügung, wenn sich der Cursor im Modulfenster befindet.
291
Werkzeuge für die Arbeit im VBE
7.12.1
Eigenschaften und Methoden auflisten
Mit dem Merkmal EIGENSCHAFTEN UND METHODEN ANZEIGEN können Sie alle Objekte, Eigenschaften und Methoden anschauen, die für das aktuelle Objekt zur Verfügung stehen. Um es aufzurufen, klicken Sie mit der rechten Maustaste hinter dem Namen des Objekts und wählen dann EIGENSCHAFTEN/METHODEN ANZEIGEN. (Sie können auch (Strg)+(J) drücken.) Dann erscheinen die anwendbaren Objekte, Eigenschaften und Methoden in einem Listenfeld (siehe Abbildung 7.15). Das richtige Objekt bzw. die richtige Eigenschaft oder Methode finden Sie auf eine der folgenden Arten:
Sie fangen an, den Namen des Objekts, der Eigenschaft oder der Methode einzugeben.
Sie bewegen sich mit Hilfe des Aufwärts- oder Abwärtspfeils durch die Liste. Sie bewegen die Liste mit Hilfe des Bildlaufs und markieren Ihre Auswahl.
Abbildung 7.15: Die Liste der Eigenschaften und Methoden des Objekts TextBox
Mit folgenden Methoden fügen Sie die Auswahl in Ihren Code ein:
Doppelklicken Sie auf den Eintrag. Markieren Sie den Eintrag mit einem Klick und drücken Sie dann (ÿ) oder (¢), um die Auswahl einzufügen und in die nächste Zeile zu gelangen.
292
Kapitel 7: VBA: Eine Einführung
Mit der Option ELEMENTE AUTOMATISCH AUFLISTEN, die Sie auf der Registerkarte EDITOR des Dialogfeldes OPTIONEN finden, veranlassen Sie, dass die Merkmale EIGENSCHAFTEN UND METHODEN ANZEIGEN und KONSTANTEN ANZEIGEN automatisch aufgerufen werden, sobald Sie den Namen eines Objekts oder einer Eigenschaft eingeben.
7.12.2
Konstanten auflisten
Mit dem Merkmal KONSTANTEN ANZEIGEN wird eine aufklappbare Liste geöffnet, die gültige Konstanten für eine von Ihnen eingegebene Eigenschaft sowie für Funktionen mit Argumenten anzeigt, die Konstanten sind. Es funktioniert ähnlich wie das Merkmal EIGENSCHAFTEN UND METHODEN ANZEIGEN. Um es aufzurufen, klicken Sie mit der rechten Maustaste hinter dem Namen der Eigenschaft oder des Arguments (bei mehreren Argumenten muss das vorangehende mit einem Komma abgetrennt sein) und wählen dann KONSTANTEN ANZEIGEN. (Sie können auch (Strg)+(ª)+(J) drücken.) Dann erscheint eine Liste der gültigen Konstanten (siehe Abbildung 7.16). Die gewünschte Konstante wählen Sie mit Hilfe einer der im vorigen Abschnitt genannten Methoden aus.
Abbildung 7.16: Die Liste der Konstanten für den Parameter vbMsgBoxStyle
7.12.3
QuickInfo
Das Merkmal QUICKINFO liefert Ihnen die vollständige Syntax für eine Funktion, Anweisung, Prozedur, Methode oder Variable. Um diese zu verwenden, klicken Sie mit der rechten Maustaste hinter den Namen der Funktion, Anweisung, Prozedur, Methode oder Variablen und wählen QUICKINFO (oder drücken (Strg)+(I)). Dann
Werkzeuge für die Arbeit im VBE
293
wird ein Tipp mit der korrekten Syntax für das Element eingeblendet (siehe Abbildung 7.17). Während Sie einen Parameter in das Element eingeben, wird dieser bis zur Eingabe des Kommas, das ihn vom nächsten Parameter trennt, in fetter Schrift dargestellt.
Abbildung 7.17: Die Syntax der Funktion MsgBox
Mit der Option AUTOMATISCHE QUICKINFO, die Sie im Dialogfeld OPTIONEN finden, wird das Merkmal QUICKINFO automatisch aufgerufen, sobald Sie den Namen eines Objekts oder einer Eigenschaft eingeben.
7.12.4
Parameterinfo
Das Merkmal PARAMETERINFO liefert Ihnen Informationen über die Parameter einer Funktion, Anweisung oder Methode. Um diese zu verwenden, klicken Sie mit der rechten Maustaste hinter das Begrenzungszeichen, welches das Ende des Namens der Funktion, Anweisung oder Methode angibt, und wählen PARAMETERINFO (oder drücken (Strg)+(ª)+(I)). Dann wird eine aufklappbare Liste mit Informationen über die Parameter der Funktion oder Anweisung eingeblendet, die erst geschlossen wird, nachdem alle erforderlichen Parameter eingegeben sind, die Funktion mit optionalen Parametern vervollständigt ist oder wenn die Taste (ESC) gedrückt wird. Das Merkmal PARAMETERINFO liefert nur Informationen über die Ursprungsfunktion. Wenn Parameter einer Funktion selbst Funktionen sind, müssen Sie die QUICKINFO verwenden, um Informationen über die eingebetteten Funktionen zu erhalten.
294
7.12.5
Kapitel 7: VBA: Eine Einführung
Wort vervollständigen
Das Merkmal WORT VERVOLLSTÄNDIGEN vervollständigt ein Wort, das Sie gerade eingeben. Um es zu verwenden, müssen Sie zunächst eine ausreichende Anzahl Zeichen eingeben, damit Visual Basic das gewünschte Wort erkennen kann. Danach klicken Sie mit der rechten Maustaste und wählen WORT VERVOLLSTÄNDIGEN (oder Sie drücken (Strg)+(_____)). Dann stellt Visual Basic das Wort fertig.
7.12.6
Definition
Das Merkmal DEFINITION zeigt die Stelle im Code-Fenster, an der die ausgewählte Variable oder Prozedur definiert wurde. Um eine Definition zu bekommen, klicken Sie mit der rechten Maustaste auf den Namen der Variablen oder Prozedur Ihres Interesses und wählen DEFINITION (oder drücken (SHIFT)+(F2)). Damit wird der Cursor in das Modul an die Stelle verschoben, an der die Variable oder Prozedur definiert wurde. Wenn Sie Erfahrungen mit VBA gesammelt haben, können Sie Bibliotheken mit VBA-Funktionen und Unterroutinen anlegen. Wenn Sie sich den Aufruf einer bestimmten Unterroutine oder Funktion ansehen, wollen Sie normalerweise den zu Grunde liegenden Code sehen. Glücklicherweise gibt es in VBA einen schnellen und einfachen Weg, von Prozedur zu Prozedur zu wechseln. Nehmen Sie an, in Ihrer Anwendung steht folgender Code: Private sub cmdOkay_Click() Dim iAgeInTen As Integer If IsNull(Me!txtName) Or IsNull(Me!txtAge) Then MsgBox "You must fill in name and age" Exit Sub Else MsgBox "Your Name Is: " & Me!txtName & "_ And your Age Is: " & Nz(Me!txtAge) Call EvaluateAge (Nz(Me!txtAge)) IAgeInTen = AgePlus10(Fix(Val(Me!txtAge))) MsgBox "In 10 Years You Will Be " & iAgeInTen End If End Sub
Wenn Sie schnell in die Prozedur EvaluateAge gelangen wollen, brauchen Sie nur den Cursor an eine beliebige Stelle des Prozedurnamens zu setzen und dann (ª)+(F2) zu drücken. Damit gelangen Sie unmittelbar in die Prozedur. Mit (Strg)+(ª)+(F2) kehren Sie in die Routine zurück, aus der Sie gekommen sind (in diesem Fall cmdOkay_Click). Das funktioniert sowohl bei Funktionen als auch bei Unterroutinen.
295
Werkzeuge für die Arbeit im VBE
Sie können, wenn Sie das lieber mögen, auch mit der rechten Maustaste auf den Namen der Routine klicken, in die Sie springen wollen, und dann DEFINITION wählen. Um in die Ausgangsprozedur zurückzukehren, klicken Sie wiederum mit der rechten Taste und wählen dann LETZTE POSITION.
Wenn sich die Definition in einer Bibliothek befindet, auf die verwiesen wird, wird der Objektkatalog aufgerufen und die Definition angezeigt.
7.12.7
Geheimnisse der Programmierumgebung aufgelöst
Wenn Sie als Entwickler erst mit VBA beginnen, könnte der VBE Sie in Verwirrung stürzen. Sprechen wir zunächst über das Code-Fenster. Es besitzt zwei Kombinationsfelder, wie Sie in Abbildung 7.18 sehen. Im linken Feld werden Objekte aufgelistet. Bei einem Formular oder Bericht sind alle Objekte aufgeführt, bei einem Standardmodul, das keine Objekte besitzt, erscheint nur der Eintrag (ALLGEMEIN).
Abbildung 7.18: Das Code-Fenster mit dem Kombinationsfeld Objekte
Das rechte Kombinationsfeld enthält alle mit einem bestimmten Objekt verknüpften Ereignisprozeduren. Abbildung 7.19 zeigt alle Ereignisprozeduren, die zu einer Schaltfläche gehören. Beachten Sie, dass nur das Click-Ereignis in fetter Schrift erscheint, weil es als einziges mit einer Ereignisprozedur versehen wurde.
296
Kapitel 7: VBA: Eine Einführung
Abbildung 7.19: Das Code-Fenster mit dem Kombinationsfeld Prozedur
7.12.8
Das Projektfenster
Mit Hilfe des Projektfensters, das Sie in Abbildung 7.20 sehen, können Sie leicht zwischen den Modulen wechseln, die den Objekten in Ihrer Datenbank zugrunde liegen. Die Elemente Ihres Projekts werden im Projektfenster hierarchisch in Form eines Baumes dargestellt. Sie sind in Access-Klassen und -Module unterteilt. Sämtliche Formular-, Berichts- und Klassenmodule sind unter KLASSEN UND MODULE zu finden, alle Standardmodule unter MODULE. Um den hinter einem Objekt liegenden Code zu sehen, führen Sie einfach im Projektfenster einen Doppelklick auf das Objekt aus. Um das Objekt selbst zu sehen, z.B. ein Formular, klicken Sie im Projektfenster einmal auf den Namen des Formulars und dann auf das Werkzeug OBJEKT ANSEHEN (das zweite Symbol von links in der Symbolleiste des Projektfensters). Damit kehren Sie zu Microsoft Access zurück und das ausgewählte Objekt ist jetzt aktiv. Sie können auch das Objekt anklicken und dann CODE ANZEIGEN wählen (das linke Symbol in der Symbolleiste des Projektfensters), um den Code einzusehen, oder OBJEKT ANZEIGEN, um das Objekt anzusehen. Das Kontextmenü ermöglicht auch das Einfügen von Modulen und Klassenmodulen, den Im- und Export von Dateien, das Ausdrucken des ausgewählten Objekts und das Einsehen der Datenbankeigenschaften. Diese Merkmale werden in Kapitel 24 abgehandelt.
Werkzeuge für die Arbeit im VBE
297
Abbildung 7.20: Das Projektfenster mit allen Klassen und Modulen, die im Projekt Chap7ex enthalten sind
7.12.9
Das Eigenschaftenfenster
Das in Abbildung 7.21 gezeigte Eigenschaftenfenster ermöglicht das Ansehen und Ändern von Objekteigenschaften im VBE. Oben im Eigenschaftenfenster finden Sie ein Kombinationsfeld, in dem Sie das Objekt auswählen können, dessen Eigenschaften Sie ändern wollen. Dort werden sowohl das im Projektfenster ausgewählte übergeordnete Objekt (z.B. das Formular) als auch die in diesem enthaltenen Objekte (z.B. die Steuerelemente) aufgeführt. Nachdem ein Objekt ausgewählt wurde, lassen sich seine Eigenschaften in der Eigenschaftenliste ändern. Sie können entweder alphabetisch oder nach Kategorien geordnet dargestellt werden. Im Beispiel wurde die Befehlsschaltfläche cmdIfThenElse ausgewählt und die Eigenschaften der Schaltfläche nach Kategorien geordnet angezeigt.
7.12.10 Das Werkzeug Ansicht Microsoft Access Wenn Sie irgendwann in die Access-Anwendungsumgebung zurückkehren möchten, klicken Sie einfach auf das Symbol ANSICHT MICROSOFT ACCESS (das linke Symbol) in der Symbolleiste. Danach können Sie mit Hilfe der Taskleiste oder einer der weiter vorn in diesem Kapitel genannten Methoden in den VBE zurückkehren.
7.12.11
Suchen und ersetzen
Häufig benennen Sie eine Variable nur vorläufig, um später zu entscheiden, dass Sie den Namen ändern wollen. VBA besitzt für diesen Zweck eine hervorragende Funktion zum Suchen und Ersetzen. Sie können einfach nach Daten suchen oder nach
298
Kapitel 7: VBA: Eine Einführung
Abbildung 7.21: Das Eigenschaftenfenster mit den nach Kategorien geordneten Eigenschaften einer Befehlsschaltfläche
einem Wert und ihn durch einen anderen ersetzen. Um das Dialogfeld SUCHEN aufzurufen, das Sie in Abbildung 7.22 sehen, wählen Sie BEARBEITEN|SUCHEN oder drücken (Strg)(F).
Abbildung 7.22: Das Dialogfeld Suchen ist für die Suche nach strMessage im aktuellen Modul vorbereitet
Geben Sie den zu suchenden Text in das Textfeld SUCHEN ein. Beachten Sie, dass Sie in AKTUELLER PROZEDUR, AKTUELLEM MODUL, AKTUELLEM PROJEKT oder MARKIERTEM TEXT suchen können. Die Funktion NUR GANZES WORT SUCHEN findet den Text nicht, wenn er Teil eines Wortes ist. Wenn Sie NUR GANZES WORT SUCHEN aktivieren und dann nach »Zahl« suchen, findet VBA das Wort »Zahlen« nicht. Weitere Optionen betreffen die Groß- und Kleinschreibung sowie den Mustervergleich. Außerdem können Sie das Dialogfeld ERSETZEN benutzen, das über das Menü BEARBEITEN|ERSETZEN oder mit (Strg)(H) (oder mit (ALT)(E), (E)) aufgerufen wird, um einen Text zu suchen und durch einen anderen Text zu ersetzen (siehe Abbildung 7.23). Es bietet alle Merkmale des Dialogfeldes SUCHEN und darüber hinaus die Möglichkeit, einen Text zum Ersetzen einzugeben. Außerdem können Sie
Werkzeuge für die Arbeit im VBE
299
ERSETZEN oder ALLE ERSETZEN wählen. ERSETZEN verlangt bei jedem Vorgang eine Bestätigung, ALLE ERSETZEN jedoch nicht. Ich empfehle Ihnen, sich die Zeit zum Bestätigen der einzelnen Ersetzungen zu nehmen, weil man allzu leicht die durchschlagende Wirkung des globalen Suchens und Ersetzens falsch einschätzt.
Abbildung 7.23: Das Dialogfeld Ersetzen ist für die Suche nach strMessage im aktuellen Projekt und das Ersetzen durch strNewMessage vorbereitet
7.12.12 Die Hilfe Ein sehr sinnvolles, aber wenig bekanntes Merkmal von VBA ist die kontextsensitive Hilfe während der Programmierarbeit. Drücken Sie, während sich der Cursor in einem beliebigen VBA-Befehl oder in einer Funktion befindet, die Taste (F1), um kontextsensitive Hilfe zu diesem Befehl oder dieser Funktion einzublenden. Die meisten Hilfethemen bieten Ihnen praktische Beispiele, die den Befehl oder die Funktion innerhalb einer Routine zeigen. In Abbildung 7.24 sehen Sie die Hilfe für das Konstrukt With...End With. Beachten Sie, dass das Hilfefenster die Syntax für den Befehl, eine detaillierte Beschreibung aller Befehlsparameter sowie Bemerkungen zur Verwendung des Befehls enthält. Am oberen Rand des Fensters finden Sie Hypertext-Verknüpfungen zu verwandten Themen (Siehe auch) sowie eine Verknüpfung zu einem Verwendungsbeispiel. Wenn Sie auf BEISPIEL klicken, erscheint ein spezielles Beispiel für das Konstrukt, das Sie kopieren und in ein Modul einfügen können (siehe Abbildung 7.25). Dieses Merkmal stellt eine hervorragende Methode dar, etwas über die verschiedenen Teile von VBA zu erfahren.
7.12.13 Das Code-Fenster teilen Das VBA-Code-Fenster lässt sich teilen, damit Sie zwei Routinen desselben Moduls gleichzeitig betrachten können. Diese Option ist hilfreich, wenn Sie versuchen, ein Problem zu lösen, das zwei Prozeduren oder Ereignisroutinen in einem umfangreichen Modul betrifft. Ein Beispiel für ein geteiltes Code-Fenster sehen Sie in Abbildung 7.26. Um das Fenster zu teilen, wählen Sie FENSTER|TEILEN. Beachten Sie das Teilungsfeld. Bewegen Sie den Mauszeiger auf die graue Schaltfläche FENSTER TEILEN direkt über dem vertikalen Rollbalken des Code-Fensters. Die Größe der beiden Fenster lässt sich verändern, indem Sie auf das Teilungsfeld klicken und es dann verschieben. Das Fenster lässt sich nur in zwei Hälften teilen.
300
Kapitel 7: VBA: Eine Einführung
Abbildung 7.24: Hilfe zu With...End With
Abbildung 7.25: Ein Beispiel für With....End With
Danach können Sie mit Hilfe der aufklappbaren Listen OBJEKT und PROZEDUR in die Prozedur Ihrer Wahl wechseln. Diese Listen gelten jeweils für den Teil des geteilten Fensters, der zuletzt aktiv war.
301
Werkzeuge für die Arbeit im VBE
Abbildung 7.26: In einem geteilten Code-Fenster können Sie zwei Routinen betrachten
Nur Routinen desselben Moduls lassen sich im selben Code-Fenster betrachten, aber man kann mehrere Code-Fenster gleichzeitig öffnen. Sobald Sie ein Access-, Formular- oder Berichtsmodul öffnen, gelangen Sie in ein anderes Fenster. Jedes Modulfenster lässt sich in der Größe verändern, verschieben und teilen.
7.12.14 Die Arbeitsposition mit Hilfe von Lesezeichen markieren Die Programmierumgebung von Access 2000 lässt das Anlegen von Markierungen – so genannten »Lesezeichen« – zu, damit Sie mühelos an wichtige Stellen in Ihren Modulen zurückkehren können. Um ein Lesezeichen einzufügen, klicken Sie mit der rechten Maustaste in die Code-Zeile, in die Sie das Lesezeichen setzen wollen, und wählen UMSCHALTEN|LESEZEICHEN oder Sie wählen im Menü BEARBEITEN den Eintrag LESEZEICHEN|LESEZEICHEN SETZEN/ZURÜCKSETZEN. Sie können beliebig viele Lesezeichen einfügen. Zwischen den Lesezeichen wechseln Sie mit BEARBEITEN|LESEZEICHEN|NÄCHSTES LESEZEICHEN oder BEARBEITEN|LESEZEICHEN|VORHERIGES LESEZEICHEN. Ein Lesezeichen ist ein Schalter, den Sie mit UMSCHALTEN|LESEZEICHEN im Kontextmenü oder mit LESEZEICHEN|LESEZEICHEN SETZEN/ZURÜCKSETZEN im Menü BEARBEITEN entfernen können. Wenn alle Lesezeichen gelöscht werden sollen, wählen Sie BEARBEITEN|LESEZEICHEN|ALLE LESEZEICHEN LÖSCHEN. Lesezeichen werden beim Schließen der Datenbank nicht gespeichert.
302
Kapitel 7: VBA: Eine Einführung
Verwechseln Sie die hier beschriebenen Lesezeichen nicht mit Lesezeichen in Datensatzgruppen, die in Kapitel 12 behandelt werden.
7.13
Den VBE individuell anpassen
Access 2000 bietet Access-Programmierern weitreichende Möglichkeiten, Aussehen und Verhalten des VBE individuell anzupassen. Mit EXTRAS|OPTIONEN gelangen Sie bei aktiviertem VBE zu den Umgebungsoptionen. Abbildung 7.27 zeigt das Dialogfeld OPTIONEN, dessen verschiedene Aspekte in diesem Abschnitt ausführlich erläutert werden.
Abbildung 7.27: Das Dialogfeld Optionen
7.13.1
Programmieroptionen: Die Registerkarte Editor
Die Programmieroptionen befinden sich auf der Registerkarte EDITOR des Dialogfeldes OPTIONEN. Dazu gehören AUTOMATISCH EINZUG VERGRÖSSERN, TAB-SCHRITTWEITE, AUTOMATISCHE SYNTAXÜBERPRÜFUNG, VARIABLENDEKLARATION ERFORDERLICH, AUTOMATISCHE QUICKINFO, ELEMENTE AUTOMATISCH AUFLISTEN und AUTOMATISCHE DATEN-TIPS. Das Merkmal AUTOMATISCH EINZUG VERGRÖSSERN aktiviert den automatischen Einzug nachfolgender Code-Zeilen, d.h., dass beim Einziehen einer Zeile die nachfolgenden genauso weit eingezogen werden, bis Sie etwas anderes angeben.
Den VBE individuell anpassen
303
Die AUTOMATISCHE SYNTAXÜBERPRÜFUNG legt fest, ob Access bei jeder Betätigung der Taste (¢) nach der Eingabe einer Code-Zeile die Syntax prüft. Viele Entwickler halten diese Option für ein Ärgernis. Es kommt nämlich nicht selten vor, dass man bei der Eingabe einer Code-Zeile einen Tippfehler in einer vorhergehenden Zeile bemerkt. Wenn man dann die angefangene Zeile verlässt, um den Fehler zu korrigieren, bevor man ihn vergessen hat, bekommt man eine Meldung über falsche Syntax. Die Option VARIABLENDEKLARATION ERFORDERLICH ist unverzichtbar. Wenn sie aktiv ist, müssen alle Variablen vor Gebrauch deklariert werden, denn sie fügt die Zeile Option Explicit in den Abschnitt DEKLARATIONEN aller Module ein. Damit werden Sie gezwungen, Variablen zu deklarieren. Dadurch werden viele harmlose Tippfehler schon vom Compiler und nicht erst zur Laufzeit von den Benutzern entdeckt. Mit der Option ELEMENTE AUTOMATISCH AUFLISTEN legen Sie fest, ob die Merkmale EIGENSCHAFTEN/METHODEN ANZEIGEN und KONSTANTEN ANZEIGEN bei der Eingabe von Code im Code-Fenster automatisch aufgerufen werden, welche Ihnen durch Bereitstellen einer gültigen Liste von Eigenschaften, Methoden und Konstanten bei der Programmierarbeit helfen. Weitere Informationen dazu finden Sie in Kapitel 8. Die Option AUTOMATISCHE QUICKINFO bestimmt, ob die Syntax einer Prozedur oder Methode automatisch angezeigt wird. Wenn sie aktiv ist, werden die entsprechenden Informationen eingeblendet, sobald Sie einen Prozedur- oder Methodennamen eingeben, auf den ein Leerzeichen, ein Punkt oder eine öffnende Klammer folgt. Das Merkmal AUTOMATISCHE DATEN-TIPS zeigt beim Testen den aktuellen Wert eines ausgewählten Wertes an, wenn Sie im Unterbrechungsmodus den Mauszeiger auf die Variable setzen. Diese Funktion wird in Kapitel 13 näher erläutert.
7.13.2
Farbe, Schriftarten und -größe des Programm-Codes: Die Registerkarte Editor-Format
In Access 2000 lassen sich Farbe, Schriftart und -größe des Programm-Codes innerhalb der Programmierumgebung anpassen. Außerdem können Sie Vorder- und Hintergrundfarbe für Text im Code-Fenster, ausgewählten Text, Syntaxfehlermeldungen, Kommentare, Schlüsselwörter usw. angeben. Der Text im Code-Fenster lässt sich in einer beliebigen Windows-Schriftart in beliebiger Größe darstellen, aber damit er besser lesbar ist, sollten Sie die Schriftart FixedSys wählen.
7.13.3
Allgemeine Optionen: Die Registerkarte Allgemein
Die Registerkarte ALLGEMEIN fasst verschiedene Optionen zusammen, die das Verhalten der Entwicklungsumgebung beeinflussen. Die Option RASTER ANZEIGEN legt beispielsweise fest, ob ein Raster für Formulare angezeigt wird; die RASTEREINHEITEN
304
Kapitel 7: VBA: Eine Einführung
bestimmen den Abstand der Rasterlinien. Die weiteren Optionen auf dieser Registerkarte finden Sie in Kapitel 24.
7.13.4
Verankerungsoptionen: Die Registerkarte Verankern
Auf dieser Registerkarte können Sie angeben, ob sich die Fenster innerhalb des VBE koppeln lassen, d.h. ob sich ein Fenster an einer Seite eines anderen andockbaren Fensters »befestigen« lässt. Wenn das Fenster an eine beliebige Stelle verschoben und dort abgelegt werden kann, ist es nicht koppelbar. Folgende Fenster lassen sich koppeln: das Direktfenster, das Überwachungsfenster, das Projektfenster, das Eigenschaftenfenster und der Objektkatalog. Alle hier genannten Anpassungsoptionen gelten für die gesamte Access-Umgebung, d.h. sie beeinflussen alle Datenbanken.
7.13.5
Für die Praxis
Erforderliche Ereignisroutinen, benutzerdefinierte Funktionen, und Unterroutinen für das Zeit- und Abrechnungssystem In diesem Beispiel, das Sie in der Beispieldatenbank CHAP7.MDB finden, werden ein Formular, eine Abfrage und ein Bericht verwendet, um Kriterien zu ermitteln und dann über den Client eine Vorschau über Absatzinformationen für einen bestimmten Datumsbereich zu geben. Der Bericht rptClientInformationByProject basiert auf einer Abfrage namens qryBillingDetailByClient, welche Informationen aus einem Formular mit dem Titel frmPrintClientBilling benötigt. Dieses Formular, das Sie in Abbildung 7.28 sehen, muss geöffnet sein, damit der Vorgang erfolgreich ausgeführt wird, weil die Kriterien für die Abfrage von dort geholt werden. Der Code für die beiden Befehlsschaltflächen, der im Formular frmPrintClientBilling steht, sieht folgendermaßen aus: Sub cmdRunReport_Click() If IsNull(Me.txtStartDate) Or _ IsNull(Me.txtEndDate) Then MsgBox "Both the Start Date and End Date Must Be Filled In" Else Call RunReport("rptClientInformationByProject") End If End Sub
Den VBE individuell anpassen
305
Sub cmdClose_Click() DoCmd.Close End Sub
Abbildung 7.28: Das Formular Berichtskriterien, das die notwendigen Informationen für die dem Bericht über Abrechnungsdetails zu Grunde liegende Abfrage anfordert
Die erste Routine wertet die beiden Textfelder aus, um sicherzustellen, dass sie ausgefüllt sind. Wenn eines davon den Wert Null enthält, wird eine Meldung angezeigt, während sonst die benutzerdefinierte Routine RunReport ausgeführt wird. Die zweite Routine schließt lediglich das Formular. Die Unterroutine RunReport ist Teil eines Moduls mit dem Namen basUtils und sieht folgendermaßen aus: Sub RunReport(strReportName As String) DoCmd.OpenReport strReportName, acPreview End Sub
Die Routine übernimmt den Namen eines Berichts als Parameter und führt diesen Bericht aus. Der übrige Code, der im Bericht rptClientInfomationByClient zu finden ist, gehört zum Ereignis Open des Berichts und lautet folgendermaßen: Private Sub Report_Open(Cancel As Integer) If Not IsLoaded("frmPrintClientBilling") Then MsgBox "Print Client Billing Form Must Be Open to Run This Report", _ vbCritical, "Error!!" Cancel = True End If End Sub
306
Kapitel 7: VBA: Eine Einführung
Diese Routine ruft die benutzerdefinierte Funktion IsLoaded auf. Falls diese den Wert False zurückgibt, was bedeutet, dass das geforderte Kriterienformular nicht geöffnet ist, wird eine Meldung ausgegeben und der Bericht abgebrochen. Die Funktion IsLoaded im Modul basUtils sieht wie folgt aus: Function IsLoaded(ByVal strFormName As String) As Integer Const CLOSED = 0 Const DESIGN = 0 If SysCmd(acSysCmdGetObjectState, acForm, strFormName) <> CLOSED Then If Forms(strFormName).CurrentView <> DESIGN Then IsLoaded = True End If End If End Function
Diese Funktion ermittelt mit Hilfe der integrierten Funktion SysCmd, ob ein Formular geladen wurde. Nachdem ihr das Argument acSysCmdGetObjectState (Typ und Name des Objekts, dessen Status ausgewertet werden soll) übergeben wurde, gibt sie True oder False zurück. Dieser Wert wird mit einer benutzerdefinierten Konstanten namens CLOSED verglichen, die gleich 0 bzw. False ist. Wenn das Formular nicht geschlossen ist, wird mit Hilfe der Eigenschaft CurrentView des Formulars geprüft, ob es in der Entwurfsansicht geöffnet wurde. Wenn dies nicht zutrifft, muss es in der Formular- oder Datenblattansicht geöffnet sein und die Funktion gibt True zurück. Wenn der angegebene Datumsbereich keine Zeilen zurückgibt, erscheint im Bericht die Meldung #Error, die sich mit Hilfe des Ereignisses NoDate eines Berichts korrigieren lässt. Dieses Ereignis wird in Kapitel 10 erläutert.
Objekte, Eigenschaften, Methoden und Ereignisse
Kapitel
Hier lesen Sie:
Das Objektmodell von Access Objekte, Eigenschaften, Ereignisse und Methoden Access-Objekte mit Hilfe des Objektkatalogs kennen lernen Eigenschaften und Methoden leicht gemacht Objektvariablen deklarieren und zuweisen Unterschiede zwischen Objekten und Auflistungen Den Typ eines Steuerelements bestimmen Spezielle Eigenschaften mit Objektbezug
8.1
Das Objektmodell von Access
Objekte sind die Bestandteile einer Datenbank. Sie umfassen Tabellen, Abfragen, Formulare, Berichte, Datenzugriffsseiten, Makros und Module, die im Datenbankfenster erscheinen. Auch die Steuerelemente (Eingabefelder, Listenfelder usw.) eines Formulars oder Berichts sind Objekte. Der Schlüssel für eine erfolgreiche Programmierung liegt in Ihrer Fähigkeit, Datenbankobjekte mit Hilfe von VBA-Code während der Ausführung zu manipulieren. Außerdem ist es sehr nützlich, wenn Sie in der Lage sind, Anwendungsobjekte während der Ausführung hinzuzufügen, zu verändern oder zu entfernen. Die Beispiele dieses Kapitels finden Sie in der Datenbank Chap8Ex auf der beiliegenden CD-ROM.
308
8.1.1
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
Das Application-Objekt
Die Access-Hilfe gibt einen Überblick über den Aufbau des Objektmodells von Access. An der Spitze dieses Modells befindet sich das Application-Objekt, welches sich auf die aktive Access-Anwendung bezieht. Es enthält alle weiteren AccessObjekte und -Auflistungen, einschließlich der Auflistungen Forms, Reports, DataAccessPages und Modules sowie der Objekte CurrentData, CurrentProject, CodeProject, CodeData, Screen und DoCmd. Mit dem Application-Objekt können Sie die Eigenschaften eines Befehls verändern oder Access-Befehle selbst ausführen. So können Sie zum Beispiel festlegen, ob die integrierten Menüleisten von Access während der Ausführung der Anwendung zur Verfügung stehen sollen oder nicht. Das Objektmodell finden Sie in der Hilfe von Access 2000 unter dem Thema INFORMATIONEN ZUR PROGRAMMIERUNG/MS ACCESS VISUAL BASICSPRACHVERZEICHNIS.
8.1.2
Die Forms-Auflistung
Die Forms-Auflistung enthält alle zur Zeit geöffneten Formulare der Datenbank. Mit ihrer Hilfe können Sie eine Aktion wie zum Beispiel das Verändern der Farbe für jedes geöffnete Formular durchführen. Die Forms-Auflistung ist nicht das gleiche wie die Liste aller Formulare einer Datenbank. Diese Liste ist Bestandteil des Objekts CurrentProject, welches später in diesem Kapitel erklärt wird. Der folgende Code durchsucht die Forms-Auflistung und gibt den Namen jedes Formulars aus. Er ist im Modul basApplicationObject in der Datenbank Chap8Ex zu finden. Zu Beginn wird eine Variable für das Formularobjekt eingerichtet. Anschließend wird mit dem Konstrukt For Each ... Next jedes Formular der Forms-Auflistung herausgesucht (der Auflistung der geöffneten Formulare) und dessen Name ausgegeben. Öffnen Sie ein neues Formular, bevor Sie den Code ausführen. Führen Sie anschließend den Code aus und werfen Sie einen Blick in das DIREKTFENSTER. Schließen Sie einen Teil der Formulare und führen Sie den Code erneut aus. Die im DIREKTFENSTER angezeigte Liste der Formulare sollte jetzt anders aussehen. Das DIREKTFENSTER und dessen Verwendung werden in Kapitel 13 behandelt.
Das Objektmodell von Access
309
Sub IterateOpenForms() Dim frm As Form For Each frm in Forms Debug.Print frm.Name Next frm End Sub
Beachten Sie, dass Sie sich nicht auf Application.Forms beziehen müssen. Wenn Sie VBA-Code für Access schreiben, wird immer das Application-Objekt vorausgesetzt.
8.1.3
Die Reports-Auflistung
Wie die Forms-Auflistung alle gerade geöffneten Formulare enthält, so enthält die Reports-Auflistung dementsprechend alle zur Zeit geöffneten Berichte. Mit Hilfe der Reports-Auflistung können Sie mit jedem geöffneten Bericht eine Aktion durchführen. Der folgende Code durchsucht die Reports-Auflistung und gibt den Namen jedes Berichts an. Er ist im Modul basApplicationObject zu finden. Zu Beginn wird eine Variable für das Berichtsobjekt eingerichtet. Anschließend wird mit Hilfe des Konstrukts For Each ... Next jeder Bericht der Reports-Auflistung herausgesucht (der Auflistung der geöffneten Berichte) und dessen Name ausgegeben. Sub IterateOpenReports() Dim rpt As Report For Each rpt in Reports Debug.Print rpt.Name Next rpt End Sub
8.1.4
Die DataAccessPages-Auflistung
So wie die Forms-Auflistung alle gerade geöffneten Formulare und die Reports-Auflistung alle zurzeit geöffneten Berichte enthält, umfasst die DataAccessPages-Auflistung alle aktuell geöffneten Datenzugriffsseiten. Mit Hilfe der DataAccessPages-Auflistung können Sie eine Aktion mit jeder geöffneten Datenzugriffsseite durchführen.
8.1.5
Die Modules-Auflistung
Die Modules-Auflistung enthält alle geöffneten Standard- und Klassenmodule, wobei es keine Rolle spielt, ob sie kompiliert wurden oder Code enthalten, der gerade ausgeführt wird.
310
8.1.6
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
Das CurrentProject-Objekt
Das CurrentProject-Objekt gibt einen Verweis auf das aktuelle Projekt zurück. Es enthält Eigenschaften wie Name, Path und Connection und umfasst die folgenden Auflistungen: AllDataAccessPages, AllForms, AllMacros, AllModules und AllReports. Mit diesen Auflistungen können alle in der Datenbank gespeicherten Datenzugriffsseiten, Formulare, Makros, Module und Berichte ermittelt werden. Sie unterscheiden sich von den Auflistungen DataAccessPage, Forms, Macros, Modules und Reports insofern, als sie sich auf alle Objekte des aktuellen Projekts beziehen und nicht nur auf die gerade geöffneten. Der folgende Code sucht die Eigenschaften Name und Path des aktuellen Projekts heraus. Er verwendet das Konstrukt With ... End With, um die Eigenschaften des Objekts CurrentProject zu ermitteln. Sub CurrentProjectObject() With CurrentProject Debug.Print .Name Debug.Print .Path End With End Sub
Wie bereits erwähnt wurde, enthält das CurrentProject-Objekt Auflistungen, die sich auf verschiedene Objekte Ihrer Datenbank beziehen. Der folgende Code durchsucht die AllForms-Auflistung von CurrentProject und gibt den Namen jedes Formulars aus. SubIterateAllForms() Dim vnt As Variant With CurrentProject For Each vnt In .AllForms Debug.Print vnt.Name Next vnt End With End Sub
Die AllForms-Auflistung des CurrentProject-Objekts kann leicht mit der FormsAuflistung verwechselt werden. Die AllForms-Auflistung des CurrentProjectObjekts umfasst alle gespeicherten Formulare, die Bestandteil der Datenbank sind. Die Forms-Auflistung enthält hingegen nur die Formulare, die zurzeit im Arbeitsspeicher ausgeführt werden. Möchten Sie eine Liste aller Formulare einer Datenbank anzeigen lassen, müssen Sie die AllForms-Auflistung des CurrentProject-Objekts benutzen. Möchten Sie hingegen die Überschrift aller geöffneten Formulare ändern, dann müssen Sie die FormsAuflistung verwenden.
Das Objektmodell von Access
8.1.7
311
Das CurrentData-Objekt
Während Sie mit dem CurrentProject-Objekt auf die Anwendungskomponenten in Ihrer Datenbank zugreifen und diese verändern können, dient das CurrentDataObjekt zum Verweis auf die Datenelemente der Datenbank. Das CurrentData-Objekt enthält fünf Auflistungen: AllDatabaseDiagramms, AllQueries, AllStoredProcedures, AllTables und AllViews. Mit Hilfe dieser Auflistungen werden alle Diagramme, Abfragen, gespeicherten Prozeduren und Ansichten der Datenbank herausgesucht und verändert. Der folgende Code durchsucht die Auflistung AllTables des CurrentData-Objekts und gibt den Namen jeder Tabelle der Datenbank aus. SubIterateAllTables() Dim vnt As Variant With CurrentData For Each vnt In .AllTables Debug.Print vnt.Name Next vnt End With End Sub
8.1.8
Das CodeProject-Objekt
Das CodeProject-Objekt wird verwendet, wenn die Datenbank Code-Bibliotheken einrichtet. Es ist mit dem Objekt CurrentProject vergleichbar, verweist jedoch auf die in der Bibliotheksdatenbank gespeicherten Eigenschaften und Auflistungen. Bibliotheksdatenbanken werden in Kapitel 29 behandelt.
8.1.9
Das CodeData-Objekt
Während das CodeProject-Objekt auf die in der Bibliotheksdatenbank gespeicherten Anwendungsobjekte verweist, dient das CodeData-Objekt zum Verweis auf die Datenelemente einer Code-Bibliothek. Hierzu gehören die Diagramme, Abfragen, gespeicherten Prozeduren, Tabellen und Ansichten der Datenbank, die innerhalb der Bibliotheken gespeichert sind.
8.1.10
Das Screen-Objekt
Mit Hilfe des Screen-Objekts können Sie sich auf das Formular, das Datenblatt, die Datenzugriffsseite oder das Steuerelement beziehen, welches den Fokus hat. Das Screen-Objekt umfasst Eigenschaften, die sich auf das aktive Formular, den aktiven Bericht, das aktive oder das vorherige Steuerelement beziehen. Über diese Eigenschaften können Sie sowohl das gerade aktive Formular, den Bericht oder das Steuerelement auch das vor dem aktuellen Steuerelement aktive Steuerelement bearbeiten.
312
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
Falls Sie versuchen, sich auf das Screen-Objekt zu beziehen, wenn kein Formular oder Bericht aktiv ist, führt dies zu einem Laufzeitfehler.
8.1.11
Das DoCmd-Objekt
Das DoCmd-Objekt dient der Ausführung von Makrobefehlen oder Access-Aktionen aus VBA-Codes heraus. Der Name der Methode wird nach einem Punkt angegeben. Die meisten Methoden (z.B. die Methode OpenQuery) benötigen weitere Argumente. Mit der OpenQuery-Methode werden Access-Abfragen ausgeführt. Dabei werden folgende Argumente übergeben:
Abfragename – Der Name der auszuführenden Abfrage Ansicht – Datenblatt, Entwurf oder Vorschau Datenmodus – Hinzufügen, Bearbeitung oder Schreibgeschützt Es folgt ein Beispiel für die Methode OpenQuery des DoCmd-Objekts: DoCmd.OpenQuery "qryCustomers", acNormal, acReadOnly
Die Methode OpenQuery wird vom DoCmd-Objekt ausgeführt. Das erste Argument (der Abfragename) lautet "qryCustomer". Dies ist der Name der als Datenblattansicht (und nicht als Entwurf oder Vorschau) geöffneten Abfrage. Die Abfrage wird im schreibgeschützten Modus geöffnet, was bedeutet, dass die angezeigten Daten nicht verändert werden können.
8.2
Objekte, Eigenschaften, Ereignisse und Methoden
Vielen Benutzern ist das Konzept der Objekte, Eigenschaften und Ereignisse unverständlich, insbesondere dann, wenn sie bisher mit einer Sprache gearbeitet haben, die auf Prozeduren basiert. Wenn Sie ein produktiver und erfolgreicher Access-Programmierer werden wollen, müssen Sie die Access-Objekte, die Eigenschaften und die Ereignisse, auf die jedes Objekt reagieren kann, genau kennen.
8.2.1
Was genau sind Objekte?
Wie bereits in diesem Kapitel erwähnt wurde, gehören alle Bestandteile Ihrer Datenbank zu den »Objekten«. Sie umfassen die Tabellen, Abfragen, Formulare, Berichte, Datenzugriffsseiten, Makros und Module sowie die Komponenten dieser Objekte. Ein Tabellenobjekt enthält zum Beispiel Feld- und Indexobjekte, während ein Formular verschiedene Steuerelemente umfasst (Textfelder, Kombinationsfelder, Listenfelder usw.). Jedes Objekt einer Datenbank besitzt bestimmte Eigenschaften, die
Objekte, Eigenschaften, Ereignisse und Methoden
313
seine Erscheinung und sein Verhalten bestimmen. Jedes Objekt verfügt außerdem über spezielle Methoden, wobei es sich um die Aktionen handelt, die mit ihm durchgeführt werden können.
8.2.2
Was genau sind Eigenschaften?
Eine »Eigenschaft« ist ein Attribut eines Objekts. Jedes Objekt verfügt über mehrere Eigenschaften. Häufig teilen unterschiedliche Objektarten die gleichen Eigenschaften. In anderen Fällen beziehen sich die Objekteigenschaften auf ein spezielles Objekt. Formulare, Kombinationsfelder und Textfelder besitzen beispielsweise alle die Eigenschaft Width. Ein Formular weist außerdem die Eigenschaft RecordSource auf, über die Kombinations- und Textfelder nicht verfügen. Die meisten Eigenschaften können während des Entwurfs festgelegt und bei der Ausführung verändert werden. Bei einigen ist dies jedoch nicht möglich und auf andere kann nicht während des Entwurfs zugegriffen werden (ihre Änderung ist ausschließlich bei der Ausführung möglich). Die integrierte Hilfe von Access liefert zu jeder Eigenschaft folgende Hinweise:
Sie können die Eigenschaft über Eigenschaftenfenster, Makros oder Visual Basic setzen.
Sie können die Eigenschaft nur in der Entwurfsansicht setzen. Sie können über Visual Basic oder ein Makro auf diese Eigenschaft zugreifen. Jede dieser Beschreibungen gibt an, wann eine Eigenschaft verändert werden kann. Als Entwickler legen Sie die Werte vieler Objekteigenschaften während des Entwurfs fest. Dies sind die so genannten Starteigenschaften für die Ausführung. Weite Teile des VBA-Codes verändern diese Werte während der Ausführung, wenn auf unterschiedliche Situationen reagiert wird. Ein Textfeld besitzt zum Beispiel die Eigenschaft Visible. Bezahlt eine Kunde bar, möchten Sie möglicherweise das Textfeld mit der Kreditkartennummer gar nicht anzeigen lassen. Bezahlt er per Kreditkarte, dann können Sie der Eigenschaft Visible des Textfelds für die Kreditkarte den Wert True zuweisen. Dies ist nur eine von vielen Möglichkeiten, wie Sie die Eigenschaften eines Objekts während der Ausführung verändern können, um auf ein eingetretenes Ereignis oder eine durchgeführte Aktion zu reagieren. Sie werden sich fragen, wie Sie alle mit einem bestimmten Objekt verbundenen Eigenschaften setzen können (sowohl die, die während des Entwurfs festgelegt werden können, als auch diejenigen, die während der Ausführung verändert werden). Sie können sich selbstverständlich die Eigenschaften, die während des Entwurfs festgelegt werden, anzeigen lassen, wenn Sie das Objekt markieren. Alle Eigenschaften eines Objekts können Sie sich einfach durch Drücken der Taste (F1) für die Hilfe anzeigen lassen. Klicken Sie auf die Registerkarte INDEX und geben Sie den Namen des Objekts ein, dessen Eigenschaften Sie anzeigen lassen möchten. In Abbildung 8.1 wurde im Textfeld das Wort Combo eingegeben. Klicken Sie dann auf die Schaltflä-
314
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
che SUCHEN. Beachten Sie am Ende der Liste den Eintrag für die Eigenschaften des Kombinationsfelds. Wenn Sie auf diesen Eintrag klicken, werden Ihnen in der rechten Hälfte des Fensters Informationen zu den Eigenschaften des Kombinationsfelds angezeigt (siehe Abbildung 8.2). Möchten Sie mehr über eine bestimmte Eigenschaft erfahren, dann klicken Sie diese einfach an. In Abbildung 8.3 wurde die Eigenschaft Column gewählt. Sie können auch den Objektkatalog verwenden, um sich alle Eigenschaften eines Objekts schnell und einfach anzeigen zu lassen.
Abbildung 8.1: Das Dialogfeld der Hilfe
8.2.3
Was genau sind Ereignisse?
Das Betriebssystem Windows wird über Ereignisse gesteuert, was bedeutet, dass das Betriebssystem auf viele Ereignisse reagiert, die durch Benutzeraktionen und das Betriebssystem selbst ausgelöst werden. Access legt durch sein Objektmodell viele dieser Ereignisse offen. Ein »Ereignis« einer Access-Anwendung ist etwas, worauf Ihre Anwendung reagieren kann. Zu den Ereignissen zählen Mausbewegungen, Veränderungen der Daten, das Öffnen eines Formulars, das Hinzufügen eines Datensatzes und vieles andere mehr. Benutzer können genau wie Anwendungen Ereignisse auslösen. Sie müssen festlegen, was als Antwort auf die Ereignisse geschehen soll. Sie können mit Hilfe von Makros oder mit VBA-Code auf die Ereignisse reagieren. Jedes Access-Objekt reagiert auf unterschiedliche Ereignisse. Führen Sie die folgenden Schritte durch, um alle mit einem bestimmten Objekt verknüpften Ereignisse anzeigen zu lassen: 1. Wählen Sie das Objekt aus (z.B. ein Textfeld). 2. Öffnen Sie das Fenster EIGENSCHAFTEN.
315
Objekte, Eigenschaften, Ereignisse und Methoden
Abbildung 8.2: Eine Liste der Eigenschaften des Kombinationsfeldes
Abbildung 8.3: Die Hilfe zu der Column-Eigenschaft eines Kombinationsfeldes
3. Klicken Sie auf die Registerkarte EREIGNIS (siehe Abbildung 8.4). 4. Durchsuchen Sie die Liste der verfügbaren Ereignisse.
316
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
Abbildung 8.4: Die Liste der mit einem Textfeld verknüpften Ereignisse
8.2.4
Was genau sind Methoden?
»Methoden« sind Aktionen, die Sie für Objekte aus Ihrer Datenbank durchführen können. Die unterschiedlichen Objekte verfügen nicht nur über Eigenschaften und Ereignisse, sondern ihnen sind auch verschiedene Methoden zugeordnet. Eine Methode ist mit einer Funktion oder Subroutine vergleichbar, mit dem Unterschied, dass sich die Methode nur auf ein bestimmtes Objekt bezieht. Wenn Sie in der Online-Hilfe nach dem Schlüsselwort Methode suchen, dann finden Sie im Listenfeld THEMA AUSWÄHLEN einen Themenliste (siehe Abbildung 8.6). Falls Sie aus der Themenliste den Begriff Verzeichnis der Methoden auswählen, erscheint die zugehörige Hilfeseite. Die Methoden sind nach den Objekten gegliedert. Wird ein bestimmtes Objekt markiert, erhalten Sie Hilfe zu diesem speziellen Objekt. Sie können anschließend auf METHODEN klicken, um das Dialogfeld THEMEN GEFUNDEN mit einer Liste der Methoden dieses Objekts zu öffnen (siehe Abbildung 8.7). Wenn Sie bei einer Methodenbeschreibung auf die Verknüpfung BETRIFFT klicken, erhalten Sie eine Liste aller Objekte, auf die die gewählte Methode anwendbar ist. Klicken Sie auf den Eintrag BEISPIEL, wird Ihnen ein Beispiel mit Code für die Implementierung der gewählten Methode angezeigt.
8.3
Access-Objekte mit Hilfe des Objektkatalogs kennen lernen
Der Objektkatalog ist ein leistungsfähiges Werkzeug, mit dessen Hilfe Sie etwas über die Objekte und ihren Einsatz lernen können, die Bestandteil von Access 2000 und Microsoft Windows sind. Der Objektkatalog zeigt Informationen zu Microsoft Access-Objekten und zu anderen Objekten an. Er hilft Ihnen beim Programmieren und führt alle Eigenschaften sowie die damit verbundenen Methoden eines bestimmten Objekts auf.
317
Access-Objekte mit Hilfe des Objektkatalogs kennen lernen
Abbildung 8.5: Wie Sie Hilfe zu den Methoden erhalten
Abbildung 8.6: Der VerzeichnisEintrag der Methoden bietet Hilfen zu allen neuen Methoden und Auflistungen
Access-Objekte sind sehr komplex. Sie verfügen über viele Eigenschaften und Methoden. Der Objektkatalog erleichtert Ihnen das Verständnis der Objekte, Eigenschaften und Methoden. Er unterstützt Sie bei der Verwendung dieser Elemente, indem er Folgendes macht:
318
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
Abbildung 8.7: Das Dialogfeld Themen gefunden zeigt alle mit dem Formularobjekt verknüpften Methoden an
die verfügbaren Objekttypen anzeigen Ihnen ein schnelles Wechseln zwischen den Prozeduren der Anwendungen erlauben
die mit einem bestimmten Objekt verknüpften Eigenschaften und Methoden anzeigen
Code finden und in Ihre Anwendung einfügen
8.3.1
Den Objektkatalog verwenden
Der Objektkatalog kann einfach aus dem Editor von Visual Basic aufgerufen werden. Sie können auf die Schaltfläche OBJEKTKATALOG in der Symbolleiste klicken, die Taste (F2) drücken oder die Menüoption ANSICHT|OBJEKTKATALOG wählen. Abbildung 8.8 zeigt des Dialogfeld des Objektkatalogs Der Objektkatalog zeigt zwei Informationsebenen der gewählten Bibliothek oder Datenbank an. Wenn Sie die Datenbank Chap8Ex geöffnet haben und im aufklappbaren Listenfeld PROJEKT/BIBLIOTHEK den Eintrag Chap8Ex.MDB wählen, sieht Ihr Bildschirm ähnlich wie in Abbildung 8.8 aus. Das Listenfeld KLASSEN zeigt alle Module einschließlich der Formular- und Berichtsmodule an, während im Listenfeld ELEMENT VON alle im gewählten Modul definierten Prozeduren erscheinen. Beachten Sie das Modul basUtils, welches Bestandteil der Datenbank Chap8Ex.MDB ist. Wenn Sie in das Listenfeld auf der rechten Seite schauen, können Sie die Funktionen des
Access-Objekte mit Hilfe des Objektkatalogs kennen lernen
319
Abbildung 8.8: Das Dialogfeld des Objektkatalogs mit einem ausgewählten Datenbankobjekt
Moduls basUtils sehen. Sie können jedes Formular- und Berichtsmodul in dem Listenfeld auf der linken Seite markieren und so alle damit verbundenen Methoden und Eigenschaften im Listenfeld auf der rechten Seite anzeigen lassen. Sie können im Listenfeld PROJEKT/BIBLIOTHEK eine andere Objektbibliothek wählen (sofern auf eine solche verwiesen wird). Das Listenfeld KLASSEN zeigt die für die gewählte Bibliothek oder Datenbank definierten Methoden, Eigenschaften und Datenelemente an (siehe Abbildung 8.9). Im Kombinationsfeld BIBLIOTHEK wurde der Eintrag Access ausgewählt, so dass das Listenfeld auf der linken Seite alle Klassen von Access 2000 anzeigt. Das Listenfeld auf der rechten Seite zeigt alle Elemente des gewählten Objekts, bei dem es sich in diesem Fall um das Application-Objekt handelt. Wenn Sie sich im aufklappbaren Listenfeld BIBLIOTHEK auf andere Bibliothekstypen beziehen, können Sie auch weitere Bibliotheken hinzufügen. Diese Möglichkeit wird in Kapitel 26 behandelt.
8.3.2
Code-Vorlagen in eine Prozedur einfügen
Haben Sie die gewünschte Methode oder Eigenschaft gefunden, besteht die Möglichkeit, diese in Ihre Anwendung einzufügen. Heben Sie die Markierung der Methode oder Eigenschaft nicht auf und klicken Sie im Objektkatalog einfach auf die Schaltfläche IN ZWISCHENABLAGE KOPIEREN. Anschließend fügen Sie diese in das entsprechende Modul ein. Benötigen Sie weitere Informationen zu einer bestimmten Methode oder zu einer Eigenschaft, klicken Sie im Objektkatalog auf die Schaltfläche HILFE oder drücken die Taste (F1).
320
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
Abbildung 8.9: Im Objektkatalog die Access-2000-Bibliothek auswählen
8.4
Sich auf Objekte beziehen
Access-Objekte sind in »Auflistungen« unterteilt, bei denen es sich um Gruppen von Objekten gleichen Typs handelt. Die Forms-Auflistung ist beispielsweise eine Sammlung aller geöffneten Formulare einer Datenbank. Jedes Formular verfügt über eine Auflistung Controls, die alle Steuerelemente dieses Formulars enthält. Jedes Steuerelement ist ein Objekt, auf welches Sie sich über die Auflistung beziehen müssen, zu der es gehört. Auf ein Formular beziehen Sie sich zum Beispiel über die Forms-Auflistung. VBA bietet Ihnen drei Möglichkeiten, sich auf ein Objekt zu beziehen. Möchten Sie sich beispielsweise auf das Formular frmProjects beziehen, können Sie unter den drei folgenden Varianten wählen:
Forms!frmProjects Forms("frmProjects") Forms(0) Falls Sie die Variante Forms(0) wählen, muss es sich bei frmProjects um das erste geöffnete Formular handeln. Sie müssen dabei allerdings berücksichtigen, dass zwar jedem geladenen Formular eine Elementnummer zugewiesen wird, diese sich jedoch verändern kann, wenn während der Ausführung weitere Formulare geladen oder entladen werden. Das dritte geladene Formular kann zum Beispiel ursprünglich als Element Zwei bezeichnet worden sein. Wird das zweite Formular entladen, erhält das dritte die Nummer Eins. Sie können sich also nicht auf eine dem Formular zugewiesene Elementnummer verlassen, da diese Nummern sich verändern.
Eigenschaften und Methoden leicht gemacht
321
Sie müssen sich auf ein Steuerelement eines Formulars zuerst über die Forms-Auflistung und dann über das spezielle Formular beziehen. Der Verweis sieht wie folgt aus: Forms!frmProjects.txtClientsID
In diesem Beispiel gibt Forms den Namen der Auflistung, frmProjects den Namen des speziellen Formulars und txtClientsID den Namen eines Steuerelements des Formulars frmProjects an. Dieser Code ist in dem Code-Modul von frmProjects zu finden. Er könnte ungefähr so aussehen: Me.txtClientID
ME bezieht sich auf das derzeitige Formular oder den aktuellen Bericht. Dies ist ein
sehr allgemeiner Ansatz, da der Code in jedes Formular kopiert werden kann, welches über ein txtClientID-Steuerelement verfügt. Er würde auch dann korrekt ausgeführt. Der Verweis auf ein Steuerelement eines Berichts ist dem Verweis auf ein Steuerelement eines Formulars sehr ähnlich. Ein Beispiel: Reports!rptTimeSheet.txtHoursBilled
Dieses Beispiel bezieht sich auf das Textfeld txtHoursBilled des Berichts rptTimeSheeet, der Bestandteil der Reports-Auflistung ist. Wenn Sie wissen, wie Sie sich auf ein Objekt beziehen müssen, dann können Sie Code verfassen, der die Eigenschaften verändert und die Methoden ausführt.
8.5
Eigenschaften und Methoden leicht gemacht
Um die Eigenschaften eines Objekts zu verändern und dessen Methoden auszuführen, müssen Sie sich auf das Objekt beziehen und anschließend die entsprechende Eigenschaft oder Methode angeben. Zum Beispiel: Forms!frmHello.cmdHello.Visible = False
Diese Code-Zeile bezieht sich auf die Eigenschaft Visible des Steuerelements cmdHello, das sich im Formular frmHello der Forms-Auflistung befindet. Beachten Sie, dass Sie den Objektnamen frmHello als der Forms-Auflistung zugehörig erkennen müssen. Möchten Sie die Caption-Eigenschaft von frmHello dahingehend ändern, dass die Überschrift »Hello World« lautet, dann müssen Sie den folgenden Code verwenden: Forms!frmHello.Caption = "Hello World"
322
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
Manchmal ist es nicht einfach festzustellen, ob es sich um eine Eigenschaft oder eine Methode eines Objekts handelt. Es gibt aber eine Reihe einfacher Möglichkeiten, dies zu ermitteln. Eine Eigenschaft wird immer in einer Art Ausdruck verwendet. Sie können eine Eigenschaft beispielsweise irgendeinem Wert gleichsetzen: Forms!frmClients.txtAdress.Visible = False In diesem Fall stellen Sie den Wert der Eigenschaft Visible des Textfelds txtAdress aus dem Formular frmClients vom Wert True auf False um. Sie können den Wert einer Eigenschaft auch suchen und einer Variablen zuweisen: strFirstName = Forms!frmClients.txtFirstName.Value Außerdem können Sie den Wert einer Eigenschaft auch in einem Ausdruck verwenden: MsgBox Form!frmClients.txtFirstName,Value Der Grundgedanke hierbei ist, dass eine Eigenschaft immer irgendwo in einem Ausdruck verwendet wird. Sie kann mit etwas gleichgesetzt werden, als Wert für etwas anderes fungieren oder in einer anderen Form in einem Ausdruck zum Einsatz kommen. Eine Methode ist dagegen eine mit einem Objekt durchgeführte Aktion. Die Syntax für eine Methode lautet Objekt.Methode. Eine Methode kann nicht mit etwas anderem gleichgesetzt werden. Häufig erstellen Sie jedoch eine Objektvariable und weisen dieser etwas zu, indem Sie eine Methode aufrufen. Eine Methode sieht wie folgt aus: Forms!frmHello.txtHelloWorld.SetFocus Hier wird die Methode SetFocus für das Textfeld txtHelloWorld ausgeführt. Eine Methode, die eine Objektvariable zurückgibt, sieht folgendermaßen aus: Dim cbr As CommandBar Set cbr = CommandBars.Add("MyNewCommandBar") In diesem Beispiel wird die Methode Add der CommandBars-Auflistung verwendet, um der Objektvariablen cbr des Objekts CommandBar einen Wert zuzuweisen. Weitere Informationen finden Sie im Abschnitt »Objektvariablen deklarieren und zuweisen« weiter hinten in diesem Kapitel. Viele Benutzer sind unsicher, wann ein Ausrufungszeichen (!) und wann ein Punkt gesetzt wird. Sie können ein Ausrufungszeichen immer dann verwenden, wenn Sie ein Objekt von der dazugehörigen Auflistung trennen, wie in den folgenden zwei Beispielen: Forms!frmClients
Forms!frmClients!txtClientID Im ersten Beispiel ist frmClients Bestandteil der Forms-Auflistung, während im zweiten txtClientID zur Auflistung Controls des Formulars frmClient gehört.
Objektvariablen deklarieren und zuweisen
323
In den meisten Fällen kann ein Punkt für die Trennung von Objekt und Auflistung verwendet werden. Das kommt daher, weil es sich beim Ausdruck Me!txtClientID eigentlich um eine Abkürzung für den vollständigen Verweis Me.Controls!txtClientID handelt. Weil Controls die standardmäßige Auflistung eines Formulars ist, können Sie in der Anweisung Controls weglassen und zu Me.txtClientID abkürzen. Der Vorteil der Verwendung eines Punkts anstelle eines Ausrufungszeichens liegt darin, dass Ihnen Intellisense-Technologie zur Verfügung steht. Um dies zu testen, erstellen Sie ein Formular und fügen ein Steuerelement mit dem Namen txtFirstName hinzu. Gehen Sie im Code hinter das Formular und geben Sie Me!. ein. Sie werden bemerken, dass Intellisense nicht aufgerufen wird. Geben Sie als nächstes Me. ein. In diesem Fall wird Intellisense aufgerufen. Intellisense erleichtert die Entwicklungsarbeit durch Bereitstellung eines Listenfelds mit geeigneten gültigen Eigenschaften, Methoden, Konstanten usw. Der Punkt dient nicht nur zur Trennung eines Objekts von dessen Auflistung, sondern auch zur Trennung eines Objektformulars von einer Eigenschaft oder Methode. Der Code sieht folgendermaßen aus: Forms!frmClients.RecordSource = "tblClients" Forms!frmClients!txtClientID.Visible = False
Im ersten Beispiel wird der Eigenschaft RecordSource von frmClients der Wert tblClients zugewiesen, während im zweiten Fall die Eigenschaft Visible des Textfelds txtClientID des Formulars frmClients den Wert False erhält.
8.5.1
Standardeigenschaften
Jedes Objekt verfügt über eine Standardeigenschaft. Wenn Sie mit dieser arbeiten, müssen Sie sich im Code nicht explizit darauf beziehen. Betrachten Sie die beiden folgenden Beispiele: Forms!frmHello.txt.Value = "Hello World" Forms!frmHello.txt = "Hello World"
Die Eigenschaft Value ist die Standardeigenschaft eines Textfelds, Sie müssen sich daher in Ihrem Code nicht explizit darauf beziehen. Allerdings erhöht es die Lesbarkeit des Codes, wenn Sie die Anweisung explizit angeben, weil ungeübte Programmierer nicht erraten müssen, welche Eigenschaft hier verändert wird.
8.6
Objektvariablen deklarieren und zuweisen
»Objektvariablen« sind Variablen, die auf ein Objekt eines bestimmten Typs verweisen, wie zum Beispiel auf Datenbanken, Datensätze, Formulare, Steuerelemente oder auch von anderen Anwendungen erstellte Objekte. Sie erlauben Ihnen, Verweisabkürzungen einzuführen und Objekte an Subroutinen und Funktionen zu übergeben.
324
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
Durch Verwendung kurzer Namen zum Verweis auf Objekte mit langen Namen können Sie Ihren Code flüssiger gestalten und optimieren, indem Sie einen direkten Zeiger auf ein bestimmtes Objekt zur Verfügung stellen. Als erstes müssen Sie eine Objektvariable deklarieren. Dann weisen Sie der Objektvariablen ein bestimmtes Objekt zu (bzw. zeigen auf es): Private Sub cmdChangeCaption_Click() Dim cmdAny As CommandButton Set cmdAny = Me!cmdHello cmdAny.Caption = "Hello" End Sub
Dieser Code erzeugt eine Objektvariable mit dem Namen cmdAny vom Typ commandButton. Mit der Set-Anweisung weisen Sie anschließend mit Hilfe des Schlüsselworts Me der CommandButton-Objektvariablen das Objekt cmdHello des aktuellen Formulars zu. Zum Schluss verändern Sie die Überschrift der Objektvariablen cmdAny. Weil eine Objektvariable einen Verweis auf das ursprüngliche Objekt darstellt, ändern Sie tatsächlich die Überschrift der Schaltfläche cmdHello.
8.6.1
Objektvariablen und herkömmliche Variablen im Vergleich
Der Unterschied zwischen Objektvariablen und herkömmlichen Variablen soll mit dem folgenden Beispiel veranschaulicht werden: Dim intVar1 As Integer Dim intVar2 As Integer intVar1 = 5 intVar2 = intVar1 intVar1 = 10 Debug.Print intVar1 ' Gibt 10 aus Debug.Print intVar2 ' Gibt 5 aus
Dieser Code verwendet ganz normale Variablen. Wenn Sie diese Variablen deklarieren, erhält jede einen eigenen Speicherplatz. Der Variablen intVar2 wird zwar ursprünglich der Wert von intVar1 zugewiesen, eine Veränderung des Wertes von intVar1 hat aber keine Auswirkungen auf intVar2. Hierin unterscheidet sich der folgende Code, in dem Objektvariablen benutzt werden: Private Sub Command5_Click() Dim ctlText As TextBox Set ctlText = Forms!frmSales!txtProductID ctlText.Text = "New Text" debug.Print Forms!frmSales!txtProductID.Text 'Druckt den neuen Text End Sub
Unterschiede zwischen Objekten und Auflistungen
325
Diese Routine erzeugt eine Objektvariable mit dem Namen ctlText vom Typ TextBox. Anschließend wird der Objektvariablen das Textfeld Forms!frmSales!txtProductID zugewiesen. In der nächsten Zeile wird die Eigenschaft Text der Objektvariablen verändert. Weil die Objektvariable eigentlich auf das Textfeld des Formulars verweist, gibt die Anweisung Debug.Print den neuen Text aus.
8.6.2
Generische und spezielle Objektvariablen
Access unterstützt die Verwendung generischer Objektvariablen für Anwendungen, Steuerelemente, Formulare und Berichte. Mit generischen Objektvariablen können Sie auf jedes Objekt dieses generischen Typs verweisen: Private Sub ChangeVisible_Click() Dim ctlAny As Control Set ctlAny = Me!txtCustomerID ctlAny.Visible = False End Sub
In diesem Beispiel kann mit ctlAny auf jedes Steuerelement verwiesen werden. Vergleichen Sie den vorangegangenen Code mit dem folgenden: Private Sub ChangeVisible_Click() Dim txtAny As TextBox Set txtAny = Me!txtCustomerID txtAny.Visible = False End Sub
In diesem Fall kann mit der Objektvariablen nur auf ein Textfeld verwiesen werden.
8.6.3
Speicherbereinigung
Wenn Sie die Arbeit mit einer Objektvariablen beendet haben, sollten Sie ihr den Wert Nothing zuweisen. Im folgenden Beispiel gibt diese Anweisung alle mit dem Objekt verbundenen Speicher- und Systemressourcen frei: Set frmNew = Nothing
8.7
Unterschiede zwischen Objekten und Auflistungen
Für viele Benutzer ist die Unterscheidung zwischen einem Objekt und einer Auflistung verwirrend. Sie müssen sich ein Objekt als Element einer Auflistung vorstellen. Bei frmHello handelt es sich beispielsweise um ein Formular, welches ein Element der Forms-Auflistung ist. cmdHello stellt eine Schaltfläche des Formulars frmHello dar und gehört zur Auflistung Controls. Manchmal müssen Sie bestimmte Objekte bearbeiten, manchmal müssen Sie aber auch eine ganze Auflistung von Objekten verändern.
326
8.7.1
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
Mit einem einzelnen Objekt umgehen
Sie haben bereits einiges über den Umgang mit einem einzelnen Objekt gelernt, wie beispielsweise das Setzen der Eigenschaft Enabled für ein Textfeld: txtCustomerID.Enabled = False
Diese Zeile betrifft nur ein Textfeld und nur eine der Eigenschaften. Wenn Sie ein einzelnes Objekt behandeln, ist es aber auch denkbar, dass Sie mehrere Eigenschaften gleichzeitig bearbeiten möchten. In diesem Fall ist es meist am effektivsten, wenn Sie das Konstrukt With ... End With benutzen, das im folgenden Abschnitt erklärt wird. With...End With: Mehrere Befehle auf ein einziges Objekt anwenden Eine Möglichkeit, mehrere Eigenschaften eines Objekts zu ändern, besteht darin, nacheinander den Wert jeder Eigenschaft zu ändern: txtcustomerID.Enabled = False txtcustomerID.SpecialEffect = 1 txtcustomerID.FontSize = 16 txtcustomerID.FontWeight = 700
Betrachten Sie im Vergleich hierzu den folgenden Code: With txtcustomerID .Enabled = False .SpecialEffect = 1 .FontSize = 16 .FontWeight = 700 End With
Dieser Code verwendet das Konstrukt With ... End With, um mehrere Eigenschaften eines Objekts festzulegen. Neben der besseren Lesbarkeit des Codes bietet diese Anweisung auch eine leichte Verbesserung der Geschwindigkeit.
8.7.2
Mit einer Objektauflistung umgehen
Eine »Auflistung« ist mit einem Objektfeld vergleichbar. Das besondere an diesem Feld ist die Tatsache, dass es von Access definiert und unterhalten wird. Für Microsoft Access ist jede Auflistung ein Objekt mit jeweils eigenen Eigenschaften und Methoden. Durch VBA wird es leichter, die Auflistungen von Access-Objekten zu bearbeiten. Sie verwenden hierfür das im folgenden Abschnitt beschriebene Konstrukt For Each...Next.
Objekte an Unterroutinen und Funktionen übergeben
327
For...Each: Denselben Befehl auf mehrere Objekte anwenden Im Abschnitt »Den Typ eines Steuerelements bestimmen« weiter hinten in diesem Kapitel erfahren Sie, wie Sie die Auflistung der Steuerelemente eines Formulars in einer Schleife durchlaufen und dabei Aktionen mit allen Schaltflächen durchführen. Dies veranschaulicht eine praktische Verwendung einer Auflistung. Im folgenden Beispiel durchläuft die Schleife alle geöffneten Formulare und verändert jeweils die Überschrift: Sub FormCaption() Dim frm As Form For Each frm in Forms frm.Caption = frm.Caption " – " CurrentUser Next frm End Sub
In dieser Routine wird mit Hilfe eines Konstrukts For Each...Next in einer Schleife jedes Formular der Forms-Auflistung bearbeitet und eine Überschrift zugewiesen, die aus der Bezeichnung des Formulars und dem Benutzernamen besteht. Beim Durchlaufen der Schleife bezieht sich der Ausdruck frm.Caption auf jedes einzelne Element der Forms-Auflistung.
8.8
Objekte an Unterroutinen und Funktionen übergeben Sie können einer Subroutine oder einer Funktion nicht nur eine Zeichenfolge oder eine Zahl, sondern auch ein Objekt übergeben. Den Code hierfür finden Sie im Modul basExamples in der Datenbank Chap8Ex:
Sub ChangeCaption(frmAny as Form) frmAny.Caption = frmAny.Caption & ": " & CurrentUser End Sub
Die Routine ChangeCaption erhält einen Verweis in Form eines Parameters. Die Überschrift des Formulars wird in dieser Prozedur so verändert, dass sie den Namen des aktuellen Benutzers enthält. Die ChangeCaption-Routine wird folgendermaßen aufgerufen: Private Sub cmdChangeCaption_Click() Call ChangeCaption(Me) End Sub
328
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
In diesem Beispiel ruft das Click-Ereignis der Schaltfläche cmdChangeCaption die Routine ChangeCaption auf, indem es einen Verweis auf das Formular sendet, in welchem sich die Schaltfläche befindet. Dieser ist Bestandteil des Formulars frmChangeCaption.
8.9
Den Typ eines Steuerelements bestimmen
Wenn Sie generischen Code schreiben, kann es notwendig sein, dass Sie den Typ eines Steuerelements bestimmen. Vielleicht möchten Sie in einer Schleife alle Steuerelemente eines Formulars durchsuchen und die Eigenschaft Enabled aller Schaltflächen umschalten. Dies tun Sie über die Eigenschaft ControlType eines Steuerelements. Es folgt ein Beispiel für die Verwendung dieser Eigenschaft (Sie finden dieses Beispiel in der Datenbank Chap8Ex.MDB im Modul basExamples.): Sub FlipEnabled(frmAny As Form, ctlAny As Control) Dim ctl As Control ' Verwenden des Konstrukts For...Each zum Durchlaufen der Controls-Auflistung ctlAny.Enabled = True ctlAny.SetFocus For Each ctl In frmAny.Controls ' Bestimmen des Steuerelementtyps If ctl.ControlType = acCommandButton Then 'Sicherstellen, dass kein Versuch unternommen wird, die_ Befehlsschaltfläche zu deaktivieren, welche diese Routine aufgerufen hat If ctl.Name <> ctlAny.Name Then ctl.Enabled = Not ctl.Enabled End If End If Next ctl End Sub
Vom Formular frmTypeOf wird die Prozedur FlipEnabled aufgerufen. Jede Schaltfläche des Formulars (ADD, EDIT, DELETE usw.) sendet das Formular und den Namen eines Steuerelements an die FlipEnabled-Routine. Das gesendete Steuerelement soll nach der Ausführung der Routine den Fokus erhalten. Im folgenden Beispiel wird die Schaltfläche cmdSave an die FlipEnabled-Routine gesendet. Diese Routine setzt den Fokus auf die Schaltfläche SAVE: Private Sub cmdAdd_Click() Call FlipEnabled(Me, Me!cmdSave) End Sub
Die Routine FlipEnabled erhält das Formular und die Schaltfläche als Parameter. Sie aktiviert die übergebene Schaltfläche und setzt den Fokus darauf. Anschließend verwendet die Routine das VBA-Konstrukt For...Each, um alle Steuerelemente des For-
Den Typ eines Steuerelements bestimmen
329
mulars zu erreichen. Innerhalb des For...Each-Konstrukts wird eine Gruppe von Anweisungen für jedes Objekt im Feld oder in der Auflistung (in diesem Fall der Auflistung der Steuerelemente) wiederholt. Jedes Steuerelement des Formulars wird ausgewertet, um festzustellen, ob es sich um eine Schaltfläche handelt. Ist dies der Fall (und wurde diese Schaltfläche nicht an die Routine übergeben), dann schaltet die Routine die Eigenschaft Enabled des Steuerelements um. Die folgenden VBA-eigenen Konstanten werden bei der Bewertung der Eigenschaft ControlType eines Steuerelements berücksichtigt: VBA-Konstante
Typ des Steuerelements
acLabel
Bezeichnungsfeld
acRectangle
Rechteck
acLine
Linie
acImage
Bild
acCommandButton
Befehlsschaltfläche
acOptionButton
Optionsschaltfläche
acCheckBox
Kontrollkästchen
acOptionGroup
Optionsgruppe
acBoundObjectFrame
Gebundenes Objektfeld
acTextBox
Textfeld
acListBox
Listenfeld
acComboBox
Kombinationsfeld
acSubform
Unterformular/-bericht
acObjectFrame
Objektfeld oder Diagramm
acPageBreak
Seitenumbruch
acPage
Seite
acCustomControl
ActiveX-Steuerelement
acToggleButton
Umschaltfläche
acTabCtl
Registerkarte
Tabelle 8.1: Typen der Steuerelemente
330
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
8.10
Spezielle Eigenschaften mit Objektbezug
Mit VBA ist eine bequeme Ausführung von Aktionen mit dem aktiven Steuerelement und anderen speziellen Objekten möglich. Die folgende Liste enthält besondere Objekteigenschaften des Objektmodells von Access.
Die Eigenschaft ActiveControl bezieht sich auf das Steuerelement, welches den Fokus für ein Bildschirmobjekt, ein Formular oder einen Bericht besitzt.
Die Eigenschaft ActiveForm bezieht sich auf das Formular, das den Fokus besitzt. Die Eigenschaft ActiveReport bezieht sich auf den Bericht, der den Fokus besitzt. Die Eigenschaft Form bezieht sich auf das Formular eines untergeordneten Formulars oder auf des Formular selbst.
Me bezieht sich auf das Formular oder den Bericht, für das bzw. den gerade Code ausgeführt wird.
Modules bezieht sich auf das Modul eines Formulars oder Berichts. Die Eigenschaft Parent bezieht sich auf Formulare, Berichte oder Steuerelemente, die ein Steuerelement enthalten.
PreviousControl bezieht sich auf das Steuerelement, welches unmittelbar vor dem aktiven Steuerelement den Fokus besaß.
Die Eigenschaft RecordsetClone bezieht sich auf ein Duplikat des dem Formular zugrunde liegenden Datensatzes.
Die Eigenschaft Report bezieht sich auf den Bericht, der ein untergeordnetes Formular enthält, oder auf den Bericht selbst.
Die Eigenschaft Section bezieht sich auf den Abschnitt in einem Formular oder Bericht, in dem sich ein bestimmtes Steuerelement befindet. Im folgenden Beispiel wird gezeigt, wie mit Hilfe der Eigenschaft Screen.ActiveForm eine Unterroutine die Überschrift des aktiven Formulars ändern kann: Sub ChangeCaption() Screen.ActiveForm.Caption = Screen.ActiveForm.Caption & _ " – " & CurrentUser() End Sub
Diese Subroutine verändert die Überschrift des aktiven Formulars durch Anhängen des Wertes der Eigenschaft CurrentUser an das Ende der Überschrift.
Spezielle Eigenschaften mit Objektbezug
8.10.1
331
Für die Praxis
Umgang mit Objekten Objekte kommen überall in unserem Zeit-und Abrechnungssytem zum Einsatz. In fast allen Teilen der Anwendung werden die in diesem Kapitel beschriebenen Möglichkeiten verwendet. Das nachfolgende Beispiel wendet die eben vorgestellten Techniken an, um als Antwort auf Veränderungen des Benutzers an den Daten des Formulars frmClients Schaltflächen zu aktivieren und zu deaktivieren. Sie finden das Beispiel in der Datenbank CHAP8.MDB auf der beiliegenden CD-ROM.
8.10.2
Befehlsschaltflächen aktivieren und deaktivieren
Wenn der Benutzer gerade dabei ist, Daten eines Formulars zu verändern, werden die Anwendungsmodule Project, Time Cards, Payments und Invoice mit Sicherheit nicht benötigt. Es ist also sinnvoll, diese Optionen zu deaktivieren, bis der Benutzer die Änderungen an den Kundendaten gesichert hat. Zu Beginn sind die Schaltflächen VIEW PROJECTS, VIEW TIME CARDS, VIEW PAYMENTS und VIEW INVOICE des Formulars aktiviert, während die Schaltfläche SAVE deaktiviert ist. Die Eigenschaft KeyPreview des Formulars ist auf Yes gesetzt, so dass das Formular alle Eingaben anzeigt, bevor die einzelnen Steuerelemente diese verarbeiten. Das Ereignis KeyDown des Formulars sieht wie folgt aus: Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) If Not cmdSave.Enabled Then If ImportantKey(Keycode, Shift) Then Call FlipEnabled (Me, Activecontrol) Me.NavigationButtons = False End If Else If KeyCode = vbkeyPageDown Or KeyCode = vbKeyPageup Then Keycode = 0 End If End If End Sub
Das Ereignis KeyDown erhält automatisch den Code der Taste, die gedrückt wurde, sowie die Information, ob gleichzeitig die (ª)-Taste, (Alt) oder (Strg) gedrückt wurden. Die Ereignisroutine überprüft, ob die Schaltfläche SAVE bereits aktiviert ist. Ist dies der Fall, muss sie nicht fortgesetzt werden, da die Eigenschaft Enabled bereits gesetzt wurde. Ist die Schaltfläche SAVE noch nicht aktiviert, wird die Funktion ImportantKey aufgerufen. Ihr wird die gedrückte Taste sowie die Tatsache kundgetan, ob die (ª)-Taste, (Alt) oder (Strg) gedrückt wurde. Die Funktion ImportantKey sieht wie folgt aus:
332
Kapitel 8: Objekte, Eigenschaften, Methoden und Ereignisse
Function ImportantKey(Keycode, Shift) ImportantKey = False If Shift = 4 Then Exit Function End If If Keycode = vbKeyDelete Or Keycode = vbKeyBaok Or (Keycode > 31 _ And Keycode < 256) Then If Keycode = vbKeyflight or Keycode = vbKeyLeft or _ Keycode = vbKeyup or Keycode = vbKeyDown or _ Keycode = vbKeyPageup or Keycode = vbkeyPageDown Then Else ImportantKey = True End If End If End Funotion
Diese generische Funktion aus basUtils legt als Standardrückgabewert False fest und überprüft, ob die (Alt)-Taste gedrückt wurde. War dies der Fall, hat der Benutzer einen Menübefehl oder ein Tastenkürzel gewählt, was bedeutet, dass die Schaltflächen nicht umgeschaltet werden müssen und die Funktion daher beendet werden kann. Wurde die (Alt)-Taste nicht gedrückt, wird die tatsächlich gedrückte Taste ausgewertet. Wurden die Tasten (Entf), (æ) oder eine andere Taste mit einem ANSI-Wert zwischen 31 und 235 (mit Ausnahme der Pfeiltasten, der (½)- und (¼)Taste) gedrückt, wird von dieser Funktion der Wert True zurückgegeben. Anschließend ruft das Ereignis KeyDown des Formulars die Routine FlipEnabled auf: Sub FlipEnabled(frmAny As Form, ctlAny As Control) Dim ctl As Control If Typeof ctlAny Is CommandButton Then ctlAny.Enabled = True ctlAny.SetFocus End If For Each ctl In frmAny.Controls If Typeof ctl Is CommandButton Then If ctl.Name <> ctlAny.Name Then ctl.Enabled = Not ctl.Enabled End If End If Next ctl End Sub
Diese generische Routine, die Sie ebenfalls in basUtils finden, setzt die Eigenschaft Enabled jeder Schaltfläche des Formulars, mit Ausnahme derjenigen, die ihr übergeben wurde. Die Routine FlipEnabled erhält ein Formular und ein Steuerelement als Parameter. Sie erzeugt zu Beginn eine Steuerelementvariable und testet anschließend, ob dieses übergebene Steuerelement eine Schaltfläche war. War dies der Fall, wird die Schaltfläche aktiviert und erhält den Fokus. Die Routine durchsucht dann
Spezielle Eigenschaften mit Objektbezug
333
in einer Schleife jedes Steuerelement des Formulars, welches ihr übergeben wurde, darauf, ob es sich bei den Steuerelementen um Schaltflächen handelt. Findet sie eine Schaltfläche, deren Name nicht mit dem Namen des übergebenen Steuerelements übereinstimmt, wird die Eigenschaft Enabled dieser Schaltfläche umgeschaltet. Dem liegt folgender Gedanke zu Grunde: Wenn der Benutzer die Schaltfläche SAVE anklickt, dann kann diese nicht sofort deaktiviert werden, weil sie noch den Fokus hat. Zuerst muss ein gewähltes Steuerelement (das der Routine übergebene) deaktiviert und der Fokus der aktivierten Schaltfläche übergeben werden. Nachdem das Steuerelement aktiviert wurde, möchten Sie aber sicher nicht, dass es sofort wieder deaktiviert wird, damit es aus der verarbeitenden Schleife entfernt werden muss. Wurde die Routine FlipEnabled ausgeführt, wird der Wert der Eigenschaft NavigationButtons des Formulars auf False gesetzt. Dies ist ein wichtiger Schritt, weil der Benutzer auf keinen Fall in der Lage sein darf, sich während der Bearbeitung der Daten des Formulars von einem Datensatz zum anderen zu bewegen. Andererseits müssen Sie Schaltflächen aber auch wieder umschalten. Das Ereignis Click der Schaltfläche SAVE besteht aus folgendem Code: Private Sub cmdSave_C1ick() DoCmd.RunCommand Command:=acCmdSaveRecord Call FlipEnabled(Me, Me!Projects) Me.NavigationButtons = True End Sub
Mit diesem Code wird der aktuelle Datensatz gespeichert und die Routine FlipEnabled aufgerufen. Die FlipEnabled-Routine versetzt die Schaltflächen wieder in den Ausgangszustand. Sie können auch eine Schaltfläche zum Abbrechen hinzufügen, mit der die Änderungen rückgängig gemacht und die Schaltflächen gleichfalls zurückgesetzt werden. Außerdem sollten Sie den Benutzer daran hindern, zu anderen Datensätzen wechseln zu können, bevor er die Schaltfläche SAVE gewählt hat, beziehungsweise die Schaltflächen umschalten, wenn die Schaltfläche SAVE gewählt wurde und der Benutzer zu anderen Datensätzen wechselt. Tun Sie dies nicht, werden die Datensätze von Access automatisch gespeichert, wenn der Benutzer zu einem anderen Datensatz wechselt, und die Schaltflächen spiegeln einen unsauberen Zustand des Formulars wieder.
Fortgeschrittene Verwendung von Formularen
Kapitel
Hier lesen Sie:
Was sind Formularereignisse und wann sollten sie verwendet werden? Abschnitts- und Steuerelementereignisse und ihre Verwendung Welche Arten von Formularen kann ich erstellen und wofür eignen sie sich? Formularen benutzerdefinierte Menüs, Symbolleisten und Kontextmenüs hinzufügen
Objekte aus anderen Anwendungen einfügen Benutzerdefinierte Eigenschaften und Methoden erstellen
9.1
Formulare ergänzen
Auf Grund der grafischen Benutzerschnittstelle von Access stehen Formulare häufig im Mittelpunkt Ihrer Bemühungen, so dass Sie alle Formular- und Steuerelementereignisse kennen und wissen sollten, welchen Code Sie für jede einzelne Aufgabe programmieren müssen. Außerdem sollten Sie die verfügbaren Formulare kennen und wissen, wie Sie deren Aussehen und Verhalten beeinflussen können. Oftmals müssen Sie eigene Formulare entwickeln, weil Sie eines der integrierten Dialogfelder von VBA oder der Werkzeuge der Microsoft Office 2000 Developer Edition verwenden wollen. Gleichgültig, welche Art von Formular Sie erstellen, Sie sollten in jedem Fall alle Vorteile der in diesem Kapitel vorgestellten Tricks und Hinweise nutzen, um Ihrem Formular Menü- und Symbolleisten hinzuzufügen.
336
9.2
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Was sind Formularereignisse und wann sollten sie verwendet werden?
Microsoft Access löst 30 Formularereignisse aus, die jeweils unterschiedlichen Zwecken dienen. Access reagiert auch auf Ereignisse in Formularabschnitten oder von Steuerelementen. Die folgenden Abschnitte behandeln die Formularereignisse und deren Verwendung.
9.2.1
Current (Beim Anzeigen)
Das Ereignis Beim Anzeigen bzw. current eines Formulars ist eines der am häufigsten programmierten Ereignisse. Es tritt immer dann ein, wenn der Fokus von einem Datensatz zum nächsten wechselt. Das Current-Ereignis eignet sich hervorragend, um Code einzufügen, der jedesmal beim Anzeigen des Datensatzes ausgeführt werden soll. Es kann zum Beispiel erwünscht sein, dass der Firmenname mit einem bestimmten Hintergrund erscheint, wenn es sich um einen wichtigen Kunden handelt. Der folgende Code befindet sich im Current-Ereignis des Formulars frmClients, das Bestandteil unseres Zeit- und Abrechnungssytems ist: Private Sub Form_Current() If IsNull(Me.txtclientID) Then Me.txtcontactFirstName SetFocus End If End Sub
Diese Zeilen verschieben den Fokus zum Steuerelement txtContactFirstName, wenn der Wert des Feldes txtClientID des Datensatzes, der vom Benutzer den Fokus erhält, gleich Null ist. Dazu kommt es, wenn der Benutzer einen neuen Datensatz hinzufügt.
9.2.2
BeforeInsert (Vor Eingabe)
Das Ereignis Vor Eingabe bzw. BeforeInsert tritt ein, wenn der erste Buchstabe eines neuen Datensatzes eingegeben wird, jedoch bevor der neue Datensatz tatsächlich erstellt ist. Gibt der Benutzer in einem Text- oder Kombinationsfeld Zeichen ein, kommt es zum BeforeInsert-Ereignis, bevor das Change-Ereignis des Text- oder Kombinationsfelds eintritt. Das Formular frmProjects unseres Zeit- und Abrechnungssytems enthält ein Beispiel für die praktische Verwendung des Ereignisses BeforeInsert: Private Sub Form_BeforeInsert(Cancel As Integer) Me.ClientID = Forms.frmClients.txtClientID End Sub
Was sind Formularereignisse und wann sollten sie verwendet werden?
337
Das Formular frmProjects wird immer vom Formular frmClients aufgerufen. Die Routine für das Ereignis BeforeInsert des Formulars frmProjects setzt den Wert des Textfeldes txtClientID auf den des Textfeldes txtClientID des Formulars frmClients.
9.2.3
AfterInsert (Nach Eingabe)
Das Ereignis Nach Eingabe bzw. AfterInsert tritt ein, nachdem ein Datensatz tatsächlich eingefügt wurde. Es kann zum Wiederauffinden eines Datensatzes verwendet werden, wenn ein neuer Datensatz hinzugefügt wird. Die Reihenfolge der Ereignisse beim Einfügen eines neuen Datensatzes durch den Benutzer sieht wie folgt aus: BeforeInsert(Vor Eingabe)?BeforeUpdate(Vor Aktualisierung)?AfterUpdate (Nach Aktualisierung)-AfterInsert(Nach Eingabe)
Das Ereignis BeforeInsert tritt ein, wenn der Benutzer den ersten Buchstaben eingibt. Zum Ereignis BeforeUpdates kommt es, wenn der Benutzer den Datensatz aktualisiert. Das Ereignis AfterUpdate findet statt, wenn der Datensatz aktualisiert wird und das Ereignis AfterInsert tritt auf, wenn es sich bei dem aktualisierten Datensatz um einen neuen Datensatz handelt.
9.2.4
BeforeUpdate (Vor Aktualisierung)
Das Ereignis Vor Aktualisierung bzw. BeforeUpdate wird vor dem Aktualisieren des Datensatzes ausgelöst. Es tritt auf, wenn der Benutzer versucht, zu einem anderen Datensatz zu wechseln (auch wenn es sich um einen Datensatz eines untergeordneten Formulars handelt) oder wenn der Befehl DATENSÄTZE|DATENSATZ SPEICHERN ausgeführt wird. Das BeforeUpdate-Ereignis kann dazu verwendet werden, den Aktualisierungsvorgang abzubrechen, wenn umfangreiche Überprüfungen durchgeführt werden sollen. Fügt der Benutzer einen Datensatz hinzu, tritt das Ereignis BeforeUpdate vor dem Ereignis BeforeInsert ein. Die Nordwind-Datenbank von Access enthält ein hervorragendes Beispiel für den Einsatz des Ereignisses BeforeUpdate: Private Sub Form_BeforeUpdate(Cancel As Integer) ' Wenn die Anzahl der im Textfeld "Postleitzahl" eingegebenen Stellen ' für den im Textfeld "Land" eingegebenen Wert ungültig ist, eine ' Meldung anzeigen und den Postleitzahlenwert zurücksetzen. Select Case Me!Land Case IsNull(Me![Land]) Exit Sub Case "Frankreich", "Italien", "Spanien", "Deutschland" If Len(Me![Postleitzahl]) <> 5 Then MsgBox "Postleitzahl muss 5 Zeichen lang sein.", _
338
Kapitel 9: Fortgeschrittene Verwendung von Formularen
0, "Postleitzahlenfehler" Cancel = True Me![Postleitzahl].SetFocus End If Case "Australien", "Singapur" If Len(Me![Postleitzahl]) <> 4 Then MsgBox "Postleitzahl muss 4 Zeichen lang sein.", _ 0, "Postleitzahlenfehler" Cancel = True Me![Postleitzahl].SetFocus End If Case "Kanada" If Not Me![Postleitzahl] Like "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" Then MsgBox "Postleitzahl ist ungültig. Beispiel für _ kanadische Postleitzahl: H1J 1C3", 0, "Postleitzahlenfehler" Cancel = True Me![Postleitzahl].SetFocus End If End Select
End Sub
Dieser Code des Lieferantenformulars stellt fest, ob die Postleitzahl dem gewählten Land entspricht. Ist dies nicht der Fall, wird eine Meldung angezeigt und dem Parameter Cancel der Wert True zugewiesen, was den Aktualisierungsvorgang abbricht. Aus Gründen der Bequemlichkeit für den Benutzer wird der Fokus dem Steuerelement für die Postleitzahl übergeben. Beachten Sie, dass sich die Beispiele aus der Nordwind-Datenbank nicht an den Benennungs- und Programmierkonventionen orientieren, die in diesem Buch eingehalten werden. Um bei der Betrachtung des Codes aus der Nordwind-Datenbank von Access 2000 Irrtümer zu vermeiden, wurden alle Nordwind-Beispiele unverändert gelassen, anstatt sie den Reddick-Namenskonventionen anzupassen.
9.2.5
AfterUpdate (Nach Aktualisierung)
Das Ereignis Nach Aktualisierung bzw. AfterUpdate tritt ein, wenn der geänderte Datensatz aktualisiert wird. Mit diesem Ereignis können Sie Kombinationsfelder verwandter Formulare aktualisieren oder die Veränderung des Datensatzes protokollieren. Es folgt ein Beispiel: Private Sub Form_AfterUpdate() Me.cboSelectProduct.Requery End Sub
Was sind Formularereignisse und wann sollten sie verwendet werden?
339
Dieser Code aktualisiert das Kombinationsfeld cboSelectProduct, nachdem der bearbeitete Datensatz aktualisiert wurde.
9.2.6
Dirty (Bei Änderung)
Das Ereignis Bei Änderung bzw. Dirty tritt auf, wenn der Inhalt des Formulars oder des Textes eines Kombinationsfelds verändert wird oder es zu einer programmgesteuerten Änderung der Text-Eigenschaft eines Steuerelements kommt. Ein Beispiel: Private Sub Form_Dirty(Cancel As Integer) Call FlipEnabled(Me, ActiveControl Me.NavigationButtons = False End Sub
Dieser Code aus dem Formular frmClients unseres Zeit- und Abrechnungssytems ruft die Methode FlipEnabled auf, um die Befehlsschaltflächen des Formulars umzuschalten. Dadurch werden die Schaltflächen SAVE und CANCEL aktiviert und die übrigen Schaltflächen des Formulars deaktiviert. Der Code deaktiviert gleichzeitig die Pfeiltasten, so dass der Benutzer nicht zu anderen Datensätzen wechseln kann, solange sich die Daten nicht im korrekten Zustand befinden.
9.2.7
Delete (Beim Löschen)
Das Ereignis Beim Löschen bzw. Delete tritt beim Versuch eines Benutzers auf, einen Datensatz zu löschen, bevor dieser tatsächlich aus der Tabelle entfernt wurde. Dieses Ereignis eignet sich sehr gut für Code, der das Löschen eines Datensatzes nur unter bestimmten Bedingungen zulässt. Wird das Ereignis Delete abgebrochen, werden die Ereignisse BeforeDelConfirm und AfterDelConfirm nicht ausgeführt und der Datensatz nicht gelöscht. Löscht der Benutzer mehrere Datensätze, tritt das Ereignis Delete nach dem Löschen jedes Datensatzes ein. So können Sie für jeden Datensatz eine Bedingung auswerten und dann entscheiden, ob der Datensatz gelöscht werden soll.
9.2.8
BeforeDelConfirm (Vor Löschbestätigung)
Das Ereignis Vor Löschbestätigung bzw. BeforeDelConfirm findet nach einem DeleteEreignis statt, jedoch bevor das Dialogfeld für die Bestätigung des Löschens angezeigt wird. Brechen Sie das BeforeDelConfirm-Ereignis ab, wird der Datensatz über den Puffer für gelöschte Datensätze wiederhergestellt und das Dialogfeld zur Bestätigung des Löschens wird nicht angezeigt.
340
9.2.9
Kapitel 9: Fortgeschrittene Verwendung von Formularen
AfterDelConfirm (Nach Löschbestätigung)
Das Ereignis Nach Löschbestätigung bzw. AfterDelConfirm tritt ein, nachdem der Datensatz tatsächlich gelöscht oder das Löschen abgebrochen wurde. Wurde das Ereignis BeforeDelConfirm nicht abgebrochen, findet das Ereignis AfterDelConfirm nach dem Anzeigen des Dialogfelds für die Bestätigung statt.
9.2.10
Open (Beim Öffnen)
Das Ereignis Beim Öffnen bzw. Open tritt beim Öffnen eines Formulars vor der Anzeige des ersten Datensatzes ein. Mit Hilfe dieses Ereignisses können Sie genau steuern, was beim Öffnen des ersten Formulars geschieht. Der Code für das Ereignis Open des Formulars frmProjects des Zeit- und Abrechnungssytems sieht wie folgt aus: Private Sub Form_Open(Cancel As Integer) If Not IsLoaded("frmClients") Then MsgBox "Open the Projects form using the " & _ "Projects button on the Clients Form" Cancel = True End If End Sub
Dieser Code überprüft, ob das Formular frmClients geladen wurde. Ist dies nicht geschehen, erscheint ein Meldungsfeld und der Parameter Cancel erhält den Wert True, was das Laden des Formulars verhindert.
9.2.11
Load (Beim Laden)
Zum Ereignis Beim Laden bzw. Load kommt es, wenn ein Formular geöffnet wurde und der erste Datensatz angezeigt wird. Dieses Ereignis tritt vor dem Ereignis Open ein. Das Open-Ereignis eines Formulars kann das Öffnen eines Formulars abbrechen, was für das Ereignis Load nicht zutrifft. Die folgende Routine gehört zum Ereignis Load des Zeit- und Abrechnungssytems: Private Sub Form_Load() If Me.DataEntry And Not (IsNull(Me.OpenArgs)) Then Me.txtExpenseCode = Me.OpenArgs End If End Sub
Diese Routine untersucht die als Argument beim Öffnen an das Formular überreichte Zeichenfolge. Hat die Zeichenfolge OpenArg nicht den Wert Null, wenn das Formular im Modus für die Dateneingabe geöffnet wurde, erhält das Textfeld txtExpenseCode den gleichen Wert wie das Argument zum Öffnen. Mit diesem Code kann das Formular im Wesentlichen zwei Dinge durchführen: Wurde das Formular im Datenbankfenster geöffnet, wird keine besondere Verarbeitung vorgenommen.
Was sind Formularereignisse und wann sollten sie verwendet werden?
341
Wurde es jedoch vom Unterformular fsubTimeCardsExpenses aus geöffnet, erfolgt das Öffnen im Dateneingabemodus und der vom Benutzer angegebene Kostenschlüssel wird im Textfeld txtExpenseCode platziert.
9.2.12
Resize (Bei Größenänderung)
Das Ereignis Bei Größenänderung bzw. Resize findet statt, wenn ein Formular geöffnet oder die Größe eines Formulars verändert wird.
9.2.13
Unload (Beim Entladen)
Das Ereignis Beim Entladen bzw. Unload tritt beim Schließen eines Formulars auf, bevor es tatsächlich vom Bildschirm entfernt wird. Es wird ausgelöst, wenn der Benutzer im Menü DATEI die Option SCHLIESSEN wählt, die Anwendung durch Auswahl von SCHLIESSEN in der TASK-LISTE beendet, Windows beendet oder wenn Ihr Code das Formular schließt. Mit Hilfe des Codes für das Ereignis Unload können Sie sicherstellen, dass das Formular ordnungsgemäß entladen wird. Es kann darüber hinaus Code enthalten, der bei jedem Entladen ausgeführt werden soll. Ein Beispiel: Private Sub Form_Unload(Cancel As Integer) If Me.cmdSave.Enabled Then Select Case MsgBox("Do You Want To Save", _ vbYesNoCancel + vbCritical, _ "Please Respond") Case vbYes DoCmd.RunCommand Command:=acCmdSaveRecord Cancel = False Case vbNo On Error Resume Next DoCmd.RunCommand Command:=acCmdUndo Cancel = False Case vbCancel Cancel = True End Select End If End Sub
Dieser Code gehört zum Ereignis Unload des Formulars frmClients unseres Zeit- und Abrechnungssytems und überprüft, ob die Schaltfläche SAVE aktiviert ist. Ist das der Fall, befindet sich das Formular nicht im korrekten Zustand. Der Benutzer wird gefragt, ob er die Änderung des Datensatzes speichern möchte. Bestätigt er diese Anfrage, werden die Daten gespeichert und das Formular wird entladen. Antwortet er mit NEIN, werden die Änderungen verworfen und anschließend wird das Formular entladen. Wählt er die Option ABBRECHEN, wird der Wert des Parameters Cancel auf False gesetzt und das Formular nicht entladen.
342
9.2.14
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Close (Beim Schließen)
Das Ereignis Beim Schließen bzw. Close tritt beim Schließen und Entfernen eines Formulars vom Bildschirm nach dem Ereignis Unload auf. Denken Sie daran, dass Sie das Ereignis Unload, jedoch nicht das Ereignis Close abbrechen können. Der folgende Code gehört zum Close-Ereignis des Formulars frmClients, welches Bestandteil des Zeit- und Abrechnungssystems ist: Private Sub Form_Close() If Iskoaded("frmProjects") Then DoCmd.Close acForm, "frmProjects" End If End Sub
Wenn das Formular frmClients geschlossen wird, überprüft der Code, ob das Formular frmProjects geöffnet ist. Trifft dies zu, wird es ebenfalls geschlossen.
9.2.15
Activate (Bei Aktivierung)
Das Ereignis Bei Aktivierung bzw. Activate tritt auf, wenn das Formular den Fokus erhält und zum aktiven Fenster wird. Es wird beim Öffnen des Formulars ausgelöst, wenn der Benutzer auf das Formular oder eines seiner Steuerelemente klickt oder wenn der VBA-Code die Methode SetFocus anwendet. Der folgende Code gehört zum Ereignis Activate des Formulars frmClients unseres Zeit- und Abrechnungssystems. Er aktualisiert das Unterformular subform immer dann, wenn das Hauptformular aktiviert wird: Private Sub Form_Activate() Me.fsubClients.Requery End Sub
9.2.16
Deactivate (Bei Deaktivierung)
Das Ereignis Bei Deaktivierung bzw. Deactivate wird ausgelöst, wenn das Formular den Fokus verliert, was eintritt, wenn eine Tabelle, eine Abfrage, ein Formular, ein Bericht, ein Makro, ein Modul oder ein Datenbankfenster aktiviert wird. Es wird jedoch nicht ausgelöst, wenn ein Dialogfeld, ein Popup-Formular oder eine andere Anwendung aktiviert wird. Das folgende Beispiel verdeutlicht die Verwendung des Ereignisses Deactivate: Private Sub Form_Deactivate() ' Mit Hilfe der Eigenschaft AllowEdits die zu verbergende Symbolleiste bestimmen ' Symbolleiste Formularansicht anzeigen If Me.AllowEdits = True Then DoCmd.ShowToolbar "Enter or Edit Products 2", acToolbarNo Else DoCmd.ShowToolbar "Enter or Edit Products 1", acToolbarNo
Was sind Formularereignisse und wann sollten sie verwendet werden?
343
End If DoCmd.ShowToolbar "Form View", acToolbarWhereApprop End Sub
Dieser Code wertet die Eigenschaft AllowEdits aus, um die zurzeit aktive benutzerdefinierte Symbolleiste zu ermitteln. Die entsprechende Symbolleiste wird verborgen und die Standardsymbolleiste der Formularansicht angezeigt.
9.2.17
GotFocus (Bei Fokuserhalt)
Zum Ereignis Bei Fokuserhalt bzw. GotFocus kommt es, wenn ein Formular den Fokus erhält. Es tritt nur ein, wenn sich im Formular keine sichtbaren aktivierten Steuerelemente befinden. Dieses Ereignis wird selten in einem Formular genutzt.
9.2.18
LostFocus (Bei Fokusverlust)
Das Ereignis Bei Fokusverlust bzw. LostFocus findet statt, wenn ein Formular den Fokus verliert, allerdings nur, wenn das Formular keine sichtbaren aktivierten Steuerelemente enthält. Auch dieses Ereignis wird selten in einem Formular genutzt.
9.2.19
Click (Beim Klicken)
Das Ereignis Beim Klicken bzw. Click tritt auf, wenn ein Benutzer auf einen leeren Bereich eines Formulars, auf ein deaktiviertes Steuerelement des Formulars oder den Datensatzmarkierer klickt.
9.2.20
DblClick (Beim Doppelklicken)
Das Ereignis Beim Doppelklicken bzw. DblClick wird ausgelöst, wenn der Benutzer doppelt auf einen leeren Bereich eines Formulars, auf ein deaktiviertes Steuerelement oder den Datensatzmarkierer des Formulars klickt.
9.2.21
MouseDown (Bei Maustaste Ab)
Zum Ereignis Bei Maustaste Ab bzw. MouseDown kommt es, wenn ein Benutzer auf einen leeren Bereich eines Formulars, auf ein deaktiviertes Steuerelement oder den Datensatzmarkierer klickt. Dieses Ereignis tritt jedoch vor dem Ereignis Click auf. Mit seiner Hilfe können Sie feststellen, welche Maustaste gedrückt wurde.
9.2.22
MouseMove (Bei Mausbewegung)
Das Ereignis Bei Mausbewegung bzw. MouseMove findet statt, wenn der Benutzer den Mauszeiger über einen leeren Bereich des Formulars, über ein deaktiviertes Steuerelement des Formulars oder über den Datensatzmarkierer bewegt. Es wird kontinuierlich erzeugt, während der Mauszeiger über das Formular bewegt wird. Dieses Ereignis tritt vor dem Auslösen des Click-Ereignisses auf.
344
9.2.23
Kapitel 9: Fortgeschrittene Verwendung von Formularen
MouseUp (Bei Maustaste Auf)
Das Ereignis Bei Maustaste Auf bzw. MouseUp tritt ein, wenn der Benutzer die Maustaste loslässt. Wie das Ereignis MouseDown tritt es vor dem Ereignis Click auf. Mit seiner Hilfe können Sie ebenfalls feststellen, welche Maustaste gedrückt wurde.
9.2.24
KeyDown (Bei Taste Ab)
Das Ereignis Bei Taste Ab bzw. KeyDown tritt auf, wenn sich auf dem Formular keine Steuerelemente befinden oder die Formulareigenschaft KeyPreview des Formulars den Wert Yes hat. Trifft letzteres zu, werden alle Tastaturereignisse des Formulars berücksichtigt und für das Steuerelement mit dem Fokus ausgelöst. Wenn der Benutzer eine Taste gedrückt hält, tritt das KeyDown-Ereignis wiederholt auf, bis die Taste losgelassen wird. Es folgt ein Beispiel: Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) If Me.Dirty Then If KeyCode = vbKeyPageDown Or _ KeyCode = vbKeyPageUp Then KeyCode = 0 End If End If End Sub
Dieser Code aus dem Formular frmClients des Zeit- und Abrechnungssystems prüft, ob sich das Formular im korrekten Zustand befindet. Ist dies nicht der Fall und wurde die Taste (Bild¼) oder (Bild½) gedrückt, wird der Tastendruck ignoriert. Dies verhindert, dass der Benutzer sich zu einem anderen Datensatz bewegt, ohne zuvor die Schaltfläche SAVE oder CANCEL geklickt zu haben.
9.2.25
KeyUp (Bei Taste Auf)
Wie das Ereignis Bei Taste ab bzw. KeyDown tritt auch das Ereignis Bei Taste Auf bzw. KeyUp nur dann auf, wenn sich auf dem Formular keine Steuerelemente befinden oder die Eigenschaft KeyPreview des Formulars den Wert Yes hat. Dieses Ereignis findet nur einmal statt, unabhängig davon, wie lange die Taste gedrückt wird. Der Tastendruck kann durch Zuweisen des Werts Zero für KeyCode abgebrochen werden.
9.2.26
KeyPress (Bei Taste)
Das Ereignis Bei Taste bzw. KeyPress tritt auf, wenn der Benutzer eine einem ANSICode entsprechende Taste oder Tastenkombination drückt und wieder loslässt. Befinden sich auf dem Formular keine Steuerelemente oder wurde die Eigenschaft KeyPreview des Formulars auf Yes gesetzt, findet dieses Ereignis nicht statt. Der Tastendruck kann durch Zuweisen des Werts Zero für KeyCode abgebrochen werden.
Was sind Formularereignisse und wann sollten sie verwendet werden?
9.2.27
345
Error (Bei Fehler)
Das Ereignis Bei Fehler bzw. Error wird immer dann ausgelöst, wenn ein Fehler auftritt, während sich der Benutzer auf dem Formular befindet. Fehler der Jet-Engine von Microsoft werden abgefangen, für die Fehler von Visual Basic gilt dies jedoch nicht. Mit diesem Ereignis können Standardfehlermeldungen unterdrückt werden. VBA-Fehler müssen mit Hilfe des Konstrukts On Error behandelt werden. Das ErrorEreignis und der Umgang mit VBA-Fehlern werden in Kapitel 14 behandelt.
9.2.28
Filter (Bei Filter)
Das Ereignis Bei Filter bzw. Filter findet statt, wenn der Benutzer eine der Optionen FORMULARBASIERTER FILTER oder SPEZIALFILTER/-SORTIERUNG gewählt hat. Mit diesem Ereignis können Sie zuvor festgelegte Filter entfernen, Standardeinstellungen für einen Filter angeben, einen benutzerdefinierten Filter aktivieren oder verhindern, dass bestimmte Steuerelemente im Fenster FORMULARBASIERTER FILTER zur Verfügung stehen.
9.2.29
ApplyFilter (Bei angewendetem Filter)
Das Ereignis Bei angewendetem Filter bzw. ApplyFilter wird initiiert, wenn der Benutzer eine der Optionen FILTER/SORTIERUNG ANWENDEN, AUSWAHLBASIERTER FILTER oder FILTER/SORTIERUNG ENTFERNEN auswählt. Außerdem tritt das Ereignis beim Schließen der Fenster SPEZIALFILTER/SORTIERUNG und FORMULARBASIERTER FILTER auf. Mit diesem Ereignis können Sie dafür sorgen, dass der richtige Filter verwendet wird, um die Anzeige des Formulars zu verändern, bevor der Filter angewendet wird, oder um Veränderungen rückgängig zu machen, die vorgenommen wurden, als das Filter-Ereignis eintrat.
9.2.30
Timer (Zeitgeber)
Das Ereignis Zeitgeber bzw. Timer und die Eigenschaft TimerInterval bzw. Zeitgeberintervall eines Formulars arbeiten Hand in Hand. Die Eigenschaft TimerInterval kann auf einen Wert zwischen 0 und 2.147.483.647 gesetzt werden. Der gewählte Wert legt die Häufigkeit in Millisekunden fest, mit der das Timer-Ereignis auftritt. Ist der Wert der Eigenschaft TimerInterval beispielsweise auf 0 gesetzt, tritt das TimerEreignis überhaupt nicht ein. Bei einem Wert von 5000 Millisekunden wird das Ereignis alle 5 Sekunden ausgelöst. Im folgenden Beispiel wird mit dem Timer-Ereignis die Sichtbarkeit des Bezeichnungsfelds des Formulars umgeschaltet, wodurch ein Blinken erzeugt wird. Die Eigenschaft TimerInterval kann anfänglich auf einen beliebigen Wert ungleich 0 gesetzt werden, sie wird jedoch anschließend bei jeder Ausführung des Codes um 50 Millisekunden reduziert. Dadurch blinkt das Steuerelement immer schneller. Das Timer-Ereignis tritt solange auf, bis die Eigenschaft TimerInterval schließlich den Wert 0 erreicht.
346
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Private Sub Form_Timer() If Me.Label2.Visible = True Then Me.Label2.Visible = False Else Me.Label2.Visible = True End If Me.TimerInterval = Me.TimerInterval – 50 If Me.TimerInterval = 0 Then Me.Label2.Visible = True End If End Sub
9.3
Die Reihenfolge der Formularereignisse
Die Reihenfolge der Ereignisse ist etwas rätselhaft. Am besten kann man sie deutlich machen, wenn man Debug.Print-Anweisungen in die Ereignisroutinen aufnimmt, über deren Ereignisse man etwas erfahren möchte. Diese Technik wird in Kapitel 13 behandelt. Beachten Sie jedoch, dass es sich bei der Reihenfolge der Ereignisse nicht um eine exakte Wissenschaft handelt. Es ist nahezu unmöglich, für alle Situationen zu ermitteln, wann Ereignisse eintreten. Dennoch ist es hilfreich, wenn Sie die Grundsätze kennen, nach denen bestimmte Ereignisse ausgelöst werden.
9.3.1
Was geschieht beim Öffnen eines Formulars?
Wenn der Benutzer ein Formular öffnet, kommt es zu folgender Ereigniskette: Open (Beim Öffnen)->Load (Beim Laden)->Resize (Bei Größenänderung)->Activate (Bei Aktivierung)->Current (Beim Anzeigen)
Nachdem diese Formularereignisse stattgefunden haben, kommt es beim ersten Steuerelement zu den Ereignissen Enter (Beim Hingehen) und GotFocus (Bei Fokuserhalt). Beachten Sie, dass Sie das Öffnen eines Formulars nur während des Ereignisses Open bzw. Beim Öffnen abbrechen können.
9.3.2
Was geschieht beim Schließen eines Formulars?
Schließt der Benutzer ein Formular, finden folgende Ereignisse statt: Unload (Beim Entladen)->Deactivate (Bei Deaktivierung)->Close (Beim Schließen)
Vor diesen Ereignissen werden die Ereignisse Exit (Beim Verlassen) und LostFocus (Bei Fokusverlust) des aktiven Steuerelements ausgelöst.
Die Reihenfolge der Formularereignisse
9.3.3
347
Was geschieht beim Ändern der Formulargröße?
Ändert der Benutzer die Größe eines Formulars, werden unterschiedliche Ereignisse ausgelöst, je nachdem, ob das Formular minimiert, wiederhergestellt oder maximiert wird. Beim Minimieren geschieht Folgendes: Resize (Bei Größenänderung)->Deactivate (Bei Deaktivierung)
Beim Wiederherstellen eines minimierten Formulars, treten die folgenden Ereignisse auf: Activate (Bei Aktivierung)->Resize (Bei Größenänderung)
Maximiert der Benutzer ein Formular oder stellt er es wieder her, tritt nur das Ereignis Resize (Bei Größenänderung) ein.
9.3.4
Was geschieht bei der Fokusübergabe von einem Formular zu einem anderen?
Wechselt der Benutzer von einem Formular zum anderen, tritt für das erste Formular das Ereignis Deactivate (Bei Deaktivierung) ein. Anschließend kommt es für das zweite Formular zum Ereignis Activate (Bei Aktivierung). Denken Sie aber daran, dass das Ereignis Deactivate (Bei Deaktivierung) nicht stattfindet, wenn der Fokus zu einem Dialogfeld, einem Popup-Formular oder einer anderen Anwendung wechselt.
9.3.5
Was geschieht beim Drücken einer Taste?
Gibt der Benutzer einen Buchstaben ein und hat die Eigenschaft Tastenvorschau des Formulars den Wert True, kommt es zu folgenden Ereignissen: KeyDown (Bei Taste Ab)->KeyPress (Bei Taste)->Dirty (Bei Änderung)->KeyUp (Bei Taste auf)
Wenn Sie das KeyDown-Ereignis abfangen und KeyCode auf den Wert 0 setzen, werden die verbleibenden Ereignisse nicht mehr ausgelöst. Das Ereignis KeyPress erfasst nur ANSI-Tastenwerte. Dieses Ereignis ist am einfachsten zu behandeln. Sie müssen jedoch die Ereignisse KeyDown und KeyUp berücksichtigen, wenn Sie Tasten wie die (ª)-, (Alt)- oder (Strg)-Taste abfangen wollen, die keinen ANSI-Zeichen entsprechen.
9.3.6
Was geschieht beim Eintreten einer Mausaktion?
Klickt der Benutzer die Maustaste, kommt es zu folgenden Ereignissen: MouseDown (Bei Maustaste Ab)->MouseUp (Bei Maustaste Auf)->Click (Beim Klicken)
348
Kapitel 9: Fortgeschrittene Verwendung von Formularen
9.4
Abschnitts- und Steuerelementereignisse und ihre Verwendung
Für Abschnitte gibt es nur fünf Ereignisse: Click (Beim Klicken), DblClick (Beim Doppelklicken), MouseDown (Bei Maustaste Ab), MouseMove (Bei Mausbewegung) und MouseUp (Bei Maustaste auf). Diese Ereignisse spielen in Ihren Anwendungen nur selten eine wichtige Rolle. Jedes Steuerelement reagiert auf eine eigene Anzahl von Ereignissen. Viele Ereignisse sind für die meisten Steuerelemente gleich, andere hingegen sind für einzelne Steuerelemente spezifisch. Einige reagieren auch nur auf sehr wenige Ereignisse. In den folgenden Abschnitten werden alle Steuerelementereignisse erläutert. Da jedes Ereignis berücksichtigt wird, erfahren Sie, für welche Steuerelemente die Ereignisse von Bedeutung sind.
9.4.1
BeforeUpdate (Vor Aktualisierung)
Das Ereignis Vor Aktualisierung bzw. BeforeUpdate tritt bei Textfeldern, Optionsgruppen, Kombinationsfeldern und gebundenen Objektfeldern auf. Es wird vor der Aktualisierung der geänderten Daten ausgelöst. Der folgende Code gehört zum BeforeUpdate-Ereignis des Steuerelements Kunden-Code des Formulars Bestellungen aus der Nordwind-Datenbank: Private Sub KundenCode_BeforeUpdate(Cancel As Integer) ' Wenn Kombinationsfeld "KundenCode" leer ist, Meldung anzeigen. Dim strMsg As String, strTitle As String Dim intStyle As Integer If IsNull(Me!KundenCode) Or Me!KundenCode = "" Then strMsg = "Sie müssen einen Wert aus der Liste 'Rechnung an' auswählen." strTitle = "Kunde für Rechnung erforderlich" intStyle = vbOKOnly MsgBox strMsg, intStyle, strTitle Cancel = True End If End Sub
Dieser Code überprüft, ob das Steuerelement Kunden-Code den Wert Null oder eine Zeichenfolge mit der Länge 0 hat. Trifft dies zu, wird eine Meldung angezeigt und das Update-Ereignis abgebrochen.
Abschnitts- und Steuerelementereignisse und ihre Verwendung
9.4.2
349
AfterUpdate (Nach Aktualisierung)
Das Ereignis AfterUpdate bzw. AfterUpdate tritt bei Textfeldern, Optionsgruppen, Kombinationsfeldern und gebundenen Objektfeldern auf. Es wird ausgelöst, bevor die geänderten Daten des Steuerelements aktualisiert werden. Der folgende Code gehört zum AfterUpdate-Ereignis des Steuerelements txtBeginDate aus dem Formular frmPrintInvoice des Zeit- und Abrechnungssystems: Private Sub txtBeginDate_AfterUpdate() Me.fsubPrintInvoiceTime.Requery Me.fsubPrintlnvoiceExpenses.Requery End Sub
Dieser Code benötigt bei der Aktualisierung des Steuerelements txtBeginDate die Unterformulare fsubPrintInvoiceTime und fsubPrintInvoiceExpenses. Das stellt sicher, dass die beiden Unterformulare die entsprechenden Kosten und Ausgaben für den gewählten Zeitraum anzeigen.
9.4.3
Updated (Bei OLE-Aktualisierung)
Das Ereignis Bei OLE-Aktualisierung bzw. Updated tritt nur bei gebundenen Objektfeldern auf. Es wird ausgelöst, wenn die Daten des OLE-Objekts verändert wurden.
9.4.4
Updated (Bei OLE-Aktualisierung)
Das Ereignis Bei Änderung bzw. Change tritt beim Ändern der Daten in Text- und Kombinationsfeldern auf. Bei einem Textfeld wird das Ereignis ausgelöst, wenn ein Buchstabe eingegeben wird. Bei einem Kombinationsfeld wird es durch die Eingabe eines Buchstabens oder die Auswahl eines Wertes in der Liste ausgelöst. Dieses Ereignis benutzen Sie, um Vorgänge zu behandeln, die auf einer Buchstabenfolge basieren.
9.4.5
Updated (Bei OLE-Aktualisierung)
Zum Ereignis Bei Nicht in Liste bzw. NotInList kommt es nur im Zusammenhang mit Kombinationsfeldern, wenn der Benutzer im Textfeld einen Wert eingibt, der nicht in der Liste des Kombinationsfelds vorhanden ist. Auf diese Weise können Sie dem Benutzer gestatten, einen neuen Wert der Liste des Kombinationsfelds hinzuzufügen. Damit dieses Ereignis ausgelöst wird, muss die Eigenschaft LimitToList (Nur Listeneinträge) auf Yes bzw. Ja gesetzt sein. Es folgt ein Beispiel für das Formular frmPayments aus dem Zeit- und Abrechnungssystem: Private Sub cboPaymentMethodID_NotInList(NewData As String, Response As Integer) If MsgBox("Payment Method Not Found, Add?", _ vbYesNo + vbQuestion, _ "Please Respond") = vbYes Then
350
Kapitel 9: Fortgeschrittene Verwendung von Formularen
DoCmd.OpenForm "frmPaymentMethods", _ Datamode:=acFormAdd, _ WindowMode:=acDialog, _ OpenArgs:=NewData If IsLoaded("frmPaymentMethods") Then Response = acDataErrAdded DoCmd.Close acForm, "frmPaymentMethods" Else Response = acDataErrContinue End If Else Response = acDataErrContinue End If End Sub
Dieser Code wird ausgeführt, wenn der Benutzer eine Zahlungsart eingibt, die im Kombinationsfeld cboPaymentMethodID nicht vorhanden ist. Der Benutzer wird gefragt, ob der Eintrag hinzugefügt werden soll. Bestätigt er die Anfrage, wird das Formular frmPaymentMethods angezeigt. Andernfalls muss er einen anderen Eintrag in der Liste des Kombinationsfelds auswählen. Das Ereignis NotInList wird im Abschnitt »Mit dem Ereignis NotInList umgehen« noch eingehender behandelt.
9.4.6
Enter (Beim Hingehen)
Das Ereignis Beim Hingehen bzw. Enter bezieht sich auf Textfelder, Optionsgruppen, Kombinationsfelder, Listenfelder, Schaltflächen, Objektfelder und Unterformulare. Es wird ausgelöst, bevor ein Steuerelement tatsächlich den Fokus von einem anderen Steuerelement des gleichen Formulars übernimmt und bevor das Ereignis GotFocus (Bei Fokuserhalt) eintritt. Folgendes Beispiel stammt aus dem Formular frmTimeCards des Zeit- und Abrechnungssytems: Private Sub fsubTimeCards_Enter() If IsNull(Me.cboEmployeelD) Then MsgBox "Enter employee before entering time or expenses" CboEmployeelD.SetFocus End If End Sub
Wechselt der Benutzer zum Unterformulars fsubTimeCards, testet dessen EnterEreignis, ob die Angestelltennummer auf dem Hauptformular eingegeben wurde. Ist dies nicht geschehen, wird eine Meldung angezeigt und der Fokus dem Steuerelement cboEmployeeID des Hauptformulars übergeben.
Abschnitts- und Steuerelementereignisse und ihre Verwendung
9.4.7
351
Exit (Beim Verlassen)
Das Ereignis Beim Verlassen bzw. Exit tritt bei Textfeldern, Optionsgruppen, Kombinationsfeldern, Listenfeldern, Schaltflächen, Objektfeldern und Unterformularen ein. Es wird direkt vor dem Ereignis LostFocus (Bei Fokusverlust) ausgelöst.
9.4.8
GotFocus (Bei Fokuserhalt)
Das Ereignis Bei Fokuserhalt bzw. GotFocus wird durch Textfelder, Umschaltflächen, Optionsfelder, Kontrollkästchen, Kombinationsfelder, Listenfelder und Befehlsschaltflächen initiiert. Es wird ausgelöst, wenn der Fokus infolge eines Benutzereingriffs einem Steuerelement entzogen wird oder der Code die Methoden SetFocus, SelectObject, GoToRecord, GoToControl oder GoToPage ausführt. Steuerelemente erhalten den Fokus nur, wenn sie sichtbar und aktiviert sind.
9.4.9
LostFocus (Bei Fokusverlust)
Das Ereignis Bei Fokusverlust bzw. LostFocus bezieht sich auf Textfelder, Umschaltflächen, Optionsfelder, Kontrollkästchen, Kombinationsfelder, Listenfelder und Befehlsschaltflächen. Es wird ausgelöst, wenn der Fokus infolge eines Benutzereingriffs einem Steuerelement entzogen wird oder der Code die Methoden SetFocus, SelectObject, GoToRecord, GoToControl oder GoToPage ausführt. Der Unterschied zwischen den Ereignissen GotFocus/LostFocus und Enter/Exit liegt im Zeitpunkt des Eintritts. Wird der Fokus einem anderen Formular übergeben oder dem aktuellen Formular zurückgegeben, löst dies die Ereignisse GotFocus und LostFocus des Steuerelements aus. Die Ereignisse Enter und Exit finden nicht statt, wenn das Formular den Fokus verliert oder zurückerhält. Außerdem muss erwähnt werden, dass keines dieser Ereignisse stattfindet, wenn eine Auswahl über das Menü oder die Symbolleisten getroffen wird.
9.4.10
Click (Beim Klicken)
Das Ereignis Beim Klicken bzw. Click spielt bei Bezeichnungsfeldern, Textfeldern, Optionsgruppen, Kombinationsfeldern, Listenfeldern, Schaltflächen und Objektfeldern eine Rolle. Es tritt ein, wenn der Benutzer eine Maustaste über einem Steuerelement drückt und wieder loslässt. Das folgende Beispiel stammt aus dem Formular frmProjects des Zeit- und Abrechnungssytems: Private Sub cmdToggleView_Click() If Me.cmdToggleView.Caption = "&View Expenses" Then Me.fsubProjects.Visible = False Me.fsubProjectExpenses.Visible = True Me.cmdToggleView.Caption = "&View Hours"
352
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Else Me.fsubProjectExpenses.Visible = False Me.fsubProjects.Visible = True Me.cmdToggleView.Caption = "&View Expenses" End If End Sub
Dieser Code überprüft die Beschriftung der Schaltfläche cmdToggleView. Lautet diese "&View Expenses" (das &-Zeichen kennzeichnet ein Tastenkürzel), wird das Unterformular fsubProjects verborgen, das Unterformular fsubProjectsExpenses sichtbar gemacht und die Beschriftung der Schaltfläche cmdToggleView zu "&View Hours" geändert. Andernfalls wird das Unterformular fsubProjectsExpenses verborgen, das Unterformular fsubProjects sichtbar gemacht und die Beschriftung der Schaltfläche cmdToggleView in "&View Expenses" geändert. Das Click-Ereignis wird ausgelöst, wenn der Benutzer die Maustaste über einem Objekt klickt. Außerdem tritt es in folgenden Situationen ein: – wenn die Leertaste gedrückt wird, während eine Schaltfläche den Fokus besitzt – wenn die Eigenschaft Default (Standard) einer Schaltfläche auf Yes bzw. Ja gesetzt ist und die Eingabetaste gedrückt wird – wenn die Eigenschaft Cancel (Abbrechen) einer Schaltfläche auf Yes bzw. Ja gesetzt ist und die (Esc)-Taste gedrückt wird – wenn ein Tastenkürzel für eine Schaltfläche benutzt wird
9.4.11
DblClick (Beim Doppelklicken)
Das Ereignis Beim Doppelklicken bzw. DblClick bezieht sich auf Bezeichnungsfelder, Textfelder, Optionsgruppen, Kombinationsfelder, Listenfelder, Schaltflächen und Objektfelder. Es tritt ein, wenn der Benutzer eine Maustaste über einem Steuerelement innerhalb sehr kurzer Zeit zweimal klickt und wieder loslässt. Das folgende Beispiel stammt aus dem Formular fsubTimeCards des Zeit- und Abrechnungssytems: Private Sub cboWorkCodeID_DblClick(Cancel As Integer) On Error GoTo Err_cboWorkCodeID_DblClick Dim lngWorkCodeID As Long If IsNull(Me.cboWorkCodeID) Then Me.cboWorkCodeID.Text = "" Else lngWorkCodeID = Me.cboWorkCodeID Me.cboWorkCodeID = Null End If DoCmd.OpenForm "frmWorkCodes", , , , , acDialog, "GotoNew" Me.cboWorkCodeID.Requery
Abschnitts- und Steuerelementereignisse und ihre Verwendung
353
If lngWorkCodeID <> 0 Then Me.cboWorkCodeID = lngWorkCodeID Exit_cboWorkCodeID_DblClick: Exit Sub Err_cboWorkCodeID_DblClick: MsgBox Err.Description Resume Exit_cboWorkCodeID_DblClick End Sub
In diesem Beispiel wertet der Code das Kombinationsfeld cboWorkCodeID aus, um festzustellen, ob der Wert gleich Null ist. Ist dies der Fall, wird der Text des Kombinationsfelds auf eine Zeichenfolge der Länge Null gesetzt. Andernfalls wird eine Long Integer-Variable auf den gleichen Wert wie den des Kombinationsfelds und der Wert des Kombinationsfelds auf Null gesetzt. Das Formular frmWorkCodes wird angezeigt. Wurde es wieder geschlossen, wird das Kombinationsfeld cboWorkCodeID angefordert. Hat die Long Integer-Variable nicht den Wert Null, wird der Wert des Kombinationsfelds dem Wert der Long Integer-Variablen gleichgesetzt.
9.4.12
MouseDown (Bei Maus Ab)
Das Ereignis Bei Maus Ab bzw. MouseDown kann bei Bezeichnungsfeldern, Textfeldern, Optionsgruppen, Kombinationsfeldern, Listenfeldern, Schaltflächen und Objektfeldern eintreten. Es findet vor dem Click-Ereignis statt, wenn die Maustaste über einem Steuerelement ausgelöst wird.
9.4.13
MouseMove (Bei Mausbewegung)
Das Ereignis Bei Mausbewegung bzw. MouseMove gilt für Bezeichnungsfelder, Textfelder, Optionsgruppen, Kombinationsfelder, Listenfelder, Schaltflächen und Objektfelder. Es wird ausgelöst, wenn der Mauszeiger über ein Steuerelement bewegt wird.
9.4.14
MouseUp (Bei Maustaste Auf)
Das Ereignis Bei Maustaste Auf bzw. MouseUp bezieht sich auf Bezeichnungsfelder, Textfelder, Optionsgruppen, Kombinationsfelder, Listenfelder, Schaltflächen und Objektfelder. Es wird vor dem Click-Ereignis ausgelöst, wenn die Maustaste über einem Steuerelement losgelassen wird.
9.4.15
KeyDown (Bei Taste Ab)
Das Ereignis Bei Taste Ab bzw. KeyDown bezieht sich auf Textfelder, Umschaltflächen, Optionsschaltfelder, Kontrollkästchen, Kombinationsfelder, Listenfelder und gebundene Objektfelder. Es ereignet sich, wenn der Benutzer innerhalb eines Steuerelements eine Taste drückt. Es tritt wiederholt auf, bis die Taste wieder freigegeben wird, und kann durch Setzen von KeyCode auf den Wert Zero abgebrochen werden.
354
9.4.16
Kapitel 9: Fortgeschrittene Verwendung von Formularen
KeyUp (Bei Taste Auf)
Das Ereignis Bei Taste Auf bzw. KeyUp bezieht sich auf Textfelder, Umschaltflächen, Optionsschaltfelder, Kontrollkästchen, Kombinationsfelder, Listenfelder und gebundene Objektfelder. Es wird ausgelöst, wenn eine Taste innerhalb eines Steuerelements losgelassen wird. Es tritt nur einmal auf, unabhängig davon, wie lange die Taste gedrückt wird.
9.4.17
KeyPress (Bei Taste)
Das Ereignis Bei Taste bzw. KeyPress bezieht sich auf Textfelder, Umschaltflächen, Optionsschaltfelder, Kontrollkästchen, Kombinationsfelder, Listenfelder und gebundene Objektfelder. Es wird ausgelöst, wenn der Benutzer eine ANSI-Taste drückt und wieder loslässt, während das Steuerelement den Fokus besitzt. Wird KeyCode gleich Zero gesetzt, bricht das Ereignis ab.
9.5
Die Reihenfolge der Steuerelementereignisse
So wie die Formularereignisse beim Öffnen, Aktivieren und bei anderen Operationen in einer bestimmten Reihenfolge auftreten, so finden auch Steuerelementereignisse in einer festgelegten Abfolge statt. Wenn Sie den Ereigniscode für ein Steuerelement schreiben, müssen Sie wissen, in welcher Reihenfolge die Steuerelementereignisse ablaufen.
9.5.1
Was geschieht, wenn ein Steuerelement den Fokus erhält oder abgibt?
Bei der Übergabe des Fokus an ein Steuerelement kommt es zu folgenden Ereignissen: Enter (Beim Hingehen)->GotFocus (Bei Fokuserhalt)
Erfolgt die Übergabe des Fokus an das Steuerelement beim Öffnen des Formulars, laufen die Formular- und Steuerelementereignisse in der folgenden Reihenfolge ab: Open (Beim Öffnen; Formular) ->Activate (Bei Aktivierung; Formular)->Current; Formular->Enter (Beim Hingehen; Steuerelement) ÊGotFocus (Bei Fokuserhalt; Steuerelement)
Gibt das Steuerelement den Fokus ab, treten folgende Ereignisse ein: Exit (Beim Verlassen)->LostFocus (Bei Fokusverlust)
Gibt das Steuerelement den Fokus ab, weil das Formular geschlossen wird, kommt es zu den Ereignissen:
Das Schlüsselwort Me
355
Exit (Beim Verlassen; Steuerelement)->LostFocus (Bei Fokusverlust; Steuerelement)>Unload (Beim Entladen; Formular)->Deactivate (Bei Deaktivierung; Formular)>Close (Beim Schließen; Formular)
9.5.2
Was geschieht beim Aktualisieren der Daten in einem Steuerelement?
Ändern Sie die Daten in einem Steuerelement und verschieben anschließend den Fokus zu einem anderen Steuerelement, treten folgende Ereignisse ein: BeforeUpdate (Vor Aktualisierung)->AfterUpdate (Nach Aktualisierung)->Exit (Beim Verlassen)->LostFocus (Bei Fokusverlust)
Nach der Eingabe eines Zeichens in ein Text- oder Kombinationsfeld finden vor Übergabe des Fokus an ein anderes Steuerelement folgende Ereignisse statt: KeyDown (Bei Taste Ab)->KeyPress (Bei Taste)->Change (Bei Änderung)->KeyUp (Bei Taste Auf)
Bei einem Kombinationsfeld ereignet sich dies nach dem KeyUp-Ereignis, wenn das NotInList-Ereignis ausgelöst wird.
9.6
Das Schlüsselwort Me
Das Schlüsselwort Me gleicht einer implizit deklarierten Variablen. Es steht jeder Prozedur eines Formular- oder Berichtsmoduls zur Verfügung. Mit Me kann sehr gut Code für ein Formular oder einen Bericht verfasst werden. Sie können den Namen des Formulars oder Berichts ändern und der Code bleibt davon unberührt. Ein Beispiel: Me.RecordSource = "qryProjects"
Es ist auch nützlich, Me (das aktuelle Formular bzw. der aktuelle Bericht) an eine generische Prozedur in einem Modul zu übergeben, wie dies im folgenden Beispiel geschieht: Call ChangeCaption(Me)
Die Prozedur ChangeCaption sieht wie folgt aus: Sub ChangeCaption(frmAny As Form) If IsNull(frmAny.Caption) Then frmAny.Caption = "Form for – " & CurrentUser Else frmAny.Caption = frmAny.Caption & " – " & CurrentUser End If End Sub
356
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Die Prozedur ChangeCaption eines Moduls erhält ein beliebiges Formular als Parameter und wertet dann die Überschrift des übergebenen Formulars aus. Hat sie den Wert Null, weist ChangeCaption dem Formular die Beschriftung "Formular für " in Verbindung mit dem Benutzernamen zu. Andernfalls wird an die vorhandene Überschrift der Benutzername angehängt.
9.7
Welche Arten von Formularen kann ich erstellen und wann sind sie geeignet?
Mit Microsoft Access können Sie eine Vielzahl von Formularen erstellen. Wenn Sie mit den verfügbaren Eigenschaften des Formular-Assistenten von Access arbeiten, können Sie Formulare mit unterschiedlichem Erscheinungsbild und verschiedenen Funktionen einrichten. In diesem Kapitel werden die wichtigsten Formulararten beschrieben. Sie können aber selbstverständlich auch eigene Formulare entwerfen. Dabei sollten Sie jedoch auf eine Übereinstimmung mit den Standards für WindowsAnwendungen achten.
9.7.1
Einzelne Formulare: Einen Datensatz zur Zeit betrachten
Eine der gängigsten Formulararten gestattet Ihnen das Betrachten eines einzelnen Datensatzes. Das Formular in Abbildung 9.1 zeigt dem Benutzer beispielsweise einen Kundendatensatz an, von dem aus er bei Bedarf zu anderen Datensätzen wechseln kann.
Abbildung 9.1: Ein einzelnes Formular
Das Erstellen eines einzelnen Formulars ist einfach: wählen Sie für die Eigenschaft Standardansicht einfach den Wert Einzelnes Formular (siehe Abbildung 9.2).
357
Welche Arten von Formularen kann ich erstellen und wann sind sie geeignet?
Abbildung 9.2: Die Eigenschaft Standardansicht des Formulars festlegen
9.7.2
Endlosformulare: Mehrere Datensätze gleichzeitig betrachten
Häufig möchten die Benutzer mehrere Datensätze zur gleichen Zeit betrachten können. Hierfür erstellen Sie ein Endlosformular, wie es in Abbildung 9.3 zu sehen ist. Wählen Sie für die Standardansicht den Eintrag Endlosformular.
Abbildung 9.3: Ein Endlosformular
Oft werden im Zusammenhang mit Endlosformularen Unterformulare verwendet. Im Allgemeinen zeigt ein Unterformular mehrere Datensätze an. Die im Unterformular angezeigten Datensätze beziehen sich alle auf den im Hauptformular enthaltenen Datensatz. Abbildung 9.4 zeigt ein Beispiel mit zwei Unterformularen, deren Eigenschaft Standardansicht auf Endlosformular gesetzt ist. Ein Unterformular zeigt alle Bestellungen eines bestimmten Kunden und ein weiteres alle Einzelheiten einer ausgewählten Bestellung an.
358
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Abbildung 9.4: Ein Formular mit Endlosunterformularen
9.7.3
Mehrseitige Formulare: Wenn nicht alles auf einen Bildschirm passt
Der mangelnde Platz auf dem Bildschirm ist immer ein Problem, das Sie aber mit einem mehrseitigen Formular umgehen können. Die Abbildungen 9.5 und 9.6 zeigen die zwei Seiten des mehrseitigen Personalformulars, welches in der NordwindDatenbank zu finden ist. Wenn Sie das Formular in der Entwurfsansicht betrachten, erkennen Sie ein Steuerelement für einen Seitenumbruch etwa bei der 7-cm-Marke des Formulars (siehe Abbildung 9.7). Um einen Seitenumbruch einzufügen, wählen Sie in der Toolbox das Symbol für den Seitenwechsel. Anschließend klicken Sie auf die Stelle im Formular, an welcher der Umbruch erscheinen soll.
Abbildung 9.5: Die erste Seite eines mehrseitigen Formulars
359
Welche Arten von Formularen kann ich erstellen und wann sind sie geeignet?
Abbildung 9.6: Die zweite Seite eines mehrseitigen Formulars
Abbildung 9.7: Die Entwurfsansicht eines mehrseitigen Formulars
Wenn Sie ein mehrseitiges Formular erstellen, müssen Sie fünf wichtige Schritte beachten: 1. Wählen Sie für die Standardansicht die Option EINZELNES Formular aus. 2. Setzen Sie die Eigenschaft BILDLAUFLEISTEN des Formulars auf NEIN oder NUR HORIZONTAL. 3. Setzen Sie die Größenanpassung auf NEIN. 4. Platzieren Sie den Seitenwechsel genau auf der Hälfte des Detailbereichs, wenn das Formular über zwei Seiten verfügen soll. Möchten Sie mehrere Seiten einrichten, dann teilen Sie die Gesamthöhe des Detailbereichs durch die Anzahl der
360
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Seiten und fügen die Seitenwechsel an den entsprechenden Positionen auf dem Formular ein. 5. Legen Sie die Größe des Formularfensters so fest, dass genau eine Seite des Formulars hineinpasst.
9.7.4
Formulare mit Registerkarten: Für Übersichtlichkeit sorgen
Ein Formular mit Registerkarten stellt eine Alternative zu mehrseitigen Formularen dar. Access 97 und Access 2000 verfügen über ein integriertes Steuerelement für Registerkarten, mit dem Sie auf einfache Weise Gruppen von Steuerelementen zusammenfassen können. Ein Formular mit Registerkarten kann beispielsweise auf einer Registerkarte die Kunden, auf der nächsten die Bestellungen des ausgewählten Kunden und auf einer weiteren Einzelheiten einer bestimmten Bestellung anzeigen. Das Formular in Abbildung 9.8 enthält ein Registerkartensteuerelement. Es handelt sich um das Formular Personal aus der Nordwind-Datenbank. Auf der einen Registerkarte werden die Personaldaten und auf der anderen die persönlichen Daten des Mitarbeiters angezeigt. Hierfür ist keine Programmierung erforderlich.
Abbildung 9.8: Ein mehrseitiges Formular mit Registerkarten
Ein Registersteuerelement hinzufügen und seine Seiten bearbeiten Um einem Formular eine Registerkarte hinzuzufügen, wählen Sie in der Toolbox einfach das Symbol für das Registersteuerelement und legen es auf dem Formular ab. Standardmäßig erscheinen zwei Registerseiten. Um weitere Registerkarten hinzuzufügen, klicken Sie mit der rechten Maustaste auf das Steuerelement und wählen die Option SEITE EINFÜGEN. Möchten Sie eine Registerkarte entfernen, klicken Sie mit der rechten Maustaste auf die entsprechende Registerkarte und wählen die Option SEITE LÖSCHEN. Die Reihenfolge der Registerkarten ändern Sie, indem Sie ebenfalls mit der rechten Maustaste die Karte anklicken und anschließend die Option SEITENREIHENFOLGE wählen.
Welche Arten von Formularen kann ich erstellen und wann sind sie geeignet?
361
Zu Registerkarten Steuerelemente hinzufügen Sie können den Registerkarten in der gleichen Weise Steuerelemente hinzufügen, wie Sie dies auch bei einem Formular tun. Vergessen Sie jedoch nicht, vor dem Hinzufügen der Steuerelemente die Registerkarte durch Anklicken auszuwählen. Wählen Sie keine bestimmte Registerkarte aus, erscheinen die Steuerelemente auf jeder Karte. Die Aktivierreihenfolge von Steuerelementen verändern Die Steuerelemente jeder Registerkarte weisen eine eigene Aktivierreihenfolge auf. Um diese zu ändern, klicken Sie mit der rechten Maustaste auf die Registerkarte und wählen die Option AKTIVIERREIHENFOLGE. Sie können dann die Steuerelemente für die Seite beliebig neu anordnen. Die Eigenschaften des Registersteuerelements verändern Um die Eigenschaften des Registersteuerelements zu ändern, markieren Sie dieses durch Anklicken (damit soll keine bestimmte Seite ausgewählt werden). Ob Sie das Registersteuerelement gewählt haben, können Sie erkennen, wenn in der linken Ecke der Titelleiste des Eigenschaftenfensters REGISTERSTEUERELEMENT angezeigt wird (siehe Abbildung 9.9). Zu den Eigenschaften eines Registersteuerelements gehören der Name, die Schriftart auf den Registerkarten und anderes mehr.
Abbildung 9.9: Die Eigenschaften eines Registersteuerelements
Die Eigenschaften jeder Seite ändern Wählen Sie eine bestimmte Seite des Registersteuerelements aus, um dessen Eigenschaften zu ändern. Sie erkennen die Auswahl wiederum daran, dass in der linken Ecke der Titelleiste des Eigenschaftenfensters SEITE angezeigt wird (siehe Abbildung 9.10). Auf dieser Registerkarte können Sie den Namen der Seite und die Beschriftung eingeben sowie einen Hintergrund einstellen usw.
362
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Abbildung 9.10: Die Eigenschaften der Registerseite
9.7.5
Übersichtsformulare: Ihre Anwendung steuern
Mit einem Übersichtsformular können Sie Ihre Anwendung sehr gut steuern. Ein Übersichtsformular ist ein Formular mit Schaltflächen, mit denen Sie sich zu anderen Übersichtsformularen oder Formularen und Berichten bewegen können, die Ihr System bilden. Abbildung 9.11 enthält ein Übersichtsformular. Der Benutzer kann mit verschiedenen Komponenten der Datenbank arbeiten. Das Übersichtsformular unterscheidet sich von anderen Formularen dadurch, dass sein Zweck allein darin besteht, durch die Anwendung zu führen. Normalerweise ist als Rahmenart DIALOG festgelegt. Bildlaufleisten, Datensatzmarkierer oder Navigationsschaltflächen fehlen meist. Abgesehen von diesen Eigenschaften handelt es sich beim Übersichtsformular um ein ganz normales Formular. Es gibt viele Arten von Navigationsformularen und für welches Sie sich entscheiden, hängt von Ihren Erfordernissen ab.
Abbildung 9.11: Ein Beispiel für ein Übersichtsformular
Welche Arten von Formularen kann ich erstellen und wann sind sie geeignet?
9.7.6
363
Der Begrüßungsbildschirm: Ein professioneller Start einer Anwendung
Begrüßungsbildschirme verleihen Ihren Anwendungen einen professionellen Anstrich und führen den Benutzern etwas vor, während die Anwendung geladen wird. Mit den folgenden Schritten erstellen Sie ein Formular für einen Begrüßungsbildschirm: 1. Erstellen Sie ein neues Formular. 2. Setzen Sie die Eigenschaften Bildlaufleisten, Datensatzmarkierer und Navigationsschaltflächen auf Nein, Größe anpassen und Automatisch zentrieren auf Ja und Rahmenart auf Keine. 3. Setzen Sie die Eigenschaften PopUp und Gebunden auf Ja. 4. Fügen Sie dem Formular ein Bild hinzu und setzen Sie die Eigenschaften für das Bild fest. 5. Ergänzen Sie das Formular nach Bedarf mit geeignetem Text. 6. Setzen Sie die Eigenschaft Zeitgeberintervall auf die Zeit in Sekunden, für die der Begrüßungsbildschirm angezeigt werden soll. 7. Programmieren Sie das Ereignis Timer bzw. Bei Zeitgeber des Formulars für DoCmd.Close. 8. Programmieren Sie das Ereignis Unload bzw. Beim Entladen zum Öffnen Ihres Hauptübersichtsformulars. Da das Timer-Ereignis des Begrüßungsbildschirms das Formular nach dem angegebenen Zeitintervall schließt, entlädt sich der Begrüßungsbildschirm von alleine. Während des Entladens wird das Übersichtsformular geladen. Der Begrüßungsbildschirm ist in der Datenbank CHAP9EX.MDB unter dem Namen frmSplash zu finden. Beim Entladen wird das Formular frmSwitchBoard geöffnet. Sie können das Formular Ihres Begrüßungsbildschirms auch auf andere Weise implementieren. Das Formular kann beispielsweise über ein Startformular aufgerufen werden, dessen Routine für das Ereignis Open bzw. Beim Öffnen einfach nur das Formular des Begrüßungsbildschirms öffnet. Das Problem bei dieser Lösung liegt jedoch darin, dass beim Laden und Entladen des Übersichtsformulars während der Ausführung der Anwendung der Begrüßungsbildschirm noch einmal angezeigt wird. Sie können auch einen Begrüßungsbildschirm anzeigen lassen, der eine BitmapDatei mit dem Namen Ihrer Datenbank aus dem gleichen Verzeichnis der Datenbankdatei enthält. Beim Laden der Anwendung wird dann der Begrüßungsbildschirm für einige Sekunden angezeigt. Der Nachteil dabei ist, dass Sie weniger Steuerungsmöglichkeiten darüber haben, wann und wie lange der Begrüßungsbildschirm angezeigt wird.
364
9.7.7
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Dialogformulare: Informationen sammeln
Dialogformulare dienen üblicherweise dazu, Informationen vom Benutzer einzuholen. Zu Dialogformularen werden sie durch die Tatsache, dass sie gebunden sind. Das bedeutet, dass der Benutzer nicht mit der Anwendung fortfahren kann, bevor er nicht das Formular ausgefüllt hat. Dialogformulare werden im Allgemeinen dann eingesetzt, wenn Sie bestimmte Informationen vom Benutzer benötigen, damit Ihre Anwendung mit der Verarbeitung fortfahren kann. Bei einem benutzerdefinierten Dialogformular handelt es sich um ein normales Formular mit der Rahmenart Dialog, dessen Eigenschaft Gebunden auf Ja gesetzt wurde. Vergessen Sie nicht, eine Möglichkeit einzurichten, das Formular zu schließen, da die Benutzer das gebundene Formular sonst mit dem Klammeraffengriff ((Strg)+(Alt)+(Entf)) oder schlimmer noch mit der (æ)-Taste schließen müssen. Das Formular frmArchivePayments aus der Datenbank CHAP9EX.MDB ist ein Beispiel für ein Dialogformular. Das Festlegen der Eigenschaften Rahmenart auf Dialog und Gebunden auf Ja verhindert zwar, dass der Benutzer außerhalb des Formulars klicken und so die Anwendung fortsetzen kann, die Ausführung des Codes, der das Formular geöffnet hat, wird jedoch nicht angehalten. Angenommen, es soll ein Dialogformular geöffnet werden, um die Parameter für einen Bericht zu erfassen, und anschließend der Bericht mit diesen Parametern geöffnet werden; in diesem Fall muss die OpenForm-Methode zum Öffnen des Formulars die Option acDialog im Argument WindowMode enthalten, da sonst der Code nach der OpenForm-Methode fortgesetzt und der Bericht geöffnet wird, bevor die Parameter vom Benutzer abgefragt wurden.
9.8
Integrierte Dialogfelder
Access verfügt über zwei integrierte Dialogfelder: das Standardmeldungsfeld von Windows und das Eingabedialogfeld. Zum Microsoft Office Developer-Paket gehört das ActiveX-Steuerelement Common Dialog, mit dem Sie Zugriff auf andere typische Dialogfelder haben.
9.8.1
Meldungsfelder
Ein Meldungsfeld ist ein vordefiniertes Dialogfeld, das Sie in Ihre Anwendungen einbinden und mit Hilfe von Parametern anpassen können. VBA verwendet die Anweisung MsgBox (die eine Nachricht nur anzeigt) und die Funktion MsgBox, die eine Nachricht anzeigt und entsprechend einer Benutzerreaktion einen Wert zurückgibt. Das Meldungsfeld von VBA ist das gleiche, welches die meisten Windows-Anwendungen standardmäßig verwenden, so dass es den meisten Benutzern bereits vertraut ist. Anstatt ein eigenes Dialogfeld für Standardantworten erstellen zu müssen, können Sie diese bereits vorhandene Standardschnittstelle benutzen.
Integrierte Dialogfelder
365
Die Funktion MsgBox Die Funktion MsgBox übernimmt fünf Parameter. Der erste enthält die anzuzeigende Nachricht, und der zweite, numerische Parameter gibt an, welche Schaltflächen und Symbole angezeigt werden sollen. Die Tabellen 9.1 und 9.2 enthalten die nummerischen Werte für den zweiten Parameter. Anstelle dieser Werte können Sie auch die vordefinierten Konstanten aus der Tabelle einsetzen. Der dritte Parameter enthält die Beschriftung des Meldungsfelds. Der vierte und fünfte Parameter geben die Hilfedatei und die Kontext-ID an, damit dem Benutzer während der Anzeige des Meldungsfelds Hilfe zur Verfügung steht. MsgBox "Dies ist eine Nachricht", vblnformation, "Dies ist die Überschrift"
In diesem Beispiel werden die Nachricht »Dies ist eine Nachricht« und das Informationssymbol angezeigt. Die Überschrift des Meldungsfelds lautet »Dies ist die Überschrift«. In dem Meldungsfeld befindet sich die Schaltfläche OK, mit der das Dialogfeld geschlossen wird. Die MsgBox-Funktion wird normalerweise nur zum Anzeigen der Schaltfläche OK verwendet. Sie kann aber auch für verschiedene Kombinationen von Standardschaltflächen benutzt werden. Bei dieser Verwendung gibt sie die vom Benutzer gedrückte Schaltfläche zurück. Schaltflächen
Wert
vordefinierte Konstante
Nur OK
0
vbOKOnly
OK und ABBRECHEN
1
vbOKCancel
ABBRECHEN, WIEDERHOLEN und IGNORIEREN
2
vbAbortRetryIgnore
JA, NEIN und ABBRECHEN
3
vbYesNoCancel
JA und NEIN
4
vbYesNo
WIEDERHOLEN und IGNORIEREN
5
vbRetryCancel
Tabelle 9.1: Werte für die anzuzeigenden Schaltflächen
Die Werte aus Tabelle 9.1 müssen zu einem Wert aus der Tabelle 9.2 addiert werden, wenn Sie ein anderes Symbol als das Standardsymbol des Dialogfelds einschließen möchten.
366
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Symbol
Wert
Vordefinierte Konstante
KRITISCH (STOPPZEICHEN)
16
vbCritical
BESTÄTIGUNG (FRAGEZEICHEN)
32
vbQuestion
WARNUNG (!)
48
vbExclamation
INFORMATION (I)
64
vbInformation
Tabelle 9.2: Die Werte für die anzuzeigenden Symbole
Das Meldungsfeld des folgenden Beispiels zeigt die Schaltflächen JA, NEIN und ABBRECHEN an: Sub MessageBoxFunction() Dim intAnswer As Integer intAnswer = MsgBox("Sind Sie sicher?", vbYesNocancel + vbQuestion,_ "Bitte antworten Sie!") End Sub
Dieses Meldungsfeld zeigt auch das Fragezeichen an (siehe Abbildung 9.12). Der Funktionsaufruf gibt mit der Integer-Variablen intAnswer einen Wert zurück.
Abbildung 9.12: Das von der Funktion MsgBox angezeigte Dialogfeld
Mit dem Rückgabewert der Variablen können Sie wie im folgenden Beispiel die entsprechende Reaktion des Programms in Abhängigkeit von der Benutzereingabe festlegen: Sub MessageBoxAnswer() Dim intAnswer As Integer intAnswer = MsgBox("Are You Sure?", vbYesNoCancel + vbQuestion, _ "Please Respond") Select Case intAnswer Case vbYes MsgBox "I'm Glad You are Sure!!" Case vbNo MsgBox "Why Aren't You Sure?" Case vbCancel MsgBox "You Coward! You Bailed Out!!" End Select End Sub
Integrierte Dialogfelder
367
Dieser Code wertet die Antwort des Benutzers aus und zeigt eine entsprechende Nachricht an. In der Praxis würde der Code in der Case-Anweisung selbstverständlich sinnvolleren Zwecken dienen. Tabelle 9.3 führt die Rückgabewerte für die unterschiedlichen Schaltflächen der Funktion MsgBox auf. Antwort
Wert
Vordefinierte Konstante
OK
1
vbOK
Abbrechen
2
vbCancel
Abbruch
3
vbAbort
Wiederholen
4
vbRetry
Ignorieren
5
vbIgnore
Ja
6
vbYes
Nein
7
vbNo
Tabelle 9.3: Die Rückgabewerte der Funktion MsgBox
9.8.2
Eingabefelder
Die Funktion InputBox zeigt ein Dialogfeld mit einem einfachen Textfeld an und gibt den vom Benutzer eingegebenen Text zurück: Sub InputBoxExample() Dim strName As String strName = InputBox("Wie heißen Sie?",_ "Überschrift", "Standardwert") MsgBox "Sie haben eingegeben: " & strName End Sub
Diese Unterroutine zeigt das in Abbildung 9.13 gezeigte Eingabefeld an. Beachten Sie, dass der erste Parameter eine Nachricht, der zweite die Überschrift und der dritte den Standardwert enthält. Der zweite und dritte Parameter sind optional.
Abbildung 9.13: Ein Beispiel für die Verwendung der Funktion InputBox zum Einholen von Informationen
368
9.8.3
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Standardmäßige Dialogfelder
Wie bereits erwähnt wurde, handelt es sich bei dem Steuerelement für standardmäßige Dialogfelder um ein OCX-Steuerelement, welches Bestandteil von ODE ist. Sie können damit standardgemäße Windows-Dialogfelder anzeigen, wie zum Beispiel DATEI SPEICHERN, DATEI ÖFFNEN, DATEI DRUCKEN, DRUCKER EINRICHTEN, SCHRIFTARTEN und FARBEN. Das standardgemäße Steuerelement für Dialogfelder (Common Dialog) wird in Kapitel 25 behandelt.
9.9
Formularen benutzerdefinierte Menüs, Symbolleisten und Kontextmenüs hinzufügen
Sie können unbegrenzt viele eigene Menüs definieren und mit Ihren Formularen und Berichten anzeigen lassen. Jedes Menü kann mit einem oder mehreren Formularen verbunden sein. Oft werden Einschränkungen bezüglich der möglichen Benutzeraktionen während der Bearbeitung eines Formulars oder Berichts vorgenommen. Durch eigene Menüs können Sie die durchführbaren Aktionen einschränken und anpassen.
9.9.1
Ein Menü entwerfen
Vor Access 97 wurde eine benutzerdefinierte Menüleiste dadurch eingerichtet, dass der Eigenschaft MenuBar der Name eines Menüleistenmakros zugewiesen wurde. Diese Funktion wird nur noch aus Gründen der Abwärtskompatibilität unterstützt. In Access 97 und Access 2000 werden benutzerdefinierte Menüleisten, Symbolleisten und Popup-Menüs insgesamt als »Befehlsleisten« bezeichnet. Um eines dieser drei Objekte zu erstellen, wählen Sie ANSICHT|SYMBOLLEISTEN|ANPASSEN. Nachdem Sie eine eigene Menüleiste, eine Symbolleiste oder ein Popup-Menü erstellt haben, können Sie über die Eigenschaften eine Verknüpfung mit Formularen und Berichten herstellen. Mit den folgenden Schritten erstellen Sie eine eigene Menüleiste: 1. Wählen Sie ANSICHT|SYMBOLLEISTEN|ANPASSEN oder klicken Sie mit der rechten Maustaste auf eine beliebige Symbolleiste und wählen Sie die Option ANPASSEN. 2. Im Dialogfeld ANPASSEN wählen Sie auf der Registerkarte SYMBOLLEISTEN die Option NEU (siehe Abbildung 9.14). 3. Wenn Sie der neuen Befehlsleiste einen Namen zuweisen, wird diese anschließend angezeigt. 4. Klicken Sie im Dialogfeld ANPASSEN auf die Schaltfläche EIGENSCHAFTEN, um die Eigenschaften der neu erstellten Symbolleiste anzeigen zu lassen. Benennen Sie Ihre neue Symbolleiste im Dialogfeld SYMBOLLEISTENEIGENSCHAFTEN, wäh-
Formularen benutzerdefinierte Menüs hinzufügen
369
len Sie den Typ und die zulässige Art des Andockens aus und stellen Sie die übrigen Eigenschaften der Befehlsleiste ein. Im aufklappbaren Listenfeld TYP können Sie zwischen den Einträgen SYMBOLLEISTE, MENÜLEISTE und POPUP auswählen. Als Optionen für das Andocken stehen Ihnen ALLE ZULASSEN, ÄNDERUNGEN NICHT MÖGLICH, NICHT VERTIKAL und NICHT HORIZONTAL zur Verfügung. Sie können auch festlegen, ob der Benutzer das Menü oder die Symbolleiste anpassen oder verschieben darf. 5. Wählen Sie die gewünschten Optionen und klicken Sie auf die Schaltfläche SCHLIESSEN.
Abbildung 9.14: Das Dialogfeld Anpassen zum Erstellen einer neuen Befehlsleiste verwenden
Sie können der Symbolleiste, der Menüleiste oder dem Popup-Menü jetzt Elemente hinzufügen. Der Ablauf unterscheidet sich jeweils geringfügig, je nach der Art der Befehlsleiste. Um einer Befehlsleiste Elemente hinzuzufügen, klicken Sie im Dialogfeld ANPASSEN auf die Registerkarte BEFEHLE (siehe Abbildung 9.15). Ziehen Sie die gewünschten Befehlssymbole in die neue Befehlsleiste. Es folgen einige Hinweise, die Ihnen beim Erstellen eigener Menüleisten, Symbolleisten und Popup-Menüs helfen können:
Um der Menüleiste ein vollständiges, integriertes Menü hinzuzufügen, wählen Sie im Listenfeld KATEGORIEN den Eintrag Eingebaute Menüs. Klicken Sie auf das gewünschte Menü und ziehen Sie dieses aus dem Dialogfeld BEFEHLE hinüber in die Menüleiste Ihres eigenen Menüs.
Um ein eigenes Menüelement zu erstellen, wählen Sie im Listenfeld KATEGORIEN den Eintrag Neues Menü. Klicken Sie auf die Option NEUES MENÜ und ziehen Sie diese in die Menüleiste. Klicken Sie mit der rechten Maustaste auf das Menü und geben Sie im Textfeld NAME einen Namen ein.
370
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Abbildung 9.15: Der Befehlsleiste mit der Registerkarte Befehle neue Elemente hinzufügen
Möchten Sie dem Menü einen eingebauten Befehl hinzufügen, dann wählen Sie im Listenfeld KATEGORIE die entsprechende Kategorie aus und ziehen den Befehl in das Menüfeld. Das neue Element erscheint unterhalb der Menüoption.
Um ein Menü mit einem Trennstrich zu unterteilen, klicken Sie mit der rechten Maustaste auf das Menüelement, welches auf den Trennstrich folgen soll, und wählen GRUPPIERUNG BEGINNEN. Heben Sie die Auswahl des Kontrollkästchens GRUPPIERUNG BEGINNEN wieder auf, wird der Trennstrich wieder entfernt.
Menüelemente können als Text oder Schaltflächensymbol mit Text angezeigt werden. Wählen Sie die entsprechende Variante, indem Sie mit der rechten Maustaste ein Menüelement anklicken und anschließend eine der Optionen NUR TEXT (IMMER), NUR TEXT (IN MENÜS) oder SCHALTFLÄCHENSYMBOL UND TEXT wählen. Entscheiden Sie sich für eines der verfügbaren Schaltflächensymbole. Möchten Sie das Symbol verändern, klicken Sie mit der rechten Maustaste auf das Menüelement und wählen SCHALTFLÄCHE BEARBEITEN. Dies öffnet das Dialogfeld SCHALTFLÄCHEN-EDITOR (siehe Abbildung 9.16). Möchten Sie den ursprünglichen Zustand eines Schaltflächensymbols wiederherstellen, klicken Sie mit der rechten Maustaste auf das Menüelement und wählen die Option SCHALTFLÄCHE ZURÜCKSETZEN.
Möchten Sie mehrere Eigenschaften eines Menüelements auf einmal ändern, klicken Sie mit der rechten Maustaste auf das Menüelement und wählen die Option EIGENSCHAFTEN, um das Dialogfeld STEUERELEMENT-EIGENSCHAFTEN zu öffnen (siehe Abbildung 9.17). Hier können Sie die Attribute eines Menüelements wie zum Beispiel die Beschriftung, die QUICKINFO, die Hilfedatei und die Hilfekontext-ID festlegen. Außerdem können Sie mit einem benutzerdefinierten Menüelement auch eine Aktion verknüpfen, was im nächsten Abschnitt beschrieben wird.
Formularen benutzerdefinierte Menüs hinzufügen
371
Abbildung 9.16: Mit dem Schaltflächen-Editor Schaltflächensymbole verändern oder erstellen
Abbildung 9.17: Die Eigenschaften eines Menüelements im Dialogfeld Steuerelement-Eigenschaften bearbeiten
9.9.2
Einen Menüeintrag mit einem Befehl verbinden
Access bietet Ihnen die Möglichkeit, die benutzerdefinierten Menüs mit Hilfe von integrierten Befehlen und Funktionen auf einfache Weise anzupassen. Integrierte Befehle müssen Sie lediglich in die Befehlsleiste ziehen. Damit ein Befehlsleistenelement eine selbst entwickelte Funktion ausführt, müssen Sie ein Element erstellen und dessen Eigenschaften einrichten: 1. Wählen Sie im Listenfeld KATEGORIEN des Dialogfelds ANPASSEN die Kategorie Datei.
372
Kapitel 9: Fortgeschrittene Verwendung von Formularen
2. Klicken Sie die Option BENUTZERDEFINIERT an und ziehen Sie diese aus dem Listenfeld BEFEHLE an die entsprechende Position in Ihrem Menü. 3. Klicken Sie mit der rechten Maustaste auf das neue Menüelement und wählen Sie die Option EIGENSCHAFTEN. 4. Geben Sie den Namen der aufzurufenden Funktion oder Unterroutine im aufklappbaren Listenfeld BEI AKTION ein. Handelt es sich bei der aufzurufenden Prozedur um eine Funktion, müssen Sie dem Funktionsnamen ein Gleichheitszeichen voranstellen und nach dem Funktionsnamen die Parameter in Klammern angeben. 5. Klicken Sie auf die Schaltfläche SCHLIESSEN, um das Dialogfeld STEUERELEMENT-EIGENSCHAFTEN zu schließen. 6. Klicken Sie auf die Schaltfläche SCHLIESSEN, um das Dialogfeld ANPASSEN zu schließen.
9.9.3
Menüs löschen und umbenennen
Über das Dialogfeld ANPASSEN können Sie auch Menüs löschen oder umbenennen. Führen Sie hierzu die folgenden Schritte durch: 1. Klicken Sie mit der rechten Maustaste auf eine Befehlsleiste und wählen Sie die Option ANPASSEN. 2. Markieren Sie im Listenfeld SYMBOLLEISTEN die Befehlsleiste, die Sie löschen oder umbenennen möchten. 3. Klicken Sie auf die Schaltflächen LÖSCHEN oder UMBENENNEN, um die Befehlsleiste zu löschen bzw. umzubenennen.
9.9.4
Programmgesteuerte Befehlsleistenbearbeitung
Sie können Befehlsleisten auch mit Hilfe von VBA-Code hinzufügen, verändern oder entfernen, was Ihren Anwendungen Flexibilität verleiht. So können Sie zum Beispiel eine Befehlsleiste als Reaktion auf unterschiedliche Bedingungen innerhalb der Anwendung verändern. Außerdem können Sie den Benutzern auch die Möglichkeit einräumen, die Befehlsleisten Ihrer Anwendung selbst zu verändern, wie dies am Beispiel des Moduls basExamples aus der Datenbank CHAP9EX.MDB gezeigt wird. Sub CreateCustomCommandBar() On Error Resume Next Dim cbr As CommandBar Dim btn As CommandBarButton Set cbr = CommandBars("My Command Bar") If Err <> 0 Then Set cbr = CommandBars _ .Add(Name:="My Command Bar", Position:=msoBarTop)
Die integrierten Funktionen zur Formularfilterung ausnutzen
373
End If Set btn = cbr.Controls("Are You Sure?") If Err <> 0 Then ' Befehlsschaltfläche ist noch nicht vorhanden => Erstellen Set btn = cbr.Controls.Add(msoControlButton, , , , True) End If With btn .Caption = "Are You Sure?" .BeginGroup = True .OnAction = "MessageBoxAnswer" .Style = msoButtonCaption End With End Sub
Dieser Code zeigt, dass Sie über VBA die vollständige Kontrolle über das Menüleistenobjekt haben. Zuerst werden Objektvariablen der Typen CommandBar und CommandBarButton erzeugt. Die CommandBar-Objektvariable wird auf den Wert "My Command Bar" gesetzt. Führt dies zu einem Fehler, dann wissen Sie, dass "My Command Bar" gar nicht existiert. Mit der Methode Add wird die Befehlsleiste hinzugefügt und am oberen Rand des Bildschirms platziert. Anschließend versucht die Routine, auf die Schaltfläche "Sind Sie sicher?" in der Befehlsleiste zu verweisen. Führt dies zu einer Fehlermeldung, wird mit der Add-Methode der Steuerelementeauflistung des CommandBar-Objekts die Befehlsschaltfläche der Auflistung hinzugefügt. Die Beschriftung der Schaltfläche wird auf "Are You sure?" gesetzt, eine Gruppe hinzugefügt und die Aktion der Schaltfläche erhält den Aufruf der Unterroutine MessageBoxAnswer. Für die Anzeige wird festgelegt, dass nur die Beschriftung angezeigt wird.
9.10
Die integrierten Funktionen zur Formularfilterung ausnutzen
Access verfügt über zahlreiche Eigenschaften zum Filtern von Formularen, die Bestandteil der Benutzerschnittstelle sind. Sie können die Eigenschaften in Ihre Anwendung übernehmen, sie vollständig weglassen oder ihr Verhalten steuern. Damit Ihre Anwendung das Verhalten steuern kann, muss sie auf das Filter-Ereignis reagieren, was dadurch geschieht, dass sie erkennt, wann ein Datenfilter in das Formular eingefügt wird. Wurde der Filter erkannt, wird der Code zum Filter-Ereignis ausgeführt. In bestimmten Fällen kann es wünschenswert sein, das Standardverhalten des Filterbefehls zu verändern, vielleicht um einem Benutzer eine spezielle Nachricht anzuzeigen oder mit dem Code eine bestimmte Aktion durchzuführen. Es ist auch möglich, dass die Anwendung auf ein Filter-Ereignis reagieren soll, weil Sie die Anzeige des Formulars vor der Anwendung des Filters ändern möchten. Zum Beispiel können
374
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Sie für einen bestimmten Filter ausgewählte Felder deaktivieren oder verbergen. Wird der Filter entfernt, können Sie wieder zur normalen Ansicht zurückkehren. Access teilt Ihnen nicht nur mit, dass ein Filter-Ereignis eingetreten ist, sondern auch, wie der Filter eingerichtet wurde. Ausgerüstet mit diesen Informationen können Sie den Filter abfangen und dessen Verhalten wie gewünscht ändern. Wählt ein Benutzer die Option FORMULARBASIERTER FILTER oder SPEZIALFILTER/ -SORTIERUNG, erhält der Parameter FilterType einen Wert, der angibt, wie der Filter angewendet werden soll. Wählt der Benutzer die Option FORMULARBASIERTER FILTER, entspricht dieser Wert der Konstanten acFilterByForm, wählt er jedoch die Option SPEZIALFILTER/-SORTIERUNG, dann wird der Parameter der Konstanten acFilterAdvanced gleichgesetzt. Der folgende Code veranschaulicht die Verwendung dieser beiden Konstanten: PRIVATE SUB FORM_FILTER(CANCEL AS INTEGER, FILTERTYPE AS INTEGER)
SELECT CASE FILTERTYPE CASE ACFILTERBYFORM MSGBOX "YOU JUST SELECTED FILTER BY FORM" CASE ACFILTERADVANCED MSGBOX "YOU ARE NOT ALLOWED TO SELECT ADVANCED FILTER/SORT" CANCEL = TRUE END SELECT END SUB
Dieser Code des Filter-Ereignisses wertet die Filterart aus. Wurde die Option FORMULARBASIERTER FILTER gewählt, wird ein Meldungsfeld angezeigt und die Filterung verläuft wie gewöhnlich. Wählt der Benutzer dagegen die Option SPEZIALFILTER/ -SORTIERUNG, wird ihm mitgeteilt, dass dies nicht möglich ist und das Filtern abgebrochen. Sie können nicht nur überprüfen, wie der Filter aufgerufen wurde, sondern auch den Vorgang abfangen, wenn der Filter angewendet wird. Hierfür fügen Sie den folgenden Code in die Routine für das ApplyFilter-Ereignis des Formulars ein: Private Sub Form_ApplyFilter(Cancel As Integer, ApplyType As Integer) Dim intAnswer As Integer If ApplyType = acApplyFilter Then intAnswer = MsgBox("You Selected the Criteria: & _ Chr(13) & Chr(10) & Me.Filter & _ Chr(13) & Chr(10) & Are You Sure You Wish _ to Proceed?", vbYesNo + vbQuestion) If intAnswer = vbNo Then Cancel = True End If End If End Sub
Objekte aus anderen Anwendungen einfügen: Verknüpfen oder Einbetten
375
Dieser Code wertet den Parameter ApplyType aus. Ist der Wert gleich der Konstanten acApplyFilter, wird ein Meldungsfeld angezeigt und der Benutzer gefragt, ob er den Filter anwenden möchte. Bestätigt der Benutzer die Anfrage, wird der Filter angewendet, andernfalls wird das Filtern abgebrochen.
9.11
Objekte aus anderen Anwendungen einfügen: Verknüpfen oder Einbetten
Microsoft Access ist eine ActiveX-Client-Anwendung, was bedeutet, dass AccessAnwendungen Objekte von anderen Anwendungen enthalten können. Access 97 und Access 2000 sind gleichzeitig aber auch ActiveX-Server-Anwendungen. Der Einsatz von Access als ActiveX-Server wird in Kapitel 26 behandelt. Dieses Kapitel behandelt außerdem die Fähigkeit von Access, andere Anwendungen über Code zu steuern. In den folgenden Abschnitten lernen Sie, wie Sie Objekte in Ihr Access-Formular einbetten und mit diesem verknüpfen können.
9.11.1
Gebundene OLE-Objekte
Gebundene OLE-Objekte sind an Daten eines OLE-Felds der Tabelle Ihrer Datenbank gebunden. Ein Beispiel hierfür ist das Feld Foto aus der Tabelle Personal der Nordwind-Datenbank. Der Feldtyp der Tabelle Personal, der Multimediadaten unterstützt, heißt OLE-Objekt. Jeder Datensatz der Tabelle kann ein eigenes OLEObjekt enthalten. Das Formular Personal enthält ein gebundenes OLE-Steuerelement, dessen Steuerelementquelle das Feld Foto der Personal-Tabelle ist. Klicken Sie direkt auf das Foto eines Mitarbeiters, kann das OLE-Objekt direkt bearbeitet werden. Das Bild des Mitarbeiters ist unmittelbar in die Personal-Tabelle eingebettet. Das bedeutet, dass die mit dem OLE-Objekt verbundenen Daten tatsächlich in der Tabelle Personal der Access-Datenbankdatei (MDB) gespeichert werden. Wenn die eingebetteten Objekte den OLE-Standard 2.0 unterstützen, können sie direkt bearbeitet werden. Dieser Vorgang wird »direkte Aktivierung« genannt. Führen Sie die folgenden Schritte durch, um ein neues Objekt einzufügen: 1. Wechseln Sie zu dem Datensatz, der das OLE-Objekt enthalten soll. 2. Klicken mit der rechten Maustaste das OLE-Objekt-Steuerelement an und wählen Sie die Option OBJEKT EINFÜGEN, um das Dialogfeld OBJEKT EINFÜGEN zu öffnen. 3. Wählen Sie einen Objekttyp. Möchten Sie ein eingebettetes Objekt erzeugen, wählen Sie NEU ERSTELLEN. Möchten Sie eine vorhandene Datei einbetten oder verknüpfen, dann wählen Sie AUS DATEI ERSTELLEN. 4. Markieren Sie die Option AUS DATEI ERSTELLEN, ändert sich das Dialogfeld OBJEKT EINFÜGEN und sieht so wie in Abbildung 9.18 aus.
376
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Abbildung 9.18: Das Dialogfeld Objekt einfügen nach dem Markieren der Option Aus Datei erstellen
5. Wenn Sie eine Verknüpfung zu einer vorhandenen Datei erstellen möchten, aktivieren Sie das Kontrollkästchen VERKNÜPFEN. Aktivieren Sie dieses Kontrollkästchen nicht, wenn Sie eine vorhandene Datei einbetten möchten. Wenn Sie die Datei verknüpfen, enthält die Access-Tabelle einen Verweis auf die Datei sowie eine Darstellung der Daten des Objekts (eine Bitmap). Betten Sie die Datei ein, kopiert Access die Originaldatei und platziert die Kopie in der Access-Tabelle. 6. Klicken Sie auf die Schaltfläche DURCHSUCHEN und wählen Sie die einzubettende oder zu verknüpfende Datei aus. 7. Klicken Sie auf OK. Mit einem Doppelklick auf ein verknüpftes Objekt starten Sie die Anwendung, mit der das Objekt erstellt wurde. Zu einer direkten Aktivierung kommt es dabei nicht (siehe Abbildung 9.19).
Abbildung 9.19: Ein verknüpftes Objekt bearbeiten
OpenArgs
9.11.2
377
Ungebundene OLE-Objekte
Ungebundene OLE-Objekte werden nicht in der Datenbank gespeichert. Sie sind stattdessen Bestandteil des Formulars, in dem sie erstellt wurden. Wie die gebundenen können auch die ungebundenen Objekte verknüpft oder eingebettet werden. Ein ungebundenes OLE-Objekt erstellen Sie, indem Sie dem Formular ein ungebundenes Objektfeld hinzufügen.
9.12
OpenArgs
Über die Eigenschaft OpenArgs können Sie einem Formular beim Öffnen Informationen übergeben. Das Argument OpenArgs der Methode OpenForm dient zur inhaltlichen Füllung der OpenArgs-Eigenschaft eines Formulars während der Ausführung. Die Methode funktioniert wie folgt: DoCmd.OpenForm "frmPaymentMethods", _ Datamode:=acFormAdd, _ WindowMode:=acDialog, _ OpenArgs:=NewData
Dieser Code stammt aus dem Formular frmPayments des Zeit- und Abrechnungssytems. Er öffnet das Formular frmPaymentMethods, wenn eine neue Zahlungsart im Kombinationsfeld cboPaymanetMethodID hinzugefügt wird, und sendet dem Formular frmPaymentMethods das OpenArgs-Argument mit den im Kombinationsfeld hinzugefügten Daten. Die Routine zum Ereignis Load des Formulars frmPaymentMethods sieht wie folgt aus: Private Sub Form_Load() If Not IsNull(Me.OpenArgs) Then Me.txtPaymentMethod.Value = Me.OpenArgs End If End Sub
Dieser Code weist dem Textfeld txtPaymentMethod den Wert des beim Öffnen übergebenen Arguments zu. Hierzu kommt es nur, wenn das Formular frmPaymentMethods über das Formular frmPayments geöffnet wird.
9.13
Die Datenherkunft eines Formulars wechseln
Vielen Entwicklern ist nicht klar, wie einfach die Eigenschaft RecordSource (Datenherkunft) eines Formulars während der Ausführung neu gesetzt werden kann. Dieser Vorgang bietet eine gute Möglichkeit, Daten von mehr als einer Tabelle oder Abfrage mit den gleichen Feldern in einem Formular anzeigen zu lassen. Außerdem lassen sich so sehr gut die zu einem bestimmten Zeitpunkt im Formular angezeigten
378
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Daten einschränken. Durch die Technik des Änderns der Eigenschaft RecordSource während der Ausführung kann die Leistung stark verbessert werden, insbesondere bei Client-/Server-Anwendungen (siehe Listing 9.1). Dieses Beispiel stammt aus dem Formular frmShowSales der Datenbank CHAP9EX (siehe Abbildung 9.20).
Abbildung 9.20: Ändern der Eigenschaft RecordSource eines Formulars während der Ausführung Listing 9.1: Ändern der Eigenschaft RecordSource eines Formulars während der Ausführung Private Sub cmdShowSales_Click() 'Enddatum > Anfangsdatum? If Me.txtEndingDate < Me.txtBeginningDate Then MsgBox "The Ending Date must be later than the Beginning Date." txtBeginningDate.SetFocus Exit Sub End If ' '
SQL-Anweisung mit Suchkriterien erstellen und Datenherkunft festlegen
Dim strSQL As String Dim strRestrict As String Dim lngX As Long lngX = Me.optSales.Value strRestrict = ShowSalesValue(lngX) ' SQL-Anweisung erstellen strSQL = "SELECT DISTINCTROW tblCustomers.CompanyName, _ qryOrderSubtotals.OrderID, " strSQL = strSQL & "qryOrderSubtotals.Subtotal , tblOrders.ShippedDate " strSQL = strSQL & "FROM tblCustomers INNER JOIN (qryOrderSubtotals INNER JOIN _
Die Datenherkunft eines Formulars wechseln
379
tblOrders ON " strSQL = strSQL & "qryOrderSubtotals.OrderID = tblOrders.OrderID) ON " strSQL = strSQL & "tblCustomers.CustomerID = tblOrders.CustomerID " strSQL = strSQL & "WHERE (tblOrders.ShippedDate Between Forms!frmShowSales!txtBeginningDate " strSQL = strSQL & "And Forms!frmShowSales!txtEndingDate) " strSQL = strSQL & "And " & strRestrict strSQL = strSQL & " ORDER BY qryOrderSubtotals.Subtotal DESC;" ' Datenherkunft festlegen Me.fsubShowSales.Form.RecordSource = strSQL ' ' ' If
Falls den Kriterien keine Datensätze entsprechen, die Datenherkunft des_ Unterformulars zurücksetzen, eine Meldung anzeigen und den Fokus aufs_ Textfeld BeginningDate bewegen Me.fsubShowSales.Form.RecordsetClone.RecordCount = 0 Then Me.fsubShowSales.Form.RecordSource = "SELECT CompanyName FROM tblCustomers WHERE False;" MsgBox "No records match the criteria you entered.", vbExclamation, "No Records Found" Me.txtBeginningDate.SetFocus Else ' Steuerelement im Detailbereich aktivieren EnableControls Me, acDetail, True ' Einfügemarke auf ShowSalesSubform bewegen Me.fsubShowSales!txtCompanyName.SetFocus End If End Sub Private Function ShowSalesValue(lngOptionGroupValue As Long) As String ' Rückgabewerte wurden in der Optionsgruppe Sales ausgewählt ' Konstanten für Optionsgruppenwerte definieren Const conSalesUnder1000 = 1 Const conSalesOver1000 = 2 Const conAllSales = 3 ' Create restriction based on value of option group. Select Case lngOptionGroupValue Case conSalesUnder1000: ShowSalesValue = "qryOrderSubtotals.Subtotal < 1000" Case conSalesOver1000: ShowSalesValue = "qryOrderSubtotals.Subtotal >= 1000" Case Else ShowSalesValue = "qryOrderSubtotals.Subtotal = True" End Select End Function
380
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Zu Beginn der Routine wird der Wert der Optionsgruppe optSales des Hauptformulars frmShowSales in einer Variablen vom Typ Long Integer gespeichert. Anschließend wird die Funktion ShowSalesValue aufgerufen, die drei Konstanten deklariert. Danach wird der übergebene Parameter ausgewertet (die Variable vom Typ Long Integer mit dem Wert der Optionsgruppe). Anhand dieses Werts wird eine Auswahlzeichenfolge für die Zwischensumme gebildet, die Bestandteil der SQL-Anweisung für die Datenherkunft des Unterformulars wird und den Bereich der im Unterformular angezeigten Verkaufszahlen eingrenzt. Die Routine ShowSales bildet anschließend eine Zeichenfolge mit einer SQL-Anweisung, welche alle erforderlichen Felder der Tabelle tblCustomers und der Abfrage qryOrderSubtotals auswählt. Sie bildet eine WHERE-Klausel, die sowohl txtBeginningDate und txtEndingDate vom Hauptformular als auch den von der Funktion ShowSalesValue als Zeichenfolge zurückgegebenen Wert einschließt. Wenn die SQL-Anweisung zusammengestellt ist, wird die RecordSource-Eigenschaft des Unterformularsteuerelements der SQL-Anweisung gleichgesetzt. Die RecordCount-Eigenschaft von RecordSetClone (der dem Formular zu Grunde liegende Datensatz) wird ausgewertet, um festzustellen, ob irgendein Datensatz die in RecordSource angegebenen Kriterien erfüllt. Hat der Datensatzzähler den Wert Null, werden im Unterformular keine Datensätze angezeigt und der Benutzer wird darauf hingewiesen, dass kein Datensatz die angegebenen Kriterien erfüllt. Werden hingegen Datensätze gefunden, wird der Abschnitt Detail aktiviert und der Fokus dem Unterformular übergeben.
9.14
Fortgeschrittener Umgang mit Kombinationsund Listenfeldern
Kombinations- und Listenfelder sind sehr leistungsfähig. Zu den wichtigsten Fähigkeiten eines erfahrenen Access-Programmierers gehört es daher, korrekt auf das Ereignis NotInList eines Kombinationsfelds zu reagieren, das Kombinationsfeld mit Hilfe von Code zu füllen und mehrere Einträge in einem Listenfeld zu markieren. Diese Fähigkeiten werden in den folgenden Abschnitten behandelt.
9.14.1
Mit dem Ereignis NotInList umgehen
Wie bereits erwähnt, tritt das Ereignis NotInList (Nicht in Liste) auf, wenn ein Benutzer im Textbereich eines Kombinationsfelds Werte eingibt, die sich nicht in dessen Liste befinden. Zu diesem Ereignis kommt es nur, wenn die Eigenschaft LimitToList (Nur Listeneinträge) des Kombinationsfelds den Wert True hat. Es liegt bei Ihnen, ob Sie auf dieses Ereignis reagieren wollen. Es kann sinnvoll sein, nicht nur mit der standardgemäßen Fehlermeldung zu antworten, wenn die LimitToList-Eigenschaft den Wert True hat und der Benutzer versucht, einen Eintrag hinzuzufügen. Gibt der Benutzer beispielsweise bei einer Bestel-
Fortgeschrittener Umgang mit Kombinations- und Listenfeldern
381
lung den Namen eines neuen Kunden ein, sollten Sie mit der Anzeige eines Meldungsfelds reagieren, in dem der Benutzer gefragt wird, ob er wirklich einen neuen Kunden anlegen möchte. Erfolgt darauf eine Bestätigung, können Sie das Kundenformular anzeigen lassen. Nachdem Sie die Eigenschaft LimitToList auf den Wert True gesetzt haben, wird der für das Ereignis NotInList eingefügte Code ausgeführt, wenn der Benutzer versucht, einen Eintrag einzugeben, der nicht in der Liste des Kombinationsfelds enthalten ist. Es folgt ein Beispiel: Private Sub cboPaymentMethodID_NotInList(NewData As String, Response As Integer) If MsgBox("Payment Method Not Found, Add?", _ vbYesNo + vbQuestion, _ "Please Respond") = vbYes Then DoCmd.OpenForm "frmPaymentMethods", _ Datamode:=acFormAdd, _ WindowMode:=acDialog, _ OpenArgs:=NewData If IsLoaded("frmPaymentMethods") Then Response = acDataErrAdded DoCmd.Close acForm, "frmPaymentMethods" Else Response = acDataErrContinue End If Else Response = acDataErrContinue End If End Sub
Dieser Code zum Ereignis NotInList Ihres Kombinationsfelds zeigt ein Meldungsfeld an, mit dem der Benutzer gefragt wird, ob er die Zahlungsart hinzufügen möchte. Wird dies abgelehnt, kehrt er ohne Standardfehlermeldung wieder zum Formular zurück, muss aber nach wie vor einen gültigen Wert in das Kombinationsfeld eintragen. Bestätigt der Benutzer die Anfrage, wird ihm das Formular frmPaymentMethods angezeigt, um die Zahlungsart hinzuzufügen. Die Prozedur NotInList akzeptiert ein Argument mit einer Antwort, mit dem Sie VBA mitteilen können, was nach der Ausführung des Codes geschehen soll. Eine der drei folgenden Konstanten kann als Antwort mit dem Argument übergeben werden:
acDataErrAdded – Diese Konstante wird benutzt, wenn der neue Wert in die Datenherkunft des Kombinationsfelds eingefügt werden soll. Zum Hinzufügen des neuen Wertes in die Liste wird das Kombinationsfeld benötigt.
acDataErrDisplay – Diese Konstante wird verwendet, wenn VBA die Standardfehlermeldung anzeigen soll.
382
Kapitel 9: Fortgeschrittene Verwendung von Formularen
acDataErrContinue – Mit dieser Konstanten wird die VBA-eigene Fehlermeldung unterdrückt und die von Ihnen vorgegebene angezeigt. Access benötigt aber dennoch einen gültigen Eintrag im Kombinationsfeld.
9.14.2
Popup-Formulare
Die gerade beschriebene NotInList-Technik benutzt ein Popup-Formular. Gibt der Benutzer an, dass er die neue Zahlungsart hinzufügen möchte, wird das Formular frmPaymentMethods gebunden angezeigt. Dadurch wird die Ausführung des Codes in dem Formular angehalten, welches das Formular frmPaymentsMethod lädt. (In diesem Fall ist dies das Formular frmPayments.) Das Formular frmPaymentsMethod kann als Popup-Formular betrachtet werden, weil es gebunden ist und Informationen vom Formular frmPayments verwendet und das Formular frmPayments entweder auf die Schaltfläche OK oder auf die Schaltfläche ABBRECHEN reagiert. Der Code zum Ereignis Load des Formulars frmPaymentMethods des Zeit- und Abrechnungssystems sieht wie folgt aus: Private Sub Form_LOad() Me.txtPaymentMethod.Value = Me.OpenArgs End Sub
Dieser Code nutzt die als Argument erhaltenen Informationen zum Füllen des Textfelds txtPaymentMethod. Die Ausführung des Codes wird erst fortgesetzt, wenn der Benutzer die Schaltfläche OK oder CANCEL klickt. Wurde die Schaltfläche OK betätigt, wird folgender Code ausgeführt: Private Sub cmdOK_Click() Me.Visible = False End Sub
Beachten Sie, dass hier das Formular frmPaymentsMethod verborgen und nicht geschlossen wird. Nach Anklicken der Schaltfläche CANCEL, wird der folgende Code ausgeführt: Private Sub cmdCancel_Click() DoCmd.RunCommand acCmdUndo DoCmd.Close End Sub
Der mit der Schaltfläche CANCEL verbundene Code macht zuerst die vom Benutzer durchgeführten Veränderungen rückgängig. Anschließend wird das Formular frmPaymentMethods geschlossen. Bei Rückkehr zum NotInList-Ereignis des Kombinationsfelds cboPaymentMethod des Formulars frmPayments wird folgender Code ausgeführt: If IsLoaded("frmPaymentMethods") Then Response = acDataErrAdded DoCmd.Close acForm, "frmPaymentMethods"
Fortgeschrittener Umgang mit Kombinations- und Listenfeldern
383
Else Response = acDataErrContinue End If
Es wird überprüft, ob das Formular frmPaymentMethods noch geladen ist. Ist dies der Fall, muss der Benutzer auf die Schaltfläche OK geklickt haben. Der Response-Parameter wird mit acDataErrAdded gleichgesetzt, was anzeigt, dass der neue Eintrag in das Kombinationsfeld und die zu Grunde liegende Datenquelle eingefügt wurde. Abschließend wird das Formular frmPaymentMethods geschlossen. Ist das frmPaymentMethods-Formular nicht geladen, muss der Benutzer die Schaltfläche CANCEL angeklickt haben. Der Benutzer kehrt zum Kombinationsfeld zurück, wo er einen anderen Eintrag wählen muss. Die einzelnen Schritte lassen sich wie folgt zusammenfassen: 1. Das Popup-Formular wird gebunden geöffnet (wobei der Parameter WindowMode der Konstanten acDialog gleichgesetzt ist). 2. Gegebenenfalls wird der Parameter OpenArgs übergeben. 3. Bei Rückgabe eines Wertes an das ursprüngliche Formular wird überprüft, ob das Popup-Formular noch geladen ist. 4. Ist dies der Fall, werden die Informationen verwendet und das Formular anschließend geschlossen.
9.14.3
Ein Kombinations- oder Listenfeld mit Hilfe einer CallbackFunktion ausfüllen
Wie Sie wissen, kann ein Kombinationsfeld leicht durch Setzen der Eigenschaften des Steuerelements ausgefüllt werden. In den meisten Situationen reicht diese Maßnahme aus. Manchmal ist es jedoch erforderlich, ein Kombinationsfeld oder Listenfeld über das Programm etwa mit Hilfe von Werten eines Felds auszufüllen. Außerdem kann es notwendig sein, das Feld mit Tabellen- oder Berichtsnamen oder anderen Datenbankbestandteilen zu füllen. Um ein Kombinations- oder Listenfeld mit Hilfe von Code füllen zu können, erstellen Sie eine Callback-Funktion, die Access mitteilt, wie viele Zeilen und Spalten das Kombinations- oder Listenfeld enthalten soll und mit welchen Daten das Feld gefüllt wird. Dieser Funktion wird der Typ der Zeilenquellen für das Kombinations- oder Listenfeld übergeben. Access ruft diese Funktion auf und benutzt die Rückgabewerte zum Ausfüllen des Kombinations- oder Listenfelds. Das Beispiel in Listing 9.2 finden Sie im Formular frmSendToExcel der CHAP9EX-Datenbank. Listing 9.2: Ein Listenfeld mit Hilfe einer Callback-Funktion ausfüllen Function FillWithTableList(ctl As Control, vntID As Variant, _ lngRow As Long, lngCol As Long, intCode As Integer) _ As Variant
384
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Dim cat As ADOX.Catalog Dim tdf As ADOX.Table Dim qdf As ADOX.View Dim intCounter As Integer Static sastrTables() As String Static sintNumTables As Integer Dim varRetVal As Variant varRetVal = Null Select Case intCode Case acLBInitialize ' Initialisierung Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection 'Die Gesamtanzahl der Tabellen und Abfragen ermitteln sintNumTables = cat.Tables.Count + cat.Views.Count ReDim sastrTables(sintNumTables – 2) ' Jede Tabelle ermitteln und den Namen dem Listenfeld hinzufügen For Each tdf In cat.Tables If Left(tdf.Name, 4) <> "MSys" Then sastrTables(intCounter) = tdf.Name intCounter = intCounter + 1 End If Next tdf ' Jede Abfrage ermitteln und den Namen dem Listenfeld hinzufügen For Each qdf In cat.Views sastrTables(intCounter) = qdf.Name intCounter = intCounter + 1 Next qdf varRetVal = sintNumTables Case acLBOpen Öffnen varRetVal = Timer 'Eindeutige ID für Steuerelement erzeugen Case acLBGetRowCount 'Anzahl der Zeilen bestimmen varRetVal = sintNumTables Case acLBGetColumnCount 'Anzahl der Spalten bestimmen varRetVal = 1 Case acLBGetColumnWidth 'Spaltenbreite bestimmen varRetVal = -1 '-1 erzwingt Standardbreite Case acLBGetValue 'Daten empfangen varRetVal = sastrTables(lngRow) End Select FillWithTableList = varRetVal End Function
Die Funktion muss fünf vordefinierte Argumente enthalten, von denen das erste ein Steuerelement und die übrigen vom Typ Variant sein müssen. Die Funktion selbst muss einen Variant-Wert zurückgeben. Tabelle 9.4 führt die Parameter auf.
Fortgeschrittener Umgang mit Kombinations- und Listenfeldern
Argument
Beschreibung
fld
Eine Steuerelementvariable, die sich auf das zu füllende Kombinationsoder Listenfeld bezieht
id
Ein eindeutiger Wert, der das zu füllende Steuerelement angibt. Dieses Argument ist nützlich, wenn Sie mehr als nur ein Kombinations- oder Listenfeld mit der gleichen Funktion ausfüllen.
row
Die auszufüllende Zeile (auf Null basierend)
col
Die auszufüllende Spalte (auf Null basierend)
code
Ein Wert, der die gesuchte Information angibt
385
Tabelle 9.4: Die fünf vordefinierten Argumente einer Funktion Callback
Die List-Funktion wird mehrmals aufgerufen. Bei jedem Aufruf stellt Access automatisch einen anderen Wert mit der angeforderten Information für den Code bereit. Die Kodierung wird mit den in Tabelle 9.5 aufgeführten Werten durchgeführt. Code
vordefinierte Konstante
Beschreibung
Rückgabewert
0
acLBInitialize
Initialisieren
Ungleich Null, wenn die Funktion die Liste füllen kann. False oder Null, wenn es Probleme gibt
1
acLBOpen
Öffnen
Ein ID-Wert ungleich Null, wenn die Funktion die Liste füllen kann. False oder Null, wenn es Probleme gibt
3
acLBGetRowCount
Anzahl der Zeilen
Anzahl der Zeilen der Liste
4
acLBGetColumnCount
Anzahl der Spalten
Anzahl der Zeilen der Spalte
5
acLBGetColumnWidth
Spaltenbreite
Die Breite der angegebenen Spalte
6
acLBGetValue
Listeneintrag
Der Listeneintrag, der in der angegebenen Zeile und Spalte angezeigt wird
7
acLBGetFormat
Formatierungszeichenfolge
Formatierungszeichenfolge für die Formatierung des Listeneintrags
Tabelle 9.5: Bedeutung der Kodierungen
386
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Code
vordefinierte Konstante
Beschreibung
Rückgabewert
8
acLBClose
Wird nicht verwendet
9
acLBEnd
Ende (letzter Aufruf) Keiner
Tabelle 9.5: Bedeutung der Kodierungen (Forts.)
Die Funktion wird für die Codes 0, 1, 3 und 4 einmal automatisch aufgerufen. Diese Aufrufe initialisieren den Prozess und legen die Anzahl der Zeilen und Spalten des Kombinations- oder Listenfelds fest. Beim Code 5 wird die Funktion zweimal aufgerufen: einmal, um die Gesamtbreite des Felds zu bestimmen, und ein zweites Mal, um die Spaltenbreite festzulegen. Wie oft der Aufruf bei den Codes 6 und 7 erfolgt, hängt von der Anzahl der Zeilen des Felds ab (Code 3). Code 9 wird aufgerufen, wenn das Formular geschlossen oder das Kombinations- oder Listenfeld abgefragt wird. Ausgestattet mit diesem Wissen können Sie einen Blick auf die Funktion FillWithTableList werfen, bei der es sich um die Callback-Funktion zum Ausfüllen des Listenfelds handelt. Aufgabe dieser Funktion ist es, das Listenfeld mit einer Liste der Tabellen und Abfragen der aktuellen Datenbank zu füllen. Wählt der Benutzer eine Tabelle oder Abfrage aus und klickt dann auf die Schaltfläche SEND TO EXCEL, werden die Daten der ausgewählten Tabelle oder Abfrage an Excel gesendet. Die Callback-Funktion verwendet ADO-Code zum Zählen aller in der aktuellen Datenbank gefundenen Tabellen und Abfragen. ADOs (ActiveX-Datenobjekte) werden in Kapitel 12 behandelt. Jedes Element der Case-Struktur dieser Routine wird aufgerufen, wenn der entsprechende Code von Access gesendet wird. Dabei geschieht Folgendes: 1. Sendet Access den Code 0, werden die Tabellen und Ansichten gezählt. Die Routine durchläuft in einer Schleife jede Tabelle und Abfrage der Datenbank. Handelt es sich nicht um eine Systemtabelle, wird der Name dem Feld sastrTables hinzugefügt. Der Rückgabewert der Funktion entspricht der Anzahl der Tabellen und Abfragen der Datenbank. 2. Sendet Access den Code 1, ist der Rückgabewert ein eindeutiger Wert, der dem Rückgabewert der Timer-Funktion entspricht. 3. Wenn Access den Code 3 sendet, wird der Rückgabewert der Anzahl der Tabellen und Abfragen der Datenbank gleichgesetzt. 4. Beim Code 4 wird der Rückgabewert auf 1 gesetzt (eine Spalte). 5. Code 5 setzt den Rückgabewert gleich -1 und legt damit eine Standardbreite für das Kombinations- oder Listenfeld fest.
Fortgeschrittener Umgang mit Kombinations- und Listenfeldern
387
6. Den Code 6 ruft Access anschließend entsprechend des Rückgabewertes für die Anzahl der Zeilen des Kombinations- oder Listenfelds automatisch auf. Bei jedem Aufruf von Code 6 wird die Objektvariable des Formulars einem anderen Element der Formularauflistung gleichgesetzt. Die Funktion gibt den Namen der Tabelle oder Abfrage zurück. Der Name der Tabelle oder Abfrage ist der Wert, welcher dem Listenfeld hinzugefügt wird. Auf den ersten Blick mag das alles etwas kompliziert erscheinen. Wenn Sie aber erst einmal mehrere Kombinations- oder Listenfelder gefüllt haben, werden Sie sehen, dass es doch recht einfach ist. Sie müssen lediglich die Case-Struktur der Funktion FillWithTableList kopieren und als Vorlage für alle Ihre Callback-Routinen verwenden.
9.14.4
Mehrfachauswahl in einem Listenfeld
Die Listenfelder von Access 97 und Access 2000 verfügen über eine Eigenschaft für die Mehrfachauswahl. Hat sie den Wert True, kann der Benutzer mehrere Elemente eines Listenfelds auswählen. Das Programm kann anschließend auswerten, welche Elemente ausgewählt wurden und mit diesen Aktionen durchführen. Das Formular frmReportEngine aus der Datenbank CHAP9EX enthält ein Beispiel für die Mehrfachauswahl in einem Listenfeld. Listing 9.3 enthält den Code für das Ereignis Click der Schaltfläche RUN REPORTS. Listing 9.3: Ermitteln der ausgewählten Elemente eines Listenfelds für die Mehrfachauswahl Private Sub cmdRunReports_Click() Dim varItem As Variant Dim lst As ListBox Set lst = Me.lstReports ' Die Einfachauswahl hat den Wert 0, die Mehrfachauswahl den Wert 1 ' und die erweiterte Mehrfachauswahl den Wert 2 If lst.MultiSelect > 0 Then ' Alle Elemente der ItemSelected-Auflistung durchsuchen und über das ' Spaltenfeld die zugehörigen Werte ermitteln If lst.ItemsSelected.Count > 0 Then For Each varItem In lst.ItemsSelected DoCmd.OpenReport lst.ItemData(varItem), acViewPreview Next varItem End If End If End Sub
Zuerst wird überprüft, ob es sich um ein Listenfeld für die Mehrfachauswahl handelt. Trifft dies zu und wurde mindestens ein Bericht ausgewählt, werden alle Listeneinträge in einer Schleife durchsucht und jeder ausgewählte Bericht anschließend angezeigt.
388
9.15
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Fortgeschrittener Umgang mit Unterformularen
Viele unerfahrene Access-Programmierer verstehen die Zusammenhänge für das Erstellen und Verändern eines Unterformulars sowie für das Verweisen auf die Steuerelemente des Unterformulars nicht. Sie sollten deshalb die folgenden wichtigen Punkte berücksichtigen, wenn Sie mit Unterformularen arbeiten:
Der einfachste Weg, einem Hauptformular ein Unterformular hinzuzufügen, besteht darin, das Hauptformular zu öffnen und anschließend das Unterformular in das Hauptformular zu ziehen.
Die Eigenschaften LinkChildFields (Verknüpfen von) und LinkMasterFields (Verknüpfen nach) des Unterformulars legen fest, welche Felder des Hauptformulars mit welchen Feldern des Unterformulars verknüpft werden. Für diese Eigenschaften kann ein einzelner Feldname oder eine durch Semikolons getrennte Liste angegeben werden. Bei richtiger Angabe sorgen diese Eigenschaften dafür, dass alle Datensätze des Unterformulars sich auf den gerade angezeigten Datensatz des Hauptformulars beziehen.
9.15.1
Die Steuerelemente in Unterformularen ansprechen
Vielen Programmierern ist nicht klar, wie man die Steuerelemente eines Unterformulars richtig anspricht. Sie müssen jedes Objekt eines Unterformulars über das Steuerelement des Unterformulars im Hauptformular ansteuern, wie dies im folgenden Beispiel geschieht: Forms.frmCustomer.fsubOrders
Dieses Beispiel bezieht sich auf das Steuerelement fsubOrders des Formulars frmCustomer. Möchten Sie ein bestimmtes Steuerelement des Unterformulars fsubOrders ansprechen, dann können Sie auf die Auflistung der Steuerelemente des Unterformulars verweisen: Forms.frmCustomer.fsubOrders!txtOrderID
Sie können sich auch implizit auf das Steuerelement des Unterformulars beziehen: Forms!frmCustomer!fsubOrders!txtOrderID
Beide Möglichkeiten sprechen das Steuerelement txtOrderID im Formular des fsubOrder-Steuerelements auf dem Formular frmCustomer an. Um eine Eigenschaft dieses Steuerelements zu verändern, können Sie den Ausdruck wie folgt ergänzen: Forms.frmCustomer.fsubOrders!txtOrderID.Enabled = False
Mit dieser Zeile wird der Wert der Eigenschaft Enabled des txtOrdersID-Steuerelements im Formular des fsubOrders-Steuerelements auf den Wert False gesetzt.
Ein Formular mit der zu Grunde liegenden Datensatzgruppe in Einklang bringen
9.16
389
Ein Formular mit der zu Grunde liegenden Datensatzgruppe in Einklang bringen
Die Eigenschaft RecordSetClone eines Formulars dient zum Verweis auf die zu Grunde liegende Datensatzgruppe. Sie können diese Datensatzgruppe unabhängig davon verändern, was augenblicklich im Formular angezeigt wird. Ein Beispiel: Private Sub cboCompany_AfterUpdate() Me.RecordsetClone.FindFirst "[ClientID] = " & cboCompany.Value If Me.RecordsetClone.NoMatch Then MsgBox "Client Not Found" Else Me.Bookmark = Me.RecordsetClone.Bookmark End If End Sub
In diesem Beispiel wird die Methode FindFirst zur Verwendung mit der Eigenschaft RecordSetClone des Formulars aufgerufen. Die Methode sucht in der dem Formular zu Grunde liegenden Datensatzgruppe nach einem Datensatz, dessen ClientID gleich dem aktuellen Wert des Kombinationsfelds ist. Findet die Methode eine Übereinstimmung, wird das Lesezeichen des Formulars mit dem Lesezeichen der dem Formular zu Grunde liegenden Datensatzgruppe gleichgesetzt. Dieser Code kann auch durch Verwendung einer Objektvariablen zum Verweis auf RecordSetClone umgeschrieben werden: Private Sub cboCompany_AfterUpdate() Dim rs As DAO.Recordset Set rs = Me.RecordsetClone rs.FindFirst "[ClientID] = " & cboCompany.Value If rs.NoMatch Then MsgBox "Client Not Found" Else Me.Bookmark = Me.RecordsetClone.Bookmark End If End Sub
Dieser Code erzeugt eine Objektvariable, die auf die Eigenschaft RecordSetClone des Formulars verweist. Die Objektvariable der Datensatzgruppe kann durch Me.RecordSetClone ersetzt werden, weil sie auf den dem Formular zu Grunde liegenden Datensatz verweist.
390
9.17
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Benutzerdefinierte Eigenschaften und Methoden erstellen
Formulare und Berichte werden als »Klassenmodule« bezeichnet, was bedeutet, dass sie als Vorlagen für Objekte dienen, die Sie während der Ausführung als Instanzen erstellen. Öffentliche Prozeduren eines Formulars oder Berichts werden während der Ausführung zu benutzerdefinierten Eigenschaften und Methoden des Formularobjekts. Mit Hilfe von VBA-Code können Sie die Werte der benutzerdefinierten Eigenschaften des Formulars festlegen und deren Methoden ausführen.
9.17.1
Benutzerdefinierte Eigenschaften erstellen
Benutzerdefinierte Eigenschaften eines Formulars oder Berichts können auf zwei Arten erstellt werden:
Sie erstellen für das Formular oder den Bericht öffentliche Variablen. Sie erstellen die PropertyLet- und PropertyGet- Routinen. Eine öffentliche Variable als Formulareigenschaft erstellen und verwenden Mit den folgenden Schritten erstellen Sie eine benutzerdefinierte Formular- oder Berichtseigenschaft, die auf einer öffentlichen Variablen beruht, und greifen auf diese zu. Das Beispiel ist in den Formularen frmPublicProperties und frmChangePublicProperty der Datenbank CHAP9EX zu finden. 1. Erstellen Sie zuerst ein Formular für die benutzerdefinierte Eigenschaft (öffentliche Variable). 2. Platzieren Sie eine öffentliche Variable im Abschnitt Allgemeine Deklarationen des Formulars oder Berichts (siehe Abbildung 9.21).
Abbildung 9.21: Im Abschnitt Allgemeine Deklarationen eines Klassenmoduls eine öffentliche Variable erstellen
Benutzerdefinierte Eigenschaften und Methoden erstellen
391
3. Fügen Sie in dem Formular oder Bericht Code für den Zugriff auf die öffentliche Variable ein. Der Code in Abbildung 9.21 erzeugt eine öffentliche Variable mit dem Namen CustomCaption. Der Code zum Ereignis Click der Schaltfläche cmdChangeCaption weist der Caption-Eigenschaft des Formulars frmPublicProperties den Wert der öffentlichen Variablen zu. 4. Erstellen Sie ein Formular, einen Bericht oder ein Modul, mit dem der Wert der benutzerdefinierten Eigenschaft verändert wird. Abbildung 9.22 zeigt ein Formular mit dem Namen frmChangePublicProperty.
Abbildung 9.22: Die Ansicht des Formulars frmChangePublicProperty
5. Fügen Sie den Code hinzu, der den Wert der benutzerdefinierten Eigenschaft verändert. Der Code für die in Abbildung 9.21 gezeigte Schaltfläche cmdChangeCaption verändert den Wert der benutzerdefinierten Eigenschaft CustomCaption des Formulars frmPublicProperties. Um die benutzerdefinierte Eigenschaft des vorangegangenen Beispiels zu testen, führen Sie das Formular frmPublicProperties aus der Datenbank CHAP9EX.MDB auf der beiliegenden CD-ROM aus. Wenn Sie auf die Schaltfläche CHANGE FORM CAPTION klicken, passiert gar nichts, weil der Wert für die benutzerdefinierte Eigenschaft nicht gesetzt wurde. Öffnen Sie das frmChangePublicProperty-Formular und klicken Sie auf die Schaltfläche CHANGE FORM PROPERTY. Kehren Sie dann zum Formular frmChangePublicProperties zurück und klicken Sie noch einmal die Schaltfläche CHANGE FORM CAPTION. Jetzt sollte sich die Überschrift des Formulars verändern. Schließen Sie das Formular frmPublicProperties und versuchen Sie die Schaltfläche CHANGE FORM PROPERTY zu klicken. Es kommt zu einem Laufzeitfehler mit dem Hinweis, dass das angesprochene Formular nicht geöffnet ist. Mit dem folgenden Code für das Click-Ereignis von cmdPublicFormProperty können Sie diesen Fehler entfernen:
392
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Private Sub cmdPublicFormProperty_Click() Form_frmPublicProperties.CustomCaption = _ "This is a Custom Caption" Forms!frmPublicProperties.Visible =True End Sub
Dieser Code verändert mit der Syntax Formular_Formularname.Eigenschaft den Wert der Public-Eigenschaft. Ist das Formular nicht geladen, wird dies nachgeholt, das Formular bleibt aber verborgen. Die nächste Anweisung weist der Eigenschaft Visible den Wert True zu. Mit den PropertyLet- und PropertyGet-Routinen benutzerdefinierte Eigenschaften erstellen und verwenden Eine PropertyLet-Routine ist eine spezielle Unterroutine, die immer dann automatisch ausgeführt wird, wenn der Wert der Eigenschaft verändert wird. Auch eine PropertyGet-Routine ist eine spezielle Routine, die jedesmal automatisch ausgeführt wird, wenn der Wert der benutzerdefinierten Eigenschaft benötigt wird. Die Eigenschaft wird nicht mit Hilfe einer öffentlichen Variablen erstellt, sondern durch Einfügen zweier spezieller Routinen: PropertyLet und PropertyGet. Dieses Beispiel finden Sie in den Formularen frmPropertyGetLet und frmChangeWithLet der Datenbank CHAP9EX.MDB. Führen Sie die folgenden Schritte durch, um die PropertyLet- und PropertyGet-Routinen einzufügen: 1. Wählen Sie EINFÜGEN|PROZEDUR. Dies öffnet das in Abbildung 9.23 gezeigte Dialogfeld. 2. Geben Sie im Textfeld NAME den Namen der Prozedur ein. 3. Markieren Sie im Abschnitt TYP die Option PROPERTY. 4. Wählen Sie als Gültigkeitsbereich PUBLIC, damit die Eigenschaft außerhalb des Formulars sichtbar ist. 5. Klicken Sie auf OK. Die PropertyGet- und PropertyLet-Unterroutinen werden nun in das Modul eingefügt (siehe Abbildung 9.24). Beachten Sie, dass der Code zum Ereignis Click für die Schaltfläche cmdChangeCaption nicht verändert wurde. Die PropertyGet-Routine, die immer dann automatisch ausgeführt wird, wenn sich der Wert der Eigenschaft CustomCaption verändert, übernimmt einen Wert in Großbuchstaben und platziert diesen in einer privaten Variablen mit dem Namen mstrCustomCaption. Die PropertyGet-Routine nimmt den Wert der privaten Variablen und gibt dem Anfragenden den Wert der Eigenschaft zurück. Die Abfolge der Ereignisse lautet wie folgt (der Code gehört zum Formular frmChangeWithLet): Private Sub cmdPublicFormProperty_Click() Form_frmPropertyGetLet.CustomCaption = "This is a Custom Caption" Forms!frmPropertyGetLet.Visible = True End Sub
393
Benutzerdefinierte Eigenschaften und Methoden erstellen
Abbildung 9.23: Eine neue Prozedur mit dem Dialogfeld Prozedur hinzufügen einfügen
Abbildung 9.24: Mit dem Dialogfeld Prozedur hinzufügen erstellte Unterroutinen
Diese Routine versucht, der benutzerdefinierten Eigenschaft CustomCaption den Wert "This is a Custom Caption" zuzuweisen. Da sich der Wert der Eigenschaft ändert, wird die PropertyLet-Routine des Formulars frmPropertyGetLet automatisch ausgeführt: Public Property Let CustomCaption(ByVal CustomCaption As String) mstrCustomCaption = UCase$(CustomCaption) End Property
Die PropertyLet-Routine erhält den Wert "This is a Custom Caption" als Parameter. Sie verwendet die UCase-Funktion, um den übergebenen Wert zu bearbeiten und in Großbuchstaben umzuwandeln. Anschließend wird der bearbeitete Wert der privaten Variablen mstrCustomCaption zugewiesen. Die PropertyGet-Routine wird nicht eher ausgeführt, ehe der Benutzer nicht im Formular frmPropertyGetLet auf die
394
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Schaltfläche cmdChangeCaption klickt. Der Code zum Ereignis Click der Schaltfläche cmdChangeCaption sieht wie folgt aus: Private Sub cmdChangeCaption_Click() Me.Caption = CustomCaption End Sub
Da diese Routine den Wert der benutzerdefinierten Eigenschaft CustomCaption benötigt, wird die PropertyGet-Routine automatisch ausgeführt: Public Property Get CustomCaption() As String CustomCaption = mstrCustomCaption End Property
Die PropertyGet-Routine übernimmt den Wert der privaten Variablen, die von der PropertyLet-Routine zugewiesen wurde, und gibt ihn als Wert der Eigenschaft zurück. Sie werden sich vielleicht fragen, warum diese Lösung der Deklaration einer öffentlichen Variablen vorzuziehen ist. Die Verwendung der UCase-Anweisung innerhalb von PropertyLet sollte dies eigentlich deutlich machen. Bei Verwendung einer öffentlichen Variablen können Sie nicht viel tun, um den übergebenen Wert zu überprüfen oder zu verändern. Die PropertyLet-Routine bietet Ihnen jedoch die Möglichkeit, den Wert der Eigenschaft zu überprüfen und zu verändern. Da die veränderte Variable einer privaten Variablen zugewiesen und anschließend der Wert der privaten Variablen für die Rückgabe der Eigenschaft benötigt wird, haben Sie die vollständige Kontrolle darüber, was intern mit der Eigenschaft geschieht. Dieser Abschnitt bietet nur eine Einführung zu den benutzerdefinierten Eigenschaften und Methoden. Eine ausführliche Diskussion der benutzerdefinierten Klassen, Eigenschaften und Methoden finden Sie in Kapitel 28.
9.17.2
Benutzerdefinierte Methoden erstellen
Benutzerdefinierte Methoden sind öffentliche Funktionen und Unterroutinen eines Formular- oder Berichtsmoduls. Wie Sie noch erfahren werden, können sie mit der Syntax Objekt.Methode aufgerufen werden. Mit den folgenden Schritten wird eine benutzerdefinierte Methode erstellt (Sie finden die Beispiele in den Formularen frmMethods und frmExecuteMethod der Datenbank CHAP9EX): 1. Öffnen Sie den Bericht oder das Formular, welches die benutzerdefinierte Methode enthalten soll. 2. Erstellen Sie eine öffentliche Funktion oder Unterroutine (siehe Abbildung 9.25). 3. Öffnen Sie das Formular-, Berichts- oder Code-Modul, welches die benutzerdefinierte Methode ausführt.
Benutzerdefinierte Eigenschaften und Methoden erstellen
395
Abbildung 9.25: Die benutzerdefinierte Methode ChangeCaption
4. Verwenden Sie die Syntax Objekt.Methode, um die benutzerdefinierte Methode aufzurufen (siehe Abbildung 9.26).
Abbildung 9.26: Der Code für das Ereignis Click von cmdExecuteMethod
Abbildung 9.25 zeigt die benutzerdefinierte Methode ChangeCaption des Formulars frmMethods. Diese Methode ändert die Überschrift eines Formulars. Abbildung 9.26 zeigt die Routine für das Ereignis Click der Schaltfläche cmdExecuteMethod des frmExecuteMethod-Formulars. Das Ereignis verwendet die Methode ChangeCaption des Formulars frmMethods und weist anschließend der Eigenschaft Visible des Formulars den Wert True zu.
396
9.17.3
Kapitel 9: Fortgeschrittene Verwendung von Formularen
Für die Praxis
Erweiterte Techniken für Ihre Anwendung nutzen Viele der Beispiele in diesem Kapitel stammen aus dem Zeit- und Abrechnungssystem. Um Ihre eigene Anwendung aufzubessern, beginnen Sie damit, ein Startformular einzurichten, welches einen Begrüßungsbildschirm anzeigt und anschließend einige Einrichtungsfunktionen durchführt. Die Änderungen finden Sie in der Datei CHAP9EX.MDB.
9.17.4
Die Dinge mit einem Startformular zum Laufen bringen
Das Formular frmSwitchboard ist für die Anzeige des Begrüßungsbildschirms und die Durchführung erforderlicher Vorbereitungsmaßnahmen verantwortlich. Der Code zum Ereignis Load des Formulars frmSwitchboard sieht wie folgt aus: Private Sub Form_Load() DoCmd.Hourglass True DoCmd.OpenForm "frmSplash" Call GetCompanyInfo DoCmd.Hourgalss False End Sub
Die Ereignisroutine Form_Load ruft zuerst die Sanduhr auf. Anschließend wird das Begrüßungsformular geöffnet. Danach wird die Routine GetCompanyInfo aufgerufen, um die vielleicht von der Anwendung benötigte Typstruktur CompanyInfo auszufüllen. Typstrukturen werden im Kapitel 24 behandelt. Zum Schluss wird die Sanduhr wieder deaktiviert.
9.17.5
Einen Begrüßungsbildschirm erstellen
Der Begrüßungsbildschirm in Abbildung 9.27 trägt den Namen frmSplash. Das Zeitgeberintervall ist auf 3000 Millisekunden (3 Sekunden) eingestellt. Das Ereignis Timer sieht wie folgt aus: Private Sub Form_Timer() DoCmd.Close acForm, Me.Name End Sub
Abbildung 9.27: Ein vorhandenes Formular als Begrüßungsbildschirm benutzen
Benutzerdefinierte Eigenschaften und Methoden erstellen
397
Der Code hinter dem Ereignis Timer entlädt das Formular. Die Popup-Eigenschaft für frmSplash hat den Wert Ja. Für die Rahmenart ist der Wert Keine eingestellt. Daten-
satzmarkierer und Navigationsschaltflächen wurden entfernt.
Fortgeschrittene Verwendung von Berichten
Kapitel
Hier lesen Sie:
Warum dieses Kapitel von Bedeutung ist Für Berichte verfügbare Ereignisse und wann sie verwendet werden sollten Ereignisreihenfolge für Berichte Für Berichtsabschnitte verfügbare Ereignisse und wann sie verwendet werden sollten
Spezielle Berichtseigenschaften Praktische Anwendungen für Berichtsereignisse und -eigenschaften
10.1
Mit Berichten arbeiten
Kapitel 6 behandelt alle Grundlagen für den Berichtsentwurf. Berichte sind ein entscheidender Bestandteil fast jeder Anwendung, so dass Sie von Glück reden können, dass Ihnen in Access 2000 ein äußerst leistungsfähiges Berichtswerkzeug zur Verfügung steht. Die meisten Berichte sind zwar leicht zu erstellen, aber je länger Sie sich mit der Entwicklung von Access-Anwendungen beschäftigen, umso mehr werden Sie sich für die Feinheiten des Berichtsentwurfs mit Access interessieren. Dieses Kapitel behandelt Berichtsereignisse, erweiterte Techniken sowie Tipps und Tricks für den praktischen Umgang mit Berichten.
10.2
Für Berichte verfügbare Ereignisse und wann sie verwendet werden sollten
Die Berichtsereignisse sind zwar nicht so zahlreich wie die Formularereignisse, mit den abgefangenen Berichtsereignissen können Sie jedoch steuern, was beim Erstellen des Berichts geschieht. In diesem Abschnitt werden die Berichtsereignisse behan-
400
Kapitel 10: Fortgeschrittene Verwendung von Berichten
delt und der Abschnitt »Für Berichtsabschnitte verfügbare Ereignisse und wann sie verwendet werden sollten« widmet sich speziellen Ereignissen der Berichtsabschnitte.
10.2.1
Das Ereignis Open (Beim Öffnen)
Das Ereignis Open bzw. Beim Öffnen ist das erste Ereignis eines Berichts und tritt ein, bevor der Bericht gedruckt oder angezeigt und die dem Bericht zu Grunde liegende Abfrage ausgeführt wird. Es folgt ein Beispiel für die Verwendung des Ereignisses Open: Private Sub Report_Open(Cancel As Integer) On Error Resume Next DoCmd.OpenForm "frmReportDateRange", _ WindowMode:=acDialog, _ OpenArgs:="rptProjectBillingsbyWorkCode" If Not IsLoaded("frmReportDateRange") Then MsgBox "Criteria Form Not Successfully Loaded, " & _ "Canceling Report" Cancel = True End If End Sub
Sie finden dieses Beispiel im Bericht rptProjectBillingsByWorkCode aus der Datenbank CHAP10.MDB auf der dem Buch beiliegenden CD-ROM. Es wird versucht, das Formular frmReportDateRange zu öffnen, bei dem es sich um das Formular mit den Kriterien für die Parameter der dem Bericht zu Grunde liegenden Abfrage handelt. Kann das Formular nicht geladen werden, wird der Bericht abgebrochen.
10.2.2
Das Ereignis Close (Beim Schließen)
Das Ereignis Close bzw. Beim Schließen tritt vor dem Ereignis Deactivate (Bei Deaktivierung) beim Schließen eines Berichts ein. Das folgende Beispiel soll die Behandlung des Ereignisses Open veranschaulichen: Private Sub Report_Close() DoCmd.Close acForm, "frmReportDateRange" End Sub
Sie finden dieses Beispiel im Bericht rptProjectBillingsByWorkCode aus der Datenbank CHAP10.MDB auf der dem Buch beiliegenden CD-ROM. Das Formular frmReportDateRange mit den Kriterien wird beim Schließen des Berichts geschlossen, falls das Formular noch geöffnet ist.
Für Berichte verfügbare Ereignisse und wann sie verwendet werden sollten
10.2.3
401
Das Ereignis Activate (Bei Aktivierung)
Zum Ereignis Activate bzw. Bei Aktivierung des Berichts kommt es, wenn der Bericht zum aktiven Fenster wird. Es tritt nach dem Ereignis Open und vor dem Ausdrucken des Berichts ein. Häufig wird es zur Anzeige einer benutzerdefinierten Symbolleiste verwendet, die immer dann sichtbar ist, wenn der Bericht aktiv ist. Ein Beispiel: Private Sub Report_Activate() 'Die Access-eigene Symbolleiste Druckvorschau verbergen 'Die benutzerdefinierte Symbolleiste Druckvorschau anzeigen DoCmd.ShowToolbar "Druckvorschau", acToolbarNo DoCmd.ShowToolbar "Benutzerdefinierte Druckvorschau", acToolbarYes End Sub
Dieser Code verbirgt die Symbolleiste DRUCKVORSCHAU und zeigt die benutzerdefinierte Symbolleiste BENUTZERDEFINIERTE DRUCKVORSCHAU an. Wie Sie sehen werden, besteht zwischen diesem Ereignis und dem Ereignis Deactivate beim Anzeigen und Verbergen der benutzerdefinierten Symbolleiste des Berichts eine Wechselwirkung, wenn der Bericht zum aktiven Fenster wird und der Benutzer den Fokus einem anderen Fenster übergibt.
10.2.4
Das Ereignis Deactivate (Bei Deaktivierung)
Das Ereignis Deactivate bzw. Bei Deaktivierung tritt beim Wechseln zu einem anderen Access-Fenster oder beim Schließen des Berichts ein. Es tritt nicht ein, wenn der Fokus einer anderen Anwendung übergeben wird. Folgendes Beispiel veranschaulicht die Verwendung des Ereignisses Deactivate: Private Sub Report_Deactivate() 'Die Symbolleiste Benutzerdefinierte Druckvorschau verbergen 'Die eingebaute Symbolleiste Druckvorschau anzeigen DoCmd.ShowToolbar "Benutzerdefinierte Druckvorschau", acToolbarNo DoCmd.ShowToolbar "Druckvorschau", acToolbarWhereApprop End Sub
Diese Routine verbirgt die beim Auftreten des Ereignisses Activate angezeigte benutzerdefinierte Symbolleiste und weist an, dass die Symbolleiste DRUCKVORSCHAU gegebenenfalls wieder angezeigt wird. In diesem Fall soll die Symbolleiste nicht sofort erscheinen, sondern die Anzeige wieder so zurückgesetzt werden, dass sie nur angezeigt wird, wenn dies dem normalen Verhalten von Access entspricht. Diese Aufgabe übernimmt die Konstante acToolbarWhereApprop.
402
Kapitel 10: Fortgeschrittene Verwendung von Berichten
Dieser Code der Ereignisse Activate und Deactivate zeigt eine Möglichkeit, wie Symbolleisten verborgen und angezeigt werden können. Die gleiche Aufgabe kann auch die Eigenschaft Toolbar eines Berichts übernehmen. Möchten Sie jedoch mehr als eine Symbolleiste anzeigen lassen, während der Bericht aktiv ist, müssen Sie den Code zum Verbergen und Anzeigen der Symbolleisten in den Routinen zu den Ereignissen Activate und Deactivate unterbringen.
10.2.5
Das Ereignis NoDate (Bei Ohne Daten)
Entspricht kein Datensatz den Kriterien der dem Bericht zu Grunde liegenden Datensatzgruppe RecordSource, wird der Bericht ohne Daten gedruckt und #Error aus dem Detailabschnitt des Berichts angezeigt. Dieses Problem können Sie mit dem nachfolgenden Ereignis NoData bzw. Bei Ohne Daten vermeiden: Private Sub Report_NoData(Cancel As Integer) MsgBox "There ist no Data for this report._ Canceling Report..." Cancel = True End Sub
Sie finden dieses Beispiel im Bericht rptProjectBillingsByWorkCode aus der Datenbank CHAP10.MDB auf der dem Buch beiliegenden CD-ROM. Werden von der dem Bericht zu Grunde liegenden Datensatzgruppe keine Daten zurückgegeben, wird dem Benutzer ein Meldungsfeld angezeigt und Cancel erhält den Wert True. Dadurch wird der Bericht beendet und nicht weiter ausgeführt.
10.2.6
Das Ereignis Page (Bei Seite)
Mit dem Ereignis Page bzw. Bei Seite können Sie unmittelbar vor dem Senden der Seite an den Drucker etwas durchführen. Zum Beispiel können Sie mit dem Ereignis Page die Seite mit einer Umrandung versehen: Private Sub Report_Page() Me.Line (0, 0)-(Me.ScaleWidth, Me.ScaleHeight – 10), _ RGB(255, 0, 0), _ B End Sub
Diesen Code finden Sie im Bericht rptTimeSheet aus der Datenbank CHAP10.MDB. Er zeichnet eine rote Linie um den Bericht herum, die in der linken oberen Ecke beginnt und zur rechten unteren Ecke hinunterläuft. Mit den Eigenschaften ScaleWidth und ScaleHeight wird festgelegt, wo die rechte untere Ecke des Druckbereichs des Berichts liegt. Der dritte Parameter B erzeugt mit Hilfe der Koordinaten der gegenüberliegenden Ecken das Rechteck.
Ereignisreihenfolge für Berichte
10.2.7
403
Das Ereignis Error (Bei Fehler)
Kommt es beim Formatieren oder Drucken des Berichts zu einem Jet-Engine-Fehler, wird das Ereignis Error bzw. Bei Fehler ausgelöst. Dieser Fehler tritt normalerweise auf, wenn keine Datenherkunft für den Bericht vorliegt oder ein anderer diese exklusiv benutzt. Ein Beispiel: Private Sub Report_Error(DataErr As Integer, Response As Integer) If DataErr = 2580 Then MsgBox "Keine Datenherkunft für diesen Bericht vorhanden" Response = acDataErrContinue End If End Sub
Dieser Code reagiert auf den Wert 2580 für DataErr, was bedeutet, dass die Datenherkunft des Berichts nicht zur Verfügung steht. Dem Benutzer wird eine benutzerdefinierte Meldung angezeigt und die Access-Fehlermeldung unterdrückt.
10.3
Ereignisreihenfolge für Berichte
Es ist wichtig, die Reihenfolge der Ereignisse eines Berichts zu kennen. Wenn der Benutzer einen Bericht öffnet, sich eine Vorschau anzeigen lässt und den Bericht wieder schließt, treten der Reihe nach die folgenden Ereignisse auf: Open (Beim Öffnen)->Activate (Bei Aktivierung)->Close(Beim Schließen)->Deactivate (Bei Deaktivierung)
Wechselt der Benutzer zu einem anderen Bericht oder Formular, treten die folgenden Ereignisse auf: Deactivate (Bei Deaktivierung; aktueller Bericht)-> Activate (Bei Aktivierung; Formular oder Bericht)
Das Ereignis Deactivate tritt nicht ein, wenn der Benutzer zu einem Dialogfeld oder Formular, dessen Eigenschaft PopUp den Wert True hat, oder zum Fenster einer anderen Anwendung wechselt.
10.4
Für Berichtsabschnitte verfügbare Ereignisse und wann sie verwendet werden sollten
So wie der Bericht selbst über Ereignisse verfügt, so verfügt auch jeder Berichtsabschnitt über Ereignisse. Die drei Abschnittsereignisse sind die Ereignisse Format (Beim Formatieren), Print (Beim Drucken) und Retreat (Bei Rücknahme), die in den folgenden Abschnitten behandelt werden.
404
Kapitel 10: Fortgeschrittene Verwendung von Berichten
10.4.1
Das Ereignis Format (Beim Formatieren)
Das Ereignis Format bzw. Beim Formatieren tritt ein, nachdem Access die Daten für einen Berichtsabschnitt ausgewählt hat, jedoch bevor Access die Daten formatiert oder druckt. Mit diesem Ereignis können Sie das Layout des Abschnitts beeinflussen oder die Ergebnisse von Daten des Abschnitts vor dem Drucken berechnen. Listing 10.1 enthält ein Beispiel. Listing 10.1: Das Layout eines Berichts über das Ereignis Format beeinflussen Private Sub Detail2_Format(Cancel As Integer, FormatCount As Integer) ' Feststellen, ob Datensätze gedruckt werden sollen oder Fortsetzungen folgen ' Hinweis anzeigen, wenn die maximale Anzahl der _ ' Datensätze für die Seite erreicht wurde If (Me.txtRow = Me.txtOrderPage * (Me.txtRowsPerPage – 1) + 1) _ And Me.txtRow <> Me.txtRowCount Then Me.txtContinued.Visible = True End If ' Seitenumbruch anzeigen und Steuerelemente im Datensatz verbergen With Me If .txtContinued.Visible Then .txtDetailPageBreak.Visible = True .txtProductID.Visible = False .txtProductName.Visible = False .txtQuantity.Visible = False .txtUnitPrice.Visible = False .txtDiscount.Visible = False .txtExtendedPrice.Visible = False ' Increase value in Order Page. .NextRecord = False .txtOrderPage = Me.txtOrderPage + 1 Else ' Den Zeilenzähler erhöhen, wenn ein Datensatz gedruckt wird .txtRow = Me.txtRow + 1 End If End With End Sub
Sie finden diesen Code im Bericht rptInvoice aus der Datenbank CHAP10EX.MDB auf der beiliegenden CD-ROM. Der Bericht enthält Steuerelemente, die überwachen, wie viele Zeilen mit Datensätzen auf jeder Seite gedruckt werden sollen. Ist die maximale Anzahl erreicht, erscheint ein Steuerelement mit dem Hinweis, dass der Text auf der nächsten Seite fortgesetzt wird. Wenn das Steuerelement sichtbar ist, ist auch
Für Berichtsabschnitte verfügbare Ereignisse
405
das Steuerelement für den Seitenumbruch sichtbar, während alle Steuerelemente, welche die Einzelheiten des Berichts anzeigen, verborgen sind. Der Bericht wird auf diese Weise daran gehindert, zum nächsten Datensatz überzugehen.
Ein weiteres Beispiel für das Ereignis Format finden Sie im Seitenkopf des Berichts rptEmployeeSales aus der Datenbank CHAP10EX.MDB. Da es sich hier um einen ungebundenen Bericht handelt, dessen Steuerelemente mit Hilfe von VBA-Code während der Ausführung gefüllt werden, muss der Bericht ermitteln, was im Berichtskopf zu stehen hat. Dies variiert in Abhängigkeit von den Ergebnissen der Kreuztabellenabfrage, auf der der Bericht beruht. Listing 10.2 enthält den entsprechenden Code. Listing 10.2: Ungebundene Steuerelemente während der Ausführung mit Hilfe des Ereignisses Format ausfüllen Private Sub PageHeader0_Format(Cancel As Integer, FormatCount As Integer) Dim intX As Integer ' Die Spaltenüberschriften in Textfelder des Seitenkopfs setzen For intX = 1 To mintColumnCount Me("Head" + Format(intX)) = mrstReport(intX – 1).Name Next intX ' Das nächste verfügbare Textfeld Totals zur Beschriftung machen Me("Head" + Format(mintColumnCount + 1)) = "Totals" ' Nicht benutzte Textfelder im Seitenkopf verbergen For intX = (mintColumnCount + 2) To conTotalColumns Me("Head" + Format(intX)).Visible = False Next intX End Sub
Der Code durchläuft jede Spalte der Datensatzgruppe, die aus der Kreuztabellenabfrage resultiert (in der Routine zum Berichtsereignis Open). Die Seitenüberschrift des Berichts wird mit den Namen der Spalten des Abfrage-Ergebnisses gefüllt. Die letzte Seitenüberschrift erhält den Wert von Totals. Abschließend werden alle (zusätzlichen) Textfelder verborgen. Auf weitere Beispiele für die Verwendung des Ereignisses Format wird in diesem Abschnitt noch eingegangen. Durch Einfügen von Code für das Ereignis Format des Detailabschnitts des Berichts können Sie steuern, was geschieht, wenn die einzelnen Zeilen des Detailabschnitts gedruckt werden.
406
Kapitel 10: Fortgeschrittene Verwendung von Berichten
10.4.2
Das Ereignis Print (Beim Drucken)
Der Code zum Ereignis Print bzw. Beim Drucken wird ausgeführt, wenn die Daten des Abschnitts für das Drucken formatiert wurden, jedoch bevor sie tatsächlich gedruckt werden. Dieses Ereignis tritt für die einzelnen Abschnitte zu folgenden Zeitpunkten ein:
Detailabschnitt: Unmittelbar vor dem Drucken der Daten Gruppenköpfe: Unmittelbar vor dem Drucken des Gruppenkopfes. Das Ereignis Print des Gruppenkopfs bezieht sich sowohl auf den Gruppenkopf als auch auf
die erste Zeile mit Daten der Gruppe.
Gruppenfüße: Unmittelbar vor dem Drucken des Gruppenfußes. Das Ereignis Print hat Zugriff auf den Gruppenfuß sowie auf die letzte Datenzeile der Gruppe.
Listing 10.3 stammt aus der Routine zum Ereignis Print des Detailabschnitts des Berichts rptEmployeeSales der Datenbank CHAP10EX.MDB.
Listing 10.3: Beispiel für die Verwendung des Ereignisses Print zur Berechnung der Spalten- und Zeilensummen Private Sub Detail1_Print(Cancel As Integer, PrintCount As Integer) Dim intX As Integer Dim lngRowTotal As Long ' Hat PrintCount den Wert1, wird die Varaible rowTotal initialsiert ' Den Spaltensummen hinzufügen If Me.PrintCount = 1 Then lngRowTotal = 0 For intX = 2 To mintColumnCount ' Mit Spalte 2 beginnen (erstes Textfeld mit Kreuztabellenerten), ' Gesamtsumme für die aktuelle Zeile des Detailabschnitts berechnen lngRowTotal = lngRowTotal + Me("Col" + Format(intX)) ' Den Kreuztabellenwert der Summe der aktuellen Spalte hinzufügen mlngRgColumnTotal(intX) = mlngRgColumnTotal(intX) + _ Me("Col" + Format(intX)) Next intX ' Die Summe der Zeile im Textfeld des Detailabschnitts unterbringen Me("Col" + Format(mintColumnCount + 1)) = lngRowTotal ' Die Zeilensumme der Gesamtsumme hinzufügen mlngReportTotal = mlngReportTotal + lngRowTotal End If End Sub
Für Berichtsabschnitte verfügbare Ereignisse
407
Der Code beginnt mit der Auswertung der Eigenschaft PrintCount. Ist ihr Wert gleich 1, so bedeutet dies, dass das Ereignis Print für diesen Abschnitt zum ersten Mal auftritt, so dass der Wert für die Zeilensumme auf 0 gesetzt werden kann. Der Code durchläuft mit einer Schleife anschließend jedes Steuerelement des Abschnitts und bildet die Summen für jede Spalte des Berichts und die jeweilige Zeile. Nach Verlassen der Schleife platziert die Routine die Zeilensumme im entsprechenden Steuerelement und addiert diesen Wert zum Gesamtwert des Berichts. Der Detailabschnitt des Berichts kann jetzt gedruckt werden. Oft besteht Unklarheit darüber, wann Routinen für das Ereignis Format und wann sie für das Ereignis Print geschrieben werden sollten. Wenn Sie etwas durchführen, was das Seitenlayout nicht betrifft, sollten Sie das Ereignis Print verwenden. Führen Sie jedoch etwas durch, was das Erscheinungsbild des Berichts (das Layout) verändert, dann verwenden Sie das Ereignis Format.
10.4.3
Das Ereignis Retreat (Bei Rücknahme)
Manchmal muss sich Access beim Drucken zum vorhergehenden Abschnitt zurückbewegen, z.B. wenn im Dialogfeld SORTIEREN UND GRUPPIEREN die Eigenschaft ZUSAMMENHALTEN auf Mit 1. Detaildatensatz oder Ganze Gruppe gesetzt wurde. Access muss den Gruppenkopf und den ersten Detaildatensatz oder bei der Einstellung Ganze Gruppe die gesamte Gruppe formatieren. Anschließend wird festgestellt, ob der Abschnitt in die aktuelle Seite eingepasst werden kann. Die beiden Abschnitte werden zurückgenommen und anschließend formatiert und gedruckt. Ein RetreatEreignis tritt für jeden Abschnitt auf. Es folgt ein Beispiel für das Ereignis Retreat des Detailabschnitts eines Berichts: Private Sub Detail1_Retreat() ' Bei Rückgabe immer Rückkehr zum vorherigen Datensatz mrstReport.MovePrevious End Sub
Dieser Code gehört zum Ereignis Retreat des Berichts rptEmployeeSales aus der Datenbank CHAP10EX.MDB. Da es sich hier um einen ungebundenen Bericht handelt, muss der Bericht bei jedem Retreat-Ereignis zum vorherigen Datensatz der Datensatzgruppe zurückgegeben werden.
Beim Umgang mit ungebundenen Berichten müssen Sie immer sorgfältig darauf achten, dass der Datensatzzeiger mit dem Bericht in Einklang bleibt. Wurde der Datensatzzeiger beispielsweise hochgesetzt und tritt dann das Retreat-Ereignis ein, muss er wieder auf den vorherigen Datensatz zurückgesetzt werden.
408
10.4.4
Kapitel 10: Fortgeschrittene Verwendung von Berichten
Reihenfolge von Abschnittsereignissen
Die Ereignisse der Berichtsabschnitte verfügen genau wie die des Berichts über eine bestimmte Reihenfolge. Alle Format- und Print-Ereignisse der Abschnitte finden nach den Ereignissen Open und Activate, aber noch vor den Ereignissen Close und Deactivate des Berichts statt. Die Reihenfolge sieht wie folgt aus: Open (Bericht)->Activate (Bericht)->Format(Berichtsabschnitt)-> Print(Berichtsabschnitt)->Close (Bericht)->Deactivate (Bericht)
10.5
Spezielle Berichtseigenschaften
Viele Berichtseigenschaften stehen nur während der Ausführung zur Verfügung. Mit ihrer Hilfe können Sie die Verarbeitung des Berichts deutlich verfeinern. Diese Eigenschaften werden in den folgenden Abschnitten behandelt. Beispiele finden Sie im Abschnitt »Praktische Anwendungen für Berichtsereignisse und Anwendungen« dieses Kapitels.
10.5.1
MoveLayout
Die Eigenschaft MoveLayout zeigt Access an, ob zum nächsten Druckabschnitt der Seite übergegangen werden soll. Hat diese Eigenschaft den Wert False, wird die Druckposition nicht vorgeschoben.
10.5.2
NextRecord
Die Eigenschaft NextRecord gibt an, ob ein Abschnitt zum nächsten Datensatz übergehen soll. Hat die Eigenschaft den Wert False, wird der Übergang zum nächsten Datensatz unterdrückt.
10.5.3
PrintSection
Die Eigenschaft PrintSection bestimmt, ob der Abschnitt gedruckt wird. Setzen Sie die Eigenschaft auf den Wert False, können Sie das Ausdrucken dieses Abschnitts unterdrücken.
10.5.4
Zusammenspiel von MoveLayout, NextRecord und PrintSection
Durch eine Kombination der Eigenschaften MoveLayout, NextRecord und PrintSection können Sie genau festlegen, wo, wie und ob Daten gedruckt werden. Tabelle 10.1 veranschaulicht diesen Zusammenhang.
Spezielle Berichtseigenschaften
409
MoveLayout NextRecord PrintSection Auswirkung True
True
True
Wechsel zur nächsten Position und zum nächsten Datensatz und Drucken der Daten
True
False
True
Unter Beibehaltung des Datensatzes zur nächsten Position wechseln und drucken
True
True
False
Wechsel zur nächsten Position und zum nächsten Datensatz, aber die Daten nicht drucken; auf diese Weise wird ein Datensatz ausgelassen und stattdessen ein Leerraum gedruckt
True
False
False
Unter Beibehaltung des Datensatzes zur nächsten Position wechseln, aber nicht drucken; ohne zum nächsten Datensatz zu wechseln, wird ein Leerraum erzeugt
False
True
True
Die Position beibehalten, zum nächsten Datensatz wechseln und die Daten drucken; hierdurch wird ein Datensatz mit einem anderen überlagert
False
False
True
Nicht zulässig
False
True
False
Die Position beibehalten, zum nächsten Datensatz wechseln und das Drucken unterbrechen; hierdurch wird ein Datensatz ausgelassen, ohne einen Leerraum zu hinterlassen
False
False
False
Nicht zulässig
Tabelle 10.1: Das Zusammenspiel von MoveLayout, NextRecord und PrintSection
10.5.5
FormatCount
Die Eigenschaft FormatCount wertet aus, wie oft das Ereignis Format im aktuellen Berichtsabschnitt eingetreten ist. Beim Eintritt des Ereignisses Retreat tritt das Ereignis Format immer mehrfach auf. Durch Überprüfen der FormatCount-Eigenschaft können Sie dafür sorgen, dass umfangreiche Anweisungen aus dem Code zum Ereignis Format nur einmal ausgeführt werden.
10.5.6
PrintCount
Die Eigenschaft PrintCount gibt an, wie oft das Ereignis Print für den aktuellen Abschnitt eingetreten ist. Wenn das Ereignis Retreat auftritt, tritt das Ereignis Print immer mehrfach auf. Durch Überprüfen der Eigenschaft PrintCount können Sie dafür sorgen, dass Code für das Ereignis Print nur einmal ausgeführt wird.
410
10.5.7
Kapitel 10: Fortgeschrittene Verwendung von Berichten
HasContinued
Die Eigenschaft HasContinued gibt an, ob ein Teil des gerade bearbeiteten Abschnitts auf einer vorherigen Seite gedruckt wurde. Über diese Eigenschaft können Sie bestimmte Berichtssteuerelemente verbergen oder anzeigen (zum Beispiel Fortsetzung von ...), wenn der Abschnitt eine Fortsetzung hat.
10.5.8
WillContinue
Die Eigenschaft WillContinue gibt an, ob der aktuelle Abschnitt auf einer anderen Seite fortgesetzt wird. Mit dieser Eigenschaft können Sie wie bei HasContinued bestimmte Steuerelemente anzeigen oder verbergen, wenn ein Abschnitt auf einer anderen Seite fortgesetzt wird.
10.6
Praktische Anwendungen für Berichtsereignisse und -eigenschaften
Beim Entwickeln von Berichten sollten Sie darauf achten, dass der Bericht in so vielen Situationen wie möglich benutzt werden kann, was bedeutet, dass Sie den Bericht möglichst flexibel gestalten müssen. Anstatt mehrere ähnliche Berichte zu unterhalten, die bei Veränderungen jeweils alle mitgeändert werden müssen, können Sie einen Bericht anlegen, der für mehrere Situationen geeignet ist. Mittels der in diesem Abschnitt vorgestellten Ereignisse und Eigenschaften können Sie genau das erreichen. Dies kann beinhalten, dass Sie während der Ausführung die Datenherkunft wechseln, aber den gleichen Bericht zum Ausdrucken der Datenzusammenfassung oder der Detaildaten oder für beide Zwecke verwenden, die Druckposition ändern oder auch einen Bericht auf Grundlage einer Kreuztabellenabfrage mit ungebundenen Steuerelementen erstellen. Diese Möglichkeiten des Berichtsentwurfs werden in den folgenden Abschnitten behandelt.
10.6.1
Die Datenherkunft eines Berichts wechseln
Es gibt viele Situationen, in denen Sie zur Laufzeit die Datenherkunft eines Berichts wechseln müssen. Hierdurch geben Sie den Benutzern die Möglichkeit, die Bedingungen für den Bericht und die Abfrage, auf welcher der Bericht basiert, erkennbar zu verändern. Der Bericht rptClientListing aus der Datenbank CHAP10.MDB enthält den Code aus Listing 10.4. Listing 10.4: Mit Hilfe des Open-Ereignisses des Berichts die Datenherkunft wechseln Private Sub Report_Open(Cancel As Integer) On Error Resume Next DoCmd.OpenForm "frmClientListingCriteria", WindowMode:=acDialog If Not IsLoaded("frmClientListingCriteria") Then
Praktische Anwendungen für Berichtsereignisse und -eigenschaften
411
MsgBox "Criteria form not successfully loaded, " & _ "Canceling Report" Cancel = True Else Select Case Forms!frmClientListingCriteria.optCriteria.Value Case 1 Me.RecordSource = "qryClientListingCity" Case 2 Me.RecordSource = "qryClientListingStateProv" Case 3 Me.RecordSource = "qryClientListing" End Select End If End Sub
Dieser Code öffnet zu Beginn das Formular frmClientListingCriteria, wenn dies nicht bereits geschehen ist. Das Formular wird gebunden geladen und erwartet die Auswahl der Berichtskriterien durch den Benutzer (siehe Abbildung 10.1). Nachdem der Benutzer die Berichtsvorschau gewählt hat, setzt das Formular die eigene Visible-Eigenschaft auf den Wert False. Dadurch wird die Ausführung des Berichts fortgesetzt, das Formular jedoch im Speicher behalten, so dass dessen Steuerelemente für den VBA-Code zugänglich sind. Dann wird der Wert des Optionsfeldes optCriteria des Formulars ausgewertet. Je nachdem, welches Optionsfeld gewählt wurde, wird die Eigenschaft RecordSource des Berichts auf die entsprechende Abfrage gesetzt. Der folgende Code gehört zum Ereignis Close des Berichts: Private Sub Report_Close() DoCmd.Close acForm, "frmClientListingCriteria" End Sub
Abbildung 10.1: Die Eigenschaft RecordSource mit den Auswahlkriterien festlegen
Dieser Code schließt das Formular mit den Auswahlkriterien, wenn der Bericht geschlossen wird. Das Formular frmClientListingCriteria enthält wichtigen Code für das Erstellen des Berichts. Dieser gehört zum Ereignis AfterUpdate der Optionsgruppe optCriteria (siehe Listing 10.5).
412
Kapitel 10: Fortgeschrittene Verwendung von Berichten
Listing 10.5: Die Behandlungsroutine für das Ereignis AfterUpdate von optCriteriaCombo verbirgt und zeigt Kombinationsfelder an. Private Sub optCriteria_AfterUpdate() Select Case optCriteria.Value Case 1 Me.cboCity.Visible = True Me.cboStateProv.Visible = False Case 2 Me.cboStateProv.Visible = True Me.cboCity.Visible = False Case 3 Me.cboCity.Visible = False Me.cboStateProv.Visible = False End Select End Sub
Dieser Code wertet die Optionsgruppe aus. Er verbirgt und zeigt die Kombinationsfelder cboCity und cboState an, je nachdem, welches Optionsfeld gewählt wurde. Anschließend werden diese Kombinationsfelder als Kriterien für die dem Bericht rptClientListing zu Grunde liegende Abfrage benutzt.
10.6.2
Zusammenfassung und/oder Details anzeigen
Viele Programmierer erstellen drei Berichte für ihre Benutzer: einen für die Anzeige der Zusammenfassung, einen für die Details und einen, der beides anzeigt. Das ist völlig überflüssig. Da die Berichtsabschnitte während der Ausführung optional verborgen oder angezeigt werden können, können Sie einen Bericht für alle drei Aufgaben erstellen. Der Bericht rptClientBillingsByProject aus der Datenbank CHAP10.MDB veranschaulicht diese Möglichkeit. Platzieren Sie den Code aus Listing 10.6 in der Routine für das Open-Ereignis des Berichts. Listing 10.6: Das Open-Ereignis des Berichts verwenden, um Berichtsabschnitte bei Bedarf ein- und auszublenden Private Sub Report_Open(Cancel As Integer) DoCmd.OpenForm "frmReportDateRange", _ WindowMode:=acDialog, OpenArgs:="rptClientBillingsbyProject" If Not IsLoaded("frmReportDateRange") Then Cancel = True Else Select Case Forms!frmReportDateRange!optDetailLevel.Value Case 1 Me.Caption = Me.Caption & " – Summary Only" Me.lblTitle.Caption = Me.lblTitle.Caption & " – Summary Only" Me.Detail.Visible = False Case 2 Me.Caption = Me.Caption & " – Detail Only"
Praktische Anwendungen für Berichtsereignisse und -eigenschaften
413
Me.lblTitle.Caption = Me.lblTitle.Caption & " – Detail Only" Me.GroupHeader0.Visible = False Me.GroupFooter1.Visible = False Me.CompanyNameDet.Visible = True Case 3 Me.Caption = Me.Caption & " – Summary and Detail" Me.lblTitle.Caption = Me.lblTitle.Caption & " – Summary and Detail" Me.CompanyNameDet.Visible = False End Select End If End Sub
Zuerst wird das Formular frmReportDateRange aus der Datenbank CHAP10.MDB geöffnet (siehe Abbildung 10.2). Dieses Formular verfügt über eine Optionsgruppe, mit der der Benutzer gefragt wird, ob er eine Zusammenfassung, Details oder beides angezeigt bekommen möchte. Wird die Zusammenfassung gewählt, werden die Beschriftung des Berichtsfensters und das Etikett lblTitle geändert und die Eigenschaft Visible des Detailabschnitts auf den Wert False gesetzt. Wählt der Benutzer die Details, wird die Beschriftung des Berichtsfensters und das Etikett lblTitle entsprechend angepasst und der Wert der Eigenschaft Visible des Gruppenkopf- und des Gruppenfußabschnitts auf den Wert False gesetzt. Ferner wird im Detailabschnitt ein Steuerelement mit dem Firmennamen eingeblendet. Das Steuerelement CompanyName erscheint im Detailabschnitt, wenn nur die Berichtsdetails gedruckt werden, ist jedoch unsichtbar, wenn die Zusammenfassung und die Details gedruckt werden. Wurde Both für die Details gewählt, werden keine Abschnitte verborgen. Die Beschriftung des Berichtsfensters und das Etikett lblTitle werden geändert und das Steuerelement CompanyName verborgen.
Abbildung 10.2: Mit den Auswahlkriterien die Details festlegen
Den Code für die Schaltfläche PREVIEW des Formulars finden Sie in Listing 10.7. Listing 10.7: Der Code, der den vom Benutzer angegebenen Datumsbereich überprüft Private Sub cmdPreview_Click() If IsNull(Me.txtBeginDate) Or IsNull(Me.txtEndDate) Then MsgBox "You must enter both beginning and ending dates."
414
Kapitel 10: Fortgeschrittene Verwendung von Berichten
Me.txtBeginDate.SetFocus Else If Me.txtBeginDate > Me.txtEndDate Then MsgBox "Ending date must be greater than Beginning date." Me.txtBeginDate.SetFocus Else Me.Visible = False End If End If End Sub
Dieser Code stellt fest, ob sowohl das Anfangs- als auch das Enddatum angegeben wurden, und prüft, ob das Anfangs- vor dem Enddatum liegt. Sind beide Bedingungen erfüllt, wird die Visible-Eigenschaft des Formulars auf False gesetzt. Andernfalls wird eine entsprechende Fehlermeldung angezeigt.
10.6.3
Mehrere Etiketten drucken
Oftmals möchten die Benutzer mehrere Kopien des gleichen Etiketts drucken. Dies kann mit Hilfe der Eigenschaften MoveLayout, NextRecord, PrintSection und PrintCount geschehen. Das Formular in Abbildung 10.3 trägt den Namen frmClientLabelCriteria und befindet sich in der Datenbank CHAP10.MDB. Es fordert den Benutzer auf, eine Firma auszuwählen und die Anzahl der Etiketten anzugeben, die für diese Firma ausgedruckt werden sollen. Listing 10.8 enthält den Code für die Befehlsschaltfläche PRINT LABELS. Listing 10.8: Der Code, mit dem der Bericht lblClientMailingLabels für eine ausgewählte Firma gedruckt wird Sub cmdPrintLabels_Click() On Error GoTo Err_cmdPrintLabels_Click Dim stDocName As String stDocName = "lblClientMailingLabels" DoCmd.OpenReport stDocName, acPreview, , "CompanyName = '" & Me.cboCompanyName.Value & "'" Exit_cmdPrintLabels_Click: Exit Sub Err_cmdPrintLabels_Click: MsgBox Err.Description Resume Exit_cmdPrintLabels_Click End Sub
415
Praktische Anwendungen für Berichtsereignisse und -eigenschaften
Abbildung 10.3: Die Abfrage des Firmennamens und der Anzahl der zu druckenden Etiketten über die Kriterienauswahl
Beachten Sie, dass die Routine den im Kombinationsfeld ausgewählten Firmennamen als Kriterium für die Ausführung des Berichts lblClientMailingLabels verwendet. Das Ereignis Open dieses Berichts sieht wie folgt aus: Private Sub Report_Open(Cancel As Integer) If Not IsLoaded("frmClientLabelCriteria") Then MsgBox "You must Run This Report From Label Criteria Form" Cancel = True End If End Sub
Dieser Code überprüft, ob das Formular frmClientLabelCriteria geöffnet ist. Ist dies nicht der Fall, wird eine Nachricht angezeigt und der Bericht abgebrochen. Der Schlüssel für den gesamten Ablauf liegt in der Routine für das Ereignis Print des Detailabschnitts: Private Sub Detail_Print(Cancel As Integer, PrintCont AsInteger) If PrintCount < Forms!frmClientLabelCriteria.txtNumberOfLabels Then Me.NextRecord = False End If End Sub
Dieser Code vergleicht die Eigenschaft PrintCount mit der Anzahl der Etiketten, die der Benutzer drucken möchte. Solange der Wert von PrintCount niedriger als die Anzahl der angeforderten Etiketten ist, wird der Datensatzzeiger nicht hochgesetzt. Auf diese Weise werden mehrere Etiketten des gleichen Datensatzes gedruckt.
10.6.4
Die Position des Ausdrucks bestimmen
Manchmal möchten die Benutzer mehrere Kopien des gleichen Etiketts drucken, wobei sich das Adressetikett an einer bestimmten Position auf der Seite befinden soll. Dies wird dadurch erreicht, dass das Drucken mit dem ersten ungenutzten Etikett beginnt. Das Formular frmClientLabelPosition aus der Datenbank CHAP10.MDB lässt
416
Kapitel 10: Fortgeschrittene Verwendung von Berichten
den Benutzer die Position des ersten Etiketts durch Angabe der zu überspringenden Etiketten angeben (siehe Abbildung 10.4). Der Code für das Ereignis Open des Etiketts lblClientMailLabelsSkip sieht wie folgt aus: Private Sub Report_Open(Cancel As Integer) If Not IsLoaded("frmClientLabelPosition") Then MsgBox "You Must Run This Report From Label Criteria Form" Cancel = True Else mboolFirstLabel = True End If End Sub
Abbildung 10.4: Die Angabe der zu überspringenden Etiketten mit der Kriterienauswahl
Der Code überprüft, ob das Formular frmClientLabelPosition geladen ist und weist der privaten Variablen mboolFirstLabel den Wert True zu. Die Routine für das Ereignis Print des Detailabschnitts sieht wie folgt aus: Private Sub Detail_Print(Cancel As Integer, PrintCount As Integer) If PrintCount <= Forms!frmClientLabelPosition!txtLabelsToSkip _ And mboolFirstLabel = True Then Me.NextRecord = False Me.PrintSection = False Else mboolFirstLabel = False End If End Sub
Diese Routine stellt fest, ob der Wert der Eigenschaft PrintCount niedriger oder gleich der Anzahl der zu überspringenden Etiketten ist und ob die Variable mboolFirstLabel den Wert True hat. Sind beide Bedingungen erfüllt, wechselt der Bericht nicht zum nächsten Datensatz und es wird nichts gedruckt. Die Druckposition wird also vorgeschoben. Ist PrintCount größer als die Anzahl der zu überspringenden Etiketten, wird die Variable mboolFirstLabel auf den Wert False gesetzt und der Druckvorgang normal fortgesetzt. Erhält die Variable mboolFirstLabel nicht den Wert False, wird die angegebene Anzahl Etiketten zwischen den Datensätzen ausgelassen. Das Ganze funktioniert mit Hilfe des Ereignisses Print des Berichtskopfs:
417
Praktische Anwendungen für Berichtsereignisse und -eigenschaften
Private Sub ReportHeader_Format(Cancel As Integer, FormatCount As Integer) mboolFirstLabel = True End Sub
Die Routine zum Ereignis Format des Berichtskopfs setzt die Variable mboolFirstLabel wieder auf den Wert True. Diesen Schritt müssen Sie für den Fall einfügen, dass sich der Benutzer eine Vorschau anzeigen lässt und anschließend die Etiketten druckt. Wenn die Variable mboolFirstLabel nicht wieder auf den Wert True gesetzt wird, wird die gewählte Anzahl der Etiketten für den Ausdruck nicht übersprungen, weil die Bedingung zum Auslassen der Etiketten niemals zutrifft.
10.6.5
Einen Bericht auf der Basis einer Kreuztabellenabfrage erstellen
Es ist schwierig, einen Bericht auf den Ergebnissen einer Kreuztabellenabfrage aufzubauen, weil die Anzahl der Spalten normalerweise variiert. Werfen Sie einen Blick auf das Beispiel in Abbildung 10.5. Beachten Sie, dass der Name des Mitarbeiters im Kopf des Berichts als Spaltenüberschrift erscheint und dass die Produkte als Zeilentitel aufgeführt werden. Dieser Bericht entsteht mit Hilfe der Kreuztabellenabfrage qxtabEmployeeSales, die Sie in der Datenbank CHAP10EX.MDB auf der beiliegenden CD-ROM finden (siehe Abbildung 10.6). Das Problem besteht darin, dass die Anzahl der Mitarbeiter und daher auch die Spaltenüberschriften variieren können. Dieser Bericht wurde speziell für solche Fälle programmiert.
Abbildung 10.5: Ein auf einer Kreuztabellenabfrage basierender Bericht
Wird der Bericht rptEmployeeSales aus der Datenbank CHAP10EX.MDB ausgeführt, wird die Behandlungsroutine für sein Ereignis Open ausgeführt (siehe Abbildung 10.9).
418
Kapitel 10: Fortgeschrittene Verwendung von Berichten
Abbildung 10.6: Eine Kreuztabellenabfrage, die einem Bericht zugrunde liegt Listing 10.9: Code, der die Kriterien für einen Bericht ermittelt und anschließend die dem Bericht zu Grunde liegende Datensatzgruppe zusammenstellt Private Sub Report_Open(Cancel As Integer) ' Erstellen der zugrundeliegenden Datensatzgruppe des Berichts mit den ' im Formular EmployeesSalesDialogBox eingegebenen Kriterien Dim Dim Dim Dim
intX As Integer db As DAO.Database qdf As DAO.QueryDef frm As Form
Set db = CurrentDb ' Den Bericht nicht öffnen, wenn das Formular EmployeesSalesDialogBox ' nicht geladen ist If Not (IsLoaded("frmEmployeeSalesDialogBox")) Then Cancel = True MsgBox "To preview or print this report, you must open " _ & "EmployeeSalesDialogBox in Form view.", vbExclamation, _ "Must Open Dialog Box" Exit Sub End If Set frm = Forms!frmEmployeeSalesDialogBox ' Die Abfrage qxtabEmployeesSales öffnen Set qdf = db.QueryDefs("qxtabEmployeeSales") ' Die Parameter für die Abfrage entsprechend der im Formular ' EmployeesSalesDialogBox eingegebenen Werte setzen. qdf.Parameters("Forms!frmEmployeeSalesDialogBox!txtBeginningDate") _ = frm!txtBeginningDate qdf.Parameters("Forms!frmEmployeeSalesDialogBox!txtEndingDate") _ = frm!txtEndingDate ' Das Datensatzgruppenobjekt öffnen Set mrstReport = qdf.OpenRecordset
Praktische Anwendungen für Berichtsereignisse und -eigenschaften
419
' Eine Variable für die Anzahl der Spalten der Kreuztabellenabfrage setzen mintColumnCount = mrstReport.Fields.Count
End Sub
Der Code für das Ereignis Open weist einer Objektvariablen die aktuelle Datenbank zu. Anschließend wird überprüft, ob das Kriterienformular frmEmployeeSalesDialogBox geöffnet ist. Dieses Formular liefert die Kriterien für die Kreuztabellenabfrage qxtabEmployeeSales, die dem Bericht zu Grunde liegt. Es öffnet die Abfragedefinition qxtabEmployeeSales und übergibt ihm die Parameter des Kriterienformulars frmEmployeeSalesDialogBox. Danach wird anhand der Abfragedefinition eine Datensatzgruppe geöffnet und es kommt zur Anwendung der Kriterien des Formulars frmEmployeeSalesDialogBox. Die Anzahl der von der Kreuztabellenabfrage übergebenen Spalten ist sehr wichtig. Diese Zahl wird in der privaten Variablen mintColumnCount gespeichert und von den verbleibenden Funktionen zur Festlegung der mit Daten zu füllenden Spaltenanzahl benötigt. Diese Buch konzentriert sich eher auf den Einsatz von ADOs (ActiveX-Datenobjekte) als auf den von DAOs (Datenzugriffsobjekte). Sie werden sich vielleicht fragen, warum in diesem Beispiel ein DAO anstelle eines ADOs verwendet wird. Da die dem Beispiel zu Grunde liegende Abfrage eine Kreuztabellenabfrage ist und das ADO-Befehlsobjekt keine Kreuztabellenabfragen erkennt, musste in diesem Fall ein DAO benutzt werden. Als nächstes tritt das Ereignis für das Formatieren des Berichtskopfs ein. Es wechselt zum ersten Datensatz der beim Auftreten des Open-Ereignisses erstellten Datensatzgruppe. Außerdem wird die Routine InitVars aufgerufen: Private Sub ReportHeader3_Format(Cancel As Integer, FormatCount As Integer) ' Zum ersten Datensatz der Datensatzgruppe wechseln, wenn der Bericht gestartet ' oder neu gestartet wird. (Ein Bericht wird neu gestartet, wenn er über ein ' Vorschaufenster gedruckt oder bei der Vorschau zur vorhergehenden Seite ' zurückgekehrt wird.) mrstReport.MoveFirst 'Variableninitialisierung Call InitVars End Sub
420
Kapitel 10: Fortgeschrittene Verwendung von Berichten
Die Routine InitVars initialisiert einige Variablen für den Bericht: Private Sub InitVars() Dim intX As Integer ' Die Variable lngReportTotal initialisieren mlngReportTotal = 0 ' Das Feld für die Spaltensummen initialisieren For intX = 1 To conTotalColumns mlngRgColumnTotal(intX) = 0 Next intX End Sub
Die Variable mlngReportTotal enthält die Gesamtsumme des Berichts (alle Produkte, alle Vertreter) und das Feld mlngRgColumnTotal die Summen jedes Vertreters. Nach dem Ereignis für die Formatierung des Berichtskopfs tritt das Ereignis für die Formatierung des Seitenkopfs ein, dessen Behandlungsroutine Sie hier sehen: Private Sub PageHeader0_Format(Cancel As Integer, FormatCount As Integer) Dim intX As Integer ' Die Spaltenüberschriften in die Textfelder der Seitenköpfe setzen For intX = 1 To mintColumnCount Me("Head" + Format(intX)) = mrstReport(intX – 1).Name Next intX ' Das nächste Textfeld Totals als Beschriftung verwenden Me("Head" + Format(mintColumnCount + 1)) = "Totals" ' Nicht benutzte Textfelder im Seitenkopf verbergen For intX = (mintColumnCount + 2) To conTotalColumns Me("Head" + Format(intX)).Visible = False Next intX End Sub
Dieser Code verwendet die Feldnamen der Abfrage als Spaltenüberschrift für den Bericht. Diese wichtige Routine ist gut durchdacht, denn nach dem Einfügen der Spaltenüberschriften werden alle weiteren Steuerelemente im Bericht verborgen. Als nächstes tritt das Ereignis Detail1_Selection ein, so dass folgender Code ausgeführt wird: Private Sub Detail1_Format(Cancel As Integer, FormatCount As Integer) ' Werte in die Textfelder einfügen und nicht benutzte Textfelder verbergen
Praktische Anwendungen für Berichtsereignisse und -eigenschaften
421
Dim intX As Integer ' Überprüfen, ob nicht das Ende der Datensatzgruppe erreicht wurde If Not mrstReport.EOF Then ' Hat FormatCount den Wert 1, werden die Werte der Datensatzgruppe in die ' Textfelder des Detailabschnitts gesetzt. If Me.FormatCount = 1 Then For intX = 1 To mintColumnCount ' Null-Werte in 0 umwandeln Me("Col" + Format(intX)) = xtabCnulls(mrstReport(intX – 1)) Next intX ' Ungenutzte Textfelder im Detailabschnitt verbergen For intX = mintColumnCount + 2 To conTotalColumns Me("Col" + Format(intX)).Visible = False Next intX ' Zu nächsten Datensatz der Datensatzgruppe wechseln mrstReport.MoveNext End If End If
End Sub
Dieses Ereignis überprüft die EOF-Eigenschaft der Datensatzgruppe, um festzustellen, ob der letzte Datensatz der Abfrage bereits gelesen wurde. Ist dies nicht der Fall, wird überprüft, ob die Eigenschaft FormatCount des Abschnitts den Wert 1 hat. Trifft dies zu, wird jede Spalte des aktuellen Datensatzes der Datensatzgruppe gelesen. Jedes Steuerelement im Detailabschnitt wird mit Daten aus einer Spalte der Datensatzgruppe gefüllt und jedes nicht genutzte Textfeld des Detailabschnitts des Berichts versteckt. Abschließend wechselt der Code zum nächsten Datensatz der Datensatzgruppe und bereitet den Ausdruck der nächsten Berichtszeile des Detailabschnitts vor. Die Funktion xtabCnulls, mit der Null-Werte in Nullen umgewandelt werden, wird immer dann aufgerufen, wenn die dem Bericht zu Grunde liegende Datensatzgruppe gelesen wird: Private Function xtabCnulls(varX As Variant) ' Testen, ob ein Wert gleich Null ist. XtabCnulls = NZ(varX,0) End Function
Die Funktion xtabCnulls wertet jeden empfangenen Wert aus und stellt fest, ob er gleich Null ist. Ist dies der Fall, wird von der Funktion eine Null, andernfalls der überreichte Wert zurückgegeben.
422
Kapitel 10: Fortgeschrittene Verwendung von Berichten
Nach der Ausführung des Formatierungsereignisses des Detailabschnitts wird das PRINT-Ereignis für diesen Abschnitt ausgeführt: Private Sub Detail1_Print(Cancel As Integer, PrintCount As Integer) Dim intX As Integer Dim lngRowTotal As Long ' Hat PrintCount den Wert 1, wird die Variable rowTozal initialisiert. ' Der Spaltensumme hinzufügen If Me.PrintCount = 1 Then lngRowTotal = 0 For intX = 2 To mintColumnCount ' Beginnend mit Spalte 2 (erstes Textfeld mit Kreuztabellenwert) ' die Summe für die aktuelle Zeile im Detailabschnitt berechnen lngRowTotal = lngRowTotal + Me("Col" + Format(intX)) ' Den Kreuztabellenwert der Summe der aktuellen Spalte hinzufügen mlngRgColumnTotal(intX) = mlngRgColumnTotal(intX) + _ Me("Col" + Format(intX)) Next intX ' Die Zeilensumme in das Textfeld des Detailabschnitts setzen Me("Col" + Format(mintColumnCount + 1)) = lngRowTotal ' Die Zeilensumme der aktuellen Zeile der Gesamtsumme hinzufügen>> mlngReportTotal = mlngReportTotal + lngRowTotal End If End Sub
Dieser Code berechnet den Gesamtwert der Zeile und platziert ihn in der letzten Spalte des Berichts. Er berechnet außerdem die Spaltensummen und den Wert für mlngReportTotal, der die Gesamtsumme aller Spalten und Zeilen enthält. Hierfür wird geprüft, ob die Eigenschaft PrintCount dieses Abschnitts den Wert 1 hat. Trifft dies zu, wird die Variable lngRowTotal auf den Wert 0 zurückgesetzt. Beginnend mit der zweiten Spalte (Spalte 1 enthält den Produktnamen) wird durch Überprüfen jedes Steuerelements der Zeile eine Zeilensumme gebildet, deren Wert zu lngRowTotal addiert wird. Beim Passieren jeder Spalte der Zeile wird auch der Wert jeder Spalte dem entsprechenden Element im privaten Feld mlngRgColumnTotal hinzuaddiert. Die Zeilensumme wird gedruckt und zur Gesamtsumme des Bericht hinzugezählt. Wenn das Ereignis Retreat eintritt, wird folgender Code ausgeführt: Private Sub Detail1_Retreat() ' Bei erneuter Ausführung des Detailabschnitts zurück zum vorhergehenden ' Datensatz. mrstReport.MovePrevious End Sub
Praktische Anwendungen für Berichtsereignisse und -eigenschaften
423
Dieser Code setzt den Datensatzzeiger zurück auf den letzten Datensatz der Datensatzgruppe. Zum Schluss wird der Berichtsfuß gedruckt, was das Ereignis Print für die Fußzeile auslöst: Private Sub ReportFooter4_Print(Cancel As Integer, PrintCount As Integer) Dim intX As Integer ' Die Spaltensummen in Textfelder des Berichtsfußes setzen ' Beginnend mit Spalte 2 (erstes Textfeld mit Kreuztabellenwert) For intX = 2 To mintColumnCount Me("Tot" + Format(intX)) = mlngRgColumnTotal(intX) Next intX ' Gesamtsumme in Textfeld des Berichsfußes setzen Me("Tot" + Format(mintColumnCount + 1)) = mlngReportTotal ' Nicht genutzte Textfelder im Berichtskopf verbergen For intX = mintColumnCount + 2 To conTotalColumns Me("Tot" + Format(intX)).Visible = False Next intX End Sub
Dieses Ereignis durchläuft in einer Schleife jedes Steuerelement des Berichtsfußes und füllt jedes Steuerelement mit dem entsprechenden Element aus dem Feld mlngRgColumnTotal. Auf diese Weise erhalten Sie die Spaltensummen des Berichts. Am Ende wird die Gesamtsumme in der nächsten verfügbaren Spalte gedruckt. Alle weiteren Textfelder werden bei der Anzeige verborgen.
10.6.6
Die ersten und letzten Seiteneinträge im Seitenkopf drucken
Eine weitere sinnvolle Vorgehensweise ist das Drucken der ersten und letzten Seiteneinträge im Berichtskopf. Dies veranschaulicht der Bericht rptCustomerPhoneList aus der Datenbank CHAP10EX.MDB der beiliegenden CD-ROM (siehe Abbildung 10.7). Der Code für diesen Bericht basiert darauf, dass Access den Bericht zweimal durchläuft. Beim ersten Durchlauf wird einer Variablen gboolLastPage der Wert False zugewiesen. Den Wert True erhält diese Variable nur, wenn das Ereignis Format des Berichtsfußes am Ende des ersten Durchlaufs ausgeführt wird. Berücksichtigen Sie diesen Umstand, wenn Sie den Code des Berichts betrachten.
424
Kapitel 10: Fortgeschrittene Verwendung von Berichten
Abbildung 10.7: Der erste und der letzte Eintrag werden im Berichtskopf gedruckt
Die erste Routine, welche das Erstellen des Berichts betrifft, ist die Ereignisroutine Format für den Berichtskopf: Private Sub PageHeader0_Format(Cancel As Integer, FormatCount As Integer) ' Im zweiten Durchgang die Textfelder FirstEntry und LastEntry füllen>> If gboolLastPage = True Then Reports!rptCustomerPhoneList.txtFirstEntry = _ Reports!rptCustomerPhoneList.txtCompanyName Reports!rptCustomerPhoneList.txtLastEntry = _ gstrLast(Reports!rptCustomerPhoneList.Page) End If End Sub
Die Routine Format für den Seitenkopf prüft, ob die Variable gboolLastPage den Wert True hat. Beim ersten Durchlauf des Berichts hat diese Variable den Wert False. Beim zweiten Durchlauf werden die Textfelder txtFirstEntry und txtLastEntry mit Daten gefüllt (beide erscheinen im Berichtskopf). Das Textfeld txtFirstEntry erhält den Wert des Steuerelements txtCompanyName des aktuellen Datensatzes (der erste Datensatz der Seite) und txtLastEntry die entsprechende Elementnummer aus dem Feld CustomerPhoneList. Jedes Element des Felds CustomerPhoneList wird mit Hilfe des Format-Ereignisses des Seitenfußes beim ersten Durchlauf des Berichts gefüllt. Als nächstes wird der Code zum Ereignis Format des Seitenfußes ausgeführt: Private Sub PageFooter2_Format(Cancel As Integer, FormatCount As Integer) ' Beim ersten Durchlauf die Feldgröße erhöhen und den letzten Datensatz der Seite ' dem Feld hinzufügen
Praktische Anwendungen für Berichtsereignisse und -eigenschaften
425
If Not gboolLastPage Then ReDim Preserve gstrLast(Reports!rptCustomerPhoneList.Page + 1) gstrLast(Reports!rptCustomerPhoneList.Page) = _ Reports!rptCustomerPhoneList.txtCompanyName End If End Sub
Dieses Ereignis stellt fest, ob die Variable gboolLastPage den Wert False hat. Ist dies der Fall (was während des ersten Durchlaufs des Berichts zutrifft), wird das Feld gstrLast für das Hinzufügen eines neuen Elements neu dimensioniert. Der Wert des Steuerelements txtCompanyName des letzten Datensatzes der Seite wird in dem neuen Element des Felds gstrLast gespeichert. Dieser Wert erscheint unter Umständen im Seitenkopf dieser Seite als letzter Firmenname der Seite. Abschließend wird die Routine zum Ereignis Format des Berichtsfußes ausgeführt: Private Sub ReportFooter4_Format(Cancel As Integer, FormatCount As Integer) Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset ' Nach Abschluß des ersten Durchlaufs ein Flag setzen gboolLastPage = True ' Datensatzgruppe für den Bericht öffnen rst.Open "tblCustomers", CurrentProject.Connection, adOpenStatic ' Zum letzten Datensatz in der Datensatzgruppe wechseln rst.MoveLast ' Letzten Datensatz in das Feld einfügen>> ReDim Preserve gstrLast(Reports!rptCustomerPhoneList.Page + 1) gstrLast(Reports!rptCustomerPhoneList.Page) = rst!CompanyName End Sub
Die Routine für den Berichtsfuß weist der Variablen gboolLastPage den Wert True zu und öffnet mit Hilfe der Kundentabelle eine Datensatzgruppe. Dies ist die Datensatzgruppe, auf der der Bericht basiert. Dann wechselt die Routine zum letzen Datensatz der Datensatzgruppe und fügt den Wert des Feldes CompanyName des letzten Datensatzes der Datensatzgruppe in ein zusätzliches Element des Datenfelds ein. Der erste Durchlauf des Berichts ist damit abgeschlossen. Wenn sich der Benutzer bei einer Druckvorschau zu jeder Seite des Berichts bewegt oder wenn die Ausgabe der einzelnen Seiten erfolgt, wird das Format-Ereignis für den Seitenkopf ausgeführt. Der Firmenname des ersten Datensatzes der Seite wird im Steuerelement txtFirst Entry platziert und das entsprechende Element aus dem Feld gstrLast im Steuerelement txtLastEntry untergebracht.
426
Kapitel 10: Fortgeschrittene Verwendung von Berichten
10.6.7
Einen mehrzeiligen Kreuztabellenbericht erstellen
Kreuztabellenabfragen sind naturgemäß in ihren Ergebnissen eingeschränkt, da sie im Ergebnis nicht mehrere Datenzeilen unterbringen können. So haben Sie beispielsweise nicht die Möglichkeit, die Monate als Spaltenüberschrift zu wählen und anschließend den niedrigsten, den durchschnittlichen und den höchsten Umsatz jedes einzelnen Mitarbeiters als Beschriftung für die Zeilen festzulegen. Der in Abbildung 10.8 gezeigte Bericht rptSalesAverages aus der Datenbank CHAP10EX.MDB löst dieses Problem.
Abbildung 10.8: Ein Beispiel für einen mehrzeiligen Kreuztabellenbericht
Jedes Mal, wenn die Routine für das Ereignis Format des Seitenkopfes ausgeführt wird, wird der Wert des Steuerelements txtPrintWhat auf den Wert 0 gesetzt: Private Sub PageHeader1_Format(Cancel As Integer, FormatCount As Integer) ' Das Textfeld PrintWhat am Anfang der Seite auf 0 setzen. Me.txtPrintWhat = 0 End Sub
Nach der Ausführung der Format-Ereignisroutine des Seitenkopfes wird die Routine zum Ereignis Format des Gruppenkopfs gestartet: Private Sub GroupHeader2_Format(Cancel As Integer, FormatCount As Integer) ' Druckinformationen in den Zeilenüberschriften in der richtigen Reihenfolge ' Die Textfelder SalespersonLastName und FirtsName drucken,
Praktische Anwendungen für Berichtsereignisse und -eigenschaften
427
' die Ettiketten Minimum, Average und Maximum verbergen, ' das Textfeld PrintWhat auf -1 setzen und nicht zum ' nächsten Datensatz übergehen With Me If .txtPrintWhat = 0 Then .txtSalespersonLastName.Visible = True .txtFirstName.Visible = True .lblMinimum.Visible = False .lblAverage.Visible = False .lblMaximum.Visible = False .txtPrintWhat = True .NextRecord = False ' Die Textfelder SalespersonLastName und FirtsName verbergen und ' die Ettiketten für Minimum, Average und Maximum drucken und ' das Textfeld PrintWhat auf 0 setzen Else .txtSalespersonLastName.Visible = False .txtFirstName.Visible = False .lblMinimum.Visible = True .lblAverage.Visible = True .lblMaximum.Visible = True .txtPrintWhat = 0 End If End With End Sub
Wenn das Ereignis Format für das Feld LastName des Gruppenkopfes (GroupHeader2) zum ersten Mal auftritt, ist der Wert des Steuerelements txtPrintWhat gleich False. Die Steuerelemente txtSalePersonalLastName und txtFirstName werden sichtbar gemacht und die Steuerelemente lblMinimum, lblAverage und lblMaximum verborgen. Der Wert des Steuerelements txtPrintWhat wird schließlich wieder auf False gesetzt. Sonst enthält der Bericht nur noch eine Routine für das Ereignis Format des Gruppenkopfs mit dem Auslieferungsdatum (GroupHeader3): Private Sub GroupHeader3_Format(Cancel As Integer, FormatCount As Integer) ' Daten in der richtigen Spalte drucken ' Nicht um nächsten Datensatz übergehen oder den nächsten Abschnitt drucken>> If Me.Left < Me.txtLeftMargin + (Month(Me.ShippedDate) + 1) _ * Me.txtColumnWidth Then Me.NextRecord = False Me.PrintSection = False End If End Sub
Dieser Code vergleicht die Eigenschaft Left des Berichts mit dem Ergebnis eines Ausdrucks. Die Eigenschaft Left gibt die Entfernung des aktuellen Abschnitts von
428
Kapitel 10: Fortgeschrittene Verwendung von Berichten
der linken Ecke der Seite an. Diese Zahl wird mit dem Wert verglichen, der sich ergibt, wenn zum Steuerelement txtLeftMargin der aktuelle Monat plus 1 addiert und anschließend mit dem Wert des Steuerelements txtColumnWidth multipliziert wird. Ergibt der Ausdruck den Wert True, wird den Eigenschaften NextRecord und PrintSection der Wert False zugewiesen. Dadurch wird der Drucker veranlasst, sich zur nächsten Druckposition zu begeben, den Datensatz aber beizubehalten und nichts zu drucken, so dass eine Leerzeile im Bericht entsteht. Sie werden sich fragen, wofür dieser komplizierte Ausdruck notwendig ist. Einfach ausgedrückt, handelt es sich um einen Algorithmus, der dafür sorgt, dass gedruckt wird und Access zum nächsten Datensatz nur dann wechselt, wenn die Daten für den Monat Januar zum Drucken bereit sind.
10.6.8
Für die Praxis
Der Bericht rptEmployeeBillingsByProject Fast jeder Bericht des Zeit- und Abrechnungssytems verwendet eine der in diesem Kapitel vorgestellten Lösungen. Tatsächlich sind die in diesem Kapitel behandelten Berichte rptClientListing, rptClientBillingsByProjetct, lblClientMailingLabels und lblClientMailingLabelsskip ein elementarer Bestandteil dieser Anwendung. Der Bericht rptEmployeeBillingsByProject wurde in diesen Kapitel nicht erläutert. Die in diesem Bericht enthaltene Routine für das Ereignis NoDate sieht wie folgt aus: Private Sub Report_NoDate(Cancel As Integer) MsgBox "There is no data for this report. Canceling report..." Cancel = True End Sub
Enthält die Eigenschaft RecordSource des Berichts keine Daten, wird ein Meldungsfeld angezeigt und der Bericht abgebrochen. Die Routine für das Ereignis Open des Berichts sieht wie folgt aus: Private Sub Report_Open(Cancel As Integer) DoCmd.OpenForm "frmReportDateRange", WindowMode:=acDialog, OpenArgs:="rptClientBillingsbyProject" If Not IsLoaded("frmReportDateRange") Then Cancel = True Else Select Case Forms!frmReportDateRange!optDetailLevel.Value Case 1 Me.Caption = Me.Caption & " – Summary Only" Me.lblTitle.Caption = Me.lblTitle.Caption & " – Summary Only" Me.Detail.Visible = False Case 2 Me.Caption = Me.Caption & " – Detail Only" Me.lblTitle.Caption = Me.lblTitle.Caption & " – Detail Only" Me.GroupHeader0.Visible = False
Praktische Anwendungen für Berichtsereignisse und -eigenschaften
429
Me.GroupFooter1.Visible = False Me.CompanyNameDet.Visible = True Case 3 Me.Caption = Me.Caption & " – Summary and Detail" Me.lblTitle.Caption = Me.lblTitle.Caption & " – Summary and Detail" Me.CompanyNameDet.Visible = False End Select End If End Sub
Dieser Code öffnet ein Formular mit dem Namen frmReportDateRange (siehe Abbildung 10.9), das erforderlich ist, weil damit die Kriterien für die dem Bericht zu Grunde liegende Abfrage festgelegt werden. Wird dieses Formular nicht erfolgreich geladen, wird der Bericht abgebrochen.
Abbildung 10.9: Ein Formular für die Kriterienauswahl
Das abschließende Close-Ereignis führt zur Ausführung folgenden Codes: Private Sup Report_Close() DoCmd.Close acForm, "frmReportDateChange" End Sub
Der Bericht räumt nach dem Schließen auf und beendet das Kriterienformular.
Fortgeschrittene Abfragetechniken
Kapitel
Hier lesen Sie:
Aktionsabfragen Spezielle Abfrage-Eigenschaften Abfragen optimieren Kreuztabellenabfragen Äußere Verknüpfungen Selbstverknüpfungen SQL Union-Abfragen Pass-Through-Abfragen Die Weitergabe von Nullwerten und Abfrage-Ergebnisse Unterabfragen Das Ergebnis einer Funktion als Abfragekriterium verwenden Die Werte für eine Parameterabfrage aus einem Formular einlesen In Kapitel 4 haben Sie die Grundlagen des Aufbaus von Abfragen kennengelernt. Access besitzt jedoch wesentlich weiter reichendere Möglichkeiten. Neben den verhältnismäßig einfachen Auswahlabfragen, die in Kapitel 4 behandelt wurden, können Sie auch Kreuztabellenabfragen, Union-Abfragen, Abfragen mit Selbstverknüpfungen sowie Abfragen mit vielen weiteren Auswahlkriterien durchführen. Auch Abfragen, die die Informationen verändern und nicht nur suchen, sind ohne Weiteres möglich. Dieses Kapitel behandelt diese Themen sowie weitere Möglichkeiten zum Aufbau von Abfragen.
432
11.1
Kapitel 11: Fortgeschrittene Abfragetechniken
Aktionsabfragen
Mit Aktionsabfragen können Sie problemlos Daten verändern, ohne dafür Code schreiben zu müssen. Häufig ist diese Methode sogar wesentlich effektiver als das Programmieren einer speziellen Routine. Es stehen vier Arten von Aktionsabfragen zur Verfügung: Aktualisierungs-, Lösch-, Anfüge- und Tabellenerstellungsabfragen. Mit einer Aktualisierungsabfrage verändern Sie die Daten einer Tabelle, mit einer Löschabfrage entfernen Sie Datensätze, mit einer Anfügeabfrage fügen Sie einer vorhandenen Tabelle Datensätze hinzu und mit der Tabellenerstellungsabfrage erstellen Sie eine vollständig neue Tabelle. Jeder Abfragetyp und dessen Verwendung wird in den folgenden Abschnitten erklärt.
11.1.1
Aktualisierungsabfragen
Mit einer Aktualisierungsabfrage werden alle oder einige Datensätze geändert, die bestimmte Kriterien erfüllen. Dabei kann der Inhalt eines oder mehrerer Felder in mehreren Tabellen in einem Durchgang geändert werden (beispielsweise ist es möglich, das Gehalt der Mitarbeiter eines bestimmten Bundeslandes um 10% zu erhöhen). Wie bereits erwähnt wurde, sind Aktualisierungsabfragen meist effektiver als eine Veränderung der Daten mit Hilfe von VBA-Code und stellen somit eine angemessene Methode zur Veränderung von Tabellendaten dar. Mit den folgenden Schritten führen Sie eine Aktualisierungsabfrage durch: 1. Klicken Sie in der Objektliste des Datenbankfensters auf ABFRAGEN. 2. Doppelklicken Sie auf ERSTELLT SICHT.
EINE NEUE
ABFRAGE
IN DER
ENTWURFSAN-
3. Im Dialogfeld TABELLE ANZEIGEN wählen Sie die Tabellen oder Abfragen für die Aktualisierungsabfrage und klicken anschließend auf HINZUFÜGEN. Zum Fortfahren klicken Sie auf die Schaltfläche SCHLIESSEN. 4. Um Access mitzuteilen, dass Sie eine Aktualisierungsabfrage zusammenstellen, öffnen Sie über die Symbolleiste das Dropdown-Menü ABFRAGETYP und wählen AKTUALISIERUNGSABFRAGE. Sie können dies auch über den Menübefehl ABFRAGE|AKTUALISIERUNGSABFRAGE tun. 5. Fügen Sie der Abfrage Felder hinzu, die Sie für die Kriterien benötigen oder die durch die Abfrage aktualisiert werden sollen. In Abbildung 11.1 wurde der Abfrage das Feld StateProvince hinzugefügt, weil dieses Feld für die Formulierung des Abfragekriteriums benötigt wird. Das Feld DefaultTrans wurde gewählt, weil dieses Feld aktualisiert werden soll. 6. Fügen Sie je nach Bedarf weitere Felder für die Abfragekriterien hinzu. In Abbildung 11.1 wurde StateProvince der Wert CA zugewiesen.
433
Aktionsabfragen
7. Geben Sie den entsprechenden Ausdruck für die Aktualisierung ein. Im Beispiel aus Abbildung 11.1 wird das Feld DefaultRate um 10% erhöht. Abbildung 11.1: Eine Aktualisierungsabfrage, mit welcher der Wert des Felds DefaultRate für alle Kunden in Kalifornien erhöht wird
8. Klicken Sie in der Symbolleiste auf AUSFÜHREN. Daraufhin erscheint das in Abbildung 11.2 gezeigte Meldungsfeld. (Im Abschnitt »Spezielle Anmerkungen zu Aktionsabfragen« dieses Kapitels wird noch erklärt, wie Sie dieses Meldungsfeld durch Programmierung unterdrücken können.) Klicken Sie auf JA, um fortzufahren. Alle Datensätze, die der angegebenen Bedingung entsprechen, werden nun aktualisiert. Abbildung 11.2: Das Meldungsfeld, mit dem Sie die Aktualisierungsabfrage bestätigen
Access-Aktualisierungsabfragen sollten in der Bezeichnung das Präfix qupd enthalten. Jede Aktionsabfrage sollte ein entsprechendes Präfix erhalten, das kenntlich macht, um welchen Abfragetyp es sich handelt. Tabelle 11.1 führt die passenden Präfixe für die Aktionsabfragen auf. Abfragetyp
Präfix
Beispiel
Aktualisierung
qupd
qupdDefaultRate
Löschen
qdel
qdelOldTimeCards
Anhängen
qapp
qappArchiveTimeCards
Tabelle erstellen
qmak
qmakTempSales
Tabelle 11.1: Präfixe für die Bezeichnung der Aktionsabfragen
434
Kapitel 11: Fortgeschrittene Abfragetechniken
Der Aktionsabfragetyp wird im Datenbankfenster jeweils mit einem eigenen Symbol angezeigt.
Alle Access-Abfragen werden als SQL-Anweisungen (SQL – Structured Query Language) gespeichert. (Die SQL-Variante von Access wird im Abschnitt »SQL« dieses Kapitels erörtert.) Der SQL-Code einer Abfrage kann über die Option SQL-ANSICHT des Menüs ANSICHT aus der Menüleiste angezeigt werden. Der SQL-Code der Aktualisierungsabfrage von Access sieht wie folgt aus: UPDATE tblClients SET tblClients._ DefaultRate = [DefaultRate]*1.1 WHERE (((tblClients.StateProvince)="CA"));
Die von der Aktualisierungsabfrage sowie von den Aktionsabfragen durchgeführten Aktionen sind nicht umkehrbar. Sie müssen äußerste Vorsicht walten lassen, wenn Sie eine Aktionsabfrage durchführen.
Es ist wichtig zu beachten, dass bei aktivierter Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD FÜR REFERENTIELLE INTEGRITÄT und bei einer Veränderung des Primärschlüssels durch eine Aktualisierungsabfrage der Fremdschlüssel aller entsprechenden Datensätze der damit verbundenen Tabellen aktualisiert wird. Wurde die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD nicht aktiviert und die referentielle Integrität erzwungen, erlaubt die Aktualisierungsabfrage nicht, dass die betroffenen Datensätze geändert werden.
11.1.2
Löschabfragen
Anstatt Tabellendaten nur zu verändern, entfernen Löschabfragen die Daten auf Dauer aus der Tabelle, wenn bestimmte Bedingungen erfüllt sind. Häufig werden sie zum Entfernen alter Datensätze benutzt, etwa um alle Datensätze des letzten Jahres zu löschen. Mit den folgenden Schritten führen Sie eine Löschabfrage durch: 1. Wählen Sie in der ENTWURFSANSICHT über das Listenfeld ABFRAGETYP der Symbolleiste die Option LÖSCHABFRAGE. Sie können dies auch über den Menübefehl ABFRAGE|LÖSCHABFRAGE tun. 2. Fügen Sie die Abfragekriterien hinzu. In der Abfrage des Beispiels aus Abbildung 11.3 werden alle Zeitkarten gelöscht, die älter als 365 Tage sind.
435
Aktionsabfragen
Abbildung 11.3: Mit einer Löschabfrage werden alle Zeitkarten gelöscht, die älter als 365 Tage sind
3. Klicken Sie in der Symbolleiste auf AUSFÜHREN. Es erscheint das in Abbildung 11.4 gezeigte Meldungsfeld. Dieses Meldungsfeld können Sie durch Programmierung unterdrücken (siehe »Spezielle Anmerkungen zu Aktionsabfragen« weiter hinten in diesem Kapitel).
Abbildung 11.4: Das Bestätigungsfeld für die Löschabfrage
4. Klicken Sie auf JA, um die Datensätze permanent aus der Tabelle zu löschen. Hinter der Löschabfrage verbirgt sich der folgende SQL-Code: DELETE tblTimeCards.DateEntered FROM tblTimeCards WHERE (((tblTimeCards.DateEntered)
Oft ist es sinnvoll, sich die Ergebnisse eine Aktionsabfrage anzeigen zu lassen, bevor man die von den Kriterien der Abfrage betroffenen Datensätze tatsächlich verändert. Wenn Sie vor dem Klicken der Schaltfläche AUSFÜHREN in der Symbolleiste auf die Schaltfläche ANSICHT klicken, werden Ihnen die von der Aktionsabfrage betroffenen Datensätze angezeigt. Falls erforderlich, können Sie der Abfrage zeitweise Schlüsselfelder hinzufügen, die Ihnen zusätzliche Informationen zu den betroffenen Datensätzen liefern.
Beachten Sie, dass bei aktivierter Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD REFERENTIELLE INTEGRITÄT alle betroffenen Datensätze aus der Tabelle gelöscht werden. Wurde die Option AKTUALISIERUNGSWEITERGABE AN DETAILFELD nicht aktiviert und die referentielle Integrität erzwungen, erlaubt die
436
Kapitel 11: Fortgeschrittene Abfragetechniken
Löschabfrage nicht, dass die betroffenen Datensätze gelöscht werden. Möchten Sie die Datensätze auf der 1-Seite einer Beziehung löschen, müssen Sie zuerst die damit verbundenen Datensätze auf der n-Seite löschen.
11.1.3
Anfügeabfragen
Mit der Anfügeabfrage können Sie Datensätze an eine vorhandene Tabelle anfügen. Dies geschieht häufig im Verlaufe einer Archivierung. Zuerst werden die zu archivierenden Datensätze mit einer Anfügeabfrage an die Archivdaten angehängt und anschließend mit einer Löschabfrage aus der Stammtabelle entfernt. Mit den folgenden Schritten führen Sie eine Anfügeabfrage durch: 1. Wählen Sie in der ENTWURFSANSICHT über das Listenfeld ABFRAGETYP der Symbolleiste die Option ANFÜGEABFRAGE. Dies kann auch über den Menübefehl ABFRAGE|LÖSCHABFRAGE geschehen.
Abbildung 11.5: Angeben, welche Daten an welche Tabelle angehängt werden sollen und welche Datenbank die Tabelle enthält
2. Wählen Sie die Tabelle aus, an welche die Daten angefügt werden sollen. 3. Ziehen Sie alle Felder, deren Daten in der zweiten Tabelle enthalten sein sollen, in die Abfrage. Stimmen die Feldbezeichnungen beider Tabellen überein, verknüpft Access den Feldnamen der Ausgangstabelle automatisch mit dem entsprechenden Feld der Zieltabelle (siehe Abbildung 11.6). Stimmen die Namen nicht überein, müssen Sie explizit angeben, welche Felder der Ausgangstabelle sich auf welche Felder der Zieltabelle beziehen. 4. Geben Sie die Abfragekriterien an. Beachten Sie, dass in Abbildung 11.6 alle Datensätze, bei denen im Feld DateEntered das Jahr 1995 angegeben ist, an die Zieltabelle angefügt werden. 5. Um die Abfrage auszuführen, klicken Sie in der Symbolleiste auf AUSFÜHREN. Es erscheint das in Abbildung 11.7 gezeigte Meldungsfeld. 6. Klicken Sie auf JA, um den Vorgang abzuschließen.
437
Aktionsabfragen
Abbildung 11.6: Eine Löschabfrage, mit der die Felder TimeCardID, EmployeeID und DateEntered aller im Jahr 1995 eingestellten Mitarbeiter an eine andere Tabelle angehängt werden
Abbildung 11.7: Das Dialogfeld für die Bestätigung der Anfügeabfrage
Der Anfügeabfrage liegt der folgende SQL-Code zu Grunde: INSERT INTO tblTimeCardsArchive ( TimeCardID, EmployeeID, DateEntered ) SELECT tblTimeCards.TimerCardID, tblTimeCards.EmployeeID, tblTimeCards.DateEntered FROM tblTimeCards WHERE (((tblTimeCards.DateEntered) Between #1/1/95# And #12/31/95#));
Bei Anfügeabfragen dürfen Sie den Primärschlüssel nicht verletzen. Hängen Sie Datensätze an, die Primärschlüsselwerte mehrdeutig machen, wird das in Abbildung 11.8 gezeigte Meldungsfeld angezeigt. Fahren Sie mit dem Anfügen fort, werden nur diejenigen Datensätze angehängt, die den Primärschlüssel der Zieltabelle nicht verletzen.
11.1.4
Tabellenerstellungsabfragen aufbauen
Eine Tabellenerstellungsabfrage fügt im Unterschied zur Anfügeabfrage einer vorhandenen Tabelle keine Datensätze hinzu, sondern erstellt eine neue Tabelle, bei der es sich häufig um eine temporäre Tabelle handelt, die für eine zwischenzeitliche Verarbeitung benötigt wird. Eine temporäre Tabelle dient oft dazu, Daten vorübergehend einzufrieren, während ein Bericht ausgeführt wird. Durch das Zusammenstellen temporärer Tabellen und das Ausführen des Berichts mit diesen Tabellen können Sie sicherstellen, dass die Benutzer die dem Bericht zu Grunde liegenden
438
Kapitel 11: Fortgeschrittene Abfragetechniken
Abbildung 11.8: Die bei einer Verletzung des Primärschlüssels oder einer Gültigkeitsregel durch die Anfügeabfrage und Umwandlung angezeigte Warnung
Daten während der Ausführung nicht verändern können. Häufig dienen Tabellenerstellungsabfragen auch dazu, einem Benutzer bestimmte Datensätze oder Felder zur Verfügung zu stellen. Mit den folgenden Schritten führen Sie eine Tabellenerstellungsabfrage durch: 1. Wählen Sie in der ENTWURFSANSICHT über das Listenfeld ABFRAGETYP der Symbolleiste die Option TABELLENERSTELLUNGSABFRAGE. Dies ist auch über das Menü ABFRAGE|TABELLENERSTELLUNGSABFRAGE möglich. Dies öffnet das in Abbildung 11.9 gezeigte Dialogfeld.
Abbildung 11.9: Geben Sie einen Namen für die neue Tabelle ein und wählen Sie die Datenbank, in der sie untergebracht werden soll
2. Geben Sie einen Namen für die neue Tabelle ein und klicken Sie auf OK. 3. Ziehen Sie alle Felder für die neue Tabelle in die Abfrage. Oft enthält die neue Tabelle das Ergebnis einer Anweisung (siehe Abbildung 11.10). 4. Fügen Sie die Abfragekriterien hinzu. 5. Klicken Sie in der Symbolleiste auf AUSFÜHREN, um die Abfrage auszuführen. Es erscheint das in Abbildung 11.7 gezeigte Meldungsfeld. 6. Klicken Sie auf JA, um den Vorgang abzuschließen.
439
Aktionsabfragen
Abbildung 11.10: Fügen Sie einer Tabellenerstellungsabfrage eine Anweisung hinzu
Abbildung 11.11: Das Dialogfeld für die Bestätigung der Tabellenerstellungsabfrage
Führen Sie die gleiche Tabellenerstellungsabfrage mehrmals aus, werden die gleichnamigen bereits erstellten Tabellen immer endgültig überschrieben, was mit der in Abbildung 11.12 gezeigten Warnung angekündigt wird. Abbildung 11.12: Die von der Tabellenerstellungsabfrage angezeigte Warnung, wenn bereits eine Tabelle gleichen Namens vorhanden ist
Der Tabellenerstellungsabfrage liegt der folgende SQL-Code zu Grunde: SELECT tblTimeCards.TimeCardID, tblTimeCards.EmployeeID, tblTimeCards.DateEntered [DateEntered]+365 AS ArchiveDate INTO tblOldTimeCards FROM tblTimeCards WHERE (((tblTimeCards.TimeCardID) Between 1 And 10));
11.1.5
Spezielle Anmerkungen zu Aktionsabfragen
Wenn Sie Aktionsabfragen über das Datenbankfenster oder programmgesteuert ausführen, können zusätzliche Warnungen wie die in Abbildung 11.13 angezeigt wer-
440
Kapitel 11: Fortgeschrittene Abfragetechniken
den. Diese Nachricht sowie alle anderen Abfragenachrichten können per Programm unterdrückt werden, wenn Sie die Methode SetWarnings des DoCmd-Objekts benutzen. Der Code sieht wie folgt aus: DoCmd.SetWarnings False
Der Wert von DoCmd.Warnings sollte unbedingt wieder auf True gesetzt werden, damit die Warnungen nach dem Durchführen der Abfrage wieder angezeigt werden. Geschieht dies nicht, können zu einem späteren Zeitpunkt Daten versehentlich gelöscht oder verändert werden, ohne dass zuvor eine Warnung angezeigt wird. Abbildung 11.13: Eine Warnung, die angezeigt werden kann, wenn Sie eine Aktionsabfrage programmgesteuert durchführen
Um Warnungen durch eine Veränderung der Access-Umgebung zu unterdrücken, wählen Sie EXTRAS|OPTIONEN, klicken auf die Registerkarte BEARBEITEN/SUCHEN und heben die Markierung des Kontrollkästchens BESTÄTIGEN|AKTIONSABFRAGEN auf. Der entscheidende Unterschied zwischen dem Unterdrücken der Warnungen mittels des DoCmd-Objekts oder über EXTRAS|OPTIONEN besteht darin, dass das DoCmdObjekt die Steuerung der Anwendung überlässt, während das Unterdrücken über das Menü EXTRAS|OPTIONEN die Warnungen für alle von einem bestimmten Benutzer ausgeführten Anwendungen unterdrückt.
11.1.6
Aktionsabfragen im Vergleich zur programmgesteuerten Datensatzverarbeitung
Wie bereits erwähnt wurde, können Aktionsabfragen wesentlich effektiver sein als VBA-Codes. Werfen Sie einen Blick auf das folgende Beispiel: Sub ModifyRate() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset With rst .CursorType = adOpenKeyset
Spezielle Abfrage-Eigenschaften
441
.LockType = adLockOptimistic .Open "tblEmployees", CurrentProject.Connection Do Until .EOF !BillingRate = !BillingRate + 1 .Update .MoveNext Loop End With End Sub
Diese Unterroutine durchläuft in einer Schleife die Tabelle tblEmployees. Sie erhöht die Rechnungsquote um den Wert 1. Vergleichen Sie die Unterroutine ModifyRate mit dem folgenden Code: Sub RunActionQuery() DoCmd.OpenQuery "qupdBillingRate" End Sub
Wie Sie sehen, ist die Unterroutine RunActionQuery wesentlich einfacher aufgebaut. Die in Abbildung 11.14 gezeigte Abfrage qupdBillingRate führt die gleichen Aufgaben durch wie die Unterroutine ModifyRate. In den meisten Fällen wird die Aktionsabfrage wesentlich effektiver ausgeführt.
Abbildung 11.14: Die Abfrage qupdBillingRate erhöht den Wert des Felds BillingRate um eins
11.2
Spezielle Abfrage-Eigenschaften
Die Abfragen von Access 2000 besitzen zahlreiche Eigenschaften, die ihr Verhalten enorm beeinflussen. Klicken Sie mit der rechten Maustaste in den leeren Bereich in der oberen Hälfte des Abfragefensters und öffnen Sie über die Option EIGENSCHAFTEN das Eigenschaftenfenster, um sich die Eigenschaften einer Abfrage anzeigen zu lassen (siehe Abbildung 11.15). Viele dieser Eigenschaften wurden bereits im Kapitel 4 erörtert, die Eigenschaften Keine Duplikate, Eindeutige Datensätze und Spitzenwerte werden in den folgenden Abschnitten behandelt.
442
Kapitel 11: Fortgeschrittene Abfragetechniken
Abbildung 11.15: Die allgemeinen Eigenschaften einer Abfrage
11.2.1
Keine Duplikate
Wird die Eigenschaft Keine Duplikate auf Nein gesetzt, enthält das Abfrage-Ergebnis keine Duplikate für Feldkombinationen. Abbildung 11.16 zeigt beispielsweise eine Abfrage mit den Feldern Country und City der Tabelle tblClients. Die Eigenschaft Keine Duplikate wurde in diesem Beispiel auf Nein gesetzt, was dem Standardwert entspricht. Beachten Sie, dass viele Kombinationen von Ländern und Städten mehrfach auftauchen. Hierzu kommt es, wenn mehr als ein Kunde in einer bestimmten Stadt eine Landes gefunden wird. Vergleichen Sie dieses Beispiel mit Abbildung 11.17, in der die Eigenschaft Keine Duplikate auf Ja gesetzt wurde. Jede Kombination eines Landes mit einer Stadt wird hier nur einmal angeführt.
11.2.2
Eindeutige Datensätze
In Access 2000 lautet der Standardwert für Keine Duplikate im Unterschied zu früheren Versionen Nein. Wird Ja gewählt, wird die Anweisung DISTINCTROW in die der Abfrage zu Grunde liegende SQL-Anweisung mit einbezogen. Die Eigenschaft Keine Duplikate wird nur bei Abfragen mit mehreren Tabellen angewendet und bei Abfragen mit nur einer Tabelle ignoriert. Die Anweisung DISTINCTROW lässt eine Aktualisierung der Ergebnisse einer Abfrage mit mehreren Tabellen zu, indem sichergestellt wird, dass jeder Datensatz der Abfrage-Ergebnisse nur einmal auftaucht.
11.2.3
Spitzenwerte
Über die Eigenschaft Spitzenwerte können Sie einen Prozentsatz oder eine bestimmte Anzahl von Datensätzen angeben, die der Benutzer mit dem Ergebnis angezeigt bekommt. Sie können beispielsweise eine Abfrage formulieren, welche die
Spezielle Abfrage-Eigenschaften
443
Abbildung 11.16: Eine Abfrage, für die die Eigenschaft Keine Duplikate auf Nein gesetzt wurde
Abbildung 11.17: Eine Abfrage, für die die Eigenschaft Keine Duplikate auf Ja gesetzt wurde
444
Kapitel 11: Fortgeschrittene Abfragetechniken
Kombinationen der Bundesländer und Städte mit den besten zehn Umsätzen angibt. Ferner können Sie auch eine Abfrage ausführen, welche die Kombination der Bundesländer und Städte von 50% der besten Umsätze ausgibt. Der Spitzenwert kann auf unterschiedliche Weise angegeben werden. Es folgen zwei Beispiele:
Klicken Sie auf das Kombinationsfeld Spitzenwerte und wählen Sie eine Einstellung aus der vorgegebenen Liste aus. (Bei bestimmten Feldtypen steht dieses Kombinationsfeld nicht zur Verfügung.)
Geben Sie im Dialogfeld ABFRAGEEIGENSCHAFTEN direkt eine Zahl oder eine Zahl mit einem Prozentzeichen für den Spitzenwert ein oder wählen Sie im aufklappbaren Listenfeld einen entsprechenden Eintrag aus. Abbildung 11.18 veranschaulicht den Entwurf einer Abfrage, welche die Firmen mit 25% des Umsatzes anzeigt. Diese Gesamtsummenabfrage bildet die Summe von BillableHours multipliziert mit dem Wert von BillingRate jeder einzelnen Firma. Beachten Sie, dass die Eigenschaft Spitzenwerte auf 25% gesetzt wurde. Die Ausgabe der Abfrage ist in absteigender Reihenfolge nach den Ergebnissen der TotalAmountBerechnung sortiert (siehe Abbildung 11.19). Würde das Feld SaleAmount in absteigender Reihenfolge sortiert, würden die unteren 25% der Umsätze als AbfrageErgebnis angezeigt. Vergessen Sie nicht, dass das Feld für die Festlegung der Spitzenwerte ganz links in der Sortierreihenfolge der Abfrage stehen muss. Es wird Sie überraschen, dass die Eigenschaft Spitzenwerte scheinbar nicht immer die korrekte Anzahl der Datensätze im Abfrage-Ergebnis anzeigt. Alle Datensätze, die mit dem Wert im letzten Datensatz übereinstimmen, werden als Teil des Abfrage-Ergebnisses zurückgegeben. Bei einer Tabelle mit 100 Datensätzen sucht die Abfrage beispielsweise nach den zehn Spitzenwerten. Im Ergebnis der Abfrage erscheinen zwölf Datensätze, wenn der zehnte, elfte und zwölfte Datensatz alle den gleichen Wert im Feld für die Bestimmung des Spitzenwerts aufweisen.
11.3
Abfragen optimieren
Zur Microsoft Jet-Engine gehört ein Optimierungsprogramm, welches überprüft, wie viel Zeit zur Durchführung jeder für eine Abfrage erforderlichen Aufgabe benötigt wird. Anschließend wird ein Plan erstellt, wie die gewünschten Ergebnisse auf schnellstem Wege zu erreichen sind. Dieser Plan basiert auf unterschiedlichen statistischen Werten:
Wie groß ist der Umfang der bei der Abfrage zu berücksichtigenden Tabellen? Wie viele Datenseiten enthält jede Tabelle? Welchen Standort haben die Tabellen der Abfrage? Welche Indizes stehen für die einzelnen Tabellen zur Verfügung?
Abfragen optimieren
445
Abbildung 11.18: Eine Gesamtsummenabfrage, welche die oberen 25% der Umsätze angibt
Abbildung 11.19: Das Ergebnis einer Gesamtsummenabfrage mit den oberen 25% des Umsatzes
Welche Indizes sind eindeutig? Weitere Statistiken
11.3.1
Abfragekompilierung
Die gerade angeführten Werte werden beim Kompilieren der Abfrage jedesmal aktualisiert. Damit eine Abfrage kompiliert werden kann, muss ein bestimmtes Attribut (Flag) gesetzt sein. Dieses Attribut kann aus einem der folgenden Anlässe gesetzt werden:
446
Kapitel 11: Fortgeschrittene Abfragetechniken
Änderungen der Abfrage werden gespeichert. Änderungen einer der Abfrage zu Grunde liegenden Tabelle werden abgespeichert.
Die Datenbank wird komprimiert. Wurde für eine Abfrage das Attribut zum Kompilieren gesetzt, dann wird sie nicht vor der Ausführung der nächsten Abfrage kompiliert. Während des Kompilierens, was etwa eine bis vier Sekunden in Anspruch nimmt, werden alle Statistiken aktualisiert und eine neue Optimierung bzw. ein neuer Abfrageplan erstellt. Da ein Abfrageplan auf einer Anzahl von Datensätzen jeder Tabelle der Abfrage beruht, sollten Sie Ihre Abfragen jedesmal öffnen und speichern, wenn sich der Datenumfang der Tabelle deutlich verändert hat. Dies gilt insbesondere dann, wenn Sie Ihre Abfrage aus der Testumgebung in die reale Umgebung übernehmen. Testen Sie die Anwendung mit nur wenigen Datensätzen in den Tabellen, während die Tabellen im realen Einsatz mehrere Tausend Datensätze umfassen, dann wird die Abfrage für nur wenige Datensätze optimiert und sieht später in der Praxis nicht effizient aus. Sie können das Problem dadurch lösen, dass Sie die tatsächliche Datenbank regelmäßig komprimieren.
11.3.2
Die Geschwindigkeit einer Abfrage analysieren
Beim Analysieren der für eine bestimmte Abfrage benötigten Zeit müssen Sie die Zeit für zwei Aufgaben besonders berücksichtigen:
Wieviel Zeit wird benötigt, um den ersten Bildschirm mit Daten anzuzeigen? Wie lange dauert es, bis Sie den letzten Datensatz des Abfrage-Ergebnisses erhalten? Die erste Messung ist sehr einfach. Es wird die Zeit gemessen, die zwischen dem Klicken der Schaltfläche AUSFÜHREN in der Symbolleiste und der Anzeige des ersten Bildschirms verstreicht. Die zweite Messung ist nicht ganz so einfach, weil Sie warten müssen, bis der Wert N in der Anzeige Datensatz 1 von N am Ende der Abfrage-Ergebnisse angezeigt wird. Beide Messungen können gleich ausfallen, wenn die Abfrage nur wenige Datensätze zurückgibt. Die Jet-Engine entscheidet, ob es effektiver ist, zuerst die Abfrage auszuführen und anschließend die Datensätze anzuzeigen oder ob die Ergebnisse der Abfrage portionsweise angezeigt werden, während die Abfrage im Hintergrund ausgeführt wird.
Abfragen optimieren
447
Mit dem Assistenten zur Leistungsanalyse können Sie feststellen, ob zusätzliche Indizes die Geschwindigkeit der Abfrage erhöhen. Es ist wichtig, dass der Assistent zur Leistungsanalyse mit den gleichen Datenmengen ausgeführt wird, die später tatsächlich vorhanden ist. Die Leistungsanalyse wird in Kapitel 15 behandelt.
11.3.3
Die Abfragegeschwindigkeit verbessern
Die Geschwindigkeit einer Abfrage kann auf verschiedene Weise gesteigert werden. Die folgende Liste mit Möglichkeiten ist nicht vollständig:
Indizieren Sie Felder auf beiden Seiten einer Verknüpfung. Wenn Sie eine permanente Beziehung zwischen zwei Tabellen einrichten, wird der Fremdschlüsselindex automatisch erstellt.
Fügen Sie der Entwurfsansicht nur die Felder hinzu, die Sie tatsächlich für die Abfrage benötigen. Wird ein Feld für die Abfragekriterien benötigt, erscheint es aber in dem Ergebnis nicht, dann heben Sie die Markierung des Kontrollkästchens in der Entwurfsansicht der Abfrage auf.
Fügen Sie für jedes Feld, welches Sie für die Sortierreihenfolge des AbfrageErgebnisses benötigen, Indizes hinzu.
Indizieren Sie alle Felder, die als Abfragekriterien dienen. Komprimieren Sie die Datenbank regelmäßig. Beim Komprimieren versucht Access, die Datensätze einer Tabelle neu zu ordnen, so dass sie sich auf zusammenhängenden Datenbankseiten befinden, die nach dem Primärschlüssel der Tabelle sortiert sind. Außerdem werden die Abfragepläne anhand der aktuellen Datenmenge neu erstellt. Diese Nebeneffekte des Komprimierens verbessern die Abfragegeschwindigkeit, wenn eine Tabelle während einer Abfrage durchsucht wird.
Führen Sie eine Abfrage mit mehreren Tabellen durch und testen Sie dabei, ob die Abfrage schneller ausgeführt wird, wenn das Kriterium auf der einen bzw. der anderen Seite der Mehrfachbeziehung steht.
Vermeiden Sie das Hinzufügen von Kriterien zu berechneten oder nicht indizierten Feldern.
Wählen Sie den kleinstmöglichen Feldtyp für jedes Feld. Erstellen Sie beispielsweise eher ein KundenID-Feld vom Typ Long Integer, anstatt das Feld FirmenName als Primärschlüssel für die Tabelle zu verwenden.
Vermeiden Sie berechnete Felder in verschachtelten Abfragen. Es ist immer besser, die Berechnungen den Abfragen der höheren Ebenen hinzuzufügen.
Platzieren Sie gegebenenfalls einige Ausdrücke im Steuerelement des Ausgangsformulars oder im Berichtssteuerelement, anstatt alle Ausdrücke in der Abfrage
448
Kapitel 11: Fortgeschrittene Abfragetechniken
unterzubringen. Wenn Sie dies tun, muss der Ausdruck wiederholt und für jedes Formular oder jeden Bericht gepflegt werden.
Benutzen Sie Tabellenerstellungsabfragen, um mit den Abfrage-Ergebnissen Tabellen zu erstellen, die auf Tabellen basieren, die sich selten ändern. Richten Sie beispielsweise eine separate Tabelle mit den Bundesländern ein, anstatt eine Liste der Bundesländer über eindeutige Datensätze aller Bundesländer der Kundentabelle anzeigen zu lassen und für die Abfrage zu benutzen.
Wenn Sie im Abfragekriterium das Schlüsselwort Wie (bzw. Like) verwenden, versuchen Sie, am Ende und nicht zu Beginn der Zeichenfolge ein Sternchen zu setzen. Wird das Sternchen ans Ende der Zeichenfolge gesetzt (z.B. Like Th*) kann die Abfragegeschwindigkeit mit einem Index verbessert werden. Steht das Sternchen zu Beginn (z.B. *Sr), ist der Einsatz eines Index nicht möglich.
Verwenden Sie Anzahl(*) bzw. Count(*) anstelle von Count([Feldname]), wenn gezählt werden soll, wie viele Datensätze einem bestimmten Kriterium entsprechen. Count(*) zählt lediglich die Gesamtzahl der Datensätze, während Count([Feldname]) tatsächlich überprüft, ob ein Wert gleich Null ist, und ihn dann bei der Gesamtberechnung unberücksichtigt lässt. Außerdem wird die Count(*)-Funktion durch das im nächsten Abschnitt vorgestellte Rushmore-Verfahren deutlich optimiert.
Verwenden Sie die SQL-Klausel Group By so selten wie möglich und versuchen Sie stattdessen die Funktion First zu benutzen. Wenn Sie zum Beispiel Umsatzinformationen nach dem Bestelldatum und der Bestellnummer aufsummieren, können Sie für das Bestelldatum die Funktion First verwenden und nur nach der Bestellnummer gruppieren, weil alle Datensätze mit einer gegebenen Bestellnummer automatisch dasselbe Bestelldatum aufweisen.
Benutzen Sie das Rushmore-Verfahren, um die Abfragen zu beschleunigen. Diese Datenzugriffstechnik, die von der Datenbank-Engine von Microsoft FoxPro PC »ausgeliehen« wurde, verbessert die Geschwindigkeit bestimmter Abfragen. Das Rushmore-Verfahren wird im folgenden Abschnitt erörtert. Das Allerwichtigste, was Sie bei diesen Hinweisen berücksichtigen müssen, ist die Tatsache, dass Sie die aufgeführten Tipps nicht blindlings anwenden dürfen. Die Optimierung von Abfragen ist eher eine Kunst als eine Wissenschaft. Was in einigen Situationen hilfreich ist, kann in anderen schädlich sein, weshalb es wichtig ist, Tests mit Ihren aktuellen Daten und Rechnern durchzuführen.
11.3.4
Das Rushmore-Verfahren
Wie bereits erwähnt wurde, handelt es sich beim Rushmore-Verfahren um eine Datenzugriffstechnik, mit der die Durchführung von Abfragen optimiert werden kann. Dieses Verfahren kann nur angewendet werden, wenn bestimmte Ausdrücke für die Abfragekriterien benutzt wurden. Es werden nicht automatisch alle Abfragen
Abfragen optimieren
449
beschleunigt, vielmehr muss eine Abfrage in bestimmter Weise aufgebaut sein, damit die Abfrage vom Rushmore-Verfahren profitieren kann. Eine Abfrage mit einem Ausdruck und einem Vergleichsoperator als Kriterium für ein indiziertes Feld kann mit dem Rushmore-Verfahren optimiert werden. Bei den Vergleichsoperatoren muss es sich um <, >, =, <=, >=, <>, Zwischen (Between), Wie (Like) oder In handeln. Es kann jeder gültige Ausdruck gewählt werden, einschließlich der Konstanten, Funktionen und Felder anderer Tabellen. Folgende Ausdrücke können beispielsweise komprimiert werden: [Age > 50] [OrderDate] Between #1/1/98# And #12/31/98# [State = "CA"]
Mit dem Rushmore-Verfahren können auch Abfragen mit durch die Operatoren Und oder Oder verknüpften Ausdrücken optimiert werden. Lassen sich beide Ausdrücke vollständig optimieren, wird die gesamte Abfrage optimiert. Ist allerdings nur ein Ausdruck vollständig optimierbar und sind beide mit Und verknüpft, wird die Abfrage nur partiell optimiert. Bei einer Verknüpfung mit Or findet keine Optimierung statt.
11.3.5
Wichtige Anmerkungen zum Rushmore-Verfahren
Die folgenden Punkte sollten Sie beim Rushmore-Verfahren berücksichtigen:
Abfragen mit dem Operator Nicht bzw. Not können nicht optimiert werden. Die Funktion Anzahl(*) bzw. Count(*) wird durch das Verfahren sehr stark optimiert.
Absteigende Indizes werden nur im Ausdruck = optimiert. Das Rushmore-Verfahren kann nicht für Abfragen von ODBC-Datenquellen verwendet werden.
Mehrfachindizes können im Zusammenhang mit dem Rushmore-Verfahren nur benutzt werden, wenn das Kriterium in der Reihenfolge des Index steht. Gibt es zum Beispiel einen Index für das Feld LastName in Verbindung mit dem Feld FirstName, kann der Index für die Suche nach LastName oder eine Kombination aus LastName und FirstName verwendet werden, nicht jedoch in einem Ausdruck, der auf dem Feld FirstName basiert.
450
11.4
Kapitel 11: Fortgeschrittene Abfragetechniken
Kreuztabellenabfragen
Eine Kreuztabellenabfrage fasst Abfrage-Ergebnisse durch Anzeigen eines Felds einer Tabelle auf der linken Seite des Datenblatts und durch zusätzliche Angaben im oberen Bereich des Datenblatts zusammen. Sie kann zum Beispiel den Betrag der Verkäufe eines Vertreters für jede Firma zusammenfassen. Der Name jeder Firma kann in der linken Spalte der Ausgabe stehen, während in der oberen Zeile die einzelnen Vertreter angeführt werden. Die Beträge erscheinen in der entsprechenden Zelle des Abfrage-Ergebnisses (siehe Abbildung 11.20). Kreuztabellenabfragen sind wahrscheinlich die umfangreichsten und am schwierigsten zu erstellenden Abfragen. Aus diesem Grund stellt Microsoft den KreuztabellenAssistenten zur Verfügung. In den folgenden Abschnitten wird das Erstellen von Kreuztabellenabfragen mit und ohne den Kreuztabellen-Assistenten beschrieben.
Abbildung 11.20: Ein Beispiel für eine Kreuztabellenabfrage, welche die Verkaufsbeträge der Vertreter für jede Firma angibt
11.4.1
Mit Hilfe des Kreuztabellen-Assistenten eine Kreuztabellenabfrage erstellen
Führen Sie die folgenden Schritte durch, um mit Hilfe des Kreuztabellen-Assistenten eine Kreuztabellenabfrage zu erstellen: 1. Wählen Sie in der Objektliste des Datenbankfensters ABFRAGEN und klicken Sie auf NEU. 2. Wählen Sie die Option KREUZTABELLENABFRAGE-ASSISTENT und klicken Sie auf OK .
Kreuztabellenabfragen
451
3. Wählen Sie die Tabelle oder Abfrage aus, welche die Grundlage der Abfrage bilden soll. Soll die Abfrage Felder von mehreren Tabellen berücksichtigen, dann müssen Sie die Kreuztabellenabfrage auf einer anderen Abfrage aufbauen, die sich auf die Tabellen und Felder bezieht, die Sie benötigen. Klicken Sie auf WEITER. 4. Wählen Sie die Felder aus, deren Werte Sie als Zeilenüberschrift für die Ausgabe der Abfrage verwenden wollen. In Abbildung 11.21 wurden die Felder Artikelname und Kunden-Code als Zeilenüberschrift gewählt. Klicken Sie auf WEITER.
Abbildung 11.21: Die Angabe der Zeilen für eine Kreuztabellenabfrage
5. Wählen Sie das Feld aus, dessen Wert als Spaltenüberschrift für die Ausgabe der Abfrage dienen soll. In Abbildung 11.22 wurde das Feld Bestelldatum als Spaltenüberschrift gewählt. Klicken Sie auf WEITER. 6. Handelt es sich bei dem als Überschrift gewählten Feld um ein Datumsfeld, fordert der Kreuztabellen-Assistent Sie auf, ein Intervall für die Gruppierung anzugeben. In Abbildung 11.23 wird das Feld Bestelldatum nach Quartalen gruppiert. Wählen Sie das gewünschte Intervall und klicken Sie auf WEITER. 7. Im nächsten Schritt fragt der Kreuztabellen-Assistent, welches Feld die Zahl enthält, die Sie für die Berechnung des Wertes jedes Spalten- und Zeilenunterabschnitts verwenden möchten. In Abbildung 11.24 wird das Feld Anzahl für jedes Produkt und jeden Kunden pro Quartal summiert. Klicken Sie auf WEITER. 8. Im letzten Schritt geben Sie den Namen für Ihre Abfrage ein. Zum Abschluss klicken Sie auf FERTIG STELLEN.
452
Kapitel 11: Fortgeschrittene Abfragetechniken
Abbildung 11.22: Angabe der Spalten für eine Kreuztabellenabfrage
Abbildung 11.23: Die Angabe eines Intervalls für die Kreuztabellenabfrage
Kreuztabellenabfragen
453
Abbildung 11.24: Die Angabe des Felds, welches die Kreuztabellenabfrage für die Berechnung benutzen soll
Abbildung 11.25 zeigt eine vollständige Kreuztabellenabfrage in der Entwurfsansicht. Beachten Sie die einzelnen wichtigen Attribute und die Kreuztabellenzeile in der Entwurfsansicht. Die Felder Artikelname und Kunden-Code wurden als Zeilenüberschriften angegeben und dienen als Gruppierungsspalte der Abfrage. Die Spaltenüberschrift enthält folgenden Ausdruck: "Qtr" & Format([OrderDate], "q")
Abbildung 11.25: Eine vollständige Kreuztabellenabfrage in der Entwurfsansicht
Dieser Ausdruck gibt das formatierte Bestelldatum für die Anzeige des Quartals zurück. Er wird auch für die Gruppierung verwendet. Das Feld Anzahl wird als ein
454
Kapitel 11: Fortgeschrittene Abfragetechniken
Wert angegeben. Die Zelle Gesamtsumme der Spalte zeigt an, dass dieses Feld eine Summe bildet (im Gegensatz zu Zählungen oder Durchschnittswerten). Beachten Sie die Spalte mit der Überschrift Gesamtsumme von Anzahl. Diese Spalte zeigt die Summen aller Spalten der Abfrage an. Sie entspricht der Spalte, welche die Werte enthält, mit Ausnahme des Alias im Namensfeld und der Tatsache, dass die Kreuztabellenzelle auf Zeilenüberschrift gesetzt wurde und nicht auf Wert (siehe Abbildung 11.26).
Abbildung 11.26: Eine Aufsummierungsspalte in einer Kreuztabellenabfrage in der Entwurfsansicht
11.4.2
Ohne den Kreuztabellen-Assistenten eine Kreuztabellenabfrage erstellen
Sie können mit dem Kreuztabellen-Assistenten zwar sehr viele Kreuztabellenabfragen erstellen, Sie sollten aber auch in der Lage sein, eine solche Abfrage ohne den Assistenten zu erstellen. Mit diesem Wissen können Sie vorhandene Kreuztabellenabfragen ändern und erhalten die bestmöglichen Steuerungsmöglichkeiten beim Erstellen neuer Abfragen. Führen Sie die folgenden Schritte durch, um eine Kreuztabellenabfrage ohne den Kreuztabellen-Assistenten zu erstellen: 1. Wählen Sie in der Objektliste des Datenbankfensters ABFRAGEN und klicken Sie auf NEU. 2. Klicken Sie doppelt auf ERSTELLT SICHT.
EINE NEUE
ABFRAGE
IN DER
ENTWURFSAN-
3. Wählen Sie die Tabelle oder Abfrage aus, die in die Entwurfsansicht der Abfrage übernommen werden soll. Klicken Sie auf die Schaltfläche HINZUFÜGEN, um die Tabelle oder Abfrage hinzuzufügen. Klicken Sie auf SCHLIESSEN. 4. Wählen Sie im Menü ABFRAGE die Option KREUZTABELLENABFRAGE.
Kreuztabellenabfragen
455
5. Fügen Sie der Entwurfsansicht die für die Ausgabe der Abfrage gewünschten Felder hinzu. 6. Klicken Sie auf die Kreuztabellenzeile jedes Felds, welches Sie als Zeilenüberschrift benutzen möchten. Wählen Sie im aufklappbaren Listenfeld ZEILENÜBERSCHRIFT aus. 7. Klicken Sie auf die Kreuztabellenzeile jedes Felds, welches Sie als Spaltenüberschrift benutzen möchten. Wählen Sie im aufklappbaren Listenfeld SPALTENÜBERSCHRIFT aus. 8. Klicken Sie auf die Kreuztabellenzeile jedes Felds, dessen Wert in die Kreuztabelle aufgenommen werden soll. Wählen Sie im aufklappbaren Listenfeld KREUZTABELLE den Eintrag WERT aus. 9. Wählen Sie im aufklappbaren Listenfeld FUNKTION eine geeignete zusammenfassende Funktion aus. 10. Geben Sie die gewünschten Zeitintervalle oder die zu verwendenden Ausdrücke ein. 11. Geben Sie die Kriterien für die Abfrage ein. 12. Legen Sie die Sortierreihenfolge jeder Spalte je nach Bedarf fest. 13. Führen Sie zum Schluss die Abfrage aus. Abbildung 11.27 zeigt eine Abfrage, in der für die Spaltenüberschrift der Monat aus dem Feld ProjectBeginDate gewählt wurde. Die Zeilenüberschrift stammt aus dem Feld EmployeeName. Die Summe des Felds ProjectTotalsEstimate bildet den Wert der Abfrage. Auch das Projetktanfangsdatum wurde als WHERE-Klausel (bzw. als Bedingung) in die Entwurfsansicht der Abfrage aufgenommen. Abbildung 11.28 zeigt die Ergebnisse der Abfrage.
Abbildung 11.27: Eine ohne den KreuztabellenAssistenten erstellte Kreuztabellenabfrage, welche die geschätzten Auftragssummen pro Mitarbeiter und Monat anzeigt
456
Kapitel 11: Fortgeschrittene Abfragetechniken
Abbildung 11.28: Das Ergebnis der in Abbildung 11.27 gezeigten Kreuztabellenabfrage
11.4.3
Feste Spaltenüberschriften erstellen
Wenn Sie keine festen Spaltenüberschriften benutzen, enthält die Ausgabe des Abfrage-Ergebnisses alle Spalten in alphabetischer Reihenfolge. Enthält Ihr AbfrageErgebnis beispielsweise die Monatsnamen, erscheinen diese in der Reihenfolge Apr, Aug, Dez usw. Durch Verwendung fester Spaltenüberschriften teilen Sie Access die Reihenfolge der Spaltenüberschriften für das Abfrage-Ergebnis mit. Spaltenüberschriften können über die Eigenschaft Fixierte Spaltenüberschriften festgelegt werden (siehe Abbildung 11.29).
Abbildung 11.29: Die Eigenschaft Fixierte Spaltenüberschriften
Alle festen Spaltenüberschriften müssen mit den zu Grunde liegenden Daten genau übereinstimmen, weil sonst Informationen unbeabsichtigt im Abfrage-Ergebnis ausgelassen werden. Wurde beispielsweise für die Spaltenüberschrift der Monat Juni eingegeben und mit der Formatanweisung für die Datenausgabe der Monat Jun festgelegt, werden alle Daten für den Monat Juni in den Abfrage-Ergebnissen ausgelassen.
Äußere Verknüpfungen
11.4.4
457
Wichtige Anmerkungen zu Kreuztabellenabfragen
Unabhängig davon, wie Kreuztabellenabfragen erstellt werden, sollten Sie einige spezielle Eigenarten beim Umgang mit diesen Abfragen berücksichtigen: 1. Sie können nur einen Wert und eine Spaltenüberschrift. jedoch mehrere Zeilenüberschriften für eine Kreuztabellenabfrage wählen. 2. Die Ergebnisse einer Kreuztabellenabfrage können nicht aktualisiert werden. 3. Sie können keine Kriterien für das Feld Wert angeben. Tun Sie dies trotzdem, erhalten Sie eine Fehlermeldung mit dem Hinweis, dass Sie für das gleiche Feld, mit dem Sie den Wert der Kreuztabellenabfrage eingeben, keine Kriterien angeben können. Ist es erforderlich, dass Sie ein Kriterium für das Feld mit dem Wert angeben, dann müssen Sie zuerst eine andere Abfrage erstellen, die Ihr Auswahlkriterium enthält, und die Kreuztabellenabfrage auf dieser Abfrage aufbauen. 4. Alle Parameter der Kreuztabellenabfrage müssen im Dialogfeld ABFRAGEPARAMETER explizit deklariert werden.
11.5
Äußere Verknüpfungen
Äußere Verknüpfungen werden verwendet, wenn Datensätze von der 1-Seite einer 1:n-Beziehung in den Abfrage-Ergebnissen enthalten sein sollen, unabhängig davon, ob es in den Tabellen der n-Seite übereinstimmende Datensätze gibt. Bei einer Kunden- und Bestellungentabelle wollen die Benutzer beispielsweise oft, dass das Abfrage-Ergebnis nur die Aufträge eines Kunden enthält. Eine innere Verknüpfung (die Standardverknüpfung) kann dies bewerkstelligen. In anderen Situationen wollen die Benutzer im Abfrage-Ergebnis alle Kunden unabhängig davon angezeigt bekommen, ob Bestellungen vorliegen oder nicht. Hierfür ist eine äußere Verknüpfung erforderlich. Es gibt zwei Arten äußerer Verknüpfungen: linke und rechte. Eine linke äußere Verknüpfung liegt vor, wenn alle Datensätze der 1-Seite einer 1:n-Beziehung im Abfrage-Ergebnis unabhängig davon enthalten sind, ob es auf der n-Seite weitere Datensätze gibt. Eine rechte äußere Verknüpfung bedeutet, dass alle Datensätze der n-Seite einer Beziehung im Abfrage-Ergebnis unabhängig davon erscheinen, ob auf der 1Seite der Beziehung Datensätze vorhanden sind. Eine rechte äußere Verknüpfung darf nicht entstehen, wenn referentielle Integrität notwendig ist. Um eine äußere Verknüpfung einzurichten, müssen Sie die Verknüpfung zwischen den Tabellen der Abfrage verändern: 1. Klicken Sie doppelt auf die Zeile, welche die Tabellen im Abfrageraster miteinander verbindet.
458
Kapitel 11: Fortgeschrittene Abfragetechniken
2. Sie gelangen in das Dialogfeld VERKNÜPFUNGSEIGENSCHAFTEN (siehe Abbildung 11.30). Wählen Sie die gewünschte Verknüpfung aus. Um eine linke äußere Verknüpfung zwischen den Tabellen einzurichten, wählen Sie die zweite Option (die dritte entspricht einer rechten äußeren Verknüpfung). Beachten Sie, dass in Abbildung 11.30 die Beschreibung wie folgt lautet: »Beinhaltet ALLE Datensätze aus 'tblClients' und nur die Datensätze aus 'tblProjects', bei denen die Inhalte der verknüpften Felder beider Tabellen gleich sind.«
Abbildung 11.30: Eine linke äußere Verknüpfung einrichten
3. Klicken Sie auf OK, um die Verknüpfung zu akzeptieren. Daraufhin wird zwischen beiden Tabellen eine äußere Verknüpfung eingerichtet. Beachten Sie, dass die Verbindungslinie zwischen den beiden Tabellen nun einen Pfeil aufweist, der auf die n-Seite der Verknüpfung verweist. Die SQL-Anweisung, welche eine linke äußere Verknüpfung erzeugt, sieht wie folgt aus: SELECT DISTINCTROW tblClients.ClientID, tblClients.CompanyName FROM tblClients LEFT JOIN tblProjects ON tblClients.ClientID = tblProjects.ClientID;
Eine linke äußere Verknüpfung kann auch zur Ermittlung aller Datensätze der 1Seite einer Verknüpfung verwendet werden, die über keinen entsprechenden Datensatz auf der n-Seite verfügen. Hierfür geben Sie als Kriterium für ein beliebiges Feld der n-Seite Is Null bzw. ISTNULL ein. In der Abfrage aus Abbildung 11.31 werden nur die Kunden ohne Bestellungen angezeigt.
Selbstverknüpfungen
459
Abbildung 11.31: Eine Abfrage, die Kunden ohne Bestellungen anzeigt
11.6
Selbstverknüpfungen
Mit einer Selbstverknüpfung können Sie eine Tabelle mit sich selbst verknüpfen. Dies wird oft getan, um den Anschein zu erwecken, die Informationen einer einzigen Tabelle seien in zwei unterschiedlichen Tabellen enthalten. Ein klassisches Beispiel stellen die Angestellten und die Vorgesetzten dar. Eine Angestelltentabelle enthält unter anderem zwei Felder: eines mit der Angestelltennummer des im Datensatz beschriebenen Angestellten und ein weiteres mit der Angestelltennummer des Vorgesetzten. Möchten Sie eine Liste mit den Namen der Angestellten und ihrer Vorgesetzten anzeigen lassen, dann benötigen Sie hierfür eine Selbstverknüpfung. Mit den folgenden Schritten richten Sie eine Selbstverknüpfung ein: 1. Klicken Sie im Datenbankfenster auf die Registerkarte ABFRAGEN und klicken Sie anschließend auf die Schaltfläche NEU. 2. Wählen Sie ENTWURFSANSICHT und klicken Sie auf OK. 3. Fügen Sie im Dialogfeld TABELLE ANZEIGEN die Tabelle für die Selbstverknüpfung in der Abfrage zweimal hinzu. Klicken Sie auf die Schaltfläche SCHLIESSEN. Beachten Sie, dass die zweite Instanz der Tabelle mit einem Unterstrich und der Zahl 1 erscheint. 4. Um den Alias der zweiten Tabelle zu ändern, klicken Sie in der Entwurfsansicht der Abfrage mit der rechten Maustaste an den oberen Rand der Tabelle und wählen EIGENSCHAFTEN. Ändern Sie die Eigenschaft ALIAS wie gewünscht. In Abbildung 11.32 wurde als Alias Supervisor angegeben. 5. Um die Verknüpfung zwischen der Tabelle und dem Alias einzurichten, ziehen Sie das Feld aus der einen Tabelle in das entsprechende Feld der Alias-Tabelle. In Abbildung 11.33 wurde das Feld SupervisorID der Tabelle tblEmployees mit dem Feld EmployeeID der Alias-Tabelle verknüpft.
460
Kapitel 11: Fortgeschrittene Abfragetechniken
Abbildung 11.32: Eine Selbstverknüpfung einrichten
6. Ziehen Sie die gewünschten Felder auf das Abfrageraster. In Abbildung 11.33 werden die Felder FirstName und LastName aus der Tabelle tblEmployees übernommen. Der Ausdruck SupervisorName (eine Zusammensetzung aus dem Vorund Nachnamen des Vorgesetzten) stammt aus der Kopie der Alias-Tabelle. Selbstverknüpfungen können im Dialogfeld für die Verknüpfungen als dauerhaft festgelegt werden, um etwa referentielle Integrität zu erreichen. In dem Beispiel mit den Angestellten und deren Vorgesetzten kann eine dauerhafte Beziehung mit referentieller Integrität eingerichtet werden, damit sichergestellt ist, dass die Angestelltennummern der Vorgesetzten nicht zusammen mit Angestelltennummern von Angestellten eingegeben werden können, die gar nicht existieren.
Abbildung 11.33: Einrichten einer Selbstverknüpfung zwischen einer Tabelle und einem Alias
11.7
SQL
Access SQL ist die den Access-Abfragen zu Grunde liegende Sprache. Deshalb sollten Sie etwas über deren Herkunft und Funktionsweise wissen. Mit Access SQL können Sie Abfragen aufbauen, ohne die Abfrage-Entwurfsansicht zu benutzen. Vielleicht müssen Sie zum Beispiel als Reaktion auf eine Benutzerschnittstelle mit
SQL
461
Ihrer Anwendung aus dem Stegreif eine SQL-Anweisung formulieren. Außerdem unterstützt Access SQL bestimmte Operationen, welche die grafische Benutzeroberfläche der Abfrageansicht nicht unterstützt. Diese SQL-Anweisungen müssen Sie über das Menü ANSICHT und die Option SQL-ANSICHT erstellen.
11.7.1
Was ist SQL und woher stammt es?
SQL ist eine Standardsprache, von der viele Dialekte abgeleitet wurden. Sie wurde in den frühen siebziger Jahren in einem Forschungslabor von IBM entwickelt und 1974 erstmals in einem Forschungsbericht formal beschrieben, der anläßlich eines Kongresses einer Gesellschaft für Rechenmaschinen veröffentlicht wurde. Die Jet-Engine 4.0, die zum Lieferumfang von Access 2000 gehört, unterstützt Access SQL und SQL-92.
11.7.2
Was müssen Sie über SQL wissen?
Sie müssen zumindest die Grundlagen von SQL kennen und wissen, wie Sie mit Hilfe von SQL-Anweisungen und -Syntax Daten auswählen, aktualisieren, löschen und anfügen können. SQL besteht eigentlich nur aus sehr wenigen Worten, deren gebräuchlichste in den folgenden Abschnitten vorgestellt werden. SQL-Syntax SQL ist sehr leicht zu erlernen. Wenn Sie Daten suchen, formulieren Sie eine SELECT-Anweisung. Die SELECT-Anweisung setzt sich aus Klauseln zusammen, welche die Auswahl der Daten festlegen. Während der Ausführung wählen die SELECTAnweisungen die Datenzeilen aus und geben sie als Datensatzgruppe zurück. Die SELECT-Klausel Die SELECT-Anweisung gibt an, welche Spalten einer Tabelle mit den Daten der Datensatzgruppe zurückgegeben werden sollen. Die einfachste SELECT-Anweisung sieht wie folgt aus: SELECT *
Diese Anweisung durchsucht alle Spalten einer Tabelle. Die nächste Anweisung durchsucht nur die Spalten ClientID und CompanyName: SELECT ClientID, CompanyName
Sie können nicht nur Tabellenspalten angeben, sondern auch Ausdrücke: SELECT ClientID, [City & ", " & [State] & " " & [PostalCode] AS Address
Diese SELECT-Anweisung durchsucht die Spalte ClientID sowie eine Pseudospalte mit Namen Address, die einen Ausdruck enthält, der sich aus den Spalten City, State und PostalCode zusammensetzt.
462
Kapitel 11: Fortgeschrittene Abfragetechniken
Die FROM-Klausel Die FROM-Klausel gibt die Tabellen und Abfragen an, aus denen die Datensätze ausgewählt werden sollen. Sie kann einen Alias enthalten, mit dem Sie sich auf eine Tabelle beziehen: FROM tblClients AS Clients
In diesem Beispiel lautet der Name der Tabelle tblClients und der Alias Clients. Kombinieren Sie die SELECT-Klausel mit einer FROM-Klausel, dann sieht die SQLAnweisung wie folgt aus: SELECT ClientID, CompanyName FROM tblClients
Diese Anweisung durchsucht die Spalten ClientID und CompanyName der Tabelle tblClients. Die WHERE-Klausel Die WHERE-Klausel schränkt die Auswahl der mit der SELECT-Anweisung gefundenen Datensätze ein. Eine WHERE-Klausel kann bis zu 40 Spalten umfassen, die mit den Schlüsselwörtern AND oder OR kombiniert werden. Eine einfache WHERE-Klausel sieht folgendermaßen aus: WHERE Country = "USA"
Mit AND können die Kriterien der WHERE-Klausel weiter eingeschränkt werden: WHERE Country = "USA" AND ContactTitle Like "Sales*"
Diese WHERE-Klausel gibt nur solche Datensätze zurück, die im Feld Country den Eintrag USA enthalten und deren Feld ContactTitle mit Sales beginnt. Anstelle von AND können Sie auch OR verwenden: WHERE Country = "USA" OR Country = "Canada"
Diese Klausel gibt alle Datensätze zurück, die im Feld Country den Eintrag USA oder Canada enthalten. Betrachten Sie zum Vergleich das folgende Beispiel: WHERE Country = "USA" OR ContactTitle Like "Sales*"
Diese Anweisung gibt alle Datensätze zurück, die im Feld Country den Eintrag USA enthalten, sowie diejenigen, deren Feld ContactTitle mit Sales beginnt. Handelsvertreter aus China werden von dieser Klausel ebenfalls zurückgegeben, weil auch deren Feld ContactTitle mit Sales beginnt. Die Kombination der WHERE-Klausel mit den Klauseln SELECT und FROM sieht wie folgt aus: SELECT ClientID, CompanyName FROM tblClients WHERE Country = "USA" OR Country = "Canada"
SQL
463
Die ORDER BY-Klausel Die ORDER BY-Klausel legt die Sortierreihenfolge der zurückgegebenen Zeilen fest. Es handelt sich um eine optionale Klausel, die wie folgt aussieht: ORDER BY ClientID
In dieser Klausel können auch mehrere Felder angegeben werden: ORDER BY Country, ClientID
Werden mehrere Felder angegeben, gibt das an linker Stelle stehende Feld die primäre Sortierung an. Jedes weitere Feld dient als untergeordnete Sortierung. Kombiniert mit dem Rest der SELECT-Anweisung ergibt sich folgender Ausdruck: SELECT ClientID, CompanyName FROM tblClients WHERE Country = "USA" OR Country = "Canada" ORDER BY ClientID
Die JOIN-Klausel Häufig müssen Sie SELECT-Anweisungen formulieren, die Daten in mehreren Tabellen suchen. In solchen Fällen ist es erforderlich, dass Sie die Tabellen mit der JOINKlausel verknüpfen. Diese Klausel unterscheidet sich in Abhängigkeit davon, ob Sie Tabellen mit einer inneren, linken äußeren oder rechten äußeren Verknüpfung miteinander verbinden. Es folgt ein Beispiel für eine innere Verknüpfung: SELECT DISTINCTROW tblClients.ClientID, tblClients.CompanyName, tblProjectsProjectName, tblProjects.ProjectDescription FROM tblClients INNER JOIN tblProjects ON tblClients.ClientID = tblProjects.ClientID
Beachten Sie, dass als Ergebnis der Abfrage vier Spalten zurückgegeben werden. Zwei Spalten stammen aus der Tabelle tblClients und zwei aus tblProjects. Die SELECT-Anweisung verwendet eine innere Verknüpfung von tblClients mit tblProjects über das Feld ClientID. Das bedeutet, dass nur Kunden mit Bestellungen als Ergebnis der Abfrage angezeigt werden. Vergleichen Sie diese Anweisung mit der folgenden: SELECT DISTINCTROW tblClients.ClientID, tblClients.CompanyName, tblProjectsProjectName, tblProjects.ProjectDescription FROM tblClients LEFT JOIN tblProjects ON tblClients.ClientID = tblProjects.ClientID
In diesem Beispiel werden die Tabellen tblClients und tblProjects über das Feld ClientID mit der LEFT JOIN-Klausel verknüpft. Das Ergebnis enthält alle Datensätze, egal ob Aufträge vorliegen oder nicht.
464
Kapitel 11: Fortgeschrittene Abfragetechniken
Das Wort OUTER wird bei der Klausel LEFT JOIN automatisch vorausgesetzt.
Die Klauseln ALL, DISTINCTROW und DISTINCT Die ALL-Klausel einer SELECT-Anweisung legt fest, dass alle Zeilen, die mit der WHEREKlausel übereinstimmen, zu den Ergebnissen gehören. Das Schlüsselwort DISTINCT wird benutzt, damit Access entsprechend den Feldern des Abfrage-Ergebnisses doppelte Zeilen entfernt. Dies hat die gleichen Auswirkungen wie das Setzen der Eigenschaft Keine Duplikate auf JA in der grafischen Entwurfsansicht. Wird das Schlüsselwort DISTINCTROW verwendet, entfernt Access alle doppelten Zeilen basierend auf allen Spalten aller Tabellen, so wie dies auch über Einstellen der Eigenschaft Eindeutige Datensätze auf JA in der grafischen Entwurfsansicht geschieht. Die GROUP BY-Klausel Mit der GROUP BY-Klausel werden statistische Summen berechnet. Sie wird auch erzeugt, wenn Sie in der grafischen Entwurfsansicht eine Summenabfrage zusammenstellen. Im folgenden Beispiel gibt die SELECT-Anweisung das Land, die Stadt und die Gesamtfrachtkosten für jede Kombination aus Land und Stadt an: SELECT DISTINCTROW tblCustomers.Country, tblCustomers.City Sum(tblOrders.Freight) AS SumOfFreight FROM tblCustomers INNER JOIN tblOrders ON tblCustomers.CustomerID = tblOrders.CustomerID GROUP BY tblCustomers.Country, tblCustomers.City
Die GROUP BY-Klausel zeigt an, dass keine Einzelheiten der ausgewählten Datensätze, sondern nur die in der GROUP BY-Klausel angegebenen Felder einmalig angezeigt werden. Eines der Felder der SELECT-Anweisung muss eine zusammenfassende Funktion enthalten. Das Ergebnis dieser zusammenfassenden Funktion wird zusammen mit den in der GROUP BY-Klausel angegebenen Feldern angezeigt. Die HAVING-Klausel Die HAVING-Klausel ist mit der WHERE-Klausel vergleichbar, unterscheidet sich jedoch in einem entscheidenden Punkt: sie wird nach der Zusammenfassung der Daten angewendet. Im folgenden Beispiel wird die Bedingung > 1000 nach der zusammenfassenden Funktion SUM für das Gruppieren angewendet: SELECT DISTINCTROW tblCustomers.Country, tblCustomers.City Sum(tblOrders.Freight) AS SumOfFreight FROM tblCustomers INNER JOIN tblOrders ON tblCustomers.CustomerID = tblOrders.CustomerID GROUP BY tblCustomers.Country, tblCustomers.City HAVING (((Sum(tblOrders.Freight))>1000))
SQL
11.7.3
465
Das Gelernte anwenden
Sie können an zwei unterschiedlichen Stellen mit SQL-Anweisungen arbeiten und diese eingeben:
Im Fenster SQL-ANSICHT einer Abfrage In VBA-Programmen Betrachten wir diese Möglichkeiten etwas genauer. Das grafische QBE-Raster als Zwei-Wege-Werkzeug Zum Schreiben von SQL-Anweisungen bietet sich die SQL-Ansicht einer Abfrage an: 1. Beginnen Sie damit, eine neue Abfrage zu erstellen. 2. Fügen Sie einige Felder und vielleicht auch einige Kriterien hinzu. 3. Wählen Sie im Menü ANSICHT die Option SQL-ANSICHT. 4. Versuchen Sie, die SQL-Anweisung mit Hilfe des in diesem Kapitel Gelernten zu ändern. 5. Wählen Sie über die Schaltfläche ANSICHT der Symbolleiste die Option ENTWURFSANSICHT. Wenn Sie nicht gegen SQL-Syntaxregeln verstoßen haben, können Sie ohne Probleme wieder zur Entwurfsansicht wechseln und das grafische Ergebnis Ihrer Veränderungen betrachten. Haben Sie einen Syntaxfehler in die SQL-Anweisung eingebaut, wird eine Fehlermeldung angezeigt, wenn Sie zur Entwurfsansicht der Abfrage zurückkehren wollen. SQL-Anweisungen in VBA-Code einbinden SQL-Anweisungen können auch direkt aus dem VBA-Code heraus ausgeführt werden. Hierfür stehen Ihnen zwei Möglichkeiten zur Verfügung:
Sie erstellen eine temporäre Abfrage und führen diese aus. Sie öffnen mit der SQL-Anweisung eine Datensatzgruppe als Grundlage für die Datensatzgruppe. VBA erlaubt das Erstellen einer Abfrage im Handumdrehen. Sie können die Abfrage ausführen, müssen sie aber nicht speichern. In der folgenden Funktion CurrentDB werden die Klammern ausgelassen, weil VBA bei Funktionen ohne Argumente keine Klammern benötigt. Sie können selbst entscheiden, ob Sie diese verwenden möchten. Der Code sieht folgendermaßen aus: Sub CreateTempQuery() Dim cmd As ADODB.Command Dim rst As ADODB.Recordset Set cmd = New ADODB.Command
466
Kapitel 11: Fortgeschrittene Abfragetechniken
With cmd .ActiveConnection = CurrentProject.Connection .CommandText = "Select ProjectID, ProjectName from " & _ "tblProjects Where ProjectTotalEstimate > 30000" .CommandType = adCmdText .Prepared = True Set rst = .Execute End With Do Until rst.EOF Debug.Print rst!ProjectID, rst!ProjectName rst.MoveNext Loop End Sub
Die Arbeit mit Datensatzgruppen wird in Kapitel 12 ausführlich behandelt. Zunächst einmal brauchen Sie nur zu verstehen, dass dieser Code eine temporäre Abfragedefinition mit einer SQL-Anweisung erstellt. In diesem Beispiel wird die Abfragedefinition der Datenbank nicht hinzugefügt, sondern die SQL-Anweisung ausgeführt, aber nicht gespeichert. Eine SQL-Anweisung kann auch Bestandteil der Open-Methode einer Datensatzgruppe sein: Sub OpenRWithSQL() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.Open "Select ProjectId, ProjectName from " & _ "tblProjects Where ProjectTotalEstimate > 30000", _ CurrentProject.Connection Do Until rst.EOF Debug.Print rst!ProjectID, rst!ProjectName rst.MoveNext Loop End Sub
Auch dieser Code wird in Kapitel 12 ausführlicher erörtert. Beachten Sie, dass das Datensatzgruppenobjekt zwei Parameter erhält. Bei dem ersten handelt es sich um eine SQL-Anweisung und beim zweiten um das Objekt Connection.
Union-Abfragen
11.8
467
Union-Abfragen
Mit einer Union-Abfrage können Sie die Daten zweier Tabellen mit ähnlichen Strukturen kombinieren. Die Ausgabe enthält Daten beider Tabellen. Eine Tabelle tblTimeCards kann beispielsweise aktuelle und eine Tabelle tblTimeCardsArchive archivierte Stempelkarten enthalten. Schwierig wird es, wenn Sie einen Bericht mit den Daten beider Tabellen erstellen möchten. Hierfür formulieren Sie eine UnionAbfrage für die Datenherkunft des Berichts: 1. Klicken Sie im Datenbankfenster in der Liste der Objekte auf ABFRAGEN und klicken Sie anschließend doppelt auf ERSTELLT EINE NEUE ABFRAGE IN DER ENTWURFSANSICHT. 2. Klicken Sie im Dialogfeld TABELLEN ANZEIGEN auf die Schaltfläche SCHLIESSEN, ohne eine Tabelle ausgewählt zu haben. 3. Wählen Sie ABFRAGE|SQL SPEZIFISCH|UNION, um ein SQL-Fenster zu öffnen. 4. Geben Sie die UNION-SQL-Klausel ein. Beachten Sie, dass Sie nicht in die Entwurfsansicht zurückkehren können (siehe Abbildung 11.34). 5. Klicken Sie in der Symbolleiste auf die Schaltfläche AUSFÜHREN, um die Abfrage auszuführen.
Abbildung 11.34: Ein Beispiel für eine UnionAbfrage, bei der die Tabelle tblTimeCards mit der Tabelle tblTimeCardsArchive verknüpft wird
468
11.9
Kapitel 11: Fortgeschrittene Abfragetechniken
Pass-Through-Abfragen
Mit der Pass-Through-Abfrage können Sie nicht interpretierte SQL-Anweisungen an die zu Grunde liegende Datenbank senden, wenn Sie etwas anderes als die JetEngine einsetzen. Diese nicht interpretierten Anweisungen sind in einem SQL-Format verfasst, das der spezifischen Datenbank entspricht. Die Jet-Engine erkennt diese Anweisung, unternimmt aber keinen Versuch, die Syntax zu analysieren oder zu verändern. Pass-Through-Abfragen werden in unterschiedlichen Situationen verwendet:
Die durchzuführende Aktion wird vom Back-End-Datenbank-Server aber nicht von Access oder ODBC-SQL unterstützt.
Access oder der ODBC-Treiber führen eine mangelhafte Syntaxanalyse der SQLAnweisung durch und senden sie in optimierter Form an die Back-End-Datenbank.
Sie möchten eine gespeicherte Prozedur auf dem Back-End-Datenbank-Server ausführen.
Sie möchten sicherstellen, dass die SQL-Anweisung auf dem Server ausgeführt wird.
Sie möchten Daten mehrerer Tabellen des Datenbank-Servers miteinander verknüpfen. Führen Sie die Verknüpfung ohne eine Pass-Through-Abfrage aus, wird sie im Arbeitsspeicher des Rechners des Benutzers vorgenommen, nachdem alle erforderlichen Daten über das Netzwerk gesendet wurden. Die Pass-Through-Abfragen bieten zwar viele Vorteile, sie sind jedoch kein Allheilmittel. Außerdem besitzen Sie einige Nachteile:
Da Sie SQL-Anweisungen senden, die für einen speziellen Datenbank-Server bestimmt sind, müssen Sie alle umschreiben, wenn Sie zu einem anderen Server wechseln möchten.
Die von einer Pass-Through-Abfrage zurückgegebenen Ergebnisse können nicht aktualisiert werden.
Die Jet-Engine führt keine Syntaxüberprüfung der Abfrage durch, bevor diese an das Datenbank-Back-End weitergereicht wird. Nachdem Sie nun die Vor- und Nachteile einer Pass-Through-Abfrage kennen, sollen Sie jetzt lernen, wie eine solche Abfrage erstellt wird: 1. Klicken Sie im Datenbankfenster in der Liste der Objekte auf ABFRAGEN und klicken Sie anschließend doppelt auf ERSTELLT EINE NEUE ABFRAGE IN DER ENTWURFSANSICHT. 2. Klicken Sie im Dialogfeld TABELLEN ANZEIGEN auf die Schaltfläche SCHLIESSEN, ohne eine Tabelle ausgewählt zu haben.
469
Die Weitergabe von Nullwerten und Abfrage-Ergebnisse
3. Wählen Sie ABFRAGE|SQL öffnen.
SPEZIFISCH|PASS-THROUGH,
um ein SQL-Fenster zu
4. Geben Sie die SQL-Anweisung im Dialekt des Back-End-Datenbank-Servers ein. 5. Öffnen Sie das Dialogfeld EIGENSCHAFTEN und geben Sie für die ODBC-Verbindung die entsprechende Zeichenfolge ein (siehe Abbildung 11.35).
Abbildung 11.35: Eine SQL-PassThrough-Abfrage, die bestimmte Felder der SalesTabelle der Datenquelle PublisherInfo auswählt
6. Klicken Sie in der Symbolleiste auf die Schaltfläche AUSFÜHREN, um die Abfrage auszuführen.
11.10
Die Weitergabe von Nullwerten und AbfrageErgebnisse
Null-Werte können an den Abfrage-Ergebnissen schwere Schäden auslösen, da sie
weitergereicht werden. Betrachten Sie Abbildung 11.36 und beachten Sie dabei, dass beim Einfügen von Werten in den Feldern parts oder labor das Resultat der Addition beider Felder Null ist, wenn eines der Felder Null-Werte enthält. In Abbildung 11.37 wurde dieser Fehler berichtigt. Die beiden Werte werden mit dem folgenden Ausdruck addiert: TotalPrice: NZ([Parts]) + NZ([Labor])
Dieser Ausdruck wandelt mit der Nz-Funktion vor der Addition die Null-Werte in 0 um.
470
Kapitel 11: Fortgeschrittene Abfragetechniken
Abbildung 11.36: Weitergabe von Null in einem Abfrage-Ergebnis
Abbildung 11.37: Eine Möglichkeit, die Weitergabe von Null zu unterbinden
11.11
Unterabfragen
Mit Unterabfragen können Sie eine SELECT-Anweisung in eine andere SELECT-Anweisung einbetten. Platzieren Sie eine Unterabfrage in den Kriterien einer Abfrage, dann basiert eine Abfrage auf den Ergebnissen einer anderen. Abbildung 11.38 zeigt ein Beispiel für eine Unterabfrage. Die gezeigte Abfrage findet alle Kunden ohne Bestellungen. Die SQL-Anweisung sieht wie folgt aus: SELECT DISTINCTROW tblClients.ClientsID, tblClients.CompanyName FROM tblClients WHERE tblClients.ClientID NOT In (Select ClientID from tblProjects)
Diese Abfrage führt zuerst die SELECT-Anweisung Select ClientID from tblProjects aus. Das Ergebnis dient anschließend als Kriterium für die erste Abfrage.
Das Ergebnis einer Funktion als Abfragekriterium verwenden
471
Abbildung 11.38: Eine Abfrage mit einer Unterabfrage
11.12
Das Ergebnis einer Funktion als Abfragekriterium verwenden
Oft ist nicht bekannt, dass der Rückgabewert einer Funktion als Ausdruck in einer Abfrage oder als Parameter für eine Abfrage verwendet werden kann. Die Abfrage in Abbildung 11.39 wertet den Rückgabewert der Funktion Initials mit einer Bedingung aus, um festzustellen, ob ein Mitarbeiter Bestandteil des AbfrageErgebnisses ist. Die unten aufgeführte Initials-Funktion (Sie finden diese auch im Modul basUtils der Datenbank CHAP11EX.MDB auf der beiliegenden CD-ROM) übernimmt zwei Zeichenfolgen und gibt den ersten Buchstaben jeder Zeichenfolge gefolgt von einem Punkt zurück: Function Initials(strFirstName As String, _ strLastName As String) As String Initials = Left(strFirstName, 1) & "." & _ Left(strLastName, 1) & "." End Function
Abbildung 11.39: Eine Abfrage, die den Rückgabewert einer Funktion als Ausdruck benutzt
472
Kapitel 11: Fortgeschrittene Abfragetechniken
Der Rückgabewert einer Funktion kann auch als Kriterium einer Abfrage dienen (siehe Abbildung 11.40). Die Abfrage dieser Abbildung benutzt eine Funktion HighlyPaid, um zu ermitteln, welche Datensätze im Abfrage-Ergebnis erscheinen. Diese Funktion, die Sie auch auf der beiliegenden CD-ROM im Modul basUtils der Datenbank CHAP11EX.MDB finden, sieht folgendermaßen aus: Function HighlyPaid(strTitle) As Currency Dim curHighRate As Currency Select Case strTitle Case "Sr. Programmer" curHighRate = 60 Case "Systems Analyst" curHighRate = 80 Case "Project Manager" curHighRate = 100 Case Else curHighRate = 50 End Select HighlyPaid = curHighRate End Function
Die Funktion übernimmt den Titel des Mitarbeiters als Parameter. Anschließend wertet sie diesen Wert aus und gibt einen Schwellenwert an die Abfrage zurück, der als Kriterium für die Spalte Billing Rate der Abfrage dient.
Abbildung 11.40: Eine Abfrage, die den Rückgabewert einer Funktion als Kriterium verwendet
Die Werte für eine Parameterabfrage aus einem Formular einlesen
11.13
473
Die Werte für eine Parameterabfrage aus einem Formular einlesen
Die größte Frustration bei Parameterabfragen kommt auf, wenn mehrere Parameter für die Ausführung der Abfrage erforderlich sind. Der Benutzer wird mit mehreren Dialogfeldern für die einzelnen Parameter der Abfrage konfrontiert. Die folgenden Schritte erläutern, wie eine Parameterabfrage die Werte über ein Formular erhält: 1. Erstellen Sie ein neues, ungebundenes Formular. 2. Fügen Sie Textfelder oder andere Steuerelemente für die Kriterien der einzelnen Parameter der Abfrage hinzu. 3. Bezeichnen Sie jedes Steuerelement so, dass Sie beim Lesen erkennen können, welche Daten das Steuerelement enthält. 4. Fügen Sie dem Formular eine Befehlsschaltfläche hinzu und lassen Sie diese die Parameterabfrage aufrufen (siehe Abbildung 11.41)
Abbildung 11.41: Der Code für das Ereignis Click der Befehlsschaltfläche, welche die Parameterabfrage aufruft
5. Speichern Sie das Formular. 6. Erstellen Sie die Abfrage und fügen Sie die Parameter hinzu. Jeder Parameter sollte sich auf ein Steuerelement des Formulars beziehen (siehe Abbildung 11.42).
474
Kapitel 11: Fortgeschrittene Abfragetechniken
Abbildung 11.42: Parameter, die sich auf Steuerelemente eines Formulars beziehen
7. Klicken Sie mit der rechten Maustaste in die obere Hälfte des Abfrage-Entwurffensters und wählen Sie PARAMETER. Definieren Sie im Dialogfeld PARAMETER für jeden Parameter einen Datentyp (siehe Abbildung 11.43).
Abbildung 11.43: Im Dialogfeld Parameter können Sie den Datentyp der einzelnen Parameter der Abfrage auswählen
8. Speichern und schließen Sie die Abfrage. 9. Tragen Sie die Werte im Kriterienformular ein und führen Sie durch Klicken auf die Befehlsschaltfläche die Abfrage aus.
11.13.1
Für die Praxis
Anwendung der Techniken in Ihren Anwendungen Die in diesem Kapitel vorgestellten erweiterten Abfragetechniken werden für unser Zeit- und Abrechnungssytems genutzt. Schauen Sie sich einige praktische Anwendungen dieser erweiterten Techniken an.
Die Werte für eine Parameterabfrage aus einem Formular einlesen
475
Die Beispiele dieses Abschnitts sind in der Datenbank CHAP11.MDB auf der beiliegenden CD-ROM enthalten.
11.13.2 Zahlungsarchivierung Nach einiger Zeit kann es erforderlich sein, dass Sie einige der Daten der Tabelle tblPayments archivieren. Die Zahlungsdaten werden mit zwei Abfragen archiviert. Die erste Abfrage mit dem Namen qappAppendToPaymentArchive ist eine Anfügeabfrage, die alle Daten eines bestimmten Zeitraums an die Tabelle tblPaymentsArchive sendet (siehe Abbildung 11.44). Die zweite Abfrage mit dem Namen qdelRemoveFromPayments ist eine Löschabfrage, die alle archivierten Daten aus der Tabelle tblPayments entfernt (siehe Abbildung 11.45). Die Archivierung wird über ein Formular mit der Bezeichnung frmArchivePayments durchführt, in dem der Zeitraum zur Laufzeit vom Benutzer eingegeben wird (siehe Abbildung 11.46).
Abbildung 11.44: Die Anfügeabfrage qappAppendToPaymentArchive
Abbildung 11.45: Die Löschabfrage qdelRemoveFromPayments
476
Kapitel 11: Fortgeschrittene Abfragetechniken
Abbildung 11.46: Das Formular mit den Kriterien für den Archivierungsvorgang
11.13.3 Alle Zahlungen anzeigen Bei bestimmten Gelegenheiten wollen Sie vielleicht Daten beider Tabellen miteinander kombinieren. Hierfür müssen Sie eine Union-Abfrage zum Verknüpfen der Tabellen tblPayments und tblPaymentsArchive erstellen. Abbildung 11.47 enthält den Entwurf für diese Abfrage.
Abbildung 11.47: Die Tabellen tblPayments und tblPaymentsArchive mit einer Union-Abfrage verknüpfen
11.13.4 Eine Ländertabelle erstellen Da Sie regelmäßig die Länder und Bundesländer bearbeiten, benötigen Sie wahrscheinlich eine Liste, die Ihnen alle Länder und Bundesländer Ihrer aktuellen Kunden anzeigt. Abbildung 11.48 enthält die hierfür erforderliche Abfrage. Sie benutzt die Tabelle tblClients ohne Duplikate für das Feld StateProvince. Es handelt sich hier um eine Tabellenerstellungsabfrage, welche die eindeutigen Werte dieser Liste nimmt und in die Tabelle tblProvinceState ausgibt.
Die Werte für eine Parameterabfrage aus einem Formular einlesen
477
Abbildung 11.48: Eine Tabellenerstellungsabfrage, die eine Tabelle tblStateProvince erstellt
Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Kapitel
Hier lesen Sie:
Datenzugriffsobjekte ActiveX und Datenzugriffsobjekte im Vergleich Das Datenobjektmodell Arten von ADO-Datensatzgruppen ADO-Recordset-Eigenschaften und Methoden Tabellendaten bearbeiten Datenbankobjekte erstellen Das Datenzugriffsobjektmodell (DAO) CurrentDB() Arten von DAO-Datensatzgruppen Zwischen Datensatzgruppenobjekten wählen Mit DAO-Recordset-Eigenschaften und Methoden umgehen Mit DAO-Code Tabellendaten bearbeiten Datenbankobjekte erstellen Die DAO-Container-Auflistung
12.1
Datenzugriffsobjekte
ActiveX-Datenobjekte (ADO) und Datenzugriffsobjekte werden eingesetzt, um JetEngine-Objekte mit Hilfe von Code zu erstellen, zu verändern und zu entfernen. Diese verleihen Ihnen die Flexibilität, um über die Benutzerschnittstelle hinaus die in
480
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
der Jet-Engine und anderen Formaten gespeicherten Daten zu bearbeiten. Mit Hilfe von ActiveX-Datenobjekten oder Datenzugriffsobjekten können Sie diese Aufgaben durchführen:
die Struktur einer bestehenden Datenbank analysieren Tabellen oder Abfragen hinzufügen oder verändern neue Datenbanken erstellen die grundlegenden Definitionen von Abfragen modifizieren, indem Sie die der Abfrage zu Grunde liegenden SQL-Befehle verändern
durch Datensatzmengen navigieren Tabellendaten verändern
12.2
ActiveX-Datenobjekte und Datenzugriffsobjekte im Vergleich
In den früheren Ausgaben dieses Buchs wurde lediglich auf Datenzugriffsobjekte (DAO) verwiesen. ActiveX-Datenobjekte (ADO) wurden nicht erwähnt. Der Grund hierfür liegt darin, dass sich ActiveX-Datenobjekte bei der Veröffentlichung von Access 97 noch in einem sehr frühen Entwicklungsstadium befanden. Als ich mit dem Schreiben dieses Buchs begann, musste ich eine Entscheidung treffen, ob ich ADO, DAO oder beides behandeln soll. Ich habe mir diese Frage eine ganze Zeit lang durch den Kopf gehen lassen. Obwohl ich empfehle, neue Entwicklungen mit Hilfe von ADO vorzunehmen, wäre das Entfernen der DAO betreffenden Erläuterungen aus diesem Buch verfrüht. Ich habe mich entschieden, in diesem Kapitel sowohl ADO als auch DAO zu besprechen. In der ersten Hälfte dieses Kapitels wird ADO abgedeckt. Falls Sie eine neue Anwendung entwickeln oder die Möglichkeit haben, eine bereits bestehende Anwendung zu überarbeiten, ist die erste Hälfte des Kapitels für Sie gedacht. Wenn Sie nicht mit DAO vertraut sind und mit vorhandenen Anwendungen arbeiten müssen, stellt Ihnen die zweite Hälfte des Kapitels die Grundlagen von DAO bereit. Wenn Sie schließlich bereits über DAO-Kenntnisse verfügen und DAO und ADO vergleichen und gegenüberstellen wollen, zeigt Ihnen dieses Kapitel, wie Sie diese Aufgaben mit Hilfe der beiden Datenzugriffsverfahren durchführen können. Obwohl DAO in diesem Kapitel behandelt wird, werden im Rest dieses Buches alle erforderlichen Datenzugriffe mit ADO vorgenommen.
Das Datenobjektmodell von ActiveX
12.3
481
Das Datenobjektmodell von ActiveX
Abbildung 12.1 zeigt einen Überblick über das von Microsoft stammende Datenobjektmodell (ADO-Modell) von ActiveX. Im Gegensatz zu dem Datenzugriffsobjektmodell (DAO-Modell) ist das ADO-Objektmodell nicht hierarchisch aufgebaut.
Fehler Felder Connection
Eigenschaften
Command
Datensatz Eigenschaften Parameter Eigenschaften Eigenschaften
12.3.1
Abbildung 12.1: Das ADO-Objektmodell
Das Connection-Objekt
Das Connection-Objekt definiert eine Sitzung für einen Benutzer und eine Datenquelle. Obwohl das ADO-Objekt nicht als hierarchisch erachtet wird, wird das Connection-Objekt als das sich auf der höchsten Ebene befindende ADO-Objekt betrachtet. Nach dem Erstellen eines ADO-Objekts können Sie dieses mit mehreren Datensatzgruppen verwenden. Das verbessert die Leistung und vereinfacht Ihren Programm-Code wesentlich. Ein Connection-Objekt muss vor seiner Verwendung deklariert werden. Diese Deklaration sieht folgendermaßen aus: Dim cnn as ADODB.Connection
Nach dem Deklarieren des Connection-Objekts muss eine neue Objektinstanz von Connection gebildet werden. Der Code hat folgendes Aussehen: Set cnn = New ADODB.Connection
Dieses Connection-Objekt muss dann geöffnet werden. Die Methode Open des Connection-Objekts erhält eine Verbindungszeichenfolge sowie als Parameter optional eine Benutzerkennung, ein Passwort und Optionen. Unten sehen Sie ein Beispiel für die einfachste Verwendung der Methode Open: cnn.Open CurrentProject.Connection
482
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
In diesem Beispiel wird die Verbindung mit der Methode Open des ConnectionObjekts hergestellt. Die Verbindungszeichenfolge wird bereitgestellt, die von der Eigenschaft Connection des Objekts CurrentProject zurückgegeben wird. Auf diese Weise wird eine Verbindung geöffnet, die auf der mit der aktuellen Datenbank assoziierten Verbindung basiert. Der Verweis auf die mit dem aktuellen Projekt verknüpfte Verbindung lässt sich wie folgt ändern: cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;" &_ "Persist Security Info=False;" &_ "User ID=Admin;" &_ "Data Source=Q:\Clients\sams\" &_ "Mastering Access 2000 Development\Databases" &_ "\Chap12Ex.mdb;"
Die vollständige zum Einrichten einer Verbindung erforderliche Routine sehen Sie in Listing 12.1. Listing 12.1:
Erstellen eines Connection-Objekts
Sub CreateConnection() Dim cnn As ADODB.Connection Set cnn = New ADODB.Connection cnn.Open CurrentProject.Connection cnn.Close Set cnn = Nothing End Sub
Listing 12.1 und der überwiegende Teil des in diesem Kapitel aufgeführten Codes befinden sich auf der diesem Buch beiliegenden CD-ROM in der Datei CHAP12EX.MDB.
12.3.2
Das Recordset-Objekt
Ein Recordset-Objekt wird eingesetzt, um Datensätze als eine Gruppe zu betrachten, und verweist auf die von einer Datenanforderung zurückgegebene Zeilenmenge. Wie bei einem Connection-Objekt müssen Sie ein Recordset-Objekt vor seiner Verwendung deklarieren. Der Code sieht wie folgt aus: Dim rst as ADODB.Recordset
Nach dem Deklarieren des Recordset-Objekts muss eine Instanz von diesem gebildet werden. Dies funktioniert so: Set rst = New ADODB.Recordset
Wie beim Connection-Objekt wird die Methode Open verwendet, damit das RecordsetObjekt auf eine Datensatzmenge zeigt. Der Code hat folgendes Aussehen: rst.Open "Select * From tblClients", CurrentProject.Connection
Das Datenobjektmodell von ActiveX
483
Der erste Parameter der Methode Open gibt die Datenquelle an. Bei der Quelle kann es sich um den Namen einer Tabelle, eine SQL-Anweisung, den Namen einer gespeicherten Prozedur, den Variablennamen eines Command-Objekts oder den Dateinamen einer persistenten Datensatzgruppe handeln. Im Beispiel ist die SQL-Anweisung Select die Quelle. Der zweite Parameter der Methode Open muss entweder eine gültige Verbindungszeichenfolge oder der Name eines Connection-Objekts sein. Im Beispiel gibt die Eigenschaft Connection des Objekts CurrentProject eine Zeichenfolge zurück, die als Verbindungszeichenfolge verwendet wird. Der vollständige Code ist in Listing 12.2 aufgeführt. Listing 12.2:
Erstellen einer Datensatzgruppe mit Hilfe einer Verbindungszeichenfolge
Sub CreateRecordset1() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.Open "Select * From tblClients", CurrentProject.Connection Debug.Print rst.GetString rst.Close Set rst = Nothing End Sub
Beachten Sie, dass nach dem Öffnen der Datensatzgruppe das Resultat der Methode GetString des Recordset-Objekts im Direktfenster ausgegeben wird. Die Methode GetString des Recordset-Objekts erstellt auf der Basis der in der Datensatzgruppe enthaltenen Daten eine Zeichenfolge. Zum jetzigen Zeitpunkt ist dies ein einfaches Verfahren, um zu überprüfen, ob Ihr Code wie erwartet funktioniert. Beachten Sie ebenfalls, dass die Methode Close des Recordset-Objekts zum Schließen der Datensatzgruppe verwendet wird. Die Methode Close bewirkt, wenn sie auf ein Connectionoder ein Recordset-Objekt angewendet wird, die Freigabe der zugewiesenen Systemressourcen, entfernt das Objekt jedoch nicht aus dem Arbeitsspeicher. Dazu setzt man den Wert des Recordset-Objekts auf Nothing. Obwohl dieser Code recht gut arbeitet, ziehe ich es vor, vor dem Ausführen der Methode Open die Parameter der Methode als Eigenschaften des Recordset-Objekts zu setzen. Sie werden feststellen, dass auf diese Weise Ihr Code beim Hinzufügen von Parametern zur Methode Open wesentlich lesbarer wird. Den Code finden Sie in Listing 12.3. Listing 12.3:
Erstellen einer Datensatzgruppe mit Hilfe der Eigenschaft ActiveConnection
Sub CreateRecordset2() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.Open "Select * From tblClients" Debug.Print rst.GetString rst.Close Set rst = Nothing End Sub
484
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Letztlich kann man anstelle einer Connection-Zeichenfolge ein Connection-Objekt einsetzen. Dasselbe Connection-Objekt lässt sich für mehrere Datensatzgruppen verwenden. Den Code sehen Sie in Listing 12.4. Listing 12.4:
Erstellen eines Datensatzes mit Hilfe eines Connection-Objekts
Sub CreateRecordset3() Dim cnn As ADODB.Connection Dim rst1 As ADODB.Recordset Dim rst2 As ADODB.Recordset Set cnn = New ADODB.Connection Set rst1 = New ADODB.Recordset Set rst2 = New ADODB.Recordset cnn.ConnectionString = CurrentProject.Connection cnn.Open rst1.ActiveConnection = cnn rst1.Open "Select * From tblClients" rst2.ActiveConnection = cnn rst2.Open "Select * From tblPayments" Debug.Print rst1.GetString Debug.Print rst2.GetString rst1.Close rst2.Close cnn.Close Set rst1 = Nothing Set rst2 = Nothing Set cnn = Nothing End Sub
Beachten Sie, dass sowohl rst1 als auch rst2 dasselbe Connection-Objekt verwenden.
12.3.3
Das Command-Objekt
Das ADO-Objekt Command verkörpert eine mit einer Datenquelle ausgeführte Abfrage, SQL-Anweisung oder gespeicherte Prozedur. Obwohl nicht in jedem Fall erforderlich, ist ein Command-Objekt insbesondere beim Ausführen von parametrisierten Abfragen und gespeicherten Prozeduren hilfreich. Genau wie beim Connection- und Recordset-Objekt muss das Command-Objekt vor seiner Verwendung deklariert werden: Dim cmd as ADODB.Command
Das Datenobjektmodell von ActiveX
485
Als nächstes muss eine Instanz des Command-Objekts gebildet werden: Set cmd = New ADODB.Command
Nach dem Erstellen einer Instanz des Command-Objekts müssen Sie dessen Eigenschaften ActiveConnection und CommandText setzen. Wie bei einem Recordset-Objekt kann es sich bei der Eigenschaft ActiveConnection entweder um eine Verbindungszeichenfolge oder um einen Verweis auf ein Connection-Objekt handeln. Die Eigenschaft CommandText ist die vom Command-Objekt verwendete SQL-Anweisung oder gespeicherte Prozedur. Die Eigenschaften ActiveConnection und CommandText sehen wie folgt aus: cmd.ActiveConnection = CurrentProject.Connection cmd.CommandText = "tblClients"
Den vollständigen Code finden Sie in Listing 12.5. Listing 12.5:
Ein Command-Objekt verwenden
Sub CommandObject() Dim rst As ADODB.Recordset Dim cmd As ADODB.Command Set cmd = New ADODB.Command cmd.CommandText = "Select * from tblClients" cmd.ActiveConnection = CurrentProject.Connection Set rst = cmd.Execute Debug.Print rst.GetString rst.Close Set cmd = Nothing Set rst = Nothing End Sub
In diesem Beispiel wird eine Instanz des Command-Objekts gebildet. Die Eigenschaft CommandText wird auf eine SQL-Anweisung gesetzt und die Eigenschaft ActiveConnection weist auf die mit der aktuellen Datenbank assoziierte Verbindung. Die Ergebnisse der SQL-Anweisung werden mit Hilfe der Methode Execute des CommandObjekts in das Recordset-Objekt zurückgegeben.
486
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
12.4
Arten von ADO-Datensatzgruppen
Die Methode Open eines Recordset-Objekts verfügt über drei Parameter, die sich auf die Art der erstellten Datensatzgruppe auswirken. Diese Parameter sind: CursorType, LockType und Options. Diese Parameter werden kombiniert, um festzulegen, welche Bewegungsarten innerhalb einer Datensatzgruppe ausführbar sind, in welchen Fällen von anderen Benutzern an den einer Datensatzgruppe zu Grunde liegenden Daten vorgenommene Änderungen sichtbar sind und ob die Daten der Datensatzgruppe aktualisiert werden können.
12.4.1
Der Parameter CursorType
Wenn Sie eine Datensatzgruppe öffnen, wird der Parameter CursorType standardmäßig auf adOpenForwardOnly gesetzt. Dies bedeutet, dass Sie sich lediglich vorwärts durch die Datensätze der Datensatzgruppe bewegen und keine von anderen Benutzern vorgenommenen Hinzufügungen, Bearbeitungen oder Löschungen sehen können. Außerdem sind viele Eigenschaften und Methoden wie beispielsweise die Eigenschaft RecordCount und die Methode MovePrevious nicht verfügbar. Für den Parameter CursorType stehen drei weitere Werte zur Verfügung: adOpenStatistic, adOpenKeyset und adOpenDynamic. Die Option adOpenStatistic ermöglicht, sich vorwärts und rückwärts durch die Datensätze einer Datensatzgruppe zu bewegen, aber von anderen Benutzern an den der Datensatzgruppe zu Grunde liegenden Daten vorgenommene Änderungen werden von der Datensatzgruppe nicht wahrgenommen. Die Option adOpenKeyset bietet dasselbe wie die Option adOpenStatistic, darüber hinaus werden von anderen Benutzern durchgeführte Veränderungen in der Datensatzgruppe sichtbar. Schließlich werden bei der Option adOpenDynamic alle von anderen Benutzern vorgenommenen Hinzufügungen, Bearbeitungen und Löschungen von der Datensatzgruppe erkannt. Die Eigenschaft CursorType der Datensatzgruppe lässt sich auf eine von zwei Weisen setzen, wobei eine die Verwendung als Parameter der Methode Open des RecordsetObjekts ist. Dies wird in Listing 12.6 veranschaulicht. Listing 12.6:
CursorType als Parameter der Open-Methode
Sub StaticRecordset1() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.Open "Select * from tblClients", _ CursorType:=adOpenStatic Debug.Print rst.RecordCount
Arten von ADO-Datensatzgruppen
487
rst.Close Set rst = Nothing
End Sub
Beachten Sie, dass in Listing 12.6 die Eigenschaft CursorType als Parameter der Methode Open erscheint. Vergleichen Sie Listing 12.6 und Listing 12.7. Listing 12.7:
Die Eigenschaft CursorType als Eigenschaft des Recordset-Objekts angeben
Sub StaticRecordset2() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenStatic rst.Open "Select * from tblClients" Debug.Print rst.RecordCount rst.Close Set rst = Nothing
End Sub
In Listing 12.7 wird der Parameter CursorType vor dem Ausführen der Methode Open als Eigenschaft des Recordset-Objekts gesetzt. Durch Abtrennen der Eigenschaften von der Methode Open wird die Lesbarkeit des Codes verbessert.
12.4.2
Der Parameter LockType
Obwohl die Eigenschaft CursorType festlegt, welche Bewegungen innerhalb der Datensatzgruppe erfolgen können und ob von anderen Benutzern vorgenommene Änderungen erkannt werden, wirkt sich der Parameter CursorType nicht in geringster Weise auf die Aktualisierbarkeit der Daten einer Datensatzgruppe aus. Tatsächlich wird eine Datensatzgruppe standardmäßig im schreibgeschützten Modus geöffnet. Die Datensatzgruppe lässt sich ausschließlich durch Ändern der Eigenschaft LockType aktualisierbar machen. Der Parameter LockType verfügt über die Optionen adLockReadOnly, adLockPessimistic, adLockOptimistic und adLockBatchOptimistic. Die voreingestellte Option adLockReadOnly gestattet keine Änderungen an der Datensatzgruppe. Die anderen Optionen erlauben das Aktualisieren der Daten der Datensatzgruppe. Die Unterschiede liegen im Zeitpunkt, zu dem die Datensätze gesperrt werden. Bei der Option adLockPessimistic wird der Datensatz gesperrt, sobald der Bearbeitungsprozess einsetzt. Bei der Option adLockOptimistic wird der Datensatz
488
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
beim Aufrufen der Methode Update gesperrt. Mit Hilfe der Option adLockBatchOptimistic können Sie die Sperrung hinausschieben, bis ein Stapel von Datensätzen aktualisiert wird. Alle diese Optionen werden eingehend in Kapitel 17 besprochen. Die Eigenschaft LockType lässt sich wie die Eigenschaft CursorType als Parameter der Methode Open oder als Eigenschaft des Recordset-Objekts setzen. Listing 12.8 zeigt die Einrichtung des Sperrentyps als Eigenschaft des Recordset-Objekts. Listing 12.8:
Konfiguration des Parameters LockType
Sub OptimisticRecordset()
Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenStatic rst.LockType = adLockOptimistic rst.Open "Select * from tblClients" rst!City = "Westlake Village" rst.Update Debug.Print rst!City rst.Close Set rst = Nothing
End Sub In Listing 12.8 wird die Eigenschaft LockType auf adLockOptimistic gesetzt. Der Datensatz wird gesperrt, sobald die Methode Update des Recordset-Objekts aufgerufen wird.
12.4.3
Der Parameter Options
Der Parameter Options legt fest, wie der Datenanbieter das die Quelle bezeichnende Argument einrichten soll. Die gültigen Auswahlmöglichkeiten sind in Tabelle 12.1 aufgeführt. Wert
Beschreibung
AdCmdText
Der Datenanbieter bewertet die Quelle als Befehl.
AdCmdTable
Zum Zurückgeben aller Zeilen der in der Quelle angegebenen Tabelle wird eine SQL-Anweisung erzeugt.
Tabelle 12.1: Gültige Auswahlmöglichkeiten für den Parameter Options
Arten von ADO-Datensatzgruppen
489
Wert
Beschreibung
AdCmdTableDirect
Der Datenanbieter gibt alle Zeilen der in der Quelle genannten Tabelle zurück.
AdCmdStoredProc
Der Datenanbieter bewertet die Quelle als gespeicherte Prozedur.
AdCmdUnknown
Der Typ des Befehls in der Quelle ist unbekannt.
AdCmdFile
Die Quelle wird als beständige Datensatzgruppe bewertet.
AdAsyncExecute
Die Quelle wird asynchron ausgeführt.
AdAsyncFetch
Die anfängliche, in der Eigenschaft Initial Fetch Size angegebene Menge wird abgerufen.
adAsyncFetchNonBlocking
Der Primär-Thread wird während des Datenabrufs niemals blockiert.
Tabelle 12.1: Gültige Auswahlmöglichkeiten für den Parameter Options (Forts.)
Die Voreinstellung für den Wert des Parameters Options ist adCmdUnknown. Falls der Parameter Options nicht ausdrücklich angegeben wird, versucht der Datenanbieter diesen während der Ausführung des Codes zu ermitteln, was sich nachteilig auf die Leistung auswirkt. Aus diesem Grund ist das Angeben dieses Parameters von Bedeutung. Listing 12.9 veranschaulicht die Verwendung des Options-Parameters der Methode Open. Listing 12.9:
Der Parameter Options der Methode Open
Sub OptionsParameter() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenStatic rst.LockType = adLockOptimistic rst.Open "Select * from tblClients", _ Options:=adCmdText rst!City = "Westlake Village" rst.Update Debug.Print rst!City rst.Close Set rst = Nothing
End Sub
In Listing 12.9 wird der Parameter Options auf adCmdText gesetzt. Dies führt dazu, dass die Quelle als SQL-Anweisung bewertet wird.
490
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
12.5
Mit ADO-Recordset-Eigenschaften und -Methoden umgehen
Das ADO-Recordset-Objekt verfügt über eine Vielzahl von Eigenschaften und Methoden, die Ihnen das Navigieren durch eine Datensatzgruppe, das Sortieren, Filtern und Finden von Daten sowie das Aktualisieren der in einer Datensatzgruppe enthaltenen Daten gestattet. Die am häufigsten eingesetzten Eigenschaften und Methoden werden in den folgenden Abschnitten behandelt.
12.5.1
Methoden zum Verschieben von Datensätzen
Wenn Sie eine Variable des Recordset-Objekts gesetzt haben, möchten Sie vermutlich die Daten innerhalb der Datensatzgruppe bearbeiten. Tabelle 12.2 zeigt einige Methoden, mit deren Hilfe Sie sich durch die Datensätze einer Datensatzgruppe bewegen können. Methode
Bewegung
MoveFirst
Zum ersten Datensatz einer Datensatzgruppe
MoveLast
Zum letzten Datensatz einer Datensatzgruppe
MovePrevious
Zum vorhergehenden Datensatz einer Datensatzgruppe
MoveNext
Zum nächsten Datensatz einer Datensatzgruppe
Tabelle 12.2: Methoden zum Navigieren durch die Datensätze einer Datensatzgruppe
Listing 12.10 zeigt ein Beispiel für die Verwendung der Methoden, die zum Navigieren durch die Datensätze eines Recordset-Objekts dienen. Listing 12.10: Methoden zum Bewegen durch die Datensätze eines Recordset-Objekts Sub RecordsetMovements() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenStatic rst.Open "Select * from tblProjects" Debug.Print rst!ProjectID rst.MoveNext Debug.Print rst!ProjectID rst.MoveLast Debug.Print rst!ProjectID rst.MovePrevious
Mit ADO-Recordset-Eigenschaften und -Methoden umgehen
491
Debug.Print rst!ProjectID rst.MoveFirst Debug.Print rst!ProjectID rst.Close Set rst = Nothing End Sub
Dieser Code öffnet eine auf der Tabelle tblProjects basierende Datensatzgruppe. Sobald die Datensatzgruppe geöffnet ist, wird die ProjectID im Direktfenster ausgegeben. Die Methode MoveNext des Recordset-Objekts wird verwendet, um sich zum nächsten Datensatz zu bewegen. Wieder wird die ProjectID im Direktfenster ausgegeben. Die Methode MovePrevious bewegt den Datensatzzeiger einen Datensatz zurück und zieht die erneute Ausgabe der ProjectID nach sich. Schließlich setzt die Methode MoveFirst den Datensatzzeiger auf den ersten Datensatz und die ProjectID wird ausgegeben. Die Datensatzgruppe wird geschlossen und das Recordset-Objekt zerstört.
12.5.2
Beschränkungen einer Datensatzgruppe
Bevor Sie mit dem Navigieren durch Datensatzgruppen beginnen können, müssen Sie zwei Eigenschaften von Datensatzgruppen verstehen: BOF und EOF. Die Namen dieser Eigenschaften sind veraltete Abkürzungen, die für »beginning of file« (Dateianfang) und »end of file« (Dateiende) stehen. Mit ihrer Hilfe wird bestimmt, ob Sie die Grenzen Ihrer Datensatzgruppe erreicht haben. Die Eigenschaft BOF ist True, wenn sich der Datensatzzeiger vor dem ersten Datensatz befindet, und die Eigenschaft EOF hat den Wert True, wenn der Datensatzzeiger hinter dem letzten Datensatz steht. Sie werden die Eigenschaft EOF normalerweise einsetzen, wenn Sie sich mit Hilfe der Methode MoveNext in Vorwärtsrichtung durch Ihre Datensatzgruppe bewegen. Diese Eigenschaft erhält den Wert True, wenn Sie durch die letzte Ausführung der Methode MoveNext die Grenzen der Datensatzgruppe verlassen haben. Analog dazu ist BOF am hilfreichsten, wenn Sie die Methode MovePrevious einsetzen. Sie müssen einige wichtige Merkmale der Eigenschaften BOF und EOF beachten: 1. Falls eine Datensatzgruppe keine Datensätze enthält, haben sowohl die Eigenschaft BOF als auch die Eigenschaft EOF den Wert True. 2. Wenn Sie eine Datensatzgruppe mit mindestens einem Datensatz öffnen, werden die Eigenschaften BOF und EOF auf False gesetzt. 3. Falls der Datensatzzeiger auf den ersten Datensatz einer Datensatzgruppe weist und die Methode MovePrevious ausgeführt wird, erhält die Eigenschaft BOF den Wert True. Wenn Sie noch einmal versuchen, die Methode MovePrevious auszuführen, tritt ein Laufzeitfehler auf.
492
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
4. Falls sich der Datensatzzeiger auf dem letzten Datensatz einer Datensatzgruppe befindet und die Methode MoveNext aufgerufen wird, wird die Eigenschaft EOF auf den Wert True gesetzt. Wenn Sie erneut versuchen, die Methode MoveNext auszuführen, zieht dies einen Laufzeitfehler nach sich. 5. Wenn die Eigenschaften BOF und EOF auf True gesetzt werden, behalten sie diesen Wert solange bei, bis Sie einen gültigen Datensatz ansteuern. 6. Wenn der einzige Datensatz einer Datensatzgruppe gelöscht wird, bleiben die Eigenschaften BOF und EOF solange False, bis Sie versuchen, sich auf einen anderen Datensatz zuzubewegen. Listing 12.11 zeigt ein Beispiel dafür, wie man mit Hilfe der Eigenschaft EOF die Grenzen einer Datensatzgruppe bestimmt. Listing 12.11: Bestimmen der Grenzen einer Datensatzgruppe Sub DetermineLimits() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenStatic rst.Open "Select * from tblProjects" Do Until rst.EOF Debug.Print rst![ClientID] rst.MoveNext Loop rst.Close Set rst = Nothing End Sub
In Listing 12.11 wird eine Datensatzgruppe auf der Grundlage der Tabelle tblProjects geöffnet und die Eigenschaft EOF ausgewertet. Solange die Eigenschaft EOF gleich False ist, wird der Inhalt des Felds ClientID ausgegeben und der Datensatzzeiger rückt auf den nächsten Datensatz der Datensatzgruppe vor.
12.5.3
Die Anzahl der Datensätze in einer Datensatzgruppe feststellen
Die Eigenschaft RecordCount gibt die Anzahl der Zeilen einer Datensatzgruppe zurück. Nicht alle Arten von Datensatzgruppen und Datenanbietern unterstützen die Eigenschaft RecordCount. Falls diese Eigenschaft nicht unterstützt wird, tritt kein Fehler auf, sondern der Wert von RecordCount wird auf -1 gesetzt. Listing 12.12 zeigt ein Beispiel.
Mit ADO-Recordset-Eigenschaften und -Methoden umgehen
493
Listing 12.12: Eine die Eigenschaft RecordCount nicht unterstützende Datensatzgruppe Sub CountRecordsBad() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.Open "Select * from tblProjects" Debug.Print rst.RecordCount rst.Close Set rst = Nothing End Sub
'Gibt -1 aus
Da der Parameter CursorType standardmäßig den Wert adOpenForwardOnly aufweist ist und ein nur Vorwärtsbewegungen gestattender Cursor die Eigenschaft RecordCount nicht unterstützt, wird im Direktfenster -1 ausgegeben. Listing 12.13 behebt dieses Problem. Listing 12.13: Eine die Eigenschaft RecordCount unterstützende Datensatzgruppe Sub CountRecordsGood() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenStatic rst.Open "Select * from tblProjects" Debug.Print rst.RecordCount rst.Close Set rst = Nothing
'Gibt RecordCount aus
End Sub
Beachten Sie, dass CursorType auf adOpenStatic gesetzt wird. Da statische Cursors die Eigenschaft RecordCount unterstützen, wird die korrekte Anzahl von Datensätzen im Direktfenster ausgegeben. Falls Sie mit der DAO-Eigenschaft RecordCount vertraut sind, wird Sie die ADO-Eigenschaft RecordCount möglicherweise überraschen. Bei DAO gibt die Eigenschaft RecordCount lediglich die Anzahl der besuchten Datensätze der Datensatzgruppe zurück. Dies bedeutet, dass Sie sich beim Verwenden von DAO auf dem letzten Datensatz der Datensatzgruppe bewegen müssen, um eine genaue Zählung der Datensätze zu erhalten. Obwohl dieser Schritt bei der Verwendung von ADO überflüssig ist, müssen Sie beachten, dass der Versuch, die Eigenschaft RecordCount abzurufen, zu einem gravierenden Leistungseinbruch führen kann. Ob sich das Abrufen von RecordCount nachteilig auf die Leistung auswirkt, hängt vom jeweiligen Datenanbieter der Datenbank ab.
494
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Eine wichtige Verwendung der Eigenschaft RecordCount besteht in der Feststellung, dass eine Datensatzgruppe Datensätze enthält. Dieser wichtige Verwendungszweck der Eigenschaft RecordCount wird in Listing 12.14 veranschaulicht. Listing 12.14: Überprüfung, ob in einer Datensatzgruppe Datensätze zurückgegeben werden Sub CheckARecordset() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenStatic rst.Open "Select * from tblEmpty" If Not AreThereRecords(rst) Then MsgBox "Recordset Empty...Unable to Proceed" End If rst.Close Set rst = Nothing End Sub Function AreThereRecords(rstAny As ADODB.Recordset) As Boolean AreThereRecords = rstAny.RecordCount End Function
Die Routine CheckARecordset öffnet eine auf der Tabelle mit der Bezeichnung tblEmpty basierende Datensatzgruppe. Die Tabelle tblEmpty enthält keine Daten. Die Routine CheckARecordset ruft die Funktion AreThereRecords auf und übergibt ihr einen Verweis auf die Datensatzgruppe. Die Funktion AreThereRecords wertet die Eigenschaft RecordCount der ihr übergebenen Datensatzgruppe aus. Sie gibt den Wert False zurück, wenn RecordCount den Wert Null aufweist, und True, wenn der Parameter RecordCount einen anderen Wert als Null hat.
12.5.4
Datensätze sortieren, filtern und finden
Manchmal ist das Sortieren, Filtern und Finden von Daten innerhalb einer Datensatzgruppe erforderlich. Die Eigenschaften Sort und Filter sowie die Methode Find ermöglichen Ihnen das Durchführen dieser Aufgaben. Diese Methoden werden in den folgenden Abschnitten erläutert. Eine Datensatzgruppe sortieren Die Eigenschaft Sort ermöglicht Ihnen das Sortieren der Daten einer bestehenden Datensatzgruppe. Ihre Verwendung wird in Listing 12.15 dargestellt.
Mit ADO-Recordset-Eigenschaften und -Methoden umgehen
495
Listing 12.15: Die Eigenschaft Sort des Recordset-Objekts Sub SortRecordset() Dim rst As ADODB.Recordset Dim intCounter As Integer Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorLocation = adUseClient rst.Open "Select * from tblTimeCardHours" Debug.Print "NOT Sorted!!!" Do Until rst.EOF Debug.Print rst![DateWorked] rst.MoveNext Loop Debug.Print "Now Sorted!!!" rst.Sort = "[DateWorked]" Do Until rst.EOF Debug.Print rst![DateWorked] rst.MoveNext Loop rst.Close Set rst = Nothing End Sub
Der Code beginnt, indem eine auf den tblTimeCardHours-Tabellen aufbauende Datensatzgruppe geöffnet wird. Die Ausgabe der Datensätze der Datensatzgruppe erfolgt in ihrer »natürlichen« Reihenfolge. Als nächstes werden die Daten mit Hilfe der Eigenschaft Sort nach dem Feld DateWorked sortiert. Beachten Sie, dass die Eigenschaft Sort auf einen Feldwert gesetzt wird. Wenn Sie eine Sortierung nach mehr als einem Feld vornehmen wollen, müssen die Feldnamen durch Kommata voneinander getrennt werden. Wenn die Datensätze erneut ausgegeben werden, erscheinen sie in der durch das Feld DateWorked vorgegebenen Reihenfolge. Zum Sortieren in absteigender Reihenfolge muss auf den Feldnamen ein Leerzeichen und danach das Schlüsselwort DESC folgen.
Eine Datensatzgruppe filtern In manchen Fällen kann es vorkommen, dass Sie aus den in einer Datensatzgruppe zurückgegebenen Daten eine Untermenge von diesen auswählen wollen. Die Eigenschaft Filter hilft Ihnen beim Durchführen dieser Aufgabe. Ihre Verwendung wird in Listing 12.16 verdeutlicht.
496
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Listing 12.16: Die Eigenschaft Filter des Recordset-Objekts Sub FilterRecordSet() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenKeyset rst.LockType = adLockOptimistic rst.Open "Select * from tblTimeCardhours" Debug.Print "Without Filter" Do Until rst.EOF Debug.Print rst![DateWorked] rst.MoveNext Loop rst.Filter = "DateWorked >= #1/1/1995# and DateWorked <= #1/5/1995#" Debug.Print "With Filter" Do Until rst.EOF Debug.Print rst![DateWorked] rst.MoveNext Loop rst.Close Set rst = Nothing End Sub
In diesem Beispiel wird eine auf der Tabelle tblTimeCardHours basierende Datensatzgruppe geöffnet. Die Datensätze werden ohne Anwendung eines Filters ausgegeben. Dann wird die Eigenschaft Filter gesetzt, um die Datenmenge ausschließlich auf Datensätze zu beschränken, bei denen der Wert des Felds DateWorked zwischen 1/1/1995 und 1/5/1995 liegt. Wiederum werden die Datensätze der Datensatzgruppe ausgegeben. Es ist nicht effizient, eine große Datensatzgruppe zu erstellen und dann ausschließlich die von Ihnen benötigten Daten herauszufiltern. Wenn Sie wissen, dass Sie nur bestimmte Kriterien erfüllende Datensätze brauchen, sollten Sie anhand dieser Kriterien eine Datensatzgruppe erstellen. Der Leistungsunterschied kann schwerwiegend sein, insbesondere wenn es sich um Client-Server-Daten handelt. Insgesamt sollten Sie die Eigenschaft Filter nur einsetzen, wenn Sie es zu Anfang mit einer umfangreichen Menge von Datensätzen zu tun haben und dann mit einer Untermenge dieser Datensätze eine Operation durchführen müssen.
Um nach der Anwendung eines Filters zur vollständigen Datensatzmenge zurückzukehren, setzen Sie die Eigenschaft Filter auf eine Zeichenfolge mit der Länge Null (»«).
Mit ADO-Recordset-Eigenschaften und -Methoden umgehen
497
Einen bestimmten Datensatz in einer Datensatzgruppe finden Die Methode Find ermöglicht es Ihnen, einen bestimmten Datensatz innerhalb einer Datensatzgruppe zu finden. Sie unterscheidet sich von der Eigenschaft Filter darin, dass alle Datensätze der Datensatzgruppe verfügbar bleiben. Listing 12.17 veranschaulicht die Verwendung der Methode Find. Listing 12.17: Die Methode Find eines Recordset-Objekts Sub FindProject(lngValue As Long) Dim rst As ADODB.Recordset Dim strSQL As String Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenStatic rst.Open "Select * from tblProjects" strSQL = "[ProjectID] = " & lngValue rst.Find strSQL If rst.EOF Then MsgBox lngValue & " Not Found" Else MsgBox lngValue & " Found" End If rst.Close Set rst = Nothing End Sub
Da die Routine FindProject in mehr als einem Modul erscheint, muss sie wie folgt aufgerufen werden: Call basADORecordsets.FindProject(1) Indem man der Bezeichnung der Routine den Namen des Moduls voranstellt, wird die Unklarheit hinsichtlich der Frage ausgeräumt, welche FindProject-Routine ausgeführt werden soll. In diesem Beispiel wird eine auf allen Datensätzen der Tabelle tblProjects basierende Datensatzgruppe geöffnet. Mit Hilfe der Methode Find wird der erste Datensatz gefunden, dessen ProjectID einem bestimmten Wert entspricht. Falls kein Datensatz gefunden wird, hat die Eigenschaft EOF des Recordset-Objekts den Wert True.
498
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Im Gegensatz zu seinem DAO-Gegenstück unterstützt ADO nicht die Eigenschaften FindFirst, FindNext, FindPrevious und FindLast. Die Standardverwendung der Methode Find findet den »nächsten« die angegebenen Kriterien erfüllenden Datensatz. Dies bedeutet, dass sich der Datensatzzeiger am Anfang der Datensatzgruppe befinden muss, da die entsprechenden Datensätze sonst möglicherweise nicht gefunden werden. Die Parameter SkipRows, SearchDirection und Start der Methode Find ändern dieses Standardverhalten. Der Parameter SkipRows ermöglicht Ihnen die Angabe der Entfernung von der aktuellen Zeile zur Festlegung des Suchanfangs. Mit Hilfe des Parameters SearchDirection können Sie bestimmen, ob die Suche von der aktuellen Zeile aus vorwärts oder rückwärts erfolgen soll. Schließlich legt der Parameter Start den Ausgangspunkt der Suche fest.
12.5.5
Die Eigenschaft AbsolutePosition
Die Eigenschaft AbsolutePosition eines Recordset-Objekts setzt oder erwirkt die Rückgabe der Position der aktuellen Zeile innerhalb der Datensatzgruppe. Ihre Verwendung wird in Listing 12.18 verdeutlicht. Listing 12.18: Die Eigenschaft AbsolutePosition eines Recordset-Objekts Sub FindPosition(lngValue As Long) Dim rst As ADODB.Recordset Dim strSQL As String Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenStatic rst.Open "Select * from tblProjects" strSQL = "[ProjectID] = " & lngValue rst.Find strSQL If rst.EOF Then MsgBox lngValue & " Not Found" Else Debug.Print rst.AbsolutePosition End If rst.Close Set rst = Nothing End Sub
In diesem Beispiel dient die Methode Find zum Finden eines Projekts mit einer bestimmten ProjectID. Falls das Projekt gefunden wird, wird die Position des gefundenen Datensatzes im Direktfenster ausgegeben.
Mit ADO-Recordset-Eigenschaften und -Methoden umgehen
12.5.6
499
Die Eigenschaft Bookmark
Die Eigenschaft Bookmark eines Recordset-Objekts gibt eine Variant-Variable zurück, die als eindeutiger Bezeichner für diesen bestimmten Datensatz dieser Datensatzgruppe dient. Die Eigenschaft Bookmark wird eingesetzt, um die aktuelle Position zu speichern und sie jederzeit schnell und einfach zurückzugeben. Dies wird in Listing 12.19 veranschaulicht. Listing 12.19: Die Eigenschaft Bookmark eines Recordset-Objekts Sub UseBookMark() Dim rst As ADODB.Recordset Dim strSQL As String Dim vntPosition As Variant Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenStatic rst.Open "Select * from tblProjects" vntPosition = rst.Bookmark Do Until rst.EOF Debug.Print rst!ProjectID rst.MoveNext Loop rst.Bookmark = vntPosition Debug.Print rst!ProjectID rst.Close Set rst = Nothing End Sub
In diesem Beispiel wird ein eindeutiger Bezeichner für den aktuellen Datensatz in einer Variable vom Typ Variant gespeichert. Der Code arbeitet dann die restlichen Datensätze der Datensatzgruppe mit Hilfe einer Schleife ab. Wenn dies abgeschlossen ist, wird die Eigenschaft Bookmark des Recordset-Objekts auf den Wert des in der Variant-Variablen abgelegten eindeutigen Bezeichners gesetzt. Nicht alle Datensatzgruppen unterstützen den Parameter Bookmark. Ob dies zutrifft, hängt sowohl vom Datenanbieter als auch vom Typ der erstellten Datensatzgruppe ab.
500
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
12.5.7
Parameterabfragen ausführen
Zum Zeitpunkt des Entwurfs werden Ihnen die Kriterien für eine Datensatzgruppe nicht immer bekannt sein. Glücklicherweise ermöglicht Ihnen ADO das Angeben von Parametern für die Eigenschaft CommandText des Command-Objekts. Listing 12.20 stellt ein Beispiel bereit. Listing 12.20: Eine Parameterabfrage ausführen Sub RunParameterQuery(datStart As Date, datEnd As Date) Dim cmd As ADODB.Command Dim rst As ADODB.Recordset Set cmd = New ADODB.Command cmd.ActiveConnection = CurrentProject.Connection cmd.CommandText = "Select * from tblTimeCardHours " & _ "Where DateWorked Between ? and ?" cmd.CommandType = adCmdText Set rst = cmd.Execute(Parameters:=Array(datStart, datEnd)) Do Until rst.EOF Debug.Print rst![TimeCardID], rst![DateWorked] rst.MoveNext Loop rst.Close Set rst = Nothing Set cmd = Nothing End Sub
Beachten Sie in diesem Beispiel, dass die Eigenschaft CommandText zwei Fragezeichen enthält. Jedes von ihnen wird als Parameter betrachtet. Die Parameter werden beim Aufrufen der Methode Execute des Command-Objekts angegeben. Beachten Sie, dass dem Argument Parameters der Methode Execute ein Feld mit den Parameterwerten übergeben wird.
12.6
Tabellendaten mit Hilfe von ADO-Code bearbeiten
Bis zu diesem Zeitpunkt wurde in diesem Kapitel lediglich der Prozess zum Abrufen von Daten aus einer Datensatzgruppe erläutert. Es geschieht häufig, dass Sie die Daten einer Datensatzgruppe aktualisieren müssen. Die folgenden Abschnitte zeigen Ihnen, wie Sie Daten datensatzweise ändern, einen Stapel von Datensätzen aktualisieren, Datensätze löschen und Datensätze hinzufügen können.
Tabellendaten mit Hilfe von ADO-Code bearbeiten
12.6.1
501
Datensätze einzeln ändern
Es ist möglich, eine Datensatzgruppe mit Hilfe einer Schleife zu durchlaufen und alle darin enthaltenen Datensätze zu verändern. Dieses Verfahren wird in Listing 12.21 vorgestellt. Listing 12.21: Datensätze einzeln verändern Sub IncreaseEstimate() Dim Set Dim Dim
rst As ADODB.Recordset rst = New ADODB.Recordset strSQL As String intUpdated As Integer
rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenDynamic rst.LockType = adLockOptimistic rst.Open ("Select * from tblProjectsChange") strSQL = "ProjectTotalEstimate < 30000" intUpdated = 0 rst.Find strSQL Do Until rst.EOF intUpdated = intUpdated + 1 rst!ProjectTotalEstimate = rst!ProjectTotalEstimate * 1.1 rst.Update rst.Find strSQL, 1, adSearchForward Loop Debug.Print intUpdated & " Records Updated" rst.Close Set rst = Nothing End Sub
In diesem Beispiel wird eine auf allen Datensätzen der Tabelle tblProjectsChange basierende Datensatzgruppe geöffnet. Der erste Datensatz wird gefunden, bei dem der Wert von ProjectTotalEstimate unter 30.000 liegt. Der Wert von ProjectTotal Estimate wird um 10 Prozent erhöht und der Datensatz aktualisiert. Dann wird der nächste die Kriterien erfüllende Datensatz gesucht. Dieser Prozess setzt sich fort, bis alle den angegebenen Kriterien entsprechenden Datensätze gefunden wurden. Dieser Code ist aus verschiedenen Gesichtspunkten ineffizient. Das erste Problem liegt darin, dass eine auf allen Datensätzen der Tabelle tblProjectsChange aufbauende Datensatzgruppe geöffnet wird, obwohl lediglich die Datensätze aktualisiert werden müssen, bei denen der Wert von ProjectTotalEstimate kleiner als 30.000 ist.
502
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Ein wirksamerer Ansatz bestünde darin, eine Datensatzgruppe zu öffnen, die lediglich die zu aktualisierenden Datensätze enthält. Außerdem wäre es zweckmäßiger, zum Durchführen der Aktualisierung einfach eine Aktionsabfrage auszuführen. Dies wird im folgenden Abschnitt besprochen. Wenn Sie DAO gewohnt sind, wird Ihnen das Verhalten von ADO möglicherweise eine Überraschung bereiten. Erstens wird bei ADO keine Edit-Methode verwendet, während bei DAO deren Verwendung vor dem Zuweisen von Feldwerten erforderlich ist. Außerdem wird ein Datensatz nicht aktualisiert, wenn Sie vergessen, die Methode Update für eine DAO-Datensatzgruppe aufzurufen. Im Gegensatz dazu ist bei ADO die Methode Update integriert. Die Aktualisierung erfolgt automatisch, sobald der Datensatzzeiger bewegt wird. Diese Verhaltensunterschiede können zu großen Überraschungen führen!
12.6.2
Veränderungen an mehreren Datensätzen vornehmen
Wie im vorhergehenden Abschnitt erwähnt, ist es nicht effizient, eine Datensatzgruppe zu öffnen und dann jeden Datensatz einzeln zu aktualisieren. Wesentlich wirksamer ist das Ausführen einer Aktionsabfrage. Listing 12.22 veranschaulicht diesen Prozess. Listing 12.22: Veränderungen an mehreren Datensätzen einer Datensatzgruppe vornehmen Sub RunUpdateQuery() Dim cnn As ADODB.Connection Set cnn = New ADODB.Connection cnn.Open CurrentProject.Connection cnn.Execute "qryIncreaseTotalEstimate" cnn.Close End Sub
In diesem Beispiel wird mit Hilfe der Methode Execute des Connection-Objekts eine gespeicherte Abfrage mit der Bezeichnung qryIncreaseTotalEstimate ausgeführt und alle in der Abfrage enthaltenen Kriterien werden angewendet.
12.6.3
Einen vorhandenen Datensatz löschen
Sie können mit Hilfe von ADO-Code einen Datensatz in einer Datensatzgruppe löschen. Der Code erscheint in Listing 12.23. Listing 12.23: Einen vorhandenen Datensatz löschen Sub DeleteCusts(lngProjEst As Long) Dim rst As ADODB.Recordset Dim intCounter As Integer
Tabellendaten mit Hilfe von ADO-Code bearbeiten
503
Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenDynamic rst.LockType = adLockOptimistic rst.Open "Select * from tblProjectsChange" intCounter = 0 Do Until rst.EOF If rst!ProjectTotalEstimate < lngProjEst Then rst.Delete intCounter = intCounter + 1 End If If Not rst.EOF Then rst.MoveNext End If Loop Debug.Print intCounter & " Customers Deleted" rst.Close Set rst = Nothing End Sub
Bei diesem Beispiel wird eine Datensatzgruppe basierend auf allen Datensätzen der Tabelle tblProjectsChange geöffnet. Der Code arbeitet alle Datensätze der Datensatzgruppe über eine Schleife ab. Falls der Wert von ProjectTotalEstimate unter dem der Routine als Parameter übergebenen Wert liegt, wird der Datensatz mit Hilfe der Methode Delete des Recordset-Objekts aus der Datensatzgruppe gelöscht. Wie in Listing 12.21 erläutert, ist dieses Beispiel sehr ineffizient. Sie könnten entweder eine Datensatzgruppe ausschließlich mit den zu löschenden Datensätzen öffnen oder diese Aufgabe mit einer Aktionsabfrage durchführen. Wenn Sie einen Provider verwenden, der gespeicherte Prozeduren unterstützt, ist es am wirksamsten, Daten mit Hilfe von gespeicherten Prozeduren hinzuzufügen, zu bearbeiten und zu löschen, da gespeicherte Prozeduren auf dem Server ausgeführt werden und keine Daten über das Netzwerkkabel senden.
12.6.4
Einen neuen Datensatz hinzufügen
Sie können mit Hilfe von ADO Daten nicht nur bearbeiten und löschen, sondern auch Datensätze hinzufügen. Dieser Vorgang wird in Listing 12.24 erläutert. Listing 12.24: Einer Datensatzgruppe einen neuen Datensatz hinzufügen Private Sub cmdAddADO_Click() Dim rst As ADODB.Recordset
504
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
If IsNull(Me.txtProjectName) Or _ IsNull(Me.cboClientID) Then MsgBox "The Project Name and Client must be Filled In" Else Set rst = New ADODB.Recordset With rst .ActiveConnection = CurrentProject.Connection .CursorType = adOpenKeyset .LockType = adLockOptimistic .Open "Select * from tblProjectsChange Where ProjectID = 0" .AddNew !ProjectName = Me.txtProjectName !ProjectDescription = Me.txtProjectDescription !ClientID = Me.cboClientID .Update Me.txtProjectID = !ProjectID End With End If End Sub
Dieser Code, eine Ereignisprozedur für eine Befehlsschaltfläche auf der Basis von frmUnbound, beginnt, indem er die Eigenschaft CursorType der Datensatzgruppe auf adOpenKeyset und die Eigenschaft LockType auf adLockOptimistic setzt. Mit Hilfe der Methode AddNew wird ein Puffer für einen neuen Datensatz erstellt. Alle Feldwerte werden auf der Grundlage der in den Textfeldern des Formulars enthaltenen Werte zugewiesen. Die Methode Update schreibt die Daten auf die Festplatte. Da das Feld ProjectID ein Feld des Typs AutoWert darstellt, wird das Textfeld txtProjectIP aktualisiert, sodass es den zugewiesenen AutoWert-Wert wiedergibt. Bei DAO befinden Sie sich nach dem Hinzufügen eines neuen Datensatzes nicht an dessen Position. Bei ADO steuern Sie beim Aufrufen der Methode Update die Position des neuen Datensatzes an.
12.7
Datenbankobjekte mit Hilfe von ADO-Code erstellen und bearbeiten
Obwohl Sie in den meisten Fällen die Struktur Ihrer Datenbank vor dem Einsetzen Ihrer Anwendung entwerfen, kann es vorkommen, dass Sie Datenbankobjekte zur Laufzeit gestalten oder verändern müssen. Glücklicherweise können Sie diese Aufgabe mit Hilfe von ADO-Code erledigen. In den folgenden Abschnitten wird das
Datenbankobjekte mit Hilfe von ADO-Code erstellen und bearbeiten
505
Hinzufügen und Löschen von Tabellen, das Verändern von Beziehungen und Erstellen von Abfragen erläutert, wobei in allen Fällen ADO-Code zum Einsatz kommt. Dies sind nur einige der Aufgaben, die Sie durchführen können.
12.7.1
Mit Hilfe von Code eine Tabelle hinzufügen
Es ist verhältnismäßig einfach, mit Hilfe von ADO-Code eine Tabelle hinzuzufügen. In Listing 12.25 finden Sie ein Beispiel. Listing 12.25: Eine Tabelle hinzufügen Sub CreateTable() Dim cat As ADOX.Catalog Dim tdf As ADOX.Table Dim idx As ADOX.Index Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection 'Eine neue Tabelle erstellen Set tdf = New ADOX.Table 'Der Tabellendefinition ein Feld hinzufügen With tdf .Name = "tblFoods" Set .ParentCatalog = cat .Columns.Append "FoodID", adInteger .Columns("FoodID").Properties("AutoIncrement") = True .Columns.Append "Description", adWChar .Columns.Append "Calories", adInteger End With cat.Tables.Append tdf Set idx = New ADOX.Index idx.Name = "PrimaryKey" idx.Columns.Append "FoodID" idx.PrimaryKey = True idx.Unique = True tdf.Indexes.Append idx Set idx = Nothing Set cat = Nothing End Sub
506
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Der Code beginnt mit der Erstellung eines ADOX-Tabellenobjekts und setzt die Eigenschaften Name und ParentCatalog des Table-Objekts. Dann verwendet er die Methode Append der Columns-Auflistung der Tabelle, um alle Felder an diese anzuhängen. Nach dem Anfügen aller Spalten fügt der Code das Table-Objekt mit Hilfe der Methode Append der Tables-Auflistung des Catalog-Objekts an die Datenbank an. Nach dem Anhängen der Tabelle an das Catalog-Objekt lassen sich der Tabelle Indizes hinzufügen. Es wird eine Instanz eines Index-Objekts erstellt und deren Eigenschaft Name gesetzt. Als nächstes wird mit Hilfe der Methode Append des IndexObjekts diesem eine Spalte hinzugefügt. Die Indexeigenschaften PrimaryKey und Unique werden beide auf den Wert True gesetzt. Zum Abschluss erfolgt das Anhängen des Index-Objekts an die Indexes-Auflistung des Table-Objekts. Beim Ausführen von Code zum Anhängen eines Objekts tritt ein Fehler auf, falls dieses Objekt bereits vorhanden ist. Sie müssen in Ihrer Routine entweder eine Fehlerbehandlung zum Handhaben dieser Möglichkeit einschließen oder die bestehende Objektinstanz vor der Anfügung des neuen Objekts löschen.
12.7.2
Mit Hilfe von Code eine Tabelle entfernen
In manchen Fällen ist es erforderlich, eine Tabelle aus einer Datenbank zu entfernen. Glücklicherweise lässt sich dies mit Hilfe von ADO-Code einfach bewerkstelligen. Der Ablauf wird in Listing 12.26 veranschaulicht. Listing 12.26: Eine Tabelle entfernen Sub DeleteTable() Dim cat As ADOX.Catalog Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection cat.Tables.Delete "tblFoods" End Sub
Zunächst wird ein Catalog-Objekt deklariert und eine Instanz von diesem gebildet. Dann wird die Methode Delete der Tables-Auflistung des Catalog-Objekts verwendet, um die Tabelle aus der Datenbank zu entfernen.
12.7.3
Mit Hilfe von Code Beziehungen einrichten
Falls Ihre Anwendung einer Datenbank neue Tabellen hinzufügt, könnte das Einrichten neuer Beziehungen zwischen diesen Tabellen erforderlich werden. Listing 12.27 zeigt, wie man eine Beziehung zwischen zwei Tabellen einer Datenbank erstellt.
Datenbankobjekte mit Hilfe von ADO-Code erstellen und bearbeiten
507
Listing 12.27: Eine Beziehung einrichten Sub CreateRelation() Dim cat As ADOX.Catalog Dim tbl As ADOX.Table Dim fk As ADOX.Key Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection Set tbl = cat.Tables("tblPeople") Set fk = New ADOX.Key fk.Name = "PeopleFood" fk.Type = adKeyForeign fk.RelatedTable = "tblFoods" fk.Columns.Append "FoodId" fk.Columns("FoodID").RelatedColumn = "FoodID" tbl.Keys.Append fk Set cat = Nothing Set tbl = Nothing Set fk = Nothing End Sub
Der Code beginnt, indem er ein Table-Objekt auf eine Tabelle mit den Fremdschlüsseln in der Beziehung weisen lässt. Eine Instanz eines Key-Objekts wird erstellt und dessen Eigenschaft Name gesetzt. Als nächstes wird die Eigenschaft Type des KeyObjekts eingerichtet. Die Eigenschaft RelatedTable wird auf den Namen der an der Beziehung beteiligten Tabelle mit den Primärschlüsseln gesetzt. Mit Hilfe der Methode Append der Columns-Auflistung des Key-Objekts wird das Feld mit dem Fremdschlüssel an das Key-Objekt angehängt. Danach setzt der Code die Eigenschaft RelatedColumn der Spalte auf den Wert des Namens des Felds mit dem Primärschlüssel. Abschließend wird das Key-Objekt der Keys-Auflistung des Table-Objets angehängt.
12.7.4
Mit Hilfe von Code eine Abfrage erstellen
Manchmal kann es erforderlich werden, auf die Schnelle eine Abfrage zu erstellen und diese dauerhaft in einem Teil der Datenbank zu speichern. Listing 12.28 verdeutlicht diesen Prozess. Listing 12.28: Eine Abfrage erstellen Sub CreateQuery() Dim cat As ADOX.Catalog Dim cmd As ADODB.Command Dim strSQL As String
508
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection Set cmd = New ADODB.Command cmd.CommandText = "Select * From tblClients Where State='CA'" cat.Views.Append "qryCAClients", cmd cat.Views.Refresh Set cat = Nothing Set cmd = Nothing End Sub
Der Code erstellt zunächst ein Catalog- und ein Command-Objekt und bildet eine Instanz von diesen. Die Eigenschaft CommandText des Command-Objekts wird auf den Namen der SQL-Anweisung gesetzt, die der Abfrage zu Grunde liegt. Mit Hilfe der Methode Append der Views-Auflistung des Catalog-Objekts wird das Command-Objekt an die mit dem angegebenen Namen bezeichnete Abfrage angehängt und die ViewAuflistung des Catalog-Objekts dann aufgefrischt.
12.8
Das Datenzugriffsobjektmodell (DAO)
Abbildung 12.2 zeigt einen Überblick über das Datenzugriffsobjektmodell für die Datenbank-Engine Jet 4.0. An der Spitze der Hierarchie befindet sich die als DBEngine-Objekt bezeichnete Jet-Datenbank-Engine von Microsoft. Das DBEngine-Objekt enthält all die anderen Objekte, die Bestandteil der Hierarchie sind. Es ist das einzige Objekt, das nicht über eine mit ihm verbundene Auflistung verfügt. Jedes Objekt innerhalb des Datenzugriffsobjektmodells ist wichtig, da Sie die verschiedenen Objekte mit Hilfe von Code zur Laufzeit bearbeiten werden, um die für Ihre Anwendung erforderlichen Aufgaben durchzuführen. In den folgenden Abschnitten werden jedes bedeutendere Objekt und seine Auswirkungen auf Ihre Programmiertätigkeit beschrieben.
12.8.1
Workspaces
Die Workspaces-Auflistung enthält Workspace-Objekte, von denen jedes einen bestimmten von einem Benutzer verwendeten Bereich definiert. Die gesamten Sicherheits- und Transaktionsabläufe für einen gegebenen Benutzer finden innerhalb eines bestimmten Workspace statt. Sie können mit Hilfe eines Programms mehrere Workspaces erstellen. Das ist von großem Wert, da Sie sich mit Hilfe dieses Verfahrens im Hintergrund unter einem anderen Benutzernamen anmelden und Aufgaben erledigen können, die mit der Sicherheitsstufe des aktuellen Benutzers nicht gestattet wären. Sie können sich beispielsweise als Mitglied der Gruppe Admins
Das Datenzugriffsobjektmodell (DAO)
509
anmelden, die Struktur einer Tabelle ändern, wozu der aktuelle Benutzer nicht berechtigt wäre, und sich wieder abmelden, ohne dass der Benutzer des Systems jemals erfährt, ob irgend etwas geschehen ist.
12.8.2
Users
Die Users-Auflistung enthält die User-Objekte für einen bestimmten Workspace. Jedes User-Objekt ist ein durch eine Arbeitsgruppendatenbank definiertes Benutzerkonto. Da jeder Benutzer Mitglied einer oder mehrerer Gruppen ist, enthält jedes User-Objekt eine Groups-Auflistung, die aus den Gruppen besteht, in denen ein bestimmter Benutzer Mitglied ist. User-Objekte lassen sich zur Laufzeit einfach hinzufügen und bearbeiten.
12.8.3
Groups
Die Groups-Auflistung enthält alle Group-Objekte für einen bestimmten Workspace. Jedes Group-Objekt ist eine durch eine Arbeitsgruppendatenbank definierte Gruppe. Da jede Gruppe Benutzer enthält, weist das Group-Objekt eine Users-Auflistung mit allen Benutzern auf, die Mitglied der Gruppe sind. Wie User-Objekte lassen sich Group-Objekte zur Laufzeit einfach hinzufügen und bearbeiten. DBEngine
Workspace Datenbank
TableDef
QueryDef
Feld
Feld
Recordset
Feld
Relation
Container
Feld
Dokument
Anwender
Gruppe
Gruppe
Anwender
Abbildung 12.2: Das DAO-Objektmodell
Index Parameter Feld
Fehler
12.8.4
Databases
Die Databases-Auflistung enthält alle momentan geöffneten Datenbanken eines bestimmten Workspace. Sie können mehrere Datenbanken gleichzeitig öffnen. Bei diesen geöffneten Datenbanken kann es sich um Jet-Datenbanken oder um externe Datenbanken handeln. Ein Database-Objekt bezeichnet eine bestimmte Datenbank innerhalb der Databases-Auflistung. Wie in Listing 12.29 gezeigt, ist es kein Problem, mit Hilfe einer Schleife die Databases-Auflistung zu durchlaufen und den Namen jedes darin enthaltenen Database-Objekts zu drucken.
510
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Listing 12.29: Den Namen jeder Datenbank in einem Workspace drucken Sub EnumerateDBs() Dim ws As Workspace Dim db As Database Dim db1 As Database Dim db2 As Database Set ws = DBEngine(0) Set db1 = CurrentDb Set db2 = ws.OpenDatabase("Chap9.MDB") For Each db In ws.Databases Debug.Print db.Name Next db End Sub
Der Code geht mit Hilfe einer Schleife die geöffneten Datenbanken im aktuellen Workspace durch und druckt den Namen jeder geöffneten Datenbank. Weiterhin ist es problemlos möglich, all die anderen zum Erstellen, Verändern und Bearbeiten von Database-Objekten erforderlichen Arbeiten zur Laufzeit durchzuführen.
12.8.5
TableDefs
Die TableDefs-Auflistung enthält alle in einer bestimmten Datenbank zusammengefassten Tabellen, ob diese nun geöffnet oder geschlossen sind. Außerdem enthält die TableDefs-Auflistung verknüpfte Tabellen und eingehende Informationen über alle Tabellen. Man kann die TableDefs-Auflistung problemlos mit Hilfe einer Schleife abarbeiten und verschiedene Eigenschaften (wie beispielsweise den Namen) jedes Table-Objekts innerhalb der Auflistung drucken. Listing 12.30 zeigt ein Beispiel, in dem anhand der TableDefs-Auflistung die Eigenschaften jedes Table-Objekts sowie die Eigenschaften von jedem Index der Tabelle gedruckt werden.
12.8.6
Indexes
Jedes TableDef-Objekt enthält eine Indexes-Auflistung, die alle Indizes der Tabelle auflistet. Jeder Index umfasst seinerseits eine zum Beschreiben der Indexfelder dienende Fields-Auflistung. Listing 12.30: Verwenden der TableDefs- und Indexes-Auflistung Sub EnumerateTablesAndIndexes() Dim db As Database Dim tbl As dao.TableDef Dim idx As dao.Index Dim fld As dao.Field
Das Datenzugriffsobjektmodell (DAO)
511
Set db = CurrentDb For Each tbl In db.TableDefs Debug.Print "Table: "; tbl.Name For Each idx In tbl.Indexes Debug.Print " Index: "; idx.Name Debug.Print " Primary="; idx.PRIMARY; ", Unique="; idx.Unique For Each fld In idx.Fields Debug.Print " Field:"; fld.Name Next fld Next idx Next tbl End Sub
Der Code arbeitet mit einer Schleife die Tabellendefinitionen der aktuellen Datenbank ab und druckt den Namen jeder in der Datenbank enthaltenen Tabelle. Danach druckt er den Namen jedes Tabellenindex und den aller darin enthaltenen Felder. Man kann problemlos Code schreiben, um Tabellen und Indizes zur Laufzeit hinzuzufügen, zu entfernen, zu verändern oder anderweitig zu bearbeiten.
12.8.7
QueryDefs
Die QueryDefs-Auflistung schließt alle in einer bestimmten Datenbank enthaltenen Abfragen ein. Mit Hilfe einer Schleife lässt sich die QueryDefs-Auflistung einfach durchgehen und man kann, wie in Listing 12.31 gezeigt, verschiedene Informationen über jede Abfrage ausdrucken. Listing 12.31: Mit Hilfe der QueryDefs-Auflistung Informationen über alle Abfragen drucken Sub EnumerateQueries() Dim db As Database Dim qry As QueryDef Set db = CurrentDb For Each qry In db.QueryDefs Debug.Print qry.Name Debug.Print qry.SQL Next qry End Sub
Dieser Code geht mit Hilfe einer Schleife die Abfragedefinitionen der aktuellen Datenbank durch und druckt den Namen und die mit jeder QueryDef verbundene SQL-Anweisung. Man kann problemlos Code schreiben, um Abfragen zur Laufzeit hinzuzufügen, zu entfernen, zu verändern oder anderweitig zu bearbeiten.
512
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
12.8.8
Fields
Fields-Auflistungen sind in TableDef-, QueryDef-, Index-, Relation- und RecordsetObjekten enthalten. Die Fields-Auflistung eines Objekts stellt die Auflistung der Feldobjekte innerhalb des übergeordneten Objekts dar. Ein TableDef-Objekt enthält Field-Objekte, die zum Beispiel in der speziellen Tabelle enthalten sind. Mit Hilfe
des übergeordneten Objekts können Sie, wie in Listing 12.32 gezeigt, Informationen über dessen Fields-Auflistung erhalten. Listing 12.32: Informationen aus der Fields-Auflistung gewinnen Sub EnumerateFields() Dim db As Database Dim tbl As TableDef Dim fld As Field Set db = CurrentDb For Each tbl In db.TableDefs For Each fld In tbl.Fields Debug.Print fld.Name Debug.Print fld.Type Next fld Next tbl End Sub
Dieser Code arbeitet mit einer Schleife die Tabellendefinitionen der aktuellen Datenbank ab. Dabei druckt er den Namen und Typ jedes in der Fields-Auflistung der TableDef aufgeführten Felds. Mit Hilfe von Code lassen sich auch zur Laufzeit Feldattribute hinzufügen, entfernen oder verändern. Bei einer großen Datenbank gibt dieser Code vermutlich mehr Informationen aus, als im Puffer des Direktfensters Platz haben. Es wäre sinnvoll, an einer beliebigen Stelle eine Pause in den Code einzufügen, um sich den Inhalt des Direktfensters ansehen zu können. Beachten Sie, dass es sich bei der Eigenschaft Type um einen ganzzahligen Wert handelt. Jeder von dieser Eigenschaft zurückgegebene Integer-Wert verkörpert einen anderen Feldtyp. Es ist sinnvoll, eine case-Anweisung zu schreiben, die den Integer-Wert in eine aussagefähigere Textzeichenfolge umwandelt.
12.8.9
Parameters
Access-Abfragen können Parameter enthalten. Diese Parameter werden erstellt, so dass der Benutzer zur Laufzeit von der Abfrage benötigte Informationen angeben kann. Jedes QueryDef-Objekt verfügt über eine aus Parameter-Objekten bestehende Parameters-Auflistung. Wie in Listing 12.33 gezeigt, können Sie Code schreiben, um diese Parameter zur Laufzeit zu bearbeiten.
Das Datenzugriffsobjektmodell (DAO)
513
Listing 12.33: Eine Liste der Parameter aller Abfragen erstellen Sub EnumerateParameters() Dim db As Database Dim qry As QueryDef Dim prm As Parameter Set db = CurrentDb For Each qry In db.QueryDefs Debug.Print "*****" & qry.Name & "*****" For Each prm In qry.Parameters Debug.Print prm.Name Next prm Next qry End Sub
Dieser Code geht mit Hilfe einer Schleife das QueryDefs-Objekt der aktuellen Datenbank durch. Er druckt den Namen des QueryDefs-Objekts und durchläuft mit einer Schleife dessen Parameters-Auflistung, wobei er die Bezeichnung jedes Parameters druckt. Mit Hilfe von Code können Parameter-Objekte zur Laufzeit hinzugefügt, entfernt und bearbeitet werden.
12.8.10 Recordsets Recordset-Objekte existieren ausschließlich zur Laufzeit. Ein solches Objekt dient zum Bezeichnen einer Menge von Objekten, die aus einer oder mehreren Tabellen stammen. Die Recordsets-Auflistung enthält alle Recordset-Objekte, die momentan innerhalb des aktuellen Database-Objets geöffnet sind. Recordset-Objekte werden später in diesem Kapitel im Abschnitt »Arten von DAO-Datensatzgruppen« ausführlich erläutert.
12.8.11 Relations Die Relations-Auflistung enthält alle Relation-Objekte, welche die innerhalb eines Database-Objekts eingerichteten Beziehungen beschreiben. Der Code in Listing 12.34 geht die aktuelle Datenbank mit einer Schleife durch und druckt die Table und ForeignTable des Relation-Objekts. Listing 12.34: Die Relations-Auflistung Sub EnumerateRelations() Dim db As Database Dim rel As Relation Set db = CurrentDb
514
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
For Each rel In db.Relations Debug.Print rel.Table & " Related To: " & rel.ForeignTable Next rel End Sub
Beziehungen können mit Hilfe von VBA-Code zur Laufzeit erstellt, entfernt und verändert werden.
12.8.12 Containers Die Containers-Auflistung enthält Informationen über jedes gespeicherte DatabaseObjekt. Mit Hilfe der Containers-Auflistung können Sie, wie in Listing 12.35 gezeigt, alle in der aktuellen Datenbank enthaltenen Objekte betrachten und verändern. Listing 12.35: Eine Liste aller Container einer Datenbank erstellen Sub EnumerateContainers() Dim db As Database Dim cnt As Container Set db = CurrentDb For Each cnt In db.Containers Debug.Print cnt.Name Next cnt End Sub
Der Code geht mit einer Schleife die Container-Auflistung durch und druckt den Namen jedes Container-Objekts. Das Ergebnis besteht aus DataAccessPages-, Databases-, Forms-, Modules-, Relationships-, Reports-, Scripts-, SysRel- und Tables-Objekten.
12.8.13 Dokumente Ein Document-Objekt verkörpert ein bestimmtes Objekt in der Documents-Auflistung. Sie können, wie in Listing 12.36 gezeigt, die Documents-Auflistung eines ContainerObjekts mit einer Schleife durchgehen. Listing 12.36: Alle Name-Eigenschaften von Document-Objekten drucken Sub EnumerateForms() Dim db As Database Dim cnt As Container Dim doc As Document Set db = CurrentDb Set cnt = db.Containers!Forms
Das Datenzugriffsobjektmodell (DAO)
515
For Each doc In cnt.Documents Debug.Print doc.Name Next doc End Sub
Bei diesem Code verweist ein Container-Objekt auf die Formulare der aktuellen Datenbank. Dann arbeitet der Code alle Dokumente des Container-Objekts ab und druckt die Namen aller Container-Objekte (in diesem Fall die Namen aller Formulare). Es ist wichtig, den Unterschied zwischen dem Formular-Container und der FormsAuflistung zu verstehen. Der »Formular-Container« ist ein Teil der ContainersAuflistung und enthält alle zur Datenbank gehörenden Formulare. Die Forms»Auflistung« enthält alle zur Laufzeit geöffneten Formulare. Die Eigenschaften jedes Formulars des Formular-Containers unterscheiden sich von den Eigenschaften eines Formulars der Forms-Auflistung.
12.8.14 Properties Jedes Datenzugriffsobjekt hat eine Properties-Auflistung. Die Properties-Auflistung eines Objekts stellt eine Liste der mit diesem bestimmten Objekt verbundenen Eigenschaften dar. Dies gibt Ihnen, wie in Listing 12.37 gezeigt, eine allgemeine Möglichkeit zum Betrachten und Abändern der Eigenschaften eines beliebigen Objekts. Mit Hilfe dieser Auflistung können Sie allgemeine Routinen zum Erledigen häufig anfallender Aufgaben erstellen. Sie können zum Beispiel eine Routine schreiben, um die Schriftgröße aller Steuerelemente auf 8 Punkte zu setzen. Ihre Routine würde sich der Properties-Auflistung bedienen, um sicherzustellen, dass das Steuerelement über die Eigenschaft Font verfügt, bevor sie versucht, die Schriftgröße zu setzen. Listing 12.37: Alle Eigenschaften eines Document-Objekts ausdrucken Sub EnumerateProperties() Dim db As Database Dim cnt As Container Dim doc As Document Dim prp As Property Set db = CurrentDb Set cnt = db.Containers!Forms For Each doc In cnt.Documents Debug.Print doc.Name For Each prp In doc.Properties
516
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Debug.Print prp.Name & " = " & prp.Value Next prp Next doc End Sub
Der Code geht mit Hilfe einer Schleife jedes Formular der aktuellen Datenbank durch und druckt alle Eigenschaften jedes Form-Objekts aus.
12.8.15 Errors Die Errors-Auflistung besteht aus Error-Objekten. Ein Error-Objekt enthält Informationen über den zuletzt aufgetretenen Fehler. Jedesmal, wenn eine Operation einen Fehler erzeugt, werden eventuell vorhandene vorherige Fehler aus der ErrorsAuflistung entfernt. In manchen Fällen kann eine Einzeloperation mehr als einen Fehler verursachen, so dass der Errors-Auflistung beim Auftreten eines einzelnen Datenzugriffsfehlers möglicherweise ein oder mehrere Error-Objekte hinzugefügt werden.
12.9
DBEngine
Wie erwähnt, verweist das DBEngine-Objekt auf die sich an der Spitze der Hierarchie der Datenzugriffsobjekte befindende Jet-Datenbank-Engine. Das DBEngine-Objekt enthält lediglich zwei Auflistungen: Workspaces und Errors. Zum Verweisen auf die aktuelle Datenbank können Sie die im nächsten Abschnitt besprochene Funkton CurrentDB() verwenden. Um auf eine andere als die aktuelle Datenbank zu verweisen, müssen Sie sich, wie in Listing 12.38 gezeigt, auf das DBEngine-Objekt beziehen. Listing 12.38: Auf die Eigenschaften des DBEngine-Objekts zugreifen Sub ReferToCurrentDB() Dim ws As Workspace Dim db As Database Set ws = DBEngine(0) Set db = ws.OpenDatabase("Chap11") Debug.Print db.Version End Sub
Dieser Code erzeugt eine auf den aktuellen Workspace zeigende Workspace-Objektvariable. Dann wird mit Hilfe der Methode OpenDatabase des Workspace-Objekts eine andere Datenbank geöffnet und die Datenbankversion von der Routine ausgedruckt.
CurrentDB()
12.10
517
CurrentDB()
Microsoft bietet eine Abkürzung zum Erstellen einer auf die aktuelle Datenbank verweisenden Objektvariablen an. Mit Hilfe der Funktion CurrentDB() müssen Sie weder zuerst auf den Workspace verweisen noch die Methode OpenDatabase aufrufen. Stattdessen setzen Sie, wie in Listing 12.39 gezeigt, die Database-Objektvariable auf das Ergebnis der Funktion CurrentDB(). Listing 12.39: Eine Liste der Fehler der aktuellen Datenbank erstellen Sub UseCurrentDBFunc() Dim db As Database Set db = CurrentDb() Debug.Print db.Version End Sub
Dieser Code setzt die Database-Objektvariable, so dass sie auf das aktuelle Datenbankobjekt verweist. Dann druckt sie die Version der Datenbank-Engine und alle in der Errors-Auflistung enthaltenen Fehler aus. Die Funktion CurrentDB() kann nicht zum Verweisen auf Objekte eingesetzt werden, die nicht Teil der aktuellen Datenbank sind. Wie bei allen keine Argumente benötigenden VBA-Funktionen sind die Klammern hinter CurrentDB optional.
12.11
Arten von DAO-Datensatzgruppen
Ein Recordset-Objekt verkörpert die Datensätze einer Tabelle oder die von einer Abfrage zurückgegebenen Datensätze. Es kann eine direkte Verknüpfung mit der Tabelle, eine dynamische Menge von Datensätzen oder eine Momentaufnahme (Snapshot) der Daten zu einem bestimmten Zeitpunkt darstellen. Recordset-Objekte werden zur unmittelbaren Bearbeitung von Daten einer Datenbank eingesetzt. Sie ermöglichen es Ihnen, Daten den Anforderungen Ihrer Anwendung entsprechend hinzuzufügen, zu bearbeiten, zu entfernen oder durch diese zu navigieren. DAO unterstützt drei Arten von Recordset-Objekten: Dynasets, Snapshots und Tabellen.
12.11.1
Dynasets
Sie können mit Hilfe eines Recordset-Objekts des Typs Dynaset lokale oder verknüpfte Tabellen bzw. die Ergebnisse von Abfragen bearbeiten. Bei einem »Dynaset« handelt es sich eigentlich um eine Menge von Verweisen auf Tabellendaten. Über ein »Dynast« können Sie Daten aus mehreren Tabellen ziehen und aktualisieren – selbst aus Tabellen anderer Datenbanken. Tatsächlich können die in einem Dynaset zusammengefassten und die Daten enthaltenen Tabellen aus Datenbanken eines anderen Typs stammen (wie beispielsweise dem SQL-Server von Microsoft, Paradox und dBase).
518
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Wie der Name schon sagt, ist ein Dynaset eine dynamische Datensatzmenge. Dies bedeutet, dass am Dynaset vorgenommene Änderungen in den ihm zu Grunde liegenden Tabellen wiedergegeben werden und von anderen Systembenutzern durchgeführte Modifikationen an den als Grundlage des Dynasets dienenden Tabellen in diesem reflektiert werden. Obwohl ein Dynaset nicht den schnellsten Typ eines Recordset-Objekts darstellt, ist er mit Sicherheit der flexibelste.
12.11.2 Snapshots Ein Recordset-Objekt des Typs Snapshot ist einem Dynaset ähnlich. Der bedeutendste Unterschied besteht darin, dass die in einem Snapshot eingeschlossenen Daten durch den Zeitpunkt seiner Erstellung festgelegt werden. Aus diesem Grund lassen sich die Daten eines Snapshot nicht verändern und werden nicht aktualisiert, wenn andere Benutzer Änderungen an den zu Grunde liegenden Tabellen vornehmen. Dieses Merkmal kann einen Vorteil oder Nachteil darstellen. Es ist natürlich dann ein Nachteil, wenn die Daten einer Datensatzgruppe aktualisierbar sein müssen. Es wirkt sich vorteilhaft aus, wenn Sie einen Bericht ausführen und sicherstellen wollen, dass sich die Daten während der Berichterstellung nicht verändern. Deshalb ist es möglich, einen Snapshot zu erzeugen und den Bericht anhand des SnapshotObjekts zu erstellen. Bei kleinen Ergebnismengen sind Snapshots effektiver als Dynasets, da ein Snapshot-Objekt einen geringeren Verarbeitungsaufwand nach sich zieht. Unabhängig von dem geringeren Aufwand sind Snapshots in der Regel beim Zurückgeben von Datensatzgruppen mit einem großen Datenvolumen (im Allgemeinen bei mehr als 500 Datensätzen) weniger wirksam. Der Grund liegt darin, dass bei der Erstellung eines Snapshot-Objekts dem Benutzer alle Felder eines Datensatzes zurückgegeben werden, wenn auf diesen zugegriffen wird. Im Gegensatz dazu enthält ein Dynaset-Objekt eine Menge von Primärschlüsseln für die in der Datensatzgruppe enthaltenen Datensätze. Die anderen Felder werden dem Benutzer nur zurückgegeben, wenn sie zum Bearbeiten oder Anzeigen benötigt werden.
12.11.3 Tabellen Ein Recordset-Objekt des Typs Table wird häufig zum Bearbeiten von mit Microsoft Access oder der Jet-Datenbank-Engine erstellten lokalen oder verknüpften Tabellen eingesetzt. Wenn Sie eine tabellenartige Datensatzgruppe öffnen, werden alle Operationen unmittelbar mit der Tabelle ausgeführt. Bestimmte Operationen, wie beispielsweise eine Seek-Operation, können ausschließlich mit einer Datensatzgruppe des Typs Table ausgeführt werden. Beim Sortieren und Filtern von Datensätzen erzielen Sie mit dieser Art Datensatzgruppe die beste Leistung.
Zwischen den verfügbaren Arten von DAO-Datensatzgruppenobjekten wählen
519
Der Nachteil einer Datensatzgruppe des Typs Table besteht darin, dass sie ausschließlich Daten von nur einer Tabelle enthalten kann und sich nicht mit Join- oder Union-Abfragen öffnen lässt. Außerdem kann sie nicht mit Tabellen verwendet werden, die mit anderen als Jet-Engines erstellt wurden (wie beispielsweise ODBC- und andere ISAM-Datenquellen).
12.12
Zwischen den verfügbaren Arten von DAODatensatzgruppenobjekten wählen
Zum Treffen einer Entscheidung über die Art der zu verwendenden Datensatzgruppe gehört eine Analyse der Zielstellung, um so den am besten geeigneten Typ zu bestimmen. Wenn das Hauptgewicht auf einer schnellen Suche liegt und das Abrufen aller Datensätze kein Problem darstellt, ist eine Tabelle die beste Wahl. Falls Sie das Ergebnis einer Abfrage abrufen müssen und Ihre Ergebnismenge bearbeitbar sein muss, ist ein Dynaset am besten geeignet. Wenn das Ergebnis nicht aktualisierbar sein, aber aus einer verhältnismäßig kleinen Untermenge von Daten bestehen muss, ist ein Snapshot das Mittel der Wahl.
12.13
Mit DAO-Recordset-Eigenschaften und -Methoden umgehen
Wie andere Objekte besitzen Recordset-Objekte Eigenschaften und Methoden. Die Eigenschaften sind die Attribute der Recordset-Objekte, während es sich bei den Methoden um die Aktionen handelt, denen Sie die Recordset-Objekte unterziehen können. Einige Eigenschaften sind zur Laufzeit nur lesbar, andere lassen sich lesen und schreiben.
12.13.1 Eine Recordset-Variable bilden Bei der Arbeit mit einer Datensatzgruppe müssen Sie zunächst eine Recordset-Variable erstellen. Zur Bildung einer Recordset-Objektvariablen setzen Sie die Methode OpenRecordset ein. Als erstes müssen Sie eine allgemeine Recordset-Variable deklarieren und dann in dieser, wie in Listing 12.40 gezeigt, mit Hilfe einer Set-Anweisung auf eine bestimmte Datensatzgruppe verweisen. Listing 12.40: Eine Datensatzgruppe öffnen Sub OpenTable() Dim dbInfo As Database Dim rstClients As Recordset Set dbInfo = CurrentDb()
520
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Set rstClients = dbInfo.OpenRecordset("tblClients") Debug.Print rstClients.Updatable End Sub
Dieser Code erstellt eine Database- und eine Recordset-Objektvariable. Dann verwendet sie die Funktion CurrentDB, um in der Database-Objektvariablen einen Verweis auf die aktuelle Datenbank einzurichten. Als nächstes weist er mit Hilfe der Methode OpenRecordset den auf der Tabelle tblClients basierenden Datensatz der Objektvariable rstClients zu. Die Art der erstellten Datensatzgruppe wird durch den als Standard für das Objekt voreingestellten oder einen zweiten Parameter der Methode OpenRecordset festgelegt. Falls die Methode OpenRecordset mit einer Tabelle ausgeführt und kein zweiter Parameter angegeben wird, wird die Datensatzgruppe wie eine des Typs Tabelle geöffnet. Wenn die Methode OpenRecordset auf eine Abfrage angewendet und kein zweiter Parameter definiert wird, wird die Datensatzgruppe als Dynaset-Datensatzgruppe geöffnet. Sie können dieses Standardverhalten überschreiben, indem Sie, wie in Listing 12.41 gezeigt, der Methode OpenRecordset einen zweiten Parameter übergeben. Listing 12.41: Eine Dynaset-Datensatzgruppe auf einer Tabelle öffnen Sub OpenDynaSet() Dim dbInfo As Database Dim rstClients As Recordset Set dbInfo = CurrentDb() Set rstClients = dbInfo.OpenRecordset("tblClients", dbOpenDynaset) Debug.Print rstClients.Updatable End Sub
Dieser Code öffnet die Datensatzgruppe als Dynaset. Darin enthalten sind die Konstanten dbOpenTable, dbOpenDynaset und dbOpenSnapshot, die zum Öffnen eines Recordset-Objekts verwendet werden können. Eine Abfrage lässt sich ausschließlich als Recordset-Objekt des Typs Dynaset oder Snapshot öffnen. Listing 12.42 zeigt den zum Öffnen einer auf einer Abfrage basierenden Datensatzgruppe erforderlichen Code. Listing 12.42: Eine auf einer Abfrage basierende Datensatzgruppe öffnen Sub OpenQuery() Dim dbInfo As Database Dim rstClients As Recordset Set dbInfo = CurrentDb() Set rstClients = dbInfo.OpenRecordset("qryHoursByProject", dbOpenSnapshot) Debug.Print rstClients.Updatable End Sub
Mit DAO-Recordset-Eigenschaften und -Methoden umgehen
521
Wie in Access 95 unterscheidet sich in Access 97 und Access 2000 die richtige zum Erstellen eines Recordset-Objekts einzusetzende Methode von der, die bei den Vorgängerversionen von Access verwendet wurde. Bei den früheren Versionen war es ausreichend, eine Objektvariable des Typs Dynaset, Snapshot oder Table zu dimensionieren und dann mit Hilfe der Methoden CreateDynaset, CreateSnapshot und OpenTable des Database-Objekts den entsprechenden Typ einer Datensatzgruppe zu erstellen. Diese Methode zum Bilden von Datensatzgruppen ist in Access 97 und Access 2000 ausschließlich aus Gründen der Rückwärtskompatibilität enthalten. Sie sollte vermieden und durch den in diesem Abschnitt bereitgestellten Code ersetzt werden.
12.13.2 Eine Datensatzgruppe durch Angabe von Argumenten öffnen Microsoft bietet verschiedene Argumente zum Steuern des Verfahrens an, nach dem eine Datensatzgruppe geöffnet wird. Es folgen die Argumente und ihre Verwendung:
dbAppendOnly – Wenn diese Option verwendet wird, lassen sich der Datensatzgruppe Datensätze ausschließlich hinzufügen. Bestehende Daten können nicht angezeigt oder verändert werden. Diese Option ist hilfreich, wenn Sie sicherstellen wollen, dass die Verarbeitung sich nicht auf vorhandene Daten auswirkt und betrifft lediglich Dynasets.
dbConsistent – Dieses Argument ist auf Dynasets anwendbar. Es ermöglicht ausschließlich konsistente Aktualisierungen. Dies bedeutet, dass Sie bei einer 1:nVerknüpfung lediglich die Felder aktualisieren können, die nicht in anderen Datensätzen des Dynasets vorkommen. Hierbei handelt es sich um das standardmäßige Argument für Dynasets.
dbDenyRead – Dieses Argument verhindert, dass andere Benutzer die in dieser Datensatzgruppe enthaltenen Daten auch nur lesen können, solange die Datensatzgruppe geöffnet ist. Sie können diese Option ausschließlich bei Datensatzgruppen in Tabellenform einsetzen.
dbDenyWrite – Diese Option verhindert bei der Erstellung eines Dynasets oder Snapshots, dass alle anderen Benutzer Änderungen an den in der Datensatzgruppe enthaltenen Datensätzen vornehmen, bis die Datensatzgruppe geschlossen ist. Die anderen Benutzer können die in der Datensatzgruppe eingeschlossenen Daten immer noch ansehen. Wenn diese Option auf eine Datensatzgruppe des Typs Table angewendet wird, ist den anderen Benutzern das Öffnen der zu Grunde liegenden Tabelle nicht möglich.
dbForwardOnly – Dieses Argument erstellt einen Snapshot, bei dem ein Bildlauf in Vorwärtsrichtung möglich ist. Diese Art von Datensatzgruppe ist schnell, weist aber Einschränkungen auf, da Sie zum direkten Navigieren durch den Snapshot lediglich die Methoden Move und MoveNext einsetzen können.
522
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
dbInconsistent – Dieses Argument ermöglicht inkonsistente Aktualisierungen. Das bedeutet, dass Sie bei einer 1:n-Verknüpfung alle Spalten der Datensatzgruppe aktualisiern können.
dbReadOnly – Diese Option verhindert, dass Ihre Datensatzgruppe Daten verändert. Falls Sie nicht wollen, dass die Daten innerhalb der Datensatzgruppe aktualisierbar sind, aber eine große Anzahl von zurückgegebenen Datensätzen erwarten und die von Dynasets gebotenen Vorteile bei der Seitendarstellung nutzen wollen, wäre es sinnvoll, die Datensatzgruppe als Dynaset zu öffnen.
dbSeeChanges – Diese Option stellt sicher, dass ein Benutzer einen Fehler erhält, wenn der Code die Methode Edit aufruft und ein anderer Benutzer die Daten vor Ausführung der Methode Update verändert. Diese Option ist in einer Umgebung mit einem hohen Datenverkehrsaufkommen hilfreich, in der es wahrscheinlich ist, dass zwei Benutzer einen Datensatz zur selben Zeit abändern. Diese Option ist ausschließlich bei Datensatzgruppen des Typs Dynaset und Table anwendbar.
dbSQLPassThrough – Wenn eine SQL-Anweisung die Quelle der Datensatzgruppe bildet, gibt dieses Argument die SQL-Anweisung zur Verarbeitung an eine ODBC-Datenbank weiter. Durch diese Option wird Jet nicht vollständig ausgeschlossen; sie verhindert einfach, dass Jet vor der Weitergabe der SQL-Anweisung an den ODBC-Treiber-Manager Änderungen an dieser vornimmt. Sie können das Argument dbSQLPassThrough ausschließlich mit Snapshots und nur den Lesezugriff gestattenden Dynasets einsetzen. Die beschriebenen Argumente lassen sich zum Erreichen der gewünschten Ziele kombiniert verwenden. Listing 12.43 zeigt das Anwenden des Arguments OpenRecordset. Listing 12.43: Ein OpenRecordset-Argument verwenden Sub OpenRecordsetArgs() Dim db As Database Dim rst As Recordset Set db = CurrentDb Set rst = db.OpenRecordset("tblProjects", dbOpenDynaset, dbReadOnly) Debug.Print rst.Updatable End Sub
Dieser Code öffnet eine Datensatzgruppe im schreibgeschützten Modus.
12.13.3 Methoden zum Verschieben von Datensätzen Wahrscheinlich möchten Sie nach dem Setzen einer Recordset-Objektvariablen die Daten der Datensatzgruppe bearbeiten. Tabelle 12.3 zeigt verschiedene Methoden, die zum Navigieren durch die Datensätze einer Datensatzgruppe dienen.
Mit DAO-Recordset-Eigenschaften und -Methoden umgehen
523
Methode
Bewegung
MoveFirst
Zum ersten Datensatz einer Datensatzgruppe
MoveLast
Zum letzten Datensatz einer Datensatzgruppe
MovePrevious
Zum vorangehenden Datensatz einer Datensatzgruppe
MoveNext
Zum nächsten Datensatz einer Datensatzgruppe
Move[0]
Eine angegebene Anzahl von Datensätzen nach vorne oder hinten
Tabelle 12.3: Methoden zum Navigieren durch die Datensätze einer Datensatzgruppe
Listing 12.44 zeigt ein Beispiel für die Verwendung der zum Bewegen durch die Datensätze dienenden Methoden bei einem Dynaset. Listing 12.44: Die Move-Methoden verwenden Sub RecordsetMovements() Dim db As Database Dim rst As Recordset Set db = CurrentDb Set rst = db.OpenRecordset("tblProjects", dbOpenDynaset) Debug.Print rst!ProjectID rst.MoveNext Debug.Print rst!ProjectID rst.MoveLast Debug.Print rst!ProjectID rst.MovePrevious Debug.Print rst!ProjectID rst.MoveFirst Debug.Print rst!ProjectID rst.Close End Sub
Dieser Code öffnet einen Dynaset. Der Datensatzzeiger wird beim Öffnen der Datensatzgruppe automatisch auf dem ersten Datensatz des Dynaset platziert. Die Routine druckt den Inhalt des Felds ProjectID und bewegt sich dann zum letzten Datensatz und gibt dessen ProjectID aus, steuert den vorhergehenden Datensatz an und druckt dessen ProjectID und geht schließlich zum ersten Datensatz, um dessen ProjectID auszudrucken. Die Methode Close wird auf das Recordset-Objekt angewendet. Es ist sinnvoll, eine geöffnete Datensatzgruppe stets vor dem Verlassen einer Routine zu schließen. Nachdem die Änderungen an der Datensatzgruppe abgeschlossen sind, schließt die Methode Close ordnungsgemäß die Datensatzgruppe und stellt sicher, dass die Veränderungen auf die Festplatte geschrieben werden.
524
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
12.13.4 Beschränkungen einer Datensatzgruppe Alle im Abschnitt über das Bestimmen der Begrenzungen einer ADO-Datensatzgruppe besprochenen Informationen sind auch auf den Umgang mit einer DAODatensatzgruppe anwendbar. Listing 12.45 zeigt ein Beispiel für DAO-Code, bei dem die Eigenschaft EOF zusammen mit der Methode MoveNext zum Einsatz kommt. Listing 12.45: Die Eigenschaft EOF mit MoveNext verwenden Sub DetermineLimits() Dim db As Database Dim rstClients As Recordset Set db = CurrentDb() Set rstClients = db.OpenRecordset("tblClients", dbOpenSnapshot) Do While Not rstClients.EOF Debug.Print rstClients![ClientID] rstClients.MoveNext Loop rstClients.Close End Sub
Der Code geht eine Datensatzgruppe des Typs Snapshot durch und druckt so lange für jeden Datensatz den Wert des Felds ClientID, bis er die Position hinter dem letzten Datensatz der Datensatzgruppe erreicht. Dann verlässt er die Schleife und schließt die Datensatzgruppe.
12.13.5 Die Anzahl der Datensätze in einer Datensatzgruppe feststellen Die Datensatzeigenschaft RecordCount gibt die Anzahl der Datensätze zurück, auf die innerhalb einer Datensatzgruppe zugegriffen wurde. Das Problem hierbei wird offensichtlich, wenn Sie eine Datensatzgruppe öffnen und sich die Eigenschaft RecordCount ansehen. Sie werden feststellen, dass die Zählung den Wert 0 ergibt, wenn die Datensatzgruppe keine Datensätze aufweist, oder den Wert 1, falls sich Datensätze in der Datensatzgruppe befinden. Die Zählung der Datensätze ist lediglich genau, wenn Sie alle Datensätze einer Datensatzgruppe aufsuchen, was sich, wie in Listing 12.46 veranschaulicht, mit Hilfe der Methode MoveLast durchführen lässt. Listing 12.46: Darstellung der Beschränkungen von RecordCount Sub CountRecords() Dim db As Database Dim rstProjects As Recordset Set db = CurrentDb() Set rstProjects = db.OpenRecordset("tblProjects", dbOpenSnapshot) Debug.Print rstProjects.RecordCount 'Druckt 0 oder 1 rstProjects.MoveLast
Mit DAO-Recordset-Eigenschaften und -Methoden umgehen
525
Debug.Print rstProjects.RecordCount 'Gibt eine genaue Zählung der Datensätze aus rstProjects.Close End Sub
Bei der Methode MoveLast gibt es jedoch einige Probleme. Sie ist langsam und ineffizient, insbesondere in einer Client-Server-Umgebung. Außerdem wird die Methode RecordCount in einer Mehrbenutzerumgebung ungenau, da andere Personen Datensätze hinzufügen bzw. aus der Tabelle entfernen können. Dies bedeutet, dass Sie auf das Bestimmen der Anzahl der Datensätze verzichten sollten, wenn dies nicht unbedingt erforderlich ist. Es gibt dennoch eine gute Verwendung für die Methode RecordCount: Mit ihrer Hilfe können Sie feststellen, ob sich Datensätze in einer Datensatzgruppe befinden. Falls Sie eine Operation durchführen, bei der möglicherweise eine leere Datensatzgruppe zurückgegeben wird, können Sie, wie in Listing 12.47 gezeigt, mit der Methode RecordCount problemlos ermitteln, ob Datensätze zurückgegeben wurden. Listing 12.47: Mit Hilfe von RecordCount überprüfen, ob eine Datensatzgruppe leer ist Sub CheckARecordset() Dim db As Database Dim rstProjects As Recordset Set db = CurrentDb() Set rstProjects = db.OpenRecordset("tblEmpty", dbOpenSnapshot) If Not AreThereRecords(rstProjects) Then MsgBox "Recordset Empty...Unable to Proceed" End If End Sub
Die Prozedur CheckARecordset öffnet eine Datensatzgruppe auf der Basis der Tabelle tblEmpty. Dann ruft sie die Funktion AreThereRecords auf, um festzustellen, ob sich Datensätze in der Datensatzgruppe befinden. Falls die Funktion AreThereRecords den Wert False zurückgibt, wird dem Benutzer eine Fehlernachricht angezeigt.
12.13.6 Datensätze sortieren, filtern und finden Machmal kann es vorkommen, dass Sie eine bestehende Datensatzgruppe sortieren oder filtern oder jeden bestimmte Kriterien erfüllenden Datensatz in der Datensatzgruppe finden müssen. Die folgenden Verfahren ermöglichen Ihnen das Sortieren, Filtern und Finden von Datensätzen innerhalb eines Recordset-Objekts. Eine Datensatzgruppe sortieren Sie können die Sortierreihenfolge eines bestehenden Dynasets oder Snapshots nicht tatsächlich verändern. Stattdessen erstellen Sie auf der Basis der ersten eine zweite in der gewünschten Reihenfolge sortierte Datensatzgruppe. Listing 12.48 zeigt, wie dieser Prozess abläuft.
526
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Listing 12.48: Eine bestehende Datensatzgruppe sortieren Sub SortRecordset() Dim db As Database Dim rstTimeCardHours As Recordset Set db = CurrentDb Set rstTimeCardHours = db.OpenRecordset("tblTimeCardHours", dbOpenDynaset) Debug.Print "NOT Sorted!!!" Do While Not rstTimeCardHours.EOF Debug.Print rstTimeCardHours![DateWorked] rstTimeCardHours.MoveNext Loop Debug.Print "Now Sorted!!!" rstTimeCardHours.Sort = "[DateWorked]" Set rstTimeCardHours = rstTimeCardHours.OpenRecordset Do While Not rstTimeCardHours.EOF Debug.Print rstTimeCardHours![DateWorked] rstTimeCardHours.MoveNext Loop End Sub
In diesem Fall sortieren Sie einen auf der Tabelle tblTimeCardHours basierenden Dynaset. Wenn Sie die Datensatzgruppe zum ersten Mal mit Hilfe einer Schleife durchlaufen und jeden Arbeitstag ausdrucken, befinden sich die Daten in der standardmäßigen (normalerweise nach dem Primärschlüssel geordneten) Reihenfolge. Nachdem die Datensatzgruppe mit Hilfe der Methode Sort sortiert wurde, erscheinen die Datensätze nach Arbeitstagen geordnet. Eine Datensatzgruppe filtern Das Filtern einer Datensatzgruppe ist ein hilfreiches Verfahren, wenn Sie eine Untermenge von Datensätzen aus Ihrer Datensatzgruppe auswählen wollen. Dies ist besonders sinnvoll, um Benutzern zu ermöglichen, sich beim Suchen nach der von ihnen benötigten Untermenge auf eine Gruppe von Datensätzen zu beschränken. Der Ablauf der Filterung einer bestehenden Datensatzgruppe ist dem des Sortierens ähnlich. Listing 12.49 stellt eine Abwandlung des Beispiels in Listing 12.48 dar. Statt eine vorhandene Datensatzgruppe zu sortieren, wird diese gefiltert. Listing 12.49: Eine bestehende Datensatzgruppe filtern Sub FilterRecordSet() Dim db As Database Dim rstTimeCardHours As Recordset Set db = CurrentDb Set rstTimeCardHours = db.OpenRecordset("tblTimeCardHours", dbOpenDynaset) Debug.Print "Without Filter" Do While Not rstTimeCardHours.EOF Debug.Print rstTimeCardHours![DateWorked] rstTimeCardHours.MoveNext
Mit DAO-Recordset-Eigenschaften und -Methoden umgehen
527
Loop rstTimeCardHours.Filter = "[DateWorked] Between #1/1/95# and #1/5/95#" Debug.Print "With Filter" Set rstTimeCardHours = rstTimeCardHours.OpenRecordset Do While Not rstTimeCardHours.EOF Debug.Print rstTimeCardHours![DateWorked] rstTimeCardHours.MoveNext Loop End Sub
Zunächst geht der Code die Datensatzgruppe mit Hilfe einer Schleife durch, ohne dass ein Filter gesetzt wurde. Der Filter wird angegeben und der Code durchläuft die Datensatzmenge erneut mit einer Schleife. Beim zweiten Durchgang werden lediglich die die Filterkriterien erfüllenden Datensätze angezeigt. Einen bestimmten Datensatz in einer Datensatzgruppe finden Die Methode Seek ermöglicht es Ihnen, Datensätze in einer Datensatzgruppe des Typs Table zu finden. Dabei handelt es sich um die in der Regel schnellste Methode zum Finden von Daten, da sie die angeforderten Daten anhand des aktuellen Index sucht. Listing 12.50 verdeutlicht die Arbeitsweise der Methode Seek. Listing 12.50: Die Methode Seek verwenden Sub SeekProject(lngProjectID As Long) Dim db As Database Dim rstProjects As Recordset Set db = CurrentDb() Set rstProjects = db.OpenRecordset("tblProjects", dbOpenTable) rstProjects.Index = "PrimaryKey" rstProjects.Seek "=", lngProjectID If rstProjects.NoMatch Then MsgBox lngProjectID & " Not Found" Else MsgBox lngProjectID & " Found" End If End Sub
Dieser Code findet anhand des Primärschlüsselindex das erste Projekt, das über die an die Funktion übergebene Projektnummer verfügt, und zeigt dann ein Meldungsfeld an, um anzugeben, ob der Wert gefunden wurde. Die Methode Seek lässt sich nicht zum Finden von Daten in einem Dynaset oder Snapshot einsetzen. Außerdem ist es nicht möglich, mit Hilfe der Methode Seek in verknüpften Tabellen nach Datensätzen zu suchen, wobei es keine Rolle spielt, ob es sich bei der verknüpften Tabelle um eine Access- oder eine Client-Server-Tabelle
528
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
handelt. In diesem Fall müssen Sie die Methoden FindFirst, FindLast, FindNext und FindPrevious einsetzen. Die Methode FindFirst findet das erste Auftreten von die Kriterien erfüllenden Daten und die Methode FindLast das letzte Vorkommen solcher Daten. Die Methoden FindNext und FindPrevious gestatten Ihnen das Suchen weiterer Stellen, an denen diese Daten auftreten. Der in Listing 12.51 vorgestellte Code verwendet die Methode FindFirst, um das erste Auftreten des ihm übergebenen Parameters zu finden. Auch er zeigt ein entsprechendes Meldungsfeld an. Listing 12.51: Die Methode FindFirst verwenden Sub FindProject(lngValue As Long) Dim db As Database Dim rstProjects As Recordset Dim sSQL As String Set db = CurrentDb() Set rstProjects = db.OpenRecordset("tblProjects", dbOpenDynaset) sSQL = "[ProjectID] = " & lngValue rstProjects.FindFirst sSQL If rstProjects.NoMatch Then MsgBox lngValue & " Not Found" Else MsgBox lngValue & " Found" End If End Sub
Zum Durchsuchen einer verknüpften Tabelle können Sie einen anderen Trick anwenden. Sie können die Datenbank öffnen, die die verknüpfte Tabelle enthält, und die Tabellendaten unmittelbar durchsuchen. Dies funktioniert aber nur, wenn es sich bei der verknüpften Tabelle um eine weitere Access-Datenbank handelt.
12.13.7 Die Eigenschaft AbsolutePosition Die Eigenschaft AbsolutePosition gibt die Position des aktuellen Datensatzes zurück. Diese wird als ein auf 0 basierender Wert ausgedrückt. Wie in Listing 12.52 gezeigt, können Sie mit seiner Hilfe angeben, an welcher Stelle einer Datensatzgruppe ein bestimmter Datensatz gefunden wurde. Listing 12.52: Die Stelle angeben, an der ein Datensatz gefunden wurde Sub FindPosition(lngValue As Long) Dim db As Database Dim rstProjects As Recordset Dim sSQL As String
Mit DAO-Recordset-Eigenschaften und -Methoden umgehen
529
Set db = CurrentDb() Set rstProjects = db.OpenRecordset("tblProjects", dbOpenDynaset) sSQL = "[ProjectID] = " & lngValue rstProjects.FindFirst sSQL If rstProjects.NoMatch Then MsgBox lngValue & " Not Found" Else Debug.Print rstProjects.AbsolutePosition End If End Sub
Dieser Code findet den ersten Datensatz, dessen ProjectID mit dem der Methode als Parameter übergebenen Long Integer-Wert übereinstimmt. Falls die ProjectID gefunden wird, erfolgt die Ausgabe des Werts der Eigenschaft AbsolutePosition des Datensatzes. Gehen Sie nicht davon aus, dass die Eigenschaft AbsolutePosition eines bestimmten Datensatzes gleich bleibt. Die Eigenschaft AbsolutePosition eines Datensatzes ändert sich, wenn Daten hinzugefügt oder entfernt werden bzw. ihre Reihenfolge sich durch das Modifizieren von Datensätzen ändert.
12.13.8 Die Eigenschaft Bookmark Eine »Textmarke« ist ein vom System erzeugtes Bytefeld, das jeden Datensatz einer Datensatzgruppe eindeutig bezeichnet. Die Eigenschaft Bookmark einer Datensatzgruppe ändert sich, wenn Sie sich auf jedem Datensatz der Datensatzgruppe bewegen. Sie wird häufig eingesetzt, wenn Sie die aktuelle Position innerhalb der Datensatzgruppe speichern müssen, um nach dem Durchführen einer Operation wieder an diese Position zurückzukehren. Dieser Prozess umfasst drei Schritte: 1. die Speicherung der aktuellen Textmarke der Datensatzgruppe in einer VariantVariablen 2. das Durchführen der Operation 3. das Setzen der Eigenschaft Bookmark auf den in der Variant-Variablen enthaltenen Wert Listing 12.53 zeigt ein Beispiel für die Verwendung einer Textmarke. Listing 12.53: Eine Textmarke verwenden Sub UseBookMark() Dim db As Database Dim rstProjects As Recordset Dim sSQL As String Dim vntPosition As Variant
530
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Set db = CurrentDb() Set rstProjects = db.OpenRecordset("tblProjects", dbOpenDynaset) vntPosition = rstProjects.Bookmark Do Until rstProjects.EOF Debug.Print rstProjects!ProjectID rstProjects.MoveNext Loop rstProjects.Bookmark = vntPosition Debug.Print rstProjects!ProjectID End Sub
Der Code beginnt, indem er eine Datensatzgruppe öffnet und die Textmarke für den ersten Datensatz in einer Variablen des Typs Variant speichert. Dann geht er mit einer Schleife jeden Datensatz der Datensatzgruppe durch und druckt den Wert des Felds ProjectID. Nach Beendigung der Schleife wird die Eigenschaft Bookmark der Datensatzgruppe auf den Wert der Variant-Variablen gesetzt, so dass die aktuelle Position innerhalb der Datensatzgruppe wieder auf die Stelle gesetzt wird, die sie vor dem Abarbeiten der Schleife innehatte.
12.13.9 Die Eigenschaft RecordsetClone Mit Hilfe der Eigenschaft RecordsetClone eines Formulars verweisen Sie auf die diesem zu Grunde liegende Datensatzgruppe. Diese Eigenschaft kommt häufig zum Einsatz, wenn Sie nach dem Durchführen einer Operation das Formular mit der ihm zu Grunde liegenden Datensatzgruppe abgleichen möchten. Listing 12.54 zeigt ein Beispiel für die Verwendung der Eigenschaft RecordsetClone. Listing 12.54: Die Eigenschaft RecordsetClone verwenden Private sub cmdFindClient_Click() 'Dieser Code ist nicht in der Beispieldatenbank enthalten Me.RecordsetClone.FindFirst "ClientID = " & Me!txtClientID If Me.RecordsetClone.NoMatch Then MsgBox Me!txtClientID & " Not Found" Else Me.Bookmark = Me.RecordsetClone.Bookmark End If End Sub
Diese Routine wendet die Methode FindFirst auf die Eigenschaft RecordsetClone des aktuellen Formulars an. Falls der Datensatz gefunden wird, wird die Eigenschaft Bookmark des Formulars auf die Textmarke der Datensatzgruppe gesetzt. Auf diese Weise wird die Position des Formulars mit der Position der ihm zu Grunde liegenden Datensatzgruppe abgeglichen.
Tabellendaten mit Hilfe von DAO-Code bearbeiten
531
12.13.10 Parameterabfragen ausführen Die Parameterabfragen von Access sind äußerst leistungsfähig. Sie ermöglichen Benutzern das Angeben von Parametern zur Laufzeit. Diese Fähigkeit ist häufig hilfreich, wenn Benutzer zur Laufzeit ein Formular ausfüllen möchten und die Werte dieses Formulars der Abfrage übergeben haben. Weiterhin kann sich das als nützliches Verfahren erweisen, um Ihren Code vor Veränderungen in der Datenbankstruktur zu schützen. Das Abfassen einer parametrisierten Abfrage ähnelt dem Schreiben einer Unterroutine, bei der dem Aufrufer die Einzelheiten hinsichtlich der Implementierung der Routine verborgen bleiben. Diese Programmiertechnik wird als »Kapselung« bezeichnet. Listing 12.55 zeigt ein Beispiel für die Verwendung von Parameterabfragen. Listing 12.55: Parameterabfragen verwenden Sub RunParameterQuery(datStart As Date, datEnd As Date) Dim db As Database Dim qd As QueryDef Dim rs As Recordset Set db = CurrentDb Set qd = db.QueryDefs("qryBillAmountByClient") qd.Parameters("Please Enter Start Date") = datStart qd.Parameters("Please Enter End Date") = datEnd Set rs = qd.OpenRecordset Do While Not rs.EOF Debug.Print rs![CompanyName], rs![BillAmount] rs.MoveNext Loop End Sub
Der Unterroutine werden zwei Datenvariablen als Parameter übergeben. Genauso einfach könnte man ihr zwei Formularsteuerelemente als Parameter übergeben. Sie öffnet eine Abfragedefinition mit der Bezeichnung qryBillAmountByClient und setzt dann die Werte der Please Enter Start Date und Please Enter End Date genannten Parameter auf die der Unterroutine als Parameter übergebenen Werte der Datenvariablen. Danach wird die Abfrage ausgeführt, indem die Methode OpenRecordset für das Recordset-Objekt aufgerufen wird.
12.14
Tabellendaten mit Hilfe von DAO-Code bearbeiten
Bis jetzt haben Sie gelernt, wie man mit Recordset-Objekten umgeht und sie mit Hilfe von Schleifen durchläuft. Nun werden Sie erfahren, wie man die in einer Datensatzgruppe enthaltenen Daten bearbeitet.
532
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
12.14.1 Datensätze einzeln ändern In vielen Fällen ist es erforderlich, eine Datensatzgruppe mit einer Schleife durchzugehen und alle eine bestimmte Kriterienmenge erfüllenden Datensätze zu bearbeiten. Listing 12.56 zeigt den zum Ausführen dieser Aufgabe benötigten Code. Listing 12.56: Eine bestimmte Kriterienmenge erfüllende Datensätze aktualisieren Sub IncreaseEstimate() Dim db As Database Dim rstProjectst As Recordset Dim sSQL As String Dim intUpdated As Integer Set db = CurrentDb() Set rstProjectst = db.OpenRecordset("tblProjectsChange", dbOpenDynaset) sSQL = "ProjectTotalEstimate < 30000" intUpdated = 0 rstProjectst.FindFirst sSQL Do While Not rstProjectst.NoMatch intUpdated = intUpdated + 1 rstProjectst.Edit rstProjectst!ProjectTotalEstimate = rstProjectst!ProjectTotalEstimate * 1.1 rstProjectst.Update rstProjectst.FindNext sSQL Loop Debug.Print intUpdated & " Records Updated" rstProjectst.Close End Sub
Dieser Code findet den ersten Datensatz, bei dem der Wert von ProjectTotalEstimate unter 30.000 liegt. Er verwendet die Methode Edit, um den aktuellen Datensatz des Dynasets für die Bearbeitung vorzubereiten und ersetzt ProjectTotalEstimate durch dessen mit 1,1 multiplizierten Wert. Danach ruft er die Methode Update auf, um die Daten auf die Festplatte zu schreiben. Schließlich findet er mit Hilfe der Methode FindNext das nächste Auftreten des Kriteriums.
12.14.2 Veränderungen an mehreren Datensätzen vornehmen Viele der Aufgaben, die Sie durch das Abarbeiten einer Datensatzgruppe mit Hilfe einer Schleife erledigen können, lassen sich auch mit einer Aktualisierungsabfrage durchführen. Das Ausführen einer Aktualisierungsabfrage ist in vielen Fällen wirksamer als das Durchlaufen einer Datensatzgruppe mit Hilfe einer Schleife. Zumindest benötigt man dazu weniger Code. Aus diesem Grund ist es wichtig zu wissen, wie man eine Aktualisierungsabfrage über Code ausführt.
Tabellendaten mit Hilfe von DAO-Code bearbeiten
533
Nehmen wir an, Sie hätten eine Abfrage mit der Bezeichnung qryChangeTotalEstimate, welche den Wert von ProjectTotalEstimate bei allen Projekten erhöht, bei denen dieser Wert kleiner als 30.000 ist. Bei der Abfrage handelt es sich um eine Aktualisierungsabfrage. Der Code in Listing 12.57 führt die gespeicherte Abfragedefinition aus. Listing 12.57: Veränderungen an mehreren Datensätzen mit Hilfe einer vordefinierten Aktionsabfrage vornehmen Sub RunUpdateQuery() Dim db As Database Dim qd As QueryDef Set db = CurrentDb Set qd = db.QueryDefs("qryIncreaseTotalEstimate") qd.Execute End Sub
Beachten Sie, dass die Methode Execute durch Ausführen der Aktionsabfrage mit der Abfragedefinition arbeitet.
12.14.3 Einen vorhandenen Datensatz löschen Die Methode Delete ermöglicht es Ihnen, Datensätze, wie in Listing 12.58 gezeigt, mit Hilfe eines Programms aus einer Datensatzgruppe zu entfernen. Listing 12.58: Datensätze mit der Methode Delete löschen Sub DeleteCusts(lngProjEst As Long) Dim db As Database Dim rstProjects As Recordset Dim intCounter As Integer Set db = CurrentDb Set rstProjects = db.OpenRecordset("tblProjectsChange", dbOpenDynaset) intCounter = 0 Do While Not rstProjects.EOF If rstProjects!ProjectTotalEstimate < lngProjEst Then rstProjects.Delete intCounter = intCounter + 1 End If rstProjects.MoveNext Loop Debug.Print intCounter & " Customers Deleted" End Sub
Dieser Code geht die Datensatzgruppe rstProjects mit Hilfe einer Schleife durch. Falls der Wert von ProjectTotalEstimate unter dem des als Parameter übergebenen liegt, wird der Datensatz gelöscht. Diese Aufgabe lässt sich auch mit einer Löschabfrage ausführen.
534
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
12.14.4 Einen neuen Datensatz hinzufügen Die Methode AddNew ermöglicht es Ihnen, wie in Listing 12.59 gezeigt, einer Datensatzgruppe Datensätze mit Hilfe eines Programms hinzuzufügen. Listing 12.59: Einer Datensatzgruppe Datensätze hinzufügen Private Sub cmdAddDAO_Click() Dim db As Database Dim rstProject As Recordset If IsNull(Me.txtProjectName) Or _ IsNull(Me.cboClientID) Then MsgBox "The Project Name and Client must be Filled In" Else Set db = CurrentDb() Set rstProject = db.OpenRecordset("tblProjectsChange", DB_OPEN_DYNASET) With rstProject .AddNew !ProjectName = Me!txtProjectName !ProjectDescription = Me!txtProjectDescription !ClientID = Me!cboClientID .Update End With Me!txtProjectID = rstProject!ProjectID End If End Sub
Der Code wird auf das ungebundene Formular frmUnbound angewendet und ruft die Methode AddNew auf, die einen für die Aufnahme von Daten bereitstehenden Puffer einrichtet. Alle Felder der Datensatzgruppe werden mit den Werten aus den Steuerelementen des Formulars gefüllt. Die Methode Update schreibt die Daten auf die Festplatte. Falls Sie das Einfügen der Methode Update vergessen, werden die Daten niemals auf der Festplatte gespeichert. Die letzte Code-Zeile funktioniert nicht. Beim Feld ProjectID handelt es sich um ein Feld des Typs AutoWert, weil dessen Wert von Access im Laufe der Aktualisierung zugewiesen wird. Diese fehlerhafte Zeile hat den Zweck, den neuerstellten Wert von ProjectID in ein Textfeld des Formulars zu kopieren. Die Zeile dient zum Veranschaulichen eines Problems: Beim Aufrufen der Methode AddNew wird der Datensatzzeiger nicht innerhalb des Dynasets bewegt. Selbst nach dem Ausführen der Methode Update bleibt der Datensatzzeiger auf dem Datensatz, auf dem er sich vor dem Aufrufen der Methode AddNew befand.
Datenbankobjekte mit Hilfe von DAO-Code erstellen und bearbeiten
535
Aus diesem Grund wird der Code einen Datensatz hinzufügen, jedoch den Wert des Felds ProjectID des vorhergehenden Datensatzes in das Textfeld txtProjectID des Formulars setzen. Um dies zu umgehen, müssen Sie sich vor dem Füllen dieses Textfelds explizit auf dem neuen Datensatz bewegen. Dies lässt sich mit Hilfe der Eigenschaft LastModified einfach bewerkstelligen.
12.14.5 Die Eigenschaft LastModified Die Eigenschaft LastModified enthält eine Textmarke für den als letzten hinzugefügten oder veränderten Datensatz. Durch das Setzen der Textmarke der Datensatzgruppe auf die Eigenschaft LastModified steuert der Datensatzzeiger den als letzten hinzugefügten Datensatz an. Listing 12.60 ist eine veränderte Version von Listing 12.59, bei der das vorher beschriebene Problem mit Hilfe der Eigenschaft LastModified gelöst wird. Listing 12.60: Die Eigenschaft LastModified nach der Methode AddNew einsetzen Private Sub cmdLastModified_Click() Dim db As Database Dim rstProject As Recordset Set db = CurrentDb() Set rstProject = db.OpenRecordset("tblProjectsChange", DB_OPEN_DYNASET) With rstProject .AddNew !ProjectName = Me!txtProjectName !ProjectDescription = Me!txtProjectDescription !ClientID = Me!cboClientID .Update .Bookmark = .LastModified End With Me!txtProjectID = rstProject!ProjectID End Sub
Beachten Sie, dass die Textmarke der Datensatzgruppe auf deren Eigenschaft LastModified gesetzt wird.
12.15
Datenbankobjekte mit Hilfe von DAO-Code erstellen und bearbeiten
Beim Entwickeln einer Access-Anwendung kann es sich als sinnvoll erweisen, Tabellen oder Abfragen hinzuzufügen, Beziehungen zu definieren oder zu bearbeiten, Sicherheitsmaßnahmen zu wechseln oder andere Datendefinitionsverfahren zur Laufzeit durchzuführen. Sie können all dies durch Bearbeiten der unterschiedlichen Datenzugriffsobjekte erreichen.
536
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
12.15.1 Mit Hilfe von Code eine Tabelle hinzufügen Zum Hinzufügen und Bearbeiten von Objekten der Jet-Engine steht eine Vielzahl von Eigenschaften und Methoden zur Verfügung. Der Code in Listing 12.61 erstellt eine Tabelle, fügt dieser einige Felder und dann einen Primärschlüsselindex hinzu. Listing 12.61: Eine Tabelle erstellen und Felder sowie einen Primärschlüsselindex hinzufügen Sub CreateTable() Dim db As Database Dim tbl As TableDef Dim fld As Field Dim idx As Index Set db = CurrentDb() 'Erstellen einer neuen Tabellendefinition. Set tbl = db.CreateTableDef("tblFoods") 'Der Tabellendefinition ein Feld hinzufügen Set fld = tbl.CreateField("FoodID", DB_TEXT, 5) tbl.Fields.Append fld Set fld = tbl.CreateField("Description", DB_TEXT, 25) tbl.Fields.Append fld Set fld = tbl.CreateField("Calories", DB_INTEGER) tbl.Fields.Append fld db.TableDefs.Append tbl 'Das Feld FoodID als den Primärschlüsselindex festlegen Set idx = tbl.CreateIndex("PrimaryKey") Set fld = idx.CreateField("FoodID") idx.PRIMARY = True idx.Unique = True idx.Fields.Append fld tbl.Indexes.Append idx Den Index der Indexes-Auflistung hinzufügen End Sub
Dieser Code erstellt eine Tabellendefinition mit der Bezeichnung tblFoods. Bevor er die Tabellendefinition der TableDefs-Auflistung hinzufügen kann, muss er die Tabelle mit Feldern versehen. Der Tabelle werden drei Felder hinzugefügt. Beachten Sie, dass Feldname und -typ sowie die Feldlänge angegeben werden. Nach dem Hinzufügen der Tabellendefinition zur Datenbank lassen sich Indizes mit der Tabelle koppeln. Bei dem in Listing 12.61 hinzugefügten Index handelt es sich um einen Primärschlüsselindex. Beim Ausführen von Code zum Anhängen eines Objekts tritt ein Fehler auf, falls dieses Objekt bereits vorhanden ist. Sie müssen in Ihrer Routine entweder eine Fehlerbehandlung zum Handhaben dieser Möglichkeit einbauen oder die bestehende Objektinstanz vor dem Anfügen des neuen Objekts löschen.
Datenbankobjekte mit Hilfe von DAO-Code erstellen und bearbeiten
537
12.15.2 Mit Hilfe von Code eine Tabelle entfernen Genau wie Sie mit Hilfe von Code eine Tabelle hinzufügen können, kann man auf diesem Weg eine Tabelle entfernen, wie in Listing 12.62 gezeigt wird. Listing 12.62: Eine Tabelle entfernen Sub DeleteTable() Dim db As DATABASE Set db = CurrentDb Db.TableDefs.Delete "tblFoods" End Sub
Die Methode Delete wird für die TableDefs-Auflistung aufgerufen. Die Tabelle, die Sie entfernen möchten, wird der Methode Delete in Form eines Arguments übergeben. Falls zwischen der von Ihnen gelöschten Tabelle und anderen Tabellen der Datenbank eine Beziehung besteht, tritt ein Fehler auf. Aus diesem Grund müssen Sie vor dem Entfernen einer Tabelle alle Beziehungen löschen, an denen diese beteiligt ist.
12.15.3 Mit Hilfe von Code Beziehungen einrichten Beim Erstellen von Tabellen in einer Access-Umgebung richten Sie im Normalfall gleichzeitig die zwischen diesen Tabellen bestehenden Beziehungen ein. Falls Sie Tabellen mit Hilfe von Code anlegen, wollen Sie vermutlich die Beziehungen zwischen diesen Tabellen ebenfalls mit Code aufbauen. Listing 12.63 zeigt ein Beispiel. Listing 12.63: Beziehungen zwischen Datenbankobjekten einrichten Sub CreateRelation() Dim db As Database Dim rel As Relation Dim fld As Field Set db = CurrentDb Set rel = db.CreateRelation() With rel .Name = "PeopleFood" .Table = "tblFoods" .ForeignTable = "tblPeople" .Attributes = dbRelationDeleteCascade End With Set fld = rel.CreateField("FoodID")
538
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
fld.ForeignName = "FoodID" rel.Fields.Append fld db.Relations.Append rel End Sub
Der Code beginnt, indem er ein neues Relation-Objekt erstellt und dann die Beziehungseigenschaften Name, Table, Foreign Table und Attributes setzt. Im Anschluss daran wird dem Relation-Objekt das Feld hinzugefügt. Schließlich erfolgt das Anfügen des Relation-Objekts an die Relations-Auflistung.
12.15.4 Mit Hilfe von Code eine Abfrage erstellen Wenn Sie Ihre Anwendung aus der Access-Laufzeitumgebung heraus starten, werden Ihre Benutzer nicht zum Gestalten ihrer eigenen Abfragen in der Lage sein, wenn Sie nicht selbst über vollständige Installationen von Access verfügen. Es wäre sinnvoll, Ihren eigenen Abfrage-Designer in Ihrer Anwendung zu integrieren und dann den Benutzern das Abspeichern der von Ihnen angelegten Abfragen zu gestatten. Zu diesem Zweck müssen Sie die Abfragen selbst mit Hilfe von Code erstellen, nachdem der Benutzer diese entworfen hat. Listing 12.64 zeigt den zum Anlegen einer Abfrage erforderlichen Code. Listing 12.64: Eine Abfrage erstellen Sub CreateQuery() Dim db As Database Dim qdf As QueryDef Dim strSQL As String Set db = CurrentDb Set qdf = db.CreateQueryDef("qryBigProjects") strSQL = "Select ProjectID, ProjectName, ProjectTotalEstimate " _ & "From tblProjects " _ & "Where ProjectTotalEstimate >= 30000" qdf.SQL = strSQL End Sub
Dieser Code erstellt mit Hilfe der Methode CreateQueryDef des Database-Objekts eine neue Abfragedefinition. Dann setzt er die mit dieser verbundene SQL-Anweisung. Das dient zum Anlegen und Speichern der Abfrage. Sie müssen sich im Klaren darüber sein, dass die Methode CreateTablDef im Gegensatz zur Methode CreateQueryDef des Database-Objekts, welche der Datenbank die Abfragedefinition sofort hinzufügt, die Tabellendefinition nicht umgehend der Datenbank übergibt. Um der Datenbank die Tabellendefinition tatsächlich anzuhängen, müssen Sie die Append-Methode der TableDefs-Auflistung verwenden.
Die DAO-Container-Auflistung
539
Sie können eine temporäre Abfragedefinition erstellen, indem Sie bei der Methode CreateQueryDef eine Zeichenfolge mit einer Länge von Null als Namensargument verwenden.
12.16
Die DAO-Container-Auflistung
Eine Container-Auflistung unterhält Informationen über gespeicherte DatabaseObjekte. Zu den Objekttypen der Container-Auflistung gehören Datenzugriffsseiten, Datenbanken, Tabellen (einschließlich Abfragen), Beziehungen, Systembeziehungen, Formulare, Berichte, Scripts (Makros) und Module. Die Container-Auflistung ist verantwortlich dafür, Jet über die Objekte der Benutzerschnittstelle zu informieren. Jet ist das übergeordnete Objekt von Datenbanken, Tabellen, Beziehungen und Systembeziehungen. Bei Formularen, Berichten, Scripts und Modulen ist die AccessAnwendung das übergeordnete Objekt. Jedes Container-Objekt besitzt eine Auflistung von Document-Objekten. Dabei handelt es sich um die eigentlichen Formulare, Berichte und anderen Objekte, die einen Teil der Datenbank bilden. Die Document-Objekte enthalten lediglich zusammenfassende Informationen über jedes Objekt (Erstellungsdatum, Eigentümer usw.), jedoch nicht die eigentlichen Objektdaten. Um innerhalb eines Containers auf ein bestimmtes Dokument zu verweisen, müssen Sie eins von zwei Verfahren einsetzen: Containers("Name")
oder Containers!Name
Zum Auflisten jedes Container-Objekts und der mit diesem verbundenen DocumentObjekte müssen Sie den in Listing 12.65 gezeigten Code verwenden. Listing 12.65: Jedes Container-Objekt und das damit verbundene Document-Objekt auflisten Sub ListAllDBObjects() Dim db As Database Dim con As Container Dim doc As Document Set db = CurrentDb For Each con In db.Containers Debug.Print "*** " & con.Name & " ***" For Each doc In con.Documents Debug.Print doc.Name Next doc Next con End Sub
540
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
Dieser Code geht mit Hilfe einer Schleife alle Dokumente aller Container durch und druckt diese aus.
12.16.1 Für die Praxis Diese Verfahren bei Ihren Anwendungen einsetzen Für die in diesem Kapitel vorgestellten Verfahrensweisen gibt es zahllose Anwendungsmöglichkeiten. In diesem Abschnitt werden lediglich einige der Möglichkeiten zum Anwenden dieser Techniken erläutert. Die an dieser Stelle angeführten Beispiele befinden sich in der Datenbankdatei CHAP12.MDB.
12.16.2 Methoden für den Umgang mit Datensatzgruppen auf einem Dateneingabeformular In manchen Fällen möchten Sie unter Umständen die Funktionen zum Bewegen durch die Datensätze sowie die zum Hinzufügen, Bearbeiten oder Entfernen bei einem Formular deaktivieren und alle diese Funktionen selbst programmieren. Das Durchführen dieser Arbeiten wäre möglicherweise sinnvoll, wenn Sie mit ClientServer-Daten arbeiten und zusätzliche Möglichkeiten zum Steuern der Dateneingabeumgebung haben wollen. Das Einsetzen dieser Techniken wäre auch dann angebracht, wenn Sie Anwendungen sowohl für die Access- als auch die Visual-BasicUmgebung schreiben und die größtmögliche Code-Kompatibilität anstreben. Unabhängig von Ihren Gründen für das Einsetzen der folgenden Verfahren ist es nützlich zu wissen, wie man einem Formular ein Recordset-Objekt zuweist und dann die dem Formular zu Grunde liegende Datensatzgruppe zum Anzeigen und Bearbeiten der Daten einsetzt.
Abbildung 12.3: Das frmRecordsetDialogfeld
Die DAO-Container-Auflistung
541
Abbildung 12.3 zeigt ein Formular, dessen zum Navigieren und zur Datensatzauswahl dienende Schaltflächen entfernt wurden. Das Formular enthält sechs Schaltflächen: MOVE PREVIOUS (<), MOVE NEXT (>), ADD, DELETE, FIND und EXIT. All diese Schaltflächen verwenden die dem Formular zu Grunde liegende Datensatzgruppe, um sich innerhalb des Formulars von Datensatz zu Datensatz zu bewegen und die darin enthaltenen Daten zu bearbeiten. Die Eigenschaft RecordSource ist nicht gesetzt. Das Ereignis Load ist dafür verantwortlich, dem Formular ein Recordset-Objekt zuzuweisen. Listing 12.66 zeigt das Ereignis Load des Formulars. Listing 12.66: Das Ereignis Load wird eingesetzt, um dem Formular ein Recordset-Objekt zuzuweisen Private Sub Form_Load() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.CursorType = adOpenKeyset rst.LockType = adLockOptimistic rst.Open "Select * from tblClients", Options:=adCmdText Set Me.Recordset = rst End Sub
Der Code beginnt, indem er ein ADODB-Recordset-Objekt deklariert und eine Instanz von ihm bildet. Danach setzt er drei Eigenschaften: ActiveConnection, CursorType und LockType. Die Methode Open wird zum Öffnen einer auf der Tabelle tblClients basierenden Datensatzgruppe eingesetzt. Schließlich wird die Datensatzgruppe mit Hilfe der Set-Anweisung der dem Formular zu Grunde liegenden Datensatzgruppe zugewiesen. Wenn einem Formular eine ADO-Datensatzgruppe zugewiesen wird und dieses Formular auf Jet-Daten aufbaut, wird das Formular im schreibgeschützten Modus erstellt. Falls eine ADO-Datensatzgruppe einem auf SQL-Daten basierenden Formular zugewiesen wird, wird das Formular im Lesen/Schreiben-Modus angelegt. Listing 12.67 zeigt den Code für die Schaltfläche zum Ansteuern des vorhergehenden Datensatzes Listing 12.67: Code für die Schaltfläche zum Ansteuern des vorhergehenden Datensatzes Private Sub cmdPrevious_Click() Me.Recordset.MovePrevious If Me.Recordset.BOF Then Me.Recordset.MoveNext
542
Kapitel 12: Was sind ActiveX-Datenobjekte und Datenzugriffsobjekte?
MsgBox "Already at First Record!!" End If Me.Bookmark = Me.Recordset.Bookmark End Sub
Diese Routine führt die Methode MovePrevious mit der Eigenschaft Recordset des Formulars aus. Falls die Eigenschaft BOF den Wert True annimmt und auf diese Weise anzeigt, dass sich der Datensatzzeiger vor dem ersten gültigen Datensatz befindet, wird die Methode MoveNext mit der Formulareigenschaft Recordset ausgeführt, damit der Datensatzzeiger auf den ersten Datensatz der Datensatzgruppe zurückkehrt. Schließlich wird die Textmarke des Formulars mit der Textmarke der Eigenschaft Recordset synchronisiert. Listing 12.67 zeigt den Code für die Schaltfläche zum Ansteuern des nächsten Datensatzes. Listing 12.68: Code für die Schaltfläche zum Ansteuern des nächsten Datensatzes Private Sub cmdNext_Click() Me.Recordset.MoveNext If Me.Recordset.EOF Then Me.Recordset.MovePrevious MsgBox "Already at Last Record!!" End If Me.Bookmark = Me.Recordset.Bookmark End Sub
Wie in Listing 12.69 zu sehen ist, ist der Code für die Schaltfläche zum Hinzufügen eines Datensatzes ein wenig problematisch. Listing 12.69: Code für die Schaltfläche zum Hinzufügen eines Datensatzes Private Sub cmsAdd_Click() Me.Recordset.AddNew Me.Recordset!CompanyName = "New Company" Me.Recordset.Update Me.Bookmark = Me.Recordset.Bookmark End Sub
Die Methode AddNew wird mit der Eigenschaft Recordset des Formulars ausgeführt. Diese Methode legt im Speicher einen Puffer an, der zum Aufnehmen der neuen Daten dient. Durch das Aufrufen der Methode Update wird der Datensatzzeiger auf den neuen Datensatz bewegt. Da es sich bei dem Feld CompanyName um ein erforderliches Feld handelt, müssen Sie dieses mit Daten füllen, bevor Sie die Methode Update für die Eigenschaft Recordset aufrufen. Durch das Setzen der Formulartextmarke auf die Eigenschaft Bookmark der Datensatzgruppe synchronisieren Sie das Formular mit dem neuen Datensatz. In einer Produktionsumgebung ist es sinnvoll, alle Textfelder zu leeren und den Benutzer vor dem Ausführen der Methoden AddNew oder Update zum Speichern oder Abbrechen zu zwingen.
Die DAO-Container-Auflistung
543
Der Ablauf beim Löschen eines Datensatzes ist, wie in Listing 12.70 gezeigt, recht einfach. Listing 12.70: Einen Datensatz löschen Private Sub cmdDelete_Click() Dim intAnswer As Integer intAnswer = MsgBox("Are You Sure???", vbYesNo + vbQuestion, "Delete Current _ Record?") If intAnswer = vbYes Then Me.Recordset.Delete Call cmdNext_Click Me.Refresh End If End Sub
Dieser Code überprüft, ob der Benutzer den Datensatz wirklich löschen will, und ruft dann für die Formulareigenschaft Recordset die Methode Delete auf. Da der aktuelle Datensatz nicht mehr gültig ist, ruft der Code das Ereignis Click der Schaltfläche cmdNext auf. Der letzte Teil des am Formular beteiligten Codes ist der Code für die Schaltfläche zum Finden eines Datensatzes und wird in Listing 12.71 gezeigt. Listing 12.71: Der Code für die Schaltfläche zum Finden eines Datensatzes Private Sub cmdFind_Click() Dim strClientID As String Dim varBookmark As Variant varBookmark = Me.Recordset.Bookmark strClientID = InputBox("Enter Client ID of Client You Want to Locate") Me.Recordset.Find "ClientID = " & strClientID, Start:=1 If Me.Recordset.EOF Then MsgBox "Client ID " & strClientID & " Not Found!!" Me.Recordset.Bookmark = varBookmark Else Me.Bookmark = Me.Recordset.Bookmark End If End Sub
Die Routine beginnt, indem sie die Textmarke des aktuellen Datensatzes in einer Variant-Variablen speichert. Der Benutzer wird zur Angabe der von ihm gesuchten Client-ID aufgefordert und dann wird die Methode Find für die Formulareigenschaft Recordset aufgerufen. Falls die Eigenschaft EOF den Wert True hat, wird der Benutzer gewarnt und die Textmarke des Datensatzes auf den in der Variant-Variablen enthaltenen Wert gesetzt, so dass der Datensatzzeiger auf die Position zurückkehrt, die er vor der Suche innehatte. Wenn die Client-ID gefunden wird, wird die Textmarke des Formulars mit der der Eigenschaft Bookmark der Eigenschaft Recordset synchronisiert.
Falls etwas nicht nach Plan läuft
Teil II
13 Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung 14 Fehlerbehandlung: Vorbereitung auf das Unvermeidliche 15 Optimieren Ihrer Anwendung
Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
Kapitel
Hier lesen Sie:
Fehler vermeiden Die Leistungsfähigkeit des Direktfensters nutzen Den Debugger aufrufen Haltepunkte zur Problemlösung einsetzen Code schrittweise durchgehen Die nächste auszuführende Anweisung festlegen Das Fenster Aufrufeliste Mit dem Lokal-Fenster arbeiten Mit Überwachungsausdrücken arbeiten Die Verarbeitung nach einem Laufzeitfehler fortsetzen Gefundenes im Direktfenster ansehen Auch ein guter Programmierer ist nicht unbedingt in der Lage, alles im ersten Anlauf richtig zu machen. Um als VBA-Programmierer volle Effizienz zu erreichen, müssen Sie die Kunst der Fehlersuche beherrschen – den Vorgang, Probleme in Ihrer Anwendung aufzuspüren und zu lösen. Dazu gehört die Lokalisierung und das Erkennen von Problembereichen in Ihrem Code. Die Fehlersuche ist ein Pflichtbestandteil der Anwendungsentwicklung. Glücklicherweise stellt der Visual Basic Editor von Access 2000 ausgezeichnete Werkzeuge zur Unterstützung der Fehlersuche bereit. Mit diesen Werkzeugen können Sie den Code schrittweise durchgehen und nach Bedarf Halte- und Überwachungspunkte setzen. Die Verwendung der VBA-Werkzeuge zur Fehlersuche ist wesentlich effizienter, als aufs Geratewohl in Korrekturen zu Ihrer Anwendung herumzustochern. Ein leistungsfähiger Befehl aus den Access 2000-Fehlersuchwerkzeugen kann Ihnen stundenlange Fehlversuche ersparen. Genau genommen kann darin der Unterschied zwi-
548
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
schen dem erfolgreichen Abschluss und der unendlichen Fortsetzung des Entwicklungsprozesses mit ungelöst hinterlassenen Problemen liegen.
13.1
Fehler vermeiden
Die beste Methode, mit Fehlern umzugehen, besteht darin, sie von vornherein zu vermeiden. Korrekte Programmiertechniken können dabei wirklich hilfreich sein. Die Verwendung von Option Explicit, strenge Typisierung, Benennungsstandards und enge Gültigkeitsbereiche können dazu beitragen, Fehler in Ihrem Code zu verhindern.
13.1.1
Option Explicit
Die Anweisung Option Explicit verlangt, dass alle Variablen vor ihrer Verwendung deklariert werden. Die Aufnahme dieser Anweisung in jedes Formular-, Code- und Berichtsmodul hilft dem VBA-Compiler, Schreibfehler in Variablennamen zu finden. Wie in Kapitel 7 ausführlich dargestellt wurde, ist die Anweisung Option Explicit ein Befehl, der im Abschnitt Allgemeine Deklarationen jedes Code-, Formular- oder Berichtsmoduls stehen kann. Der Befehl kann manuell in jedes Programm eingefügt werden. Er lässt sich auch, falls Sie dies vorziehen, automatisch einfügen, indem Sie im Visual Basic Editor (VBE) zunächst EXTRAS|OPTIONEN und dann auf der Registerkarte EDITOR den Punkt VARIABLENDEKLARATION ERFORDERLICH wählen.
13.1.2
Strenge Typisierung
Die strenge Typisierung von Variablennamen wird in Kapitel 7 behandelt. »Strenge Typisierung« bedeutet, dass Sie bei der Deklaration angeben, welcher Datentyp in der Variablen gespeichert wird. Beispielsweise wird mit Dim intCounter As Integer eine Variable initialisiert, die Zahlen vom Datentyp Integer enthält. Wenn Sie intCounter irgendwo in Ihrem Code eine Zeichenfolge zuweisen, fängt der Compiler den Fehler ab.
13.1.3
Namenskonventionen
Auch Namenskonventionen können Sie ein Stück auf dem Weg der Fehlervermeidung voranbringen. Die sorgfältige Benennung von Variablen macht Ihren Code leichter lesbar und die beabsichtigte Verwendung der Variablen klarer. Problemcode hebt sich eher ab, wenn Namenskonventionen überlegt eingesetzt werden. Namenskonventionen werden in Kapitel 1 behandelt und im Anhang detailliert ausgeführt.
Die Leistungsfähigkeit des Direktfensters nutzen
13.1.4
549
Gültigkeitsbereich von Variablen
Schließlich lässt sich das Risiko, dass ein Code-Fragment versehentlich eine Variable in einem anderen Fragment überschreibt, dadurch reduzieren, dass man den Variablen den kleinstmöglichen Gültigkeitsbereich zuweist. Wenn es möglich ist, sollten Sie lokale Variablen verwenden. Verwenden Sie Variablen auf Modulebene und globale Variablen nur dann, wenn der Wert der Variablen für mehrere Unterroutinen bzw. Module sichtbar sein muss. Weitere Informationen zu den Fragen im Zusammenhang mit dem Gültigkeitsbereich von Variablen finden Sie in Kapitel 7.
13.1.5
Fehler kommen vor!
Was Sie auch immer tun mögen, um Probleme und Fehler zu vermeiden – Fehler schleichen sich leider trotzdem in Ihren Code ein. Wahrscheinlich die hinterhältigste Sorte sind Logikfehler. Ein »Logikfehler« ist tückisch, weil er dem Compiler entgeht: Ihr Code lässt sich kompilieren, funktioniert aber nicht so wie geplant. Fehler dieser Art zeigen sich möglicherweise, wenn ein Laufzeitfehler auftritt oder wenn Sie nicht die erwarteten Ergebnisse bekommen. An dieser Stelle kommt der Debugger zu Hilfe.
13.2
Die Leistungsfähigkeit des Direktfensters nutzen
Das Direktfenster erfüllt mehrere Aufgaben. Es bietet Ihnen eine großartige Möglichkeit, VBA- und benutzerdefinierte Funktionen zu testen, es ermöglicht Ihnen während der Ausführung des Codes den Wert von Variablen abzufragen und zu ändern und Sie können sich die Ergebnisse der Debug.Print-Anweisungen ansehen. Um das Direktfenster vom Visual Basic Editor aus zu öffnen, wählen Sie eine der folgenden drei Möglichkeiten:
Klicken Sie in der Symbolleiste DEBUGGEN auf das Werkzeug DIREKTFENSTER. Wählen Sie ANSICHT|DIREKTFENSTER. Drücken Sie (Strg)(G). Sie sehen das Direktfenster in Abbildung 13.1. Die Testwerkzeuge sind über eine eigene Symbolleiste erreichbar, nämlich über die Symbolleiste DEBUGGEN. Um diese anzuzeigen, klicken Sie mit der rechten Maustaste auf eine beliebige Symbol- oder Menüleiste und wählen aus der Liste der verfügbaren Symbolleisten DEBUGGEN.
550
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
Abbildung 13.1: Das Direktfenster ermöglicht Ihnen, Funktionen zu testen und den Wert von Variablen abzufragen und zu ändern
13.2.1
Den Wert von Variablen und Eigenschaften prüfen
Das Direktfenster ermöglicht Ihnen, den Wert von Variablen und Eigenschaften zu prüfen, während Ihr Code ausgeführt wird. Das kann in Bezug darauf, was in Ihrem Code tatsächlich geschieht, recht erhellend sein. Um mit dem Direktfenster zu üben, brauchen Sie noch nicht einmal Code auszuführen. Sie müssen nur, wenn Sie sich in einem Formular, Bericht oder Modul befinden, (Strg)(G) drücken, um das Fenster aufzurufen. Um zu sehen, wie das funktioniert, tun Sie Folgendes: 1. Starten Sie das Formular frmClients aus der Datenbank CHAP13EX.MDB auf der Begleit-CD. 2. Drücken Sie (Strg)+(G), um das Direktfenster zu öffnen und zu aktivieren. Sie gelangen in den Visual Basic Editor (VBE) im Direktfenster. 3. Geben Sie ?Forms!frmClients.txtClientID.Value ein und drücken Sie (¢). Die ClientID des aktuellen Clients erscheint in der nächsten Zeile. 4. Geben Sie ?Forms!frmClients.txtCompanyName.Visible ein und drücken Sie (¢). In der nächsten Zeile erscheint das Wort True, das angibt, dass das Steuerelement sichtbar ist. 5. Geben Sie ?Forms!frmClients.txtAddress.BackColor ein und drücken Sie (¢). In der nächsten Zeile erscheint die Zahl -2147483643, welche die Hintergrundfarbe des AdressSteuerelements angibt.
Die Leistungsfähigkeit des Direktfensters nutzen
551
Ihr Bildschirm sollte jetzt so aussehen wie der in Abbildung 13.2. Sie können mit der Abfrage der Werte von Variablen oder Eigenschaften in Ihrem VBA-Code fortfahren.
Abbildung 13.2: Die Verwendung des Direktfensters zum Prüfen der Werte von Eigenschaften
13.2.2
Werte von Variablen und Eigenschaften festlegen
Sie können das Direktfenster auf drei Arten aufrufen: Sie können auf die Schaltfläche DIREKTFENSTER in der Symbolleiste DEBUGGEN klicken, (Strg)+(G) drücken oder ANSICHT|DIREKTFENSTER wählen. Ein Vorteil der Tastenkombination besteht darin, dass das Direktfenster aufgerufen wird, ohne dass ein Code-Fenster aktiv ist. Der Klick auf die Schaltfläche DIREKTFENSTER der Symbolleiste und die Wahl des Menüpunkts ANSICHT|DIREKTFENSTER sind nur vom VBE aus möglich. Sie können sich im Direktfenster nicht nur etwas anzeigen lassen – Sie können es auch benutzen, um die Werte von Variablen und Steuerelementen zu ändern, während Ihr Code ausgeführt wird. Dieses Merkmal wird noch wertvoller, wenn Sie feststellen, dass Sie Code innerhalb einer Prozedur erneut ausführen können, nachdem Sie den Wert einer Variablen geändert haben. Und so geht's: 1. Rufen Sie, falls nötig, das Direktfenster auf. Denken Sie daran, dass Sie dazu (Strg)+(G) drücken können. 2. Geben Sie im Direktbereich Forms!frmClients.txtContactTitle.Value ein. Drücken Sie (¢). Der Wert des Feldes Contact Title des aktuellen Datensatzes ändert sich daraufhin in Hello.
552
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
3. Geben Sie ein: Forms!frmClients.txtCompanyName.Visible = False. Drücken Sie (¢). Das Steuerelement txtCompanyName im Formular frmClients wird verborgen. 4. Geben Sie Forms!frmClients.txtAddress.BackColor = 123456 ein. Drücken Sie (¢). Die Hintergrundfarbe des Steuerelements txtAddress im Formular frmClients wechselt auf Grün. Das Direktfenster und Ihr Formular sehen jetzt aus wie in Abbildung 13.3.
Abbildung 13.3: Festlegen der Werte von Eigenschaften mit Hilfe des Direktfensters
Das Direktfenster ist zum Testen und für die Fehlersuche äußerst wertvoll. Die hier vorgestellten Beispiele zeigen erst den Anfang seiner Leistungsfähigkeit und Flexibilität. Änderungen an Daten während der Arbeit im Direktfenster sind permanent. Dagegen werden Änderungen an den Eigenschaften von Steuerelementen oder den Werten von Variablen nicht mit dem Formular oder Bericht zusammen gespeichert.
13.2.3
Löschen des Direktfensters
Das Direktfenster zeigt die letzten 200 Ausgabezeilen an. Wenn weitere Code-Zeilen hinzugefügt werden, verschwinden ältere Zeilen. Wenn Sie Access vollständig verlassen und in das Direktfenster zurückkehren, ist es leer. Wenn Sie es zu einem anderen Zeitpunkt löschen wollen, sind folgende drei Schritte nötig: 1. Drücken Sie, während das Direktfenster aktiv ist, (Strg)+(Pos1), um an den Anfang des Direktfensters zu gelangen.
Die Leistungsfähigkeit des Direktfensters nutzen
553
2. Halten Sie die Umschalttaste gedrückt und drücken Sie (Strg)+(Ende), um zur letzten Anweisung im Direktfenster zu kommen. 3. Drücken Sie (Entf).
13.2.4
Mit den integrierten Funktionen üben
Sie können mit dem Direktfenster neben dem Prüfen der Werte von Variablen und Eigenschaften auch jede beliebige VBA-Funktion prüfen. Dazu geben Sie die Funktion und ihre Argumente in das Direktfenster ein und stellen ihr ein Fragezeichen voran. Der folgende Code gibt beispielsweise den aktuellen Monat zurück: ?datepart("m",date)
Die nächste Zeile nennt Ihnen das Datum heute in einem Monat: ?dateadd("m",1,date)
Die nächste Zeile sagt Ihnen, wie viele Tage zwischen dem aktuellen Datum und dem Ende des Jahrtausends liegen: ?datediff("d",date(),#12/31/1999#)
13.2.5
Unterroutinen, Funktionen und Methoden ausführen
Außer dem Testen aller VBA-Funktionen ermöglicht das Direktfenster auch das Testen aller benutzerdefinierten Unterroutinen, Funktionen und Methoden. Das ist eine hervorragende Möglichkeit, Fehler in benutzerdefinierten Funktionen zu suchen. Um zu sehen, wie es funktioniert, führen Sie folgende Schritte aus: 1. Öffnen Sie das Modul basExamples in der Datenbank CHAP13EX.MDB auf der Begleit-CD. 2. Starten Sie das Direktfenster, falls es noch nicht geöffnet ist. 3. Geben Sie ?ReturnInitsFunc("Bill","Gates") ein. Damit wird die benutzerdefinierte Funktion ReturnInitsFunc aufgerufen sowie als erster Parameter "Bill" und als zweiter "Gates" übergeben. Im Direktfenster erscheint der Wert B.G.. Dies ist der Rückgabewert der Funktion. 4. Geben Sie Call ReturnInitsSub("Bill","Gates") ein. Damit wird die benutzerdefinierte Unterroutine ReturnInitsFunc aufgerufen sowie als erster Parameter "Bill" und als zweiter "Gates" übergeben. Der Wert B.G. erscheint nun in einem Meldungsfeld. Beachten Sie den Unterschied zwischen dem Aufrufen einer Funktion und dem Aufrufen einer Unterroutine. Da die Funktion einen Wert zurückgibt, müssen Sie sie unter Verwendung eines Fragezeichens aufrufen. Dagegen verwenden Sie beim Aufrufen einer Unterroutine das Schlüsselwort Call.
554
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
Sie können eine Unterroutine aus dem Direktfenster auch mit folgender Syntax aufrufen: RoutineName Parameter1, Parameter2, ... Beachten Sie, dass die Parameter nicht in Klammern zu stehen brauchen, wenn Sie das Schlüsselwort Call weglassen.
13.2.6
Etwas zur Laufzeit in das Direktfenster ausgeben
Die Möglichkeit, etwas in das Direktfenster auszugeben, ist nützlich, weil Sie prüfen können, was geschieht, wenn Ihr Code ausgeführt wird, ohne die Ausführung unterbrechen zu müssen. Außerdem ist es wertvoll, etwas in ein Fenster ausgeben zu können, während Sie testen, ohne mit der Benutzerschnittstelle Ihres Codes in Berührung zu kommen. Sie können ein Formular testen, ohne unterbrochen zu werden, und dann zurückkehren und sich die Werte von Variablen ansehen usw. Und so funktioniert dieser Vorgang: 1. Geben Sie CallLoopThroughCollection ein. Damit wird die benutzerdefinierte Unterroutine LoopThroughCollection aufgerufen. Die Werte Skating, Basketball, Hockey und Skiing erscheinen. Die Routine gibt sie in das Direktfenster aus. 2. Öffnen Sie in der Formularansicht das Formular frmDebugPrint. 3. Drücken Sie (ÿ), um vom Feld FIRST NAME zum Feld LAST NAME zu kommen. 4. Drücken Sie (ÿ), um zum Feld FIRST NAME zurückzukehren. 5. Geben Sie Ihren Vornamen ein.
Abbildung 13.4: Verwendung von Debug.PrintAnweisungen zur Ausgabe von Werten in das Direktfenster
Den Debugger aufrufen
555
6. Öffnen Sie das Direktfenster. Nehmen Sie zur Kenntnis, dass alle Anweisungen in das Direktfenster ausgegeben wurden (siehe Abbildung 13.4). Diese Debug.Print-Anweisungen sind in allen entsprechenden Formular- und Steuerelementereignissen enthalten.
13.3
Den Debugger aufrufen
Der Access-Debugger lässt sich auf unterschiedliche Art aufrufen:
Setzen Sie in Ihrem Code einen Haltepunkt. Fügen Sie in Ihren Code einen Überwachungsausdruck ein. Drücken Sie (Strg)+(Pause), während der Code ausgeführt wird. Fügen Sie eine Stopp-Anweisung in Ihren Code ein. Ein »Haltepunkt« ist ein unbedingter Punkt, an dem Sie die Ausführung des Codes aussetzen können. Er ist temporär, weil er nur wirkt, solange die Datenbank geöffnet ist. Mit anderen Worten: Haltepunkte werden nicht zusammen mit der Datenbank gespeichert. Ein »Überwachungsausdruck« ist eine Bedingung, unter der Sie die Ausführung des Codes aussetzen können. Möglicherweise ist das der Fall, wenn eine Variable counter einen bestimmten Wert erreicht. Ein Überwachungsausdruck ist ebenfalls temporär; er wird gelöscht, wenn Sie die Datenbank schließen. Eine Stopp-Anweisung ist permanent. Falls Sie vergessen, Stopp-Anweisungen aus Ihrem Code zu entfernen, stoppt die Anwendung die Ausführung auch dann, wenn der Benutzer sie einsetzt.
13.4
Haltepunkte einsetzen
Wie bereits erwähnt, ist ein Haltepunkt ein Punkt, an dem die Ausführung des Codes in jedem Fall angehalten wird. Sie können mehrere Haltepunkte in Ihren Code einfügen. Während der Ausführung können Sie Haltepunkte setzen und entfernen. Ein Haltepunkt gibt Ihnen die Möglichkeit, die Code-Ausführung in einem verdächtigen Code-Bereich anzuhalten. Sie können dann alles untersuchen, was bei der Ausführung des Codes an diesem Punkt geschieht. Durch strategisches Verteilen von Haltepunkten in Ihrem Code können Sie Code-Abschnitte, die bereits getestet sind, schnell ausführen und nur in Problembereichen anhalten. Um einen Haltepunkt zu setzen, ist Folgendes nötig: 1. Setzen Sie den Cursor in die Code-Zeile, in der Sie den Debugger starten wollen. 2. Ein Haltepunkt kann auf vier verschiedene Arten eingefügt werden:
556
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
– Drücken Sie die Funktionstaste (F9). – Klicken Sie in den grauen Randbereich links von der Code-Zeile, die den Haltepunkt enthalten soll. – Klicken Sie auf die Schaltfläche HALTEPUNKT DEBUGGEN.
EIN/AUS
in der Symbolleiste
– Wählen Sie DEBUGGEN|HALTEPUNKT EIN/AUS. Die Code-Zeile mit dem Haltepunkt erscheint in einer anderen Farbe; der Haltepunkt selbst wird durch einen Punkt gekennzeichnet. 3. Starten Sie das Formular, den Bericht oder das Modul mit dem Haltepunkt. VBA unterbricht die Ausführung genau vor der Ausführung der Code-Zeile, in der Sie den Haltepunkt platziert haben. Die Anweisung, die als nächste auszuführen ist, erscheint in einer Kontrastfarbe (Standard ist Gelb). Nachdem Ihr Code jetzt unterbrochen ist, können Sie ihn Zeile für Zeile schrittweise durchgehen, den Wert von Variablen ändern und u.a. Ihre Aufrufeliste ansehen. Denken Sie daran, dass ein Haltepunkt eigentlich ein Schalter ist. Wenn Sie einen Haltepunkt entfernen wollen, klicken Sie in den grauen Randbereich, drücken (F9) oder klicken in der Symbolleiste DEBUGGEN auf HALTEPUNKT EIN/AUS. Haltepunkte werden beim Schließen der Datenbank, beim Öffnen einer anderen Datenbank oder beim Verlassen von Access gelöscht. Am einfachsten lernen Sie den Debugger kennen, indem Sie ihn tatsächlich verwenden. Das folgende Beispiel vermittelt Ihnen Anfangserfahrungen im Setzen von Haltepunkten und Anhalten der Code-Ausführung. Es wird später weiterentwickelt. Beginnen Sie mit der Erstellung eines Formulars frmDebug, welches eine Befehlsschaltfläche mit dem Namen cmdDebug enthält. Versehen Sie die Schaltfläche mit der Beschriftung START DEBUG PROCESS. Fügen Sie den folgenden Code in die Routine für das Click-Ereignis der Befehlsschaltfläche ein: Sub cmdDebug_Click () Call Func1 End Sub
Erstellen Sie ein Modul basFuncs. Nehmen Sie in dieses drei Funktionen auf: Sub Func1 () Dim intTemp As Integer intTemp = 10 Debug.Print "We Are Now In Func1()" Debug.Print intTemp Call Func2 End Sub
Haltepunkte einsetzen
557
Sub Func2 () Dim strName As String strName = "Bill Gates" Debug.Print "We Are Now In Func2()" Debug.Print strName Call Func3 End Sub Sub Func3 () Debug.Print "We Are Now In Func3()" MsgBox "Hi there From The Func3() Sub Procedure" End Sub
Jetzt sollten Sie testen. Beginnen Sie mit der Platzierung eines Haltepunkts im ClickEreignis von cmdDebug in der Zeile Call Func1. Es folgen die einzelnen Schritte: 1. Klicken Sie an einer beliebigen Stelle in der Zeile Call Func1. 2. Klicken Sie in dem grauen Randbereich, drücken Sie die Funktionstaste (F9), klicken Sie auf die Schaltfläche HALTEPUNKT EIN/AUS in der Symbolleiste DEBUGGEN oder wählen Sie DEBUGGEN|HALTEPUNKT EIN/AUS. Die Zeile mit dem Haltepunkt wechselt die Farbe (sie wird standardmäßig rot). 3. Gehen Sie in die Formularansicht und klicken Sie auf die Schaltfläche START DEBUG PROCESS. Access unterbricht die Ausführung genau vor der Ausführung der Zeile, in der Sie den Haltepunkt gesetzt haben. VBA stellt die Zeile Call Func1 in einer anderen Farbe (standardmäßig in Gelb) dar und deutet damit an, dass es im Begriff ist, diese Zeile auszuführen (siehe Abbildung 13.5).
Abbildung 13.5: Anhalten der Code-Ausführung an einem Haltepunkt
558
13.5
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
Code schrittweise durchgehen
Access 2000 stellt Ihnen für das schrittweise Testen von Code drei Hauptoptionen zur Verfügung, die sich jeweils ein wenig unterscheiden. Die Option EINZELSCHRITT ermöglicht das schrittweise Testen jeder Code-Zeile in einer Unterroutine oder Funktion, während die Option PROZEDURSCHRITT eine Prozedur ausführt, ohne jede Code-Zeile einzeln abzuarbeiten. Die Option PROZEDUR ABSCHLIESSEN führt den gesamten Code in verschachtelten Prozeduren aus und führt Sie dann zu der Prozedur zurück, welche die Code-Zeile aufgerufen hat, in der Sie sich befinden. Das Wissen, welche Option die richtige für die Lösung eines bestimmten Problems ist, stellt eine erworbene Fähigkeit dar, die sich mit fortgesetzter Entwicklungserfahrung bildet.
13.5.1
Die Option Einzelschritt
Beim Erreichen eines Haltepunkts können Sie so fortfahren, dass Sie Ihren Code zeilenweise ausführen oder die Ausführung bis zum nächsten Haltepunkt fortsetzen. Um den Code Zeile für Zeile durchzugehen, klicken Sie in der Symbolleiste DEBUGGEN auf EINZELSCHRITT, drücken (F8) oder wählen DEBUGGEN|EINZELSCHRITT. Das folgende Beispiel veranschaulicht den Vorgang des schrittweisen Testens, der Ausgabe der Werte von Variablen in das Direktfenster und der Änderung der Werte von Variablen mit Hilfe des Direktfensters. Sie können den Testvorgang von dem Haltepunkt aus fortsetzen, den Sie im vorhergehenden Beispiel gesetzt haben. Gehen Sie zwei Schritte weiter (drücken Sie (F8)). Sie sollten sich jetzt in Func1 befinden, im Begriff, die Zeile intTemp = 10 auszuführen (siehe Abbildung 13.6). Beachten Sie, dass VBA nicht bei der Zeile Dim intTemp As Integer angehalten hat. Der Debugger stoppt grundsätzlich nicht bei Variablendeklarationen. Die Debug-Anweisungen sind im Begriff, etwas in das Direktfenster auszugeben. Noch hat Ihr Code nichts in das Fenster ausgegeben. Drücken Sie (F8) (einen Schritt weiter) noch dreimal, bis Sie die Zeile Debug.Print intTemp ausgeführt haben. Ihr Bildschirm sollte dann so aussehen wie in Abbildung 13.7. Beachten Sie die Ergebnisse der Debug.Print-Anweisungen. Nachdem Sie jetzt gesehen haben, wie man Variablen und die Ergebnisse von Ausdrücken im Direktfenster anzeigen kann, sollten Sie einen Blick darauf werfen, wie Sie das Direktfenster zur Veränderung der Werte von Variablen und Steuerelementen verwenden können. Ändern Sie zuerst den Wert von intTemp. Klicken Sie in das Direktfenster und geben Sie intTemp = 50 ein. Wenn Sie (¢) drücken, ändern Sie tatsächlich den Wert von intTemp. Geben Sie ?intTemp ein und Sie sehen, dass Access den Wert 50 zurückgibt. Außerdem können Sie den Wert von intTemp im LokalFenster sehen. Beachten Sie in Abbildung 13.8, dass die Variable intTemp gemeinsam mit ihrem Wert und ihrem Typ erscheint.
Code schrittweise durchgehen
559
Abbildung 13.6: Das Direktfenster hat innerhalb von Func1 angehalten
Abbildung 13.7: Das Direktfenster mit Einträgen, die von Debug.PrintAnweisungen erzeugt wurden
560
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
Abbildung 13.8: Das Direkt- und das Lokal-Fenster nach der Änderung des Wertes von intTemp
13.5.2
Ausführen bis zum nächsten Haltepunkt
Angenommen, Sie haben einen Haltepunkt erreicht, erkennen aber, dass das Problem weiter hinten im Code liegt. Eigentlich befindet es sich sogar in einer anderen Funktion. Sie wollen vielleicht nicht Schritt für Schritt bis zu der störenden Funktion weitergehen. Lokalisieren Sie die fragliche Funktion mit Hilfe des Dropdown-Menüs PROZEDUR und setzen Sie in der Zeile, in der Sie mit dem schrittweisen Testen weitermachen wollen, einen Haltepunkt. Jetzt können Sie mit der Ausführung des Codes fortfahren, bis Access diese Zeile erreicht. Dazu klicken Sie in der Symbolleiste DEBUGGEN auf FORTSETZEN, drücken (F5) oder wählen AUSFÜHREN|FORTSETZEN. Ihr Code wird weiter ausgeführt und hält an dem Haltepunkt an, den Sie gerade gesetzt haben. Um zu sehen, wie dies funktioniert, setzen Sie den Testvorgang mit dem nächsten Beispiel fort. Sie können sich auch dafür entscheiden, die Ausführung des Codes bis zu dem Punkt fortzusetzen, an dem sich der Cursor befindet. Dazu wählen Sie im Menü DEBUGGEN den Eintrag AUSFÜHREN BIS CURSOR-POSITION oder drücken die Tastenkombination (Strg)+(F8).
Nehmen wir an, Sie erkennen, dass sich Ihr Problem in Func3 befinden könnte. Sie möchten nicht schrittweise bis zu Func3 weitergehen. Kein Problem! Sehen Sie sich mit Hilfe des Dropdown-Menüs PROZEDUR Func3 an, wie in Abbildung 13.9 gezeigt. Setzen Sie in der Zeile Debug.Print "We Are Now in Func3()" einen Haltepunkt. Dann können Sie die Ausführung des Codes fortsetzen, bis Access diese Zeile
Code schrittweise durchgehen
561
erreicht. Um die Ausführung fortzusetzen, klicken Sie in der Symbolleiste DEBUGGEN auf FORTSETZEN, drücken (F5) oder wählen AUSFÜHREN|FORTSETZEN. Ihr Code wird weiter ausgeführt und an dem Haltepunkt unterbrochen, den Sie gerade gesetzt haben. Drücken Sie noch einmal (F5). Der Code wird bis zum Ende ausgeführt. Kehren Sie in die Formularansicht zurück.
13.5.3
Die Option Prozedurschritt
Manchmal haben Sie eine Unterroutine bereits vollständig getestet und auf Fehler geprüft. Sie wollen die Routine, in der Sie sich gerade befinden, weiter schrittweise untersuchen, aber nicht die Ausführung von Unterroutinen beobachten. In diesem Fall verwenden Sie die Option PROZEDURSCHRITT. Um eine Unterroutine oder Funktion als Ganzes auszuführen, klicken Sie in der Symbolleiste DEBUGGEN auf PROZEDURSCHRITT, drücken (SHIFT)+(F8) oder wählen DEBUGGEN|PROZEDURSCHRITT. Der Code innerhalb der Unterroutine oder Funktion, die Sie abarbeiten, wird nun ausgeführt, aber nicht schrittweise. Um mit der Option PROZEDURSCHRITT zu experimentieren, halten Sie sich an das nächste Beispiel.
Abbildung 13.9: Mit Hilfe des Dropdown-Menüs Prozedur sehen Sie sich eine weitere Funktion an
Klicken Sie wieder auf das offene Formular und noch einmal auf die Schaltfläche START DEBUG PROCESS. Da Ihre Haltepunkte immer noch gesetzt sind, werden Sie in die Code-Zeile Call Func1 geführt. Wählen Sie im Menü DEBUGGEN den Eintrag ALLE HALTEPUNKTE LÖSCHEN oder entfernen Sie diese mit der Tastenkombination (Strg)+(SHIFT)+(F9). Gehen Sie fünf Schritte weiter ((F8)), bis Sie im Begriff sind, die Zeile Call Func2 auszuführen. Nehmen wir an, Sie haben Func2 und Func3 getestet
562
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
und wissen, dass diese nicht die Ursache der Probleme in Ihrem Code sind. Klicken Sie, während Func2 als nächste auszuführende Zeile hervorgehoben ist, in der Symbolleiste auf PROZEDURSCHRITT. Beachten Sie, dass sowohl Func2 als auch Func3 ausgeführt werden, Sie jetzt jedoch so weit sind, Func1 weiter schrittweise durchzugehen. In diesem Fall werden Sie in die Zeile End Sub geführt, die unmittelbar auf den Aufruf von Func2 folgt.
13.5.4
Die Option Prozedur abschließen
Die Option PROZEDUR ABSCHLIESSEN wird verwendet, um die aktuelle Prozedur zu verlassen und zu der Prozedur zurückzukehren, welche die Code-Zeile aufgerufen hat, in der man sich befindet. Sie machen von dieser Möglichkeit Gebrauch, wenn Sie versehentlich eine Prozedur schrittweise ausführen und bemerken, dass sie vollständig getestet ist. Sie wollen den gesamten Code ausführen, der von der Prozedur, in der sie sind, aufgerufen wird, und dann in die aufrufende Prozedur zurückgehen, so dass Sie den Testvorgang fortsetzen können. Um zu testen, wie das funktioniert, halten Sie sich an das folgende Beispiel. 1. Setzen Sie im Aufruf von Func2 einen Haltepunkt. 2. Klicken Sie auf die Schaltfläche ZURÜCKSETZEN in der Symbolleiste, um die Ausführung des Codes zu unterbrechen. 3. Aktivieren Sie das Formular frmDebug und klicken Sie auf die Befehlsschaltfläche START DEBUG PROCESS. 4. Gehen Sie einen Schritt weiter, um in die erste Zeile von Func2 zu kommen. 5. Nehmen wir an, Sie erkennen, dass Sie einen Schritt zu weit gegangen sind. In Wirklichkeit hatten Sie vor, Func2 und alle von dieser Prozedur aufgerufenen Prozeduren als Ganzes auszuführen. Kein Problem! Klicken Sie auf die Schaltfläche PROZEDUR ABSCHLIESSEN, um Func2 zu verlassen und in die Zeile zurückzukehren, die auf die Zeile folgt, in der Func2 aufgerufen wurde. In diesem Fall sollten Sie sich in der Anweisung End Sub von Func1 wiederfinden.
13.6
Die nächste auszuführende Anweisung festlegen
Nachdem Sie den Code schrittweise durchgearbeitet, den logischen Fluss beobachtet und einige Variablen geändert haben, wollen Sie vielleicht den Code von einer früheren Anweisung an noch einmal ausführen. Die einfachste Möglichkeit, dies zu tun, besteht darin, auf den gelben Pfeil am Rand zu klicken und ihn zu der Anweisung zu ziehen, mit der Sie die Ausführung fortsetzen wollen. Wenn es Ihnen lieber ist, können Sie an einer beliebigen Stelle in der Code-Zeile klicken, in der Sie mit der Aus-
Das Fenster Aufrufeliste
563
führung beginnen wollen, und dann DEBUGGEN|NÄCHSTE ANWEISUNG FESTLEGEN wählen. Beachten Sie unabhängig von der gewählten Methode die Kontrastfarbe (normalerweise Gelb), die besagt, dass die nächste auszuführende Code-Zeile jetzt oberhalb dieser Anweisung steht. Sie können dann mit (F8) den Code schrittweise prüfen oder mit (F5) die normale Ausführung des Codes fortsetzen. Access lässt Sie die nächste ausführbare Code-Zeile nur innerhalb einer Prozedur festlegen. Die Option kann verwendet werden, um Code-Zeilen noch einmal auszuführen oder eine problematische Zeile zu überspringen. Das folgende Beispiel zeigt, wie der Wert einer Variablen geändert und der Code nach der Änderung erneut ausgeführt wird. Das vorhergehende Beispiel hat Sie in der letzten Code-Zeile (der Anweisung End Sub) von Func1 zurückgelassen. Sie wollen den Wert von intTemp ändern und dann alles noch einmal ausführen. 1. Gehen Sie in das Direktfenster und geben Sie intTemp = 100 ein. 2. Sie müssen die nächste auszugebende Anweisung in der Zeile Debug.Print "We Are Now In Func1" festlegen. Dazu klicken Sie auf den gelben Pfeil und ziehen diesen von der Anweisung End Sub in die genannte Code-Zeile. Beachten Sie die Kontrastfarbe (Gelb), die besagt, dass sich die nächste auszuführende Code-Zeile jetzt oberhalb der Anweisung befindet. 3. Drücken Sie (F8) (Einzelschritt) zweimal. Der Code wird jetzt mit dem Wert 100 für intTemp ausgeführt. Sehen Sie sich das Direktfenster noch einmal an. Beachten Sie die Änderung der Ergebnisse.
13.7
Das Fenster Aufrufeliste
Sie haben gelernt, wie man Haltepunkte setzt, wie man Code schrittweise und als ganze Prozedur abarbeitet, wie man das Direktfenster einsetzt, wie man die nächste auszuführende Code-Zeile festlegt und wie man die Ausführung bis zum nächsten Haltepunkt fortsetzt. Beim Erreichen eines Haltepunkts ist es häufig wichtig zu erfahren, welche Funktionen aufgerufen wurden, um Sie zu diesem Punkt zu bringen. Hier kann die Aufrufeliste helfen. Um das Fenster AUFRUFELISTE zu öffnen, klicken Sie auf die Schaltfläche AUFRUFELISTE in der Symbolleiste oder wählen ANSICHT|AUFRUFELISTE. Das Fenster in Abbildung 13.10 erscheint. Wenn Sie die Code-Zeile sehen wollen, von der aus eine bestimmte Funktion oder Unterroutine aufgerufen wurde, doppelklicken Sie auf diese Funktion und klicken dann auf ANZEIGEN. Obwohl der Ausführungspunkt nicht in die aufrufende Funktion oder Unterroutine wandert, können Sie den Code in der Prozedur sehen.
564
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
Wenn Sie mit der Ausführung des Codes fortfahren wollen, drücken Sie (F8). Sie kehren in die Prozedur zurück, die Sie gerade untersucht haben, und die nächste Code-Zeile wird ausgeführt. Wenn Sie (F5) drücken, wird Ihr Code ausgeführt, bis ein weiterer Haltepunkt oder ein Überwachungsausdruck erreicht ist. Wenn Sie dahin zurückkehren wollen, wo Sie waren, ohne weitere Code-Zeilen auszuführen, wählen Sie DEBUGGEN|NÄCHSTE ANWEISUNG ANZEIGEN. Führen Sie das nächste Beispiel aus, um diesen Vorgang zu testen.
Abbildung 13.10: Mit Hilfe des Fensters Aufrufeliste die Liste ansehen
1. Klicken Sie auf die Schaltfläche ZURÜCKSETZEN, um die Ausführung des Codes abzubrechen, falls Sie sich noch im Unterbrechungsmodus befinden. 2. Entfernen Sie den Haltepunkt im Aufruf von Func2. 3. Gehen Sie in die Prozedur Func3 in basFuncs. Setzen Sie in der Zeile Debug.Print "We Are Now In Func3()" einen Haltepunkt. 4. Starten Sie das Formular frmDebug und klicken Sie auf die Befehlsschaltfläche. Sie werden in die Zeile mit dem Haltepunkt in Func3 versetzt. 5. Öffnen Sie mit einem Klick auf die Schaltfläche AUFRUFELISTE in der Symbolleiste das Fenster AUFRUFELISTE. Wenn Sie die Code-Zeile sehen wollen, die aus Func1 heraus Func2 aufgerufen hat, doppelklicken Sie auf Func1. Obwohl der Ausführungspunkt nicht nach Func1 wandert, können Sie den Code in der Prozedur sehen. Um in die nächste auszuführende Code-Zeile zurückzukehren, wählen Sie DEBUGGEN|NÄCHSTE ANWEISUNG ANZEIGEN. 6. Drücken Sie (F5) und der Rest des Codes wird ausgeführt.
565
Mit dem Lokal-Fenster arbeiten
13.8
Mit dem Lokal-Fenster arbeiten
Mit Hilfe des Lokal-Fensters können Sie sich alle Variablen im aktuellen StackBereich sowie ihre Werte ansehen und diese ändern. Um auf das Lokal-Fenster zuzugreifen, klicken Sie in der Symbolleiste auf LOKAL-FENSTER oder wählen im Menü ANSICHT den Eintrag LOKAL-FENSTER. Es erscheinen drei Spalten: AUSDRUCK, WERT und TYP. Die Spalte AUSDRUCK zeigt Ihnen die Variablen, die benutzerdefinierten Typen, die Datenfelder und die anderen innerhalb der aktuellen Prozedur sichtbaren Objekte. Die Spalte WERT enthält den aktuellen Wert der Variablen oder des Ausdrucks. Die Spalte TYP gibt an, welchen Datentyp die Variable enthält. Variablen, die hierarchische Informationen wie beispielsweise Datenfelder enthalten, werden mit einer Schaltfläche dargestellt, die das Ein- und Ausblenden der Hierarchie-Ebenen ermöglicht. Die im Lokal-Fenster enthaltenen Informationen sind dynamisch. Sie werden bei Ausführung des Codes und beim Wechsel von Routine zu Routine automatisch aktualisiert. Abbildung 13.11 veranschaulicht, wie Sie mit Hilfe des Lokal-Fensters die für die Unterroutine Func2 verfügbaren Variablen anzeigen können. Um dieses Beispiel selbst auszuprobieren, entfernen Sie alle vorhandenen Haltepunkte. Setzen Sie dann in der Code-Zeile DebugPrint.strName in Func2 einen neuen Haltepunkt. Klicken Sie auf ZURÜCKSETZEN, falls noch Code ausgeführt wird. Um den Code bis zum Haltepunkt auszuführen, klicken Sie auf die Befehlsschaltfläche START DEBUG PROCESS. Klicken Sie auf die Schaltfläche LOKAL-FENSTER in der Symbolleiste. Klicken Sie auf das Pluszeichen, um den Inhalt der öffentlichen Variablen gintCounter zu sehen.
Abbildung 13.11: Das Lokal-Fenster
Im Lokal-Fenster lässt sich der Wert einer Variablen ändern, nicht jedoch ihr Name oder ihr Typ.
13.9
Mit Überwachungsausdrücken arbeiten
Manchmal reicht es nicht, den Wert einer Variablen oder eines Ausdrucks mit Hilfe des Direktfensters zu überprüfen. Vielleicht wollen Sie den Wert eines Ausdrucks ständig im Auge behalten. Mit Access 95 wurde die Möglichkeit eingeführt, Überwachungsausdrücke zu setzen. Das ist vor dem Start einer Prozedur oder während einer
566
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
Unterbrechung der Code-Ausführung möglich. Nachdem ein Überwachungsausdruck hinzugefügt wurde, erscheint dieser im Überwachungsfenster. Wie Sie sehen werden, gibt es verschiedene Arten von Überwachungsausdrücken.
13.9.1
Automatische Daten-Tipps verwenden
Die schnellste und einfachste Möglichkeit, sich den in einer Variablen enthaltenen Wert anzusehen, besteht in der Verwendung der Option AUTOMATISCHE DATENTIPPS. Diese steht für die Arbeit mit Modulen zur Verfügung und zwar nur im Unterbrechungsmodus. Sie ziehen dann einfach die Maus über die Variable oder den Ausdruck, deren/dessen Wert Sie prüfen wollen. Zusammen mit dem aktuellen Wert erscheint dann ein Tipp. Um die Option AUTOMATISCHE DATEN-TIPPS zu aktivieren, wählen Sie vom Visual Basic Editor (VBE) aus EXTRAS|OPTIONEN, klicken auf die Registerkarte EDITOR und aktivieren die Option AUTOMATISCHE DATEN-TIPPS, die Sie unter den Optionen für die Code-Einstellungen finden.
13.9.2
Die Option Aktuellen Wert anzeigen
Die Option AKTUELLEN WERT ANZEIGEN stellt die einfachste Art eines Überwachungsausdrucks dar. Um sie einzufügen, markieren Sie den Namen der Variablen oder des Ausdrucks, den Sie überwachen wollen, und klicken auf die Schaltfläche AKTUELLEN WERT ANZEIGEN in der Symbolleiste. Das Dialogfeld AKTUELLEN WERT ANZEIGEN (Abbildung 13.12) wird eingeblendet. Sie können auf HINZUFÜGEN klicken, um den Ausdruck als permanenten Überwachungsausdruck einzufügen, oder auf ABBRECHEN, um sich den aktuellen Wert anzusehen, ohne ihn als Überwachungsausdruck einzufügen. Wenn Sie auf HINZUFÜGEN klicken, sehen Sie das Fenster ÜBERWACHUNGSAUSDRÜCKE, das aussieht wie in Abbildung 13.13. Es wird im nächsten Abschnitt ausführlicher behandelt.
Abbildung 13.12: Mit dem Dialogfeld Aktuellen Wert anzeigen können Sie schnell den Wert einer Variablen ansehen oder einen Ausdruck als permanenten Überwachungsausdruck hinzufügen
Abbildung 13.13: Das Fenster Überwachungsausdrücke mit einem typischen Eintrag
Mit Überwachungsausdrücken arbeiten
13.9.3
567
Einen Überwachungsausdruck hinzufügen
Wie Sie gesehen haben, können Sie einen Überwachungsausdruck mit Hilfe des Dialogfeldes AKTUELLEN WERT ANZEIGEN hinzufügen. Auf diese Art lässt sich der Charakter des Überwachungsausdrucks jedoch nicht vollständig steuern. Dazu müssen Sie DEBUGGEN|ÜBERWACHUNG HINZUFÜGEN wählen. Dann erscheint das Dialogfeld ÜBERWACHUNG HINZUFÜGEN, das Sie in Abbildung 13.14 sehen. Wenn Sie über AKTUELLEN WERT ANZEIGEN oder DEBUGGEN|ÜBERWACHUNG HINZUFÜGEN einen Überwachungsausdruck setzen, können Sie dessen Einzelheiten leicht anpassen, indem Sie mit der rechten Maustaste im Fenster ÜBERWACHUNGSAUSDRÜCKE auf den Ausdruck klicken und anschließend ÜBERWACHUNG BEARBEITEN wählen.
Abbildung 13.14: Mit dem Dialogfeld Überwachung hinzufügen lassen sich die Einzelheiten eines Überwachungsausdrucks leicht festlegen
Im Textfeld AUSDRUCK geben Sie eine Variable, eine Eigenschaft, einen Funktionsaufruf oder irgendeinen anderen gültigen Ausdruck ein. Wichtig ist, die Prozedur und das Modul zu markieren, in der/dem der Ausdruck überwacht werden soll. Als nächstes geben Sie an, ob Sie den Wert des Ausdrucks nur im Direktfenster beobachten wollen oder eine Unterbrechung wünschen, wenn der Ausdruck True wird oder sich ändert. Die letzten beiden Optionen werden in den nächsten Abschnitten ausführlich behandelt. Das nächste Beispiel führt Sie durch den Vorgang, einen Überwachungsausdruck hinzuzufügen und die zu überwachende Variable beim schrittweisen Durchlaufen des Codes zu beobachten. Es veranschaulicht, wann eine Variable gültig wird bzw. ihre Gültigkeit verliert und wie sie während der Ausführung ihren Wert ändert.
568
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
1. Halten Sie zunächst die Ausführung des Codes an, falls sie gerade läuft, und entfernen Sie alle Haltepunkte. 2. Klicken Sie auf die Variable strName in Func2. 3. Klicken Sie mit der rechten Maustaste und wählen Sie ÜBERWACHUNG HINZUFÜGEN. 4. Klicken Sie auf OK, um die Prozedur Func2 als Kontext für die Variable und basFuncs als Modul für die Variable zu bestätigen. 5. Setzen Sie in der Zeile strName = "Bill Gates" einen Haltepunkt. 6. Starten Sie das Formular frmDebug und klicken Sie auf die Befehlsschaltfläche. Sehen Sie sich das Fenster ÜBERWACHUNGSAUSDRÜCKE an und beachten Sie, dass der Wert von strName eine Zeichenkette der Länge Null ist. 7. Gehen Sie einen Schritt weiter und beachten Sie, dass strName den Wert Bill Gates annimmt. 8. Gehen Sie noch drei Schritte weiter. Beachten Sie, dass strName, obwohl Sie sich in der Routine Func3 befinden, immer noch den Wert Bill Gates hat. Das liegt daran, dass sich die Variable nach wie vor im Kontext von basFuncs.Func2 im Speicher befindet. 9. Gehen Sie vier Schritte weiter, bis Sie zur Anweisung End Sub von Func2 zurückgekehrt sind. Die Variable Func2 befindet sich immer noch im Kontext. 10. Gehen Sie noch einen Schritt weiter. Die Variable strName befindet sich nun nicht mehr im Kontext, weil Func2 ausgeführt wurde.
13.9.4
Einen Überwachungsausdruck bearbeiten
Nachdem Sie einen Überwachungsausdruck hinzugefügt haben, möchten Sie vielleicht seine Einzelheiten bearbeiten oder ihn vollständig entfernen. Dazu verwenden Sie das Dialogfeld ÜBERWACHUNG BEARBEITEN. Unternehmen Sie Folgendes: 1. Aktivieren Sie das Fenster ÜBERWACHUNGSAUSDRÜCKE. 2. Markieren Sie den Ausdruck, den Sie bearbeiten wollen. 3. Wählen Sie DEBUGGEN|ÜBERWACHUNG BEARBEITEN oder klicken Sie mit der rechten Maustaste und wählen Sie ÜBERWACHUNG BEARBEITEN. Es erscheint das Dialogfeld in Abbildung 13.15. 4. Nehmen Sie Änderungen am Überwachungsausdruck vor oder klicken Sie auf LÖSCHEN, um ihn zu entfernen.
Mit Überwachungsausdrücken arbeiten
569
Abbildung 13.15: Sie können das Feld Überwachung bearbeiten einsetzen, um die Einzelheiten eines Überwachungsausdrucks zu ändern, nachdem Sie ihn hinzugefügt haben
13.9.5
Unterbrechen, wenn ein Ausdruck True ist
Ein leistungsfähiger Aspekt eines Überwachungsausdrucks ist der Umstand, dass Sie die Ausführung unterbrechen können, sobald ein Ausdruck True wird. Sie könnten beispielsweise eine Unterbrechung herbeiführen, sobald eine Public-Variable einen bestimmten Wert erreicht. Eine solche Situation kann eintreten, wenn eine Publicoder Private-Variable irgendwie verändert wird und Sie feststellen möchten, wo dies geschieht. Schauen Sie sich den folgenden Code an, der sich im Modul basFuncs von CHAP13EX.MDB befindet: Sub ChangeGlobal1() gintCounter = 50 Call ChangeGlobal2 End Sub Sub ChangeGlobal2() gintCounter = gintCounter + 10 Call ChangeGlobal3 End Sub Sub ChangeGlobal 3() Dim intCounter As Integer For intCounter = 1 To 10 gintCounter = gintCounter + intCounter Next intCounter End Sub
Vielleicht stellen Sie fest, dass gintCounter irgendwie eine Zahl über 100 erreicht und Sie sind nicht sicher, warum. Um das Problem zu lösen, fügen Sie den in Abbildung 13.16 gezeigten Überwachungsausdruck hinzu. Beachten Sie, dass der Ausdruck, auf den Sie prüfen, gintCounter > 100 heißt. Sie haben den Haltepunkt so gesetzt, dass der Code abgebrochen wird, sobald der Ausdruck True wird. Um den Code zu testen,
570
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
geben Sie im Direktfenster ChangeGlobal1 ein und drücken (¢). Der Code sollte in der Routine ChangeGlobal3 abgebrochen werden, was besagt, dass diese Routine der Übeltäter ist.
Abbildung 13.16: Definieren eines Überwachungsausdrucks, der zum Abbruch der Code-Ausführung führt, sobald der Ausdruck True wird
13.9.6
Abbrechen, wenn sich ein Ausdruck ändert
Anstatt abzubrechen, wenn ein Ausdruck True wird, wollen Sie vielleicht abbrechen, sobald sich der Wert des Ausdrucks ändert. Das ist eine hervorragende Möglichkeit, die Stelle zu ermitteln, an der sich der Wert einer Variablen auf geheimnisvolle Weise verändert. Wie UNTERBRECHEN, WENN DER WERT TRUE IST eignet sich die Option UNTERBRECHEN, WENN WERT GEÄNDERT WURDE hervorragend für die Verfolgung von Problemen mit öffentlichen und privaten Variablen. Betrachten Sie den Überwachungsausdruck, der in Abbildung 13.17 gesetzt wird. Er steht im Kontext aller Prozeduren in allen Modulen. Er soll abbrechen, sobald sich der Wert von gintCounter ändert. Wenn Sie die Routine ChangeGlobal1 ausführen, stellen Sie fest, dass der Code in der Routine ChangeGlobal1 anhält, unmittelbar nachdem der Wert von gintCounter auf 50 gesetzt wurde. Wenn Sie (F5) drücken, um die Ausführung fortzusetzen, hält der Code in ChangeGlobal2 unmittelbar nach der Erhöhung von gintCounter um 10 an. Anders ausgedrückt: die Ausführung des Codes bricht nach jeder Modifikation des Wertes von gintCounter ab.
Abbildung 13.17: Erstellen eines Überwachungsausdrucks, der den Abbruch der Code-Ausführung veranlasst, sobald sich der Wert eines Ausdrucks ändert
571
Die Ausführung nach einem Laufzeitfehler fortsetzen
13.10
Die Ausführung nach einem Laufzeitfehler fortsetzen
Beim Testen treffen Sie häufig auf Laufzeitfehler, die sich ganz einfach beheben lassen. Wenn ein Laufzeitfehler auftritt, wird ein ähnliches Dialogfeld wie in Abbildung 13.18 eingeblendet. Wenn Sie auf DEBUGGEN klicken, gelangen Sie im Code-Fenster in die Zeile, die den Fehler ausgelöst hat. Nach der Korrektur des Problems klicken Sie auf die Schaltfläche FORTSETZEN in der Symbolleiste oder wählen AUSFÜHREN|FORTSETZEN.
Abbildung 13.18: Das Dialogfeld für Laufzeitfehler
Abbildung 13.19 zeigt zum Beispiel einen Fehler wegen Division durch Null, nachdem im Dialogfeld mit dem Laufzeitfehler auf DEBUGGEN geklickt wurde. Der Wert von int2 wurde auf 20 gesetzt. Die Code-Ausführung kann jetzt ohne Fehler fortgesetzt werden.
Abbildung 13.19: Der Testmodus nach einem Fehler wegen Division durch Null
Häufig zeigt VBA nach dem Auftreten eines Fehlers eine Meldung an, die Ihnen die Möglichkeit gibt, Ihren Code zurückzusetzen. Wenn Sie dies tun, verlieren alle Variablen (inklusive Public- und Static-Variablen) ihre Werte. Sie können auch in der Symbolleiste auf ZURÜCKSETZEN klicken. Sie müssen sich entscheiden, ob es besser ist, mit gesetzten Variablen fortzufahren oder die Variablen zurückzusetzen und dann fortzufahren.
572
Kapitel 13: Fehlersuche: Ihr Schlüssel zur erfolgreichen Entwicklung
13.11
Gefundenes im Direktfenster ansehen
Obwohl der Debugger von Access hervorragend ist, gibt es im Testvorgang als solchem eine Reihe potentieller Probleme, u.a. folgende:
Der Testvorgang kann die Code-Ausführung unterbrechen, insbesondere, wenn es um Formulare geht. Wenn dies geschieht, ist es am günstigsten, Debug.PrintAnweisungen in den Code einzufügen und zu prüfen, was geschieht, nachdem der Code ausgeführt wurde.
Ähnlich wie beim vorigen Problem ist die Fehlerprüfung bei Code schwierig, in dem GotFocus- und LostFocus-Ereignisse vorkommen. Der Wechsel in den VBE (Visual Basic Editor) löst das LostFocus-Ereignis des Steuerelements aus. Die Rückkehr zum Formular führt dazu, dass das GotFocus-Ereignis des Steuerelements erneut eintritt. Wiederum stellt Debug.Print eine hervorragende Lösung dar. Sie könnten auch daran denken, Informationen zur Einsicht nach der Ausführung des Codes in ein Fehlerprotokoll zu schreiben.
Code, der die Objekte Screen.ActiveForm und Screen.ActiveControl verwendet, macht beim Testen Ärger. Wenn die IDE aktiv ist, gibt es kein aktives Formular und kein aktives Steuerelement. Das Problem wird weniger kritisch, wenn Sie solche Zeilen nach Möglichkeit vermeiden.
Seien Sie sich schließlich bewusst, dass das Zurücksetzen des Codes zu Problemen führen kann. Wenn Sie Umgebungseinstellungen ändern, finden Sie sich nach der Ausführung Ihrer Anwendung in der veränderten Umgebung wieder. Wenn Sie die Ausführung nach dem Fehler ohne Zurücksetzen fortsetzen, können alle möglichen anderen Probleme auftreten. Es ist günstig, eine spezielle Hilfsroutine zu schreiben, die die Umgebung zurücksetzt.
13.11.1
Für die Praxis
Echte Anwendungen testen Wenden Sie bei der Entwicklung des Zeit- und Abrechnungssystems die gelernten Techniken an, die Ihnen helfen, die auftretenden Probleme zu lösen. Für den Augenblick sollten Sie jedoch den Debugger verwenden, um schrittweise vorzugehen und bei einer der Routinen aus der erwähnten Anwendung mehr über den Testvorgang zu erfahren. Öffnen Sie das Formular frmClients in CHAP13EX.MDB in der Entwurfsansicht. Setzen Sie in der Code-Zeile If IsNull(Me![ClientID]) Then im Click-Ereignis der Schaltfläche VIEW PROJECT einen Haltepunkt (siehe Abbildung 13.20). Starten Sie das Formular und klicken Sie auf die Befehlsschaltfläche PROJEKT ANZEIGEN. Gehen Sie den Code schrittweise durch und beobachten Sie die Ausführung.
Gefundenes im Direktfenster ansehen
573
Abbildung 13.20: Setzen eines Haltepunkts in frmClients
Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
Kapitel
Hier lesen Sie:
Fehler beheben Fehlerbehandlung implementieren Mit Fehlerereignissen arbeiten On Error-Anweisungen Resume-Anweisungen Fehlerinformationen löschen Verschachtelte Fehlerbehandlungsroutinen Das Objekt Err Einen Fehler auslösen Die Auflistung Errors Eine allgemeine Fehlerbehandlungsroutine erstellen Verhindern, dass Ihre eigenen Fehlerbehandlungsroutinen aufgerufen werden
14.1
Fehler beheben
Fehler kommen vor, selbst ohne Zutun des Programmierers. Sie müssen Ihre Programme und Daten durch Fehlerbehandlung vor den negativen Auswirkungen von Fehlern schützen. Fehlerbehandlung wird auch als Fehlerbehebung bezeichnet. »Fehlerbehandlung« ist der Vorgang, die Reaktion von Jet oder VBA auf einen Fehler abzufangen. Sie ermöglicht dem Entwickler, die Schwere eines Fehlers zu ermitteln und in Reaktion darauf das Richtige zu tun. Dieses Kapitel zeigt Ihnen die Techniken, die zur erfolgreichen Implementierung der Fehlerbehandlung in Ihren Anwendungen erforderlich sind.
576
14.2
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
Fehlerbehandlung implementieren
Ohne Fehlerbehandlung ist der Benutzer Ihrer Anwendung gezwungen, den Anwendungs-Code abrupt zu verlassen. Sehen Sie sich das Beispiel in Listing 14.1 an. Listing 14.1:
Ein Beispiel für Code ohne Fehlerbehandlung
Private Sub cmdCauseError_Click() Call TestError1(txtValue1, txtValue2) End Sub Sub TestError1(Numerator As Integer, Denominator As Integer) Debug.Print Numerator / Denominator MsgBox "I am in Test Error" End Sub
Das Klickereignis hinter der Befehlsschaltfläche ruft die Routine TestError1 auf und übergibt ihr die Werte aus zwei Textfeldern. TestError1 akzeptiert diese Parameter und versucht, den ersten Parameter durch den zweiten zu dividieren. Wenn der zweite Parameter gleich 0 ist, tritt ein Laufzeitfehler auf. Da keine Fehlerbehandlung aktiv ist, bricht das Programm ab. Abbildung 14.1 zeigt die Fehlermeldung, die der Benutzer erhält. Wie Sie sehen können, lauten die Wahlmöglichkeiten FORTFAHREN, BEENDEN, DEBUGGEN und HILFE. Wenn der Benutzer DEBUGGEN wählt, wird das Modulfenster eingeblendet und er gelangt im Testmodus in die Code-Zeile, die den Fehler ausgelöst hat. Die Auswahl von FORTFAHREN (die nicht immer zur Verfügung steht) weist Access an, den Fehler zu ignorieren und die Ausführung des Programms fortzusetzen. BEENDEN beendet die Ausführung des Programm-Codes. Wenn die Anwendung mit der Laufzeitversion von Access läuft, wird sie beendet und der Benutzer kehrt zu Windows zurück. Wenn die Fehlerbehandlung aktiv ist, können Sie versuchen, den Fehler, falls möglich, auf geeignetere Weise zu behandeln.
Abbildung 14.1: Die Standardmeldung zur Fehlerbehandlung
Mit Fehlerereignissen arbeiten
577
Sie können Code zur Fehlerbehandlung in die Fehlerereignisprozedur eines Formulars oder Berichts integrieren. Außerdem können Sie solchen Code in jede Unterroutine, Funktion oder Ereignisroutine von VBA einfügen. Der Code in Listing 14.1 lässt sich leicht so ändern, dass der Fehler elegant abgefangen wird. Der Code in Listing 14.2 zeigt eine einfache Fehlerbehandlungsroutine. Listing 14.2:
Eine einfache Fehlerbehandlungsroutine
Sub TestError2(Numerator As Integer, Denominator As Integer) On Error GoTo TestError2_Err Debug.Print Numerator / Denominator MsgBox "I am in Test Error" Exit Sub TestError2_Err: If Err = 11 Then MsgBox "Variable 2 Cannot Be a Zero", , "Custom Error Handler" End If Exit Sub End Sub
Dieser Code steht im Modul basError, das Sie in der Datenbank CHAP14EX.MDB auf der Begleit-CD finden.
Die Routine ruft jetzt die Fehlerbehandlung auf. Wenn ein Fehler wegen Division durch Null auftritt, warnt ein Meldungsfeld den Benutzer vor dem Problem, wie Abbildung 14.2 zeigt.
Abbildung 14.2: Eine Meldung der beutzerdefinierten Fehlerbehandlungsroutine
14.3
Mit Fehlerereignissen arbeiten
Jedes Formular und jeder Bericht enthält eine Fehlerereignisprozedur. Dieses Ereignis wird von jedem Fehler der Schnittstelle oder der Jet-Datenbank-Engine ausgelöst, nicht jedoch von einem Programmierfehler des Access-Entwicklers.
578
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
Fehler treten häufig in der Schnittstelle eines Formulars oder Berichts oder in der JetDatenbank-Engine auf. Ein Benutzer könnte zum Beispiel versuchen, eine Bestellung für einen nicht vorhandenen Kunden einzugeben. Anstatt die Access-Standardfehlermeldung auszugeben, wollen Sie den Fehler vielleicht abfangen und auf bestimmte Weise behandeln. Nachdem in einem Formular ein Fehler aufgetreten ist, wird dessen Fehlerereignis ausgelöst. In Listing 14.3 sehen Sie die Routine Sub Form_Error. Diese enthält zwei Parameter. Der erste ist die Fehlernummer, der zweite die Methode, mit der Sie auf den Fehler reagieren wollen. Die Fehlernummer wird von Access erzeugt. Dieser Code, den Sie im Formular frmOrders in der Datenbank CHAP14EX.MDB finden, prüft auf einen Fehler im Zusammenhang mit referentieller Integrität. Falls ein solcher aufgetreten ist, fragt ein Meldungsfeld, ob der Benutzer den Kunden hinzufügen will. Wenn dieser mit yes antwortet, wird das Kundenformular angezeigt. Listing 14.3:
Die Routine Sub Form_Error aus dem Formular frmOrders
Private Sub Form_Error(DataErr As Integer, Response As Integer) Dim intAnswer As Integer If DataErr = 3201 Then 'Referential Integrity Error intAnswer = MsgBox("Customer Does Not Exist... _ Would You Like to Add Them Now", vbYesNo) If intAnswer = vbYes Then DoCmd.OpenForm "frmCustomer", , , , acAdd, acDialog End If End If Response = acDataErrContinue End Sub
Denken Sie daran, dass das Beispiel in Listing 14.3 nur Fehler in Bezug auf referentielle Integrität abfängt, keine Fehler anderer Art.
Sehr wichtig ist die Zeile Response = acDataErrContinue. Sie bringt Access dazu, die Code-Ausführung fortzusetzen, ohne die Standardfehlermeldung anzuzeigen. Die andere Option für Response lautet acDataErrDisplay. Sie weist Access an, die Standardfehlermeldung auszugeben. Wenn Sie gern eine Liste aller Fehler, die in Ihrem VBA-Code auftreten können, sowie eine Erläuterung der Fehlernummern hätten, wählen Sie im VBE ?|MICROSOFT VISUAL BASIC-HILFE. Klicken Sie auf die Registerkarte INDEX und geben Sie als Schlüsselwort Fehler ein. Klicken Sie auf SUCHEN. Markieren Sie im Listenfeld THEMA AUSWÄHLEN den Eintrag ERMITTELN DER VON VISUAL BASIC RESERVIERTEN
On Error-Anweisungen
579
FEHLERCODES. Der Code, der erforderlich ist, um eine Tabelle mit VBA-Fehlernummern und -beschreibungen zu erstellen, erscheint im rechten Feld des Hilfefensters. Sie können ihn in ein beliebiges Modul kopieren und starten. Dann wird eine Tabelle mit Fehlernummern und -beschreibungen erstellt.
14.4
On Error-Anweisungen
On Error-Anweisungen aktivieren die Fehlerbehandlung. Jede Routine muss eine eigene On Error-Anweisung enthalten, wenn Sie wollen, dass sie eine eigene Fehler-
behandlung betreibt. Andernfalls wird zur Fehlerbehandlung der Aufrufstack durchsucht. Wenn auch dort keine On Error-Anweisungen zu finden sind, wird die VBAeigene Fehlerbehandlung aufgerufen. Nehmen wir an, dass Func1 Func2 aufruft und Func2 Func3. Nur in Func1 gibt es eine Fehlerbehandlung. In Func3 tritt nun ein Fehler auf. Func3 gibt die Steuerung an Func2 weiter. Func2 besitzt keine Fehlerbehandlung und übergibt daher die Steuerung an Func1. Func1 behandelt den Fehler. Ein Hinweis darauf, dass die Fehlerbehandlungsroutine in Func1 nicht zwangsläufig geeignet ist, um den in Func3 aufgetretenen Fehler abzufangen, erübrigt sich. Mit Hilfe einer On Error-Anweisung können Sie die Anwendung veranlassen, zum Fehlerbehandlungs-Code zu verzweigen, in der Zeile, die unmittelbar auf den Fehler folgt, weiterzumachen oder zu versuchen, die problematische Code-Zeile erneut auszuführen. Sie müssen entscheiden, welche Reaktion sich für einen bestimmten Fehler am besten eignet. Manchmal ist es am günstigsten, wenn die Anwendung als Reaktion auf einen Fehler einfach angehalten wird. In anderen Fällen ist das Überspringen der störenden Zeile die beste Lösung. Durch Kombinieren der Anweisungen On Error GoTo, On Error Resume Next und Resume lässt sich jeder Fehler angemessen behandeln.
14.4.1
On Error GoTo
Die Anweisung On Error GoTo <Sprungmarke> sagt VBA, dass es von dieser Stelle in der Unterroutine oder Funktion zur in der Anweisung genannten Sprungmarke gehen soll, falls ein Fehler auftritt. Das ist die häufigste Form der Fehlerbehandlung. Die in der On Error-Anweisung angegebene Sprungmarke muss sich in der aktuellen Prozedur befinden und innerhalb des Moduls eindeutig sein. Listing 14.4 zeigt ein einfaches Beispiel für Fehlerbehandlung. Listing 14.4:
Ein Beispiel für Fehlerbehandlung mit der Anweisung On Error GoTo
Sub SimpleErrorHandler(iVar1 As Integer, iVar2 As Integer) On Error GoTo SimpleErrorHandler_Err
580
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
Dim sngResult As String sngResult = iVar1 / iVar2 Exit Sub SimpleErrorHandler_Err: MsgBox "Oops!" Exit Sub End Sub
Aus dieser einfachen Routine können Sie einige wichtige Dinge lernen. Sie übernimmt zwei Integer-Werte. Dann ruft sie die Fehlerbehandlungsroutine auf. Wenn ein Fehler auftritt, wird die Ausführung an der Sprungmarke fortgesetzt. Beachten Sie, dass die Routine zwei Exit Sub-Anweisungen enthält. Wenn Sie die erste entfernen, wird der Code auch ohne Auftreten eines Fehlers bis zur Sprungmarke ausgeführt. Die Exit Sub-Anweisung am Ende schließt die Prozedur elegant ab und setzt den Fehler-Code auf 0 zurück. Fehlernummer und -beschreibung in die Fehlerbehandlungsroutine integrieren Der Fehlerbehandlungs-Code in Listing 14.4 hat dem Benutzer keine sehr aussagekräftige Meldung geliefert. Die Eigenschaften DESCRIPTION und NUMBER des Objekts Err bieten uns bedeutungsvollere Fehlermeldungen. Das Objekt Err wird weiter hinten in diesem Kapitel im Abschnitt »Das Objekt Err« ausführlich behandelt. Sehen Sie sich zunächst die Eigenschaften DESCRIPTION und NUMBER an, um zu erfahren, wie Sie diese zur Erweiterung einer Fehlerbehandlungsroutine einsetzen können. Um mit ihm Fehlernummer und -beschreibung anzuzeigen, müssen Sie den Fehlerbehandlungs-Code folgendermaßen ändern: SimpleErrorHandler_Err: MsgBox "Error #" & ErrNumber & ": " & Err.Description Exit Sub
Diesmal geben Sie, anstatt die Fehlermeldung hart zu kodieren, die Fehlernummer und den internen VBA-Fehlertext aus. Abbildung 14.3 zeigt die sich daraus ergebende Fehlermeldung. Die Routine SimpleErrorHandler und alle folgenden Beispiele finden Sie im Modul basError der Datenbank CHAP14EX.MDB.
Abbildung 14.3: Eine Fehlermeldung mit Fehlernummer und -beschreibung
On Error-Anweisungen
581
On Error GoTo 0 On Error GoTo 0 wird für zwei Dinge verwendet:
Wenn Access zu seiner standardmäßigen Fehlerbehandlungsroutine zurückkehren soll
Wenn Access zur Fehlerbehandlung einer Routine zurückkehren soll, die oberhalb der aktuellen Routine liegt Im Allgemeinen wollen Sie nicht, dass Access zu seiner standardmäßigen Fehlerbehandlung zurückkehrt. Aber vielleicht ist es dann der Fall, wenn Sie den Fehler nicht abfangen können oder wenn Sie sich in der Testphase befinden und noch nicht so weit sind, eine eigene Fehlerbehandlungsroutine zu implementieren. Der Grund dafür, dass Access den Fehler an eine weiter oben angesiedelte Routine weiterleiten soll, ist wesentlich klarer. Sie tun dies, wenn Sie die Fehlerbehandlung »zentralisieren« wollen, was bedeutet, dass eine Routine mehrere andere aufrufen könnte. Anstatt in jede aufgerufene Routine eine Fehlerbehandlung zu integrieren, ist es in bestimmten Situationen günstiger, die Fehlerbehandlung in der aufrufenden Routine zu erledigen.
14.4.2
On Error Resume Next
On Error Resume Next setzt die Programmausführung in der Zeile fort, die unmittelbar auf den Fehler folgt. Dieses Konstrukt wird im Allgemeinen verwendet, wenn das Ignorieren eines Fehlers und die Fortsetzung der Code-Ausführung akzeptabel ist. Listing 14.5 zeigt ein Beispiel für eine derartige Situation. Listing 14.5:
Einen Fehler ignorieren und die Ausführung fortsetzen
Sub TestResumeNext() On Error Resume Next Kill "AnyFile" MsgBox "We Didn't die, But the Error Was: " & Err.Description End Sub
Die Kill-Anweisung wird verwendet, um eine Datei von der Festplatte zu löschen. Wenn die angegebene Datei nicht gefunden wird, tritt ein Fehler auf. Die Datei wird nur gelöscht, wenn sie vorhanden ist, und deshalb brauchen Sie sich nicht um den Fehler zu kümmern. On Error Resume Next ist für diese Situation gut geeignet, weil die Wiederaufnahme der Ausführung nach der störenden Code-Zeile keinen Schaden anrichtet.
582
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
14.5
Resume-Anweisungen
Während Sie sich im Fehlerbehandlungs-Code befinden, können Sie die Anweisungen Resume, Resume Next und Resume verwenden, um anzugeben, wie VBA auf den Fehler reagieren soll. Resume versucht, die fehlerhafte Code-Zeile erneut auszuführen, Resume Next nimmt die Ausführung nach dieser Zeile wieder auf, und Resume setzt die Ausführung an einer genannten Zeilensprungmarke fort. Die folgenden Abschnitte behandeln die Anweisungen im Einzelnen.
14.5.1
Die Anweisung Resume
Die Anweisung Resume nimmt die Ausführung des Codes in der Zeile wieder auf, die zu dem Fehler geführt hat. Sie müssen sie mit äußerster Vorsicht verwenden, weil sie den Code unwiderruflich in eine Endlosschleife führen kann. Listing 14.6 zeigt ein Beispiel für die falsche Verwendung der Anweisung Resume. Listing 14.6:
Falsche Verwendung von Resume
Function BadResume(strFileName As String) On Error GoTo BadResume_Err Dim strFile As String strfile = Dir(strFileName) If strFile = "" Then BadResume = False Else BadResume = True End If Exit Function BadResume_Err: MsgBox Error Resume End Function
Dieser Funktion wird ein Dateiname übergeben. Die Funktion Dir sucht nach dem Dateinamen und gibt True oder False zurück, abhängig davon, ob sie den Dateinamen findet. Das Problem tritt auf, wenn das angefragte Laufwerk nicht verfügbar oder nicht vorhanden ist. Dieser Code bringt den Rechner in eine endlose Schleife. Um das Problem zu beheben, sollten Sie den Code so ändern, dass er aussieht wie in Listing 14.7. Listing 14.7:
Bedingte Verwendung von Resume auf der Grundlage von Benutzerrückmeldungen
Function GoodResume(strFileName As String) On Error GoTo GoodResume_Err Dim strFile As String
583
Resume-Anweisungen
strfile = Dir(strFileName) If strFile = "" Then GoodResume = False Else GoodResume = True End If Exit Function GoodResume_Err: Dim intAnswer As Integer intAnswer = MsgBox(Error & "Would You Like to Try Again?", vbYesNo) If intAnswer = vbYes Then Resume Else ExitFunction End If End Function
In diesem Beispiel überlässt die Fehlerbehandlungsroutine dem Benutzer die Entscheidung, ob er es noch einmal versuchen will. Resume kommt nur ins Spiel, wenn der Benutzer mit Ja antwortet.
14.5.2
Die Anweisung Resume Next
Genauso, wie Sie die Fehlerbehandlung mit der Anweisung On Error Resume Next starten können, können Sie, wie Listing 14.8 zeigt, auch eine Resume Next-Anweisung in Ihre Fehlerbehandlungsroutine einbauen. Listing 14.8:
Aufnehmen einer Resume Next-Anweisung in die Fehlerbehandlungsroutine
Sub TestResumeNextInError() On Error GoTo TestResumeNextInError_Err Kill "AnyFile" MsgBox "We Didn't Die!" Exit Sub TestResumeNextInError_Err: ResumeNext End Sub
In
diesem
Beispiel
wird
der
Code
angewiesen,
die
Sprungmarke
TestResumeNextInError_Err anzusteuern, wenn ein Fehler auftritt. Diese führt eine Resume Next-Anweisung aus, welche den Fehler behebt und veranlasst, dass die Aus-
führung in der Zeile nach dem Fehler wieder aufgenommen wird.
584
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
14.5.3
Die Anweisung Resume
Mit der Anweisung Resume können Sie eine Code-Zeile angeben, in der die Ausführung nach dem Auftreten eines Fehlers wieder aufgenommen werden soll. Dies ist eine gute Möglichkeit, die beiden Exit Sub- bzw. Exit FunctionAnweisungen zu beseitigen, die in den bisher vorgestellten Fehlerbehandlungsroutinen erforderlich waren. Listing 14.9 zeigt ein Beispiel. Listing 14.9:
Mit Hilfe der Anweisung Resume angeben, wo die Ausführung nach dem Auftreten eines Fehlers fortgesetzt werden soll
Sub TestResumeLineLabel(intVar1 As Integer, intVar2 As Integer) On Error GoTo TestResumeLineLabel_Err Dim sngResult As String sngResult = intVar1 / intVar2 TestResumeLineLabel_Exit: Exit Sub TestResumeLineLabel_Err: MsgBox "Error #" & Err.Number & ": " & Err.Description Resume TestResumeLineLabel_Exit End Sub
Beachten Sie, dass diese Routine nur eine einzige Exit Sub-Anweisung enthält. Wenn kein Fehler auftritt, läuft Access bis zur Sprungmarke TestResumeLineLabel_Exit hindurch bis zur Anweisung Exit Sub. Wenn jedoch ein Fehler auftritt, wird der Code in TestResumeLineLabel_Err ausgeführt. Beachten Sie, dass die letzte Zeile der Fehlersprungmarke die Ausführung an der Sprungmarke TestResumeLineLabel_Exit wieder aufnimmt. Diese Methode der Fehlerbehebung ist sinnvoll, weil der gesamte Code, der beim Verlassen der Routine ausgeführt werden muss, an einer Stelle untergebracht werden kann. Es könnte zum Beispiel nötig sein, alle Objektvariablen auf Nothing zu setzen, wenn die Routine verlassen wird. Sie können die entsprechenden Code-Zeilen in die Routine zum Verlassen einbauen.
14.6
Fehlerinformationen löschen
Wenn ein Fehler auftritt, bleiben die Fehlerinformationen im Objekt Err erhalten, bis sie auf eine der folgenden Arten gelöscht werden:
mit Resume, Resume Next oder Resume mit Exit Sub, Exit Function oder Exit Property
Verschachtelte Fehlerbehandlungsroutinen
585
mit einer beliebigen GoTo-Anweisung durch explizite Verwendung der Methode Clear für das Objekt Err Bis die Informationen gelöscht sind, bleiben sie im Objekt Err erhalten. Nach dem Löschen sind im Objekt Err keine Informationen mehr vorhanden.
14.7
Verschachtelte Fehlerbehandlungsroutinen
Wie bereits im Abschnitt »On Error-Anweisungen« erwähnt, sucht Access im Aufruf-Stack nach einer früheren Fehlerbehandlungsroutine, wenn es in einer Unterroutine oder Funktion keine Fehlerbehandlung findet. Listing 14.10 zeigt ein Beispiel für diesen Vorgang. Listing 14.10: Im Aufruf-Stack nach einer früheren Fehlerbehandlungsroutine suchen Sub Func1() On Error GoTo Func1_Err Debug.Print "I am in Function 1" Call Func2 Debug.Print "I am back in Function 1" Exit Sub Func1_Err: MsgBox "Error in Func1" Resume Next End Sub Sub Func2() Debug.Print "I am in Function 2" Call Func3 Debug.Print "I am still in Function 1" End Sub Sub Func3() Dim sngAnswer As Single Debug.Print "I am in Function 3" sngAnswer = 5 / 0 Debug.Print "I am still in Function 3" End Sub
In dieser Situation tritt der Fehler in Func3 auf. Da Func3 keine eigene Fehlerbehandlung besitzt, wendet sie sich an Func2. Auch Func2 hat keine Fehlerbehandlung und deshalb übergibt sie die Steuerung an Func1. VBA führt den Fehler-Code in Func1 aus. Das wirkliche Problem tritt wegen der Resume Next-Anweisung auf. Die Anwendung fährt mit der Ausführung in Func1 bei der Anweisung Debug.Print "I am in Function 1" fort. Diese Art der Fehlerbehandlung ist gefährlich und verwirrend. Des-
586
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
halb ist es am besten, eine allgemeine Fehlerbehandlungsroutine zu entwickeln, auf die aus der gesamten Anwendung zugegriffen werden kann. Dies wird im Abschnitt »Eine allgemeine Fehlerbehandlungsroutine erstellen« behandelt.
14.8
Das Objekt Err
Das Objekt Err enthält Informationen über den zuletzt aufgetretenen Fehler. Wie alle Access-Objekte besitzt es Eigenschaften und Methoden. Tabelle 14.1 fasst die Eigenschaften des Objekts Err zusammen. Eigenschaft
Beschreibung
Description
Beschreibung des aufgetretenen Fehlers
HelpContext
Kontext-ID für die Hilfedatei
HelpFile
Pfad und Name der Hilfedatei
LastDLLError
Letzter in einer 32-Bit-DLL aufgetretener Fehler
Number
Nummer des aufgetretenen Fehlers
Source
System, in dem der Fehler aufgetreten ist (was äußerst sinnvoll ist, wenn Sie über OLE-Automatisierung eine weitere Anwendung, z.B. Excel, steuern)
Tabelle 14.1: Eigenschaften des Objekts Err
Das Objekt Err besitzt nur zwei Methoden: Clear und Raise. Mit der Methode Clear können Sie eine Fehlerbedingung explizit löschen. Sie wird in erster Linie eingesetzt, wenn Sie Code schreiben, der die Anweisung On Error Resume Next verwendet. Diese Anweisung löscht die Fehlerbedingung nicht. Denken Sie daran, dass es keinen Grund gibt, die Methode Clear mit irgendeiner der folgenden Anweisungen explizit aufzurufen: Resume, Exit Sub, Exit Function, Exit Property oder On Error GoTo. Wenn diese Konstrukte verwendet werden, wird die Methode Clear implizit ausgeführt. Die Methode Raise des Objekts Err wird im nächsten Abschnitt behandelt.
14.9
Einen Fehler auslösen
Die Methode Raise des Fehlerobjekts wird in folgenden Situationen eingesetzt:
wenn Sie einen Fehler mit Absicht erzeugen wollen (zum Beispiel beim Testen) wenn Sie einen benutzerdefinierten Fehler erzeugen wollen
Einen Fehler auslösen
587
wenn der aktuelle Fehler von der Fehlerroutine nicht behandelt wird und Sie anderen Teilen des Aufruf-Stacks erlauben wollen, eine Fehlerbehandlung zu versuchen
wenn Sie eine Fehlerbehandlungsroutine verschachteln wollen Die Verwendung der Methode Raise zum absichtlichen Erzeugen eines Fehlers und die Erstellung eines benutzerdefinierten Fehlers werden in den folgenden Abschnitten besprochen.
14.9.1
Einen Fehler absichtlich erzeugen
Häufig wollen Sie beim Testen einen Fehler erzeugen, um Ihre Fehlerbehandlung auszuprobieren. Anstatt zu suchen, wie ein bestimmter Fehler ausgelöst wird, können Sie die Methode Raise des Objekts Err für diese Aufgabe einsetzen, wie Listing 14.11 zeigt. Listing 14.11: Auslösen eines Fehlers Sub TestRaiseError() On Error GoTo TestRaiseError_Err Dim sngResult As String Err.Raise 11 Exit Sub TestRaiseError_Err: MsgBox "Error #" & Err.Number & ": " & Err. Description Exit Sub End Sub
Dieser Code verursacht einen error 11 (Division durch 0). Durch Erzeugen dieses Fehlers können Sie die Effizienz Ihrer Fehlerbehandlungsroutine testen.
14.9.2
Benutzerdefinierte Fehler erstellen
Eine weitere wichtige Verwendung der Methode Raise des Objekts Err ist das Erzeugen einer benutzerdefinierten Fehlerbedingung. Das ist sinnvoll, wenn Sie etwas brauchen, das keinen Access-Fehler, sondern einen benutzerdefinierten Fehler verursacht, den Sie der normalen Fehlerbehandlung unterziehen können. Da Sie mit der Methode Raise alle Eigenschaften des Objekts Err festlegen können, können Sie einen vollständig benutzerdefinierten Fehler mit einer Nummer, einer Beschreibung, einer Quelle usw. erstellen, wie Sie ihn in Listing 14.12 finden.
588
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
Listing 14.12: Einen benutzerdefinierten Fehler erstellen Sub TestCustomError() On Error GoTo TestCustomErr_Err Dim strName As String strName = InputBox("Please Enter Your Name") If Len(strName) < 5 Then ErrRaise Number:=11111, _ Description:="Length of Name is Too Short" Else MsgBox "You Entered " & strName End If Exit Sub TestCustomErr_Err: MsgBox "Error # " & Err.Number & _ " – " & Err.Description Exit Sub End Sub
Dieses Beispiel ist zwar sehr einfach, illustriert jedoch eine wesentliche Verwendungsweise benutzerdefinierter Fehler. Der Code testet darauf, ob der eingegebene Wert aus weniger als fünf Zeichen besteht. Falls ja, wird ein benutzerdefinierter Fehler (Nummer 11111) ausgegeben und die Routine macht mit der normalen Fehlerbehandlung weiter. Der Abschnitt »Eine allgemeine Fehlerbehandlungsroutine erstellen« weiter hinten in diesem Kapitel untersucht, wie man eine allgemeine Fehlerbehandlungsroutine aufbaut. Durch das Behandeln Ihrer benutzerdefinierten Fehler mit Hilfe der allgemeinen Fehlerbehandlungsroutine werden alle Fehler – nicht nur die benutzerdefinierten – auf dieselbe Weise abgearbeitet.
14.10
Die Auflistung Errors
Die Auflistung Errors ist Teil der Jet-Engine von Access und speichert die zuletzt aufgetretenen DAO-Fehler. Das ist bei der Verwendung von DAO und ODBC wichtig, wo eine Operation zu mehreren Fehlern führen kann. Wenn Sie mit jedem einzelnen Fehler zu tun haben, der von einer Operation verursacht wurde, müssen Sie in die Auflistung Errors schauen. Diese verfügt über dieselben Eigenschaften wie das Objekt Err. Wenn Sie sich die in der Auflistung Errors gespeicherten Fehler ansehen wollen, müssen Sie diese in einer Schleife durchlaufen und sich die Eigenschaften jedes Err-Objekts ansehen. Listing 14.13 zeigt den Code, den Sie dazu verwenden können. Listing 14.13: Die Fehler in der Auflistung Errors ansehen Sub TestErrorsCollection() On Error GoTo TestErrorsCollection_Err
Eine allgemeine Fehlerbehandlungsroutine erstellen
589
Dim db As DAO.Database Set db = CurrentDb db Execute ("qryNonExistent") Exit Sub TestErrorsCollection_Err: Dim ErrorDescrip As Error For Each ErrorDescrip In Errors Debug.Print ErrorDescrip.Description Next ErrorDescrip Exit Sub End Sub
Diese Routine durchläuft jedes Error-Objekt in der Auflistung Errors und gibt die Beschreibung aller enthaltenen Fehler aus.
14.11
Eine allgemeine Fehlerbehandlungsroutine erstellen
Eine »allgemeine« Fehlerbehandlungsroutine lässt sich von einer beliebigen Stelle in Ihrer Anwendung aus aufrufen und ist in der Lage, auf Fehler jeden Typs zu reagieren. Eine allgemeine Fehlerbehandlungsroutine verhindert, dass Sie in jede Unterroutine oder Funktion eine eigene Fehlerbehandlung aufnehmen müssen. Sie ermöglicht es, in der gesamten Anwendung Fehlerbehandlung auf die denkbar effizienteste Art einzuleiten. Für die Erstellung einer allgemeinen Fehlerbehandlungsroutine gibt es viele Ansätze. Sie sollte dem Benutzer Informationen über den Fehler liefern, die Ausgabe dieser Informationen ermöglichen und diese in einer Datei protokollieren. Außerdem sollte sie sich von jeder Prozedur in der Anwendung aus aufrufen lassen. Die Routine On Error (in diesem Fall die Sprungmarke AnySub_Err) jeder Prozedur, die Fehlerbehandlung durchführt, sollte so aussehen wie die Fehlerbehandlungsroutine, die Sie in der Unterroutine von Listing 14.14 sehen. Listing 14.14: Eine allgemeine Fehlerbehandlungsroutine für alle Funktionen und Unterroutinen Sub AnySub() Const SUBNAME = "ANYSUB" On Error GoTo AnySub_Err MsgBox "This is the rest of your code...." Err.Raise 11 MsgBox "We are Past the Error!!"
590
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
Exit Sub AnySub_Err: Dim intAction As Integer intAction = ErrorHandler(intErrorNum:=ErrNumber, _ strErrorDescription:=Err.Description, _ strModuleName:=MODULENAME, _ strRoutineName:_SUBNAME) Select Case intAction Case ERR_CONTINUE Resume Next Case ERR_RETRY Resume Case ERR_EXIT Exit Sub Case ERR_QUIT Quit End Select End Sub
Diese Fehlerbehandlungsroutine in AnySub erzeugt eine Variable vom Typ Integer, welche den Rückgabewert des Fehlersystems aufnimmt. Die Variable intAction enthält eine für den aufgetretenen Fehler passende Reaktion. Die Fehlerroutine ruft die allgemeine Fehlerbehandlungsfunktion ErrorHandler auf, übergibt ihr die Fehlernummer (Err.Number), eine Beschreibung des Fehlers (Err.Description), den Namen des Moduls und den Namen der Unterroutine oder Funktion, in denen der Fehler enthalten ist. Der Name des Moduls wird in der privaten Konstanten MODULENAME abgelegt, die im Abschnitt Allgemein des Moduls deklariert wurde und die Sie für jedes erstellte Modul anlegen müssen. Der Name der Unterroutine oder Funktion wird in einer lokalen Konstanten SUBNAME gespeichert. Bei diesem Ansatz erstellen Sie am Beginn jeder Prozedur eine lokale Konstante und weisen ihr den Namen der Unterroutine zu. Dies erfordert Aktualisierungsaufwand, weil sich Prozedurnamen ändern können und Sie daran denken müssen, auch Ihre Zeichenfolge zu ändern. Leider ist diese Art roher Gewalt erforderlich, falls Ihre Fehlerbehandlungsroutine Unterroutine und Modul nennen soll, weil die VBA-Umgebung beim Auftreten eines Fehlers die Namen von Unterroutine und Modul verschweigt. Wenn der Code aus der Funktion ErrorHandler zurückkehrt, wird ein Rückgabewert in die Variable intAction geschrieben, aus dem sich das Schicksal der Routine ergibt. Nachdem Sie jetzt gesehen haben, wie Sie in Ihren Prozeduren Fehlerbehandlung implementieren können, sollten Sie einen Blick auf die Funktion werfen, die beim Auftreten eines Fehlers aufgerufen wird. Sie finden diese in Listing 14.15.
Eine allgemeine Fehlerbehandlungsroutine erstellen
591
Listing 14.15: Deklaration einer Typstruktur für allgemeine Fehlerbehandlung Type typErrors intErrorNum As Integer strMessage As String strModule As String strRoutine As String strUserName As String datDateTime As Variant End Type Public gtypError As typErrors Public Public Public Public
Const Const Const Const
ERR_CONTINUE = 0 'Resume Next ERR_RETRY = 1 'Resume ERR_QUIT = 2 'End ERR_EXIT = 3 'Exit Sub or Func
Dieser Code befindet sich im Abschnitt Allgemein von basGenericErrorHandler. Die deklarierte Typstruktur enthält alle fortdauernden Informationen über den Fehler. Typstrukturen werden in Kapitel 24 behandelt. Für den Augenblick reicht es aus, wenn Sie verstehen, dass eine Typstruktur eine spezielle Art Variable darstellt, die mehrere Teile umfasst. Jeder davon enthält eine andere Information. Die öffentliche Variable gtypError enthält alle Informationen aus der Typstruktur. Die Konstanten dienen dazu, das Schicksal der Anwendung nach dem Auftreten eines Fehlers festzulegen. Listing 14.16 zeigt die Funktion ErrorHandler. Listing 14.16: Die Funktion ErrorHandler Function ErrorHandler(intErrorNum As Integer, _ strErrorDescription As String, _ strModuleName As string, _ strRoutineName As String) As Integer gtypError.intErrorNum = intErrorNum gtypError.strMessage = strErrorDescription gtypError.strModule = strModuleName gtypError.strRoutine = strRoutineName gtypError.strUserName = CurrentUser() gtypError.datDateTime = Now Call LogError Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.Open "Select Response from tblErrors Where ErrorNum = " _ & inErrorNum, CurrentProject.Connection, adOpenStatic If rstEOF Then DoCmd.OpenForm "frmError", WindowMode:=acDialog, _ OpenArgs:="ErrorHandler"
592
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
ErrorHandler = ERR_QUIT Else Select Case rst!Response Case ERR_QUIT DoCmd.OpenForm "frmError", WindowMode:=acDialog, _ OpenArgs:="Critical Error: Application will Terminate" ErrorHandler = ERR_QUIT Case ERR_RETRY ErrorHandler = ERR_RETRY Case ERR_EXIT DoCmd.OpenForm "frmError", WindowMode:=acDialog, _ OpenArgs:="Severe Error: Processing Did Not Complete" ErrorHandler = ERR_EXIT Case ERR_CONTINUE ErrorHandler = ERR_CONTINUE End Select End If End Function
Die Funktion ErrorHandler übernimmt die Fehlernummer, die Fehlerbeschreibung sowie den Namen des Moduls und der Unterroutine bzw. Funktion als Parameter. Dann schreibt sie diese Informationen sowie den aktuellen Benutzer und das Datum in die Typstruktur gtypError. Als nächstes ruft sie eine Routine auf, die den Fehler in einer Access-Tabelle protokolliert. Diese Routine schlägt die Schwere des Fehlers in der Access-Tabelle tblErrors nach, um zu entscheiden, welche Art der Fehlerbehandlung am besten passt. Wenn sich der Fehler-Code nicht in der Fehlertabelle findet, wird ein Fehlerformular angezeigt und ein Rückgabewert an die aufrufende Funktion gesendet, der angibt, dass die Ausführung der Anwendung beendet werden muss. Wenn der Fehler-Code in der Fehlertabelle ermittelt wird und sich der Fehler als schwer oder kritisch erweist, wird ein Fehlerformular eingeblendet, bevor die Steuerung an die aufrufende Routine zurückgegeben wird. In jedem Fall bekommt die aufrufende Routine den Schwere-Code für den Fehler. Im folgenden Abschnitt werden die einzelnen Schritte dieses Vorgangs detailliert behandelt.
14.11.1
Protokollieren des Fehlers
Die Routine LogError ist für die Protokollierung der Fehlerinformationen in einer Access-Tabelle verantwortlich. Da sich Benutzer häufig entschließen, das Fehlerformular nicht auszugeben oder Ihnen nicht zutreffende Informationen darüber liefern, was beim Auftreten des Fehlers geschah (bzw. Sie gar nicht über den Fehler informieren), ist es wichtig, jeden Fehler zu protokollieren, so dass Sie das Fehlerprotokoll jederzeit einsehen können. Man kann Fehler in einer Textdatei oder in einer Datentabelle festhalten. Dieser Abschnitt zeigt Ihnen beide Methoden der Fehlerprotokollierung. Beginnen Sie mit einer Fehlertabelle. Listing 14.17 zeigt die Routine LogError.
Eine allgemeine Fehlerbehandlungsroutine erstellen
593
Listing 14.17: Die Routine LogError Sub LogError() Dim cnn As ADODB.Connection Dim strSQL As String Set cnn = CurrentProject.Connection strSQL = "INSERT INTO tblErrorLog ( ErrorDate, ErrorTime, " _ "UserName, ErrorNum, ErrorString, ModuleName, RoutineName) " strSQL = strSQL & "Select #" & gtypError.datDateTime & "#, #" _ & gtypError.datDateTime & "#, '" _ & gtypError.strUserName & "', " _ & gtypError.intErrorNum & ", '" _ & gtypError.strMessage & "', '" _ & gtypError.strModule & "', '" _ & gtypError.strRoutine & "'" cnnExecute strSQL, , adExecuteNoRecords End Sub
Diese Routine verwendet die Methode Execute des ADO-Objekts Connection, um Ihrer Fehlertabelle einen Datensatz hinzuzufügen. Dieser enthält alle Informationen aus der Struktur gtypError, die schließlich in einer Tabelle mit dem Namen tblErrorLog abgelegt werden. Abbildung 14.4 zeigt die Struktur dieser Tabelle.
Abbildung 14.4: Die Struktur der Tabelle tblErrorLog
Die Alternative wäre, die Informationen in einer Fehlerprotokolldatei in Textform abzulegen, wie es in Listing 14.18 gezeigt wird. Listing 14.18: Informationen in eine Fehlerprotokolldatei in Textform schreiben Sub LogErrorText() Dim intFile As Integer intFile = FreeFile
594
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
Open CurDir & "\ErrorLog.Txt" For Append Shared As intFile Write #intFile, "LogErrorDemo", Now, Err, Error, CurrentUser() Close intFile End Sub
Dieser Code verwendet die systemnahen Dateifunktionen Open und Write, um eine ASCII-Textdatei zu öffnen und zu schreiben. Alle fehlerrelevanten Informationen werden in dieser Textdatei abgelegt. Dann wird die Datei mit dem Befehl Close geschlossen. Der potentielle Vorteil dieser Routine liegt darin, dass der Vorgang der Fehlerprotokollierung auch noch funktioniert, wenn das Problem seine Ursache in der Datenbank hat.
14.11.2 Die passende Reaktion auf einen Fehler ermitteln Nachdem der Fehler protokolliert ist, können Sie ermitteln, wie Sie am Besten auf den Fehler reagieren. Indem Sie Ihr Fehlersystem datengesteuert gestalten, können Sie jeden Fehler ein wenig anders behandeln. Abbildung 14.5 zeigt die Struktur der Tabelle tblErrors. Diese sollte eine Liste aller Fehlernummern enthalten, die Sie abfangen wollen. Sie besitzt drei Felder: ErrorNum, ErrorDescription und Response. Wenn ein Fehler auftritt, sucht die Funktion ErrorHandler einen Datensatz, dessen Wert im Feld ErrorNum mit der Nummer des aufgetretenen Fehlers übereinstimmt. Die Funktion ErrorHandler, die Sie in Listing 14.16 finden, lokalisiert mit Hilfe des Codes in Listing 14.19 den Fehler-Code in der Tabelle tblErrors. Listing 14.19: Den Fehler-Code in der Tabelle tblErrors lokalisieren Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.Open "Select Response from tblErrors Where ErrorNum = " _& intErrorNum, CurrentProject.Connection, adOpenStatic If rst.EOF Then DoCmd.OpenForm "frmError", WindowMode:= acDialog, _ OpenArgs:="ErrorHandler" ErrorHandler = ERR_QUIT Else Select Case rst!Response Case ERR_QUIT DoCmd.OpenForm "frmError", WindowMode:=acDialog, _ OpenArgs:="Critical Error: Application will Terminate" ErrorHandler = ERR_QUIT Case ERR_RETRY ErrorHandler = ERR_RETRY Case ERR_EXIT DoCmd.OpenForm "frmError", WindowMode:=acDialog, _ OpenArgs:="Severe Error: Processing Did Not Complete" ErrorHandler = ERR_EXIT Case ERR_CONTINUE
Eine allgemeine Fehlerbehandlungsroutine erstellen
595
ErrorHandler = ERR_CONTINUE End Select End If
Abbildung 14.5: Die Struktur der Tabelle tblErrors
Dieser Teil der Funktion ErrorHandler erstellt eine ADO-Objektvariable des Typs Recordset. Mit Hilfe einer Select-Anweisung öffnet sie eine Datensatzgruppe. Die Select-Anweisung durchsucht eine Tabelle mit dem Namen tblErrors. Wenn sie einen passenden Eintrag findet, bestimmt sie mit Hilfe der Spalte Response die Reaktion auf den Fehler. Beachten Sie in Listing 14.19, dass die Standardfehlerbehandlung verwendet wird, wenn die Fehlernummer in tblErrors nicht gefunden wird, was bedeutet, dass der Code alle weiteren Fehler als Gruppe behandelt. (Das ist meine Standardfehlerbehandlung, nicht die von Access.) Ist die Fehlernummer vorhanden, wird das Formular frmError geöffnet, das Feld Response ausgewertet und die entsprechende Aktion gestartet (mit Hilfe der case-Anweisung); wenn nicht, wird das Formular frmError geöffnet und die Funktion ErrorHandler gibt den Konstantenwert ERR_QUIT zurück. Bei dieser Methode brauchen Sie nur spezielle Fehler, die Sie abfangen wollen, in die Tabelle einzufügen. Wenn in tblErrors keine Datensätze gefunden werden, die zur SQL-Anweisung passen, wird das Formular frmErrors geöffnet und der Rückgabewert für die Funktion wird auf den Konstantenwert ERR_QUIT gesetzt. Bei vorhandener Fehlernummer wird das Feld Response des Datensatzes ausgewertet. Wenn dieses den Konstantenwert ERR_QUIT oder ERR_EXIT enthält, erscheint das Formular frmError, bevor dieser Wert an die fehlerhafte Funktion oder Unterroutine zurückgegeben wird. Wenn das Feld den Konstantenwert ERR_RETRY oder ERR_CONTINUE enthält, wird dieser ohne Anzeige des Formulars zurückgegeben.
596
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
Die Tabelle tblErrors finden Sie in CHAP14EX.MDB auf der CD-ROM mit dem Beispiel-Code. Um sie voll zu nutzen, müssen Sie alle abzufangenden Fehler sowie die Aktionen hinzufügen, welche die Fehlerbehandlungsroutine beim Auftreten eines Fehlers einleiten soll. Der Rückgabewert der Funktion ErrorHandler wird so verwendet, wie es Listing 14.20 zeigt. Listing 14.20: Verwendung des Rückgabewerts der Funktion ErrorHandler SUB ANYSUB()
CONST SUBNAME AS STRING = "ANYSUB" O N ERROR GOTO ANYSUB_ERR M SGBOX "THIS IS THE E RR.RAISE 11 M SGBOX "WE ARE PAST
REST OF YOUR CODE...." THE
ERROR!!"
Exit Sub AnySub_Exit: Exit Sub AnySub_Err: Dim intAction As Integer intAction = ErrorHandler(intErrorNum:=Err.Number, _ strErrorDescription:=Err.Description, _ strModuleName:=MODULENAME, _ strRoutineName:=SUBNAME) Select Case intAction Case ERR_CONTINUE Resume Next Case ERR_RETRY Resume Case ERR_EXIT Resume AnySub_Exit Case ERR_QUIT Quit End Select End Sub
In diesem Beispiel erzeugt die Routine AnySub einen Fehler mit der Nummer 11 (Division durch 0). Da in der Spalte Response von tblErrors die Zahl 3 steht und die Konstante ERR_CONTINUE diese Nummer trägt, wird das Fehlerformular angezeigt und die Routine AnySub mit einer Exit Sub-Anweisung verlassen.
Eine allgemeine Fehlerbehandlungsroutine erstellen
597
Um herauszufinden, was passiert, wenn der Fehler-Code in der Tabelle tblErrors nicht gefunden wird, starten Sie die Routine SubWithUnknownError, die Sie in basError finden. Um zu testen, was geschieht, wenn der Code ERR_CONTINUE zurückgegeben wird, führen Sie die Routine SubWithContinue aus.
14.11.3 Ein Fehlerformular erstellen Der Code im Ladeereignis des Fehlerformulars ruft, wie hier gezeigt, zwei Unterroutinen auf, nämlich GetSystemInfo und GetErrorInfo: Private Sub Form_Load() Call GetSysInfo(Me) Call GetErrorInfo(Me) Me!lblAction.Caption = Me.OpenArgs End Sub
Die erste Unterroutine heißt GetSystemInfo. Sie führt mehrere Windows-API-Aufrufe aus, um die Systeminformationen in Ihr Formular einzusetzen. Den Code finden Sie in Listing 14.21, besprochen wird er in Kapitel 27. Listing 14.21: Mit Hilfe von Code Systeminformationen abfragen Sub GetSysInfo (frmAny As Form) 'Freien Speicher besorgen Dim MS As MEMORYSTATUS MS.dwLength = Len (MS) GlobalMemoryStatus MS frmAny!lblMemoryTotal.Caption = Format(Ms.dwTotalPhys, "Standard") frmAny!lblMemoryAvail.Caption = Format(Ms.dwAvailPhys, "Standard") 'Versionsinformationen holen DImOSINfo As OSVERSIONINFO OSInfo.dwOSVersionInfoSize = Len(OSInfo) If GetVersionEx(OSInfo) Then frmAny!lblOSVersion.Caption = OSInfo.dwMajorVersion & "." _ & OSInfo.dwMinorVersion frmAny!lblBuild.Caption = OSInfo.dwBuildNumber And &HFFFF& If OSInfo.dwPlatformID = 0 Then frmAny!lblPlatformCaption = "Windows 95" Else frmAny!lblPlatformCaption = "Windows NT" End If End If 'Systeminformationen holen Dim SI As SYSTEM_INFO
598
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
GetSystemInfo SI frmAny!lblProcessor.Caption = SI.dwProcessorType End Sub
Diese API-Aufrufe erfordern die Declare-Anweisungen und -Konstanten, die Sie in Listing 14.22 finden. Sie sind in einem Modul mit dem Namen basAPI gespeichert. Listing 14.22: Windows-API-Aufrufe deklarieren Option Compare Database Option Explicit Private Declare Sub GlobalMemoryStatus Lib "Kernel32"_ (lpBuffer As MEMORYSTATUS) Private Type MEMORYSTATUS dwLength As Long dwMemoryLoad As Long dwTotalPhys As Long dwAvailPhys As Long dwTotalPageFile As Long dwAvailPagefile As Long dwTotalVirtual As Long dwAvailVirtual As Long End Type Private Declare Function GetVersionEx Lib "Kernel32" _ Alias "GetVersionExA" (lpOSInfo AS OSVERSIONINFO) As Boolean Type OSVERSIONINFO dwOSVersionInfoSize As Long dwMajorVersion As Long dwMinorVersion As Long dwBuildNumber As Long dwPlatformID As Long strReserved AsString * 128 End Type Private Declare Sub GetSystemInfo Lib "Kernel32"_ (lpSystemInfo As SYSTEM_INFO) Private Type SYSTEM_INFO dwOemID As Long dwPageSize As Long lpMinimumApplicationAddress As Long lpMaximumApplicationAddress As Long dwActiveProcessorMask As Long dwNumberOfProcessors As Long dwProcessorType As Long
Eine allgemeine Fehlerbehandlungsroutine erstellen
599
dwAllocationGranularity As Long dwReserved As Long End Type
Die zweite Unterroutine GetErrorInfo füllt die Bezeichnungsfelder des Fehlerformulars mit den Informationen aus der Struktur aus, wie in Listing 14.23 gezeigt. Listing 14.23: Die Unterroutine GetErrorInfo Sub GetErrorInfo(frmAny As Form) frmAny!lblErrorNumber.Caption = gtypError.intErrorNum frmAny!lblErrorString.Caption = gtypError.strMessage frmAny!lblUserName.Caption = gtypError.strUserName frmAny!lblDateTime.Caption = Format(gtypError.datDateTime, "c") frmAny!lblModuleName.Caption = gtypError.strModule frmAny!lblRoutineName.Caption = gtypError.strRoutine End Sub
Schließlich wird die Art des Fehlers, welche von der Funktion ErrorHandler als OpenArg gesendet wurde, in einem Bezeichnungsfeld im Formular angezeigt. Abbildung 14.6 zeigt das Fehlerformular.
Abbildung 14.6: Das Formular frmErrors zeigt wichtige Informationen über den aufgetretenen Fehler an
14.11.4 Das Fehlerformular ausdrucken Benutzer arbeiten bei der Beschreibung eines Fehlers und der entsprechenden Fehlermeldung häufig nicht sehr genau. Deshalb ist es wichtig, ihnen die Möglichkeit zu geben, die Fehlermeldung auszudrucken. Der Code in Listing 14.24 druckt das Feh-
600
Kapitel 14: Fehlerbehandlung: Vorbereitung auf das Unvermeidliche
lerformular. Er befindet sich hinter dem Klick-Ereignis der Schaltfläche mit dem Druckersymbol im Fehlerformular. Listing 14.24: Das Fehlerformular ausdrucken Sub cmdPrint_Click() On Error GoTo Err_cmdPrint_Click
DoCmd.PrintOut Exit_cmdPrint_Click: Exit Sub Err_cmdPrint_Click: MsgBox Err.Description Resume Exit_cmdPrint_Click End Sub
14.12
Verhindern, dass die eigene Fehlerbehandlung aufgerufen wird
Beim Testen Ihrer Anwendung soll nicht die eigene, sondern die Fehlerbehandlung von VBA aktiviert werden. Um dies zu erreichen, verwenden Sie das Dialogfeld OPTIONEN des VBE. Wählen Sie dazu EXTRAS|OPTIONEN und klicken Sie auf die Registerkarte ALLGEMEIN. Aktivieren Sie im Abschnitt UNTERBRECHEN BEI FEHLERN die Option BEI JEDEM FEHLER. Solange diese Option aktiv ist, wird Ihre Fehlerbehandlung ignoriert und die Access-Standardfehlerbehandlung aufgerufen. Mit Hilfe dieser Einstellung können Sie die Fehlerbehandlung an einer zentralen Stelle einund ausschalten.
14.12.1 Für die Praxis Fehlerbehandlung integrieren Code zur Fehlerbehandlung sollte in das gesamte Zeit- und Abrechnungssystem integriert werden. Das folgende Beispiel zeigt Ihnen, wie Sie die allgemeine Fehlerbehandlung in diese Anwendung einbauen. Unsere Beispielanwendung enthält eine Routine mit dem Namen GetCompanyInfo, die sämtliche Informationen über die Firma aus der Tabelle tblCompanyInfo einliest. Diese Daten werden nach Bedarf während des Betriebs der Anwendung aus der Typstruktur entnommen. Wie jede Routine besitzt auch diese ein Fehlerpotential. Die Originalroutine wurde so geändert, dass sie jetzt die allgemeine Fehlerbehandlungsroutine enthält (siehe Listing 14.25).
Verhindern, dass die eigene Fehlerbehandlung aufgerufen wird
601
Listing 14.25: Integration der allgemeinen Fehlerbehandlungsroutine in den Programm-Code Sub GetCompanyInfo() On Error GoTo GetCompanyInfo_Err Dim strSubName As String Dim rst As ADODB.Recordset strSubName = "GetCompanyInfo" Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.Open "Select * from tblCompanyInfo", Options:=adCmdText typCompanyInfo.SetUpID = rst!SetUpID typCompanyInfo.CompanyName = rst!CompanyName typCompanyInfo.Address = rst!Address typCompanyInfo.City = rst!City typCompanyInfo.StateProvince = rst!StateProvince typCompanyInfo.PostalCode = rst!PostalCode typCompanyInfo.Country = rst!Country typCompanyInfo.PhoneNumber = rst!PhoneNumber typCompanyInfo.FaxNumber = rst!PhoneNumber rst.Close Exit Sub GetCompanyInfo_Err: Dim intAction As Integer intAction = ErrorHandler(lngErrorNum:=Err.Number, _ strErrorDescription:=Err.Description, _ strModuleName:=mstrModuleName, _ strRoutineName:=strSubName) Select Case intAction Case ERR_CONTINUE Resume Next Case ERR_RETRY Resume Case ERR_EXIT Exit Sub Case ERR_QUIT Quit End Select End Sub
Beachten Sie die Anweisung On Error GoTo am Anfang der Routine und den Umstand, dass die lokale Variable strSubName deklariert und auf GetCompanyInfo gesetzt wurde. Die allgemeine Fehlerbehandlungsroutine verwendet die lokale Variable, um die Routine anzuzeigen, in der der Fehler aufgetreten ist. Die Fehlerbehandlungsroutine GetCompanyInfo_Err ruft die Funktion ErrorHandler auf und wertet dann deren Rückgabewert aus.
Optimieren Ihrer Anwendung
Kapitel Hier lesen Sie:
Mehr Leistung Einführung in die Optimierung Hard- und Software-Konfiguration modifizieren Was bringt Jet 4.0 für die Verbesserung der Leistung? Mit Hilfe der Leistungsanalyse Problembereiche ermitteln Tabellen mit dem Ziel optimaler Leistung gestalten Abfragen mit dem Ziel optimaler Leistung gestalten Anders programmieren, um die Leistung zu optimieren Formulare und Berichte mit dem Ziel optimaler Leistung gestalten
15.1
Mehr Leistung
In einer Welt, in der die Hardware häufig kaum mit der Software Schritt halten kann, ist es wichtig, dass Sie alles tun, um die Leistung Ihrer Anwendung zu optimieren. Dieses Kapitel hilft Ihnen, Ihre Anwendungen in Hinblick auf die Geschwindigkeit zu optimieren und die Anforderungen an den Arbeitsspeicher und den Platz auf der Festplatte zu reduzieren.
15.2
Einführung in die Optimierung
»Optimierung« ist die Überarbeitung der Betriebsumgebung, des VBA-Codes, der Anwendungsobjekte und der Datenstrukturen mit dem Ziel, optimale Leistung zu gewährleisten. Kurz gesagt: Optimierung besteht darin, die Anwendung schlanker und anspruchsloser zu machen.
604
Kapitel 15: Optimieren Ihrer Anwendung
Benutzer sind frustriert, wenn eine Anwendung nur langsam läuft. Wenn ein Benutzer nicht gewarnt wird, dass ein Prozess langsam ausgeführt wird, wird er häufig einen Neustart des Rechners versuchen oder ihn ausschalten, während der Prozess noch läuft. Das kann die Datenintegrität erheblich beeinträchtigen. Um das Risiko zu reduzieren, dass der Benutzer den Rechner während eines langwierigen Prozesses neu startet, ist es meistens zu empfehlen, ihm in irgendeiner Form Informationen darüber zu geben, wie lange es dauert. Das kann in Form einer Meldung geschehen, die vor dem Start des Prozesses eingeblendet wird, oder durch eine Fortschrittsanzeige, die den Verlauf des Prozesses wiedergibt. Um die Leistung einer Anwendung zu optimieren, gibt es viele Möglichkeiten – von der Verwendung eines Front-End-Werkzeugs wie der Leistungsanalyse bis hin zur strengen Einhaltung bestimmter Programmiertechniken. Dieses Kapitel beleuchtet die wichtigsten Methoden, die Ihnen zur Leistungsoptimierung zur Verfügung stehen.
15.3
Hard- und Software-Konfiguration modifizieren
Mit Access-»Umgebung« ist die Kombination aus Hard- und Software-Konfiguration gemeint, unter der Microsoft Access betrieben wird. Diese Umgebungseinstellungen können die Leistung einer Access-Anwendung erheblich beeinflussen. Die einfachste Möglichkeit, die Leistung einer Access-Anwendung zu verbessern, besteht in der Aktualisierung der Hard- und Software-Konfiguration, unter der sie läuft. Diese Art von Optimierung erfordert keinen direkten Eingriff des Entwicklers. Eine positive Nebenwirkung der meisten möglichen Umgebungsveränderungen besteht darin, dass Verbesserungen der Umgebung dem Benutzer in allen WindowsAnwendungen Vorteile bringen. Zur Verbesserung der Umgebung gehört mehr, als nur den Arbeitsspeicher auszubauen. Damit ist auch die optimale Konfiguration des Betriebssystems und der Access-Anwendung gemeint.
15.3.1
Hardware, mehr Hardware!
Windows 95, Windows 98, Windows NT und Access 2000 betteln geradezu um Hardware – je mehr, desto besser. Je schneller der Rechner ist und je mehr Arbeitsspeicher er besitzt, desto besser. Zusätzliche Hardware ist vielleicht nicht die billigste Lösung, aber mit Sicherheit die schnellste und einfachste, um die Leistung der Anwendung zu erhöhen.
Hard- und Software-Konfiguration modifizieren
605
Alles, was ich brauche, ist RAM! In erster Linie bettelt Access um Arbeitsspeicher, egal, ob Sie die vollständige Microsoft Access-Version oder die Laufzeitversion des Programms einsetzen. Microsoft Access benötigt schon unter Windows 95 und 98, seinen Standardbetriebsumgebungen, 12 MB RAM, nur um zu laufen. Das ist das unbedingt Nötige; empfohlen werden von Microsoft sogar 16 MB. Unter Windows NT benötigt Access mindestens 16 MB RAM. Beide Anforderungen können dramatisch steigen, wenn der Benutzer noch andere Anwendungen in Betrieb hat oder wenn Ihre Anwendung über OLEAutomatisierung mit anderen Anwendungen kommuniziert. Sehr direkt ausgedrückt: Je mehr RAM Sie und die Benutzer Ihrer Anwendung besitzen, desto besser ist es. 64 MB ist für Access 2000 hervorragend. Wenn jeder Ihrer Benutzer über mindestens 64 MB RAM verfügt, können Sie eigentlich aufhören, dieses Kapitel zu lesen, weil alles, was hier noch gesagt wird, im Vergleich zur Bereitstellung von mehr Arbeitsspeicher nur geringe Vorteile bringt. Wenn Sie jedoch in derselben Lage sind wie die meisten von uns, dass nicht alle Ihre Benutzer einen Pentium II mit 450 MHz und 64 MB RAM besitzen, lesen Sie weiter. Entwickler sollten einen Rechner mit mindestens 64 MB RAM zur Verfügung haben. Denken Sie daran: das ist das Minimum! Die meisten Entwickler sind sich einig, dass 128 MB für ernsthafte Entwicklungsarbeit ideal sind, insbesondere wenn Sie Client-Server-Anwendungen oder solche für Intranets oder das Internet entwickeln wollen. Defragmentieren Sie die Festplatte des Benutzers Beim Schreiben auf die Festplatte versucht der Rechner, zusammenhängenden Speicherplatz für Datendateien zu finden. Wenn sich die Festplatte füllt, werden Dateien in fragmentierter Form abgelegt. Bei jedem Versuch Ihrer Anwendung, Daten und Programme zu lesen, müssen die über die Platte verstreuten Informationen gesucht werden, was sehr zeitaufwendig ist. Deshalb ist das Defragmentieren der Festplatte, auf der die Anwendung und die Datentabellen gespeichert sind, mit Hilfe eines Programms wie des mit Windows 95, Windows 98 und Windows NT 5.0 gelieferten Defragmentierers hilfreich. Der Vorgang des Defragmentierens einer Festplatte lässt sich mit dem System Agent aus dem Microsoft Plus! Pack leicht automatisieren. Dieses Paket wird als Add-On für Windows 95 verkauft. Der System Agent ist ein nützliches Werkzeug, mit dem Sie planen können, wann und wie oft defragmentiert wird. Windows 98 wird mit dem Taskplaner ausgeliefert, der verwendet wird, um die automatische Ausführung verschiedener Systemaufgaben wie Defragmentieren (Defragmentierung) und Überprüfen des Dateisystems (Scandisk) zeitlich zu planen.
606
Kapitel 15: Optimieren Ihrer Anwendung
Komprimieren Sie Ihre Datenbank Genauso wie das Betriebssystem Ihre Dateien mit der Zeit fragmentiert, bringt auch Access eigene Formen der Fragmentierung mit sich. Bei jedem Hinzufügen und Modifizieren von Daten wächst die Datenbank. Das Problem liegt darin, dass die Datenbank nicht kleiner wird, wenn Sie Daten oder Objekte löschen. Access hinterlässt nämlich leere Seiten, auf die neue Daten geschrieben werden können. Diese werden jedoch nicht zwangsläufig mit Daten gefüllt. Der freie Platz lässt sich mit dem Dienstprogramm Compact freigeben, das zu Microsoft Access gehört. Es gibt überschüssigen Speicherplatz frei und versucht alle Datenseiten zusammenhängend abzulegen. Sie sollten Ihre Datenbank häufig komprimieren, insbesondere wenn regelmäßig Datensätze oder Datenbankobjekte (z.B. Formulare und Berichte) hinzugefügt bzw. gelöscht werden. Auf das Dienstprogramm Compact haben Sie nur Zugriff, wenn keine Datenbank geöffnet ist. Sie erreichen es über EXTRAS|DATENBANK-DIENSTPROGRAMME. Wählen Sie dann die Option DATENBANK KOMPRIMIEREN UND REPARIEREN. Es ist der Erwähnung wert, dass es günstig ist, eine Methode zur Komprimierung der Datenbank mitzuliefern, wenn Sie vorhaben, eine Access-Anwendung – möglicherweise über das Laufzeitmodul – an andere Benutzer weiterzugeben. Häufig ermöglicht das Laufzeitmodul keinen Zugriff auf den Menüpunkt KOMPRIMIEREN. Mit der Methode CompactDatabase können Sie eine Datenbank aus einer Access-Datenbank heraus komprimieren, aber dieser Befehl lässt sich nicht aus der aktuellen Anwendung aufrufen. Man muss eine zweite Anwendung erstellen, um die Methode CompactDatabase auf die Originalanwendung anwenden zu können. Verwenden Sie keine komprimierten Laufwerke Unabhängig davon, welches Komprimierungsprogramm Sie verwenden, senkt die Komprimierung von Laufwerken die Leistung von Access 2000 deutlich. Dieser Umstand ist in der Datei README dokumentiert. Bringen Sie den virtuellen Speicher auf Trab Obwohl Windows 95 und 98 versuchen, den virtuellen Speicher selbstständig zu verwalten, halten Sie es vielleicht für sinnvoll, ihnen einige zusätzliche Informationen zu geben. Um die physische Speicherstelle der Auslagerungsdatei zu verändern, klicken Sie mit der rechten Maustaste auf ARBEITSPLATZ und wählen dann im Kontextmenü den Eintrag EIGENSCHAFTEN. Wechseln Sie anschließend auf die Registerkarte LEISTUNGSMERKMALE und klicken Sie auf die Schaltfläche VIRTUELLER ARBEITSSPEICHER. Es könnte sinnvoll sein, die Auslagerungsdatei auf ein schnelleres Laufwerk oder auf ein Laufwerk mit eigener Controller-Karte zu verschieben. Alle Änderungen können sich aber auch negativ auf die Leistung auswirken. Es ist wichtig zu prüfen, ob vorgenommene Änderungen die Situation verbessern oder sie vielleicht ver-
Hard- und Software-Konfiguration modifizieren
607
schlechtern. Im Allgemeinen ist es ratsam, Windows die Größe der Auslagerungsdatei dynamisch verwalten zu lassen, es sei denn, das System verfügt nur über sehr wenig Platz auf der Festplatte. Wenn Access 2000 oder Windows auf einem komprimierten Laufwerk betrieben wird, können Sie die Leistung durch Verschieben der Auslagerungsdatei auf ein nicht komprimiertes Laufwerk steigern. Falls möglich, sollte sich die Auslagerungsdatei auf einem Laufwerk oder einer Partition befinden, das/die für sie reserviert ist, oder auf einem Laufwerk/einer Partition, auf welche(s) andere Anwendungen nur selten zugreifen. Das trägt dazu bei, dass sie zusammenhängend abgelegt wird. Betreiben Sie Access und Ihre Anwendung lokal In Kapitel 17 erfahren Sie, dass Sie sowohl das Programm Access als auch Ihre Anwendungsobjekte am besten auf dem lokalen Rechner jedes Benutzers installieren. Nur die Datentabellen sollten auf einem Datei-Server im Netzwerk abgelegt werden. Andernfalls senden Sie DLLs, OLE-Objekte, Hilfedateien, Typbibliotheken, ausführbare Dateien und Datenbankobjekte über die Leitung. Wenn Sie bei einer Access-Anwendung die geringste mögliche Leistung erzielen wollen, installieren Sie diese auf einer Arbeitsstation ohne Festplatte mit 16 MB RAM. Tun Sie alles, was möglich ist, um Windows schneller zu machen Es amüsiert mich immer wieder, dass die Benutzer mit den langsamsten Rechnern und dem wenigsten Arbeitsspeicher das meiste Zubehör in Betrieb haben. Dazu gehören Multimedia, prächtige Hintergründe und andere raffinierte Dienstprogramme. Wenn Leistung ein Problem darstellt, können Sie ausprobieren, ob der Verzicht auf einige der frivolen Nettigkeiten die Leistung Ihrer Anwendung verbessert. Falls ja, sollten Sie den Benutzer ermutigen, die Kinkerlitzchen zu beseitigen, mehr Arbeitsspeicher zu beschaffen oder aber die Leistung der Anwendung zu akzeptieren. Außerdem sollten Sie andere Anwendungen, z.B. Microsoft Excel, schließen, wenn Sie damit fertig sind. Ein weiterer Tipp, um Windows 95 und 98 schneller zu machen, ist das regelmäßige Herunterfahren und Neustarten. Ein Arbeitsspeicher tendiert zur Fragmentierung, und Anwendungen laufen dann langsamer. Windows NT kann Wochen oder Monate laufen, ohne dass ein Neustart erforderlich ist, aber bei Windows 95 und 98 habe ich festgestellt, dass es vorteilhaft ist, mehrmals täglich neu zu starten.
15.3.2
Ändern Sie die Software-Einstellungen von Access
Neben den auf der Hand liegenden Maßnahmen, die ich gerade skizziert habe, können einige kleinere Software-Kniffe viel für die Verbesserung der Leistung bringen. Die Anpassung verschiedener Einstellungen in der Windows-Registry kann die Leis-
608
Kapitel 15: Optimieren Ihrer Anwendung
tung deutlich steigern. Alle betreffen den Registry-Abschnitt ISAM. Zu den Eigenschaften, die Sie möglicherweise ändern wollen, gehören MaxBufferSize und ReadAheadPages. Beide legen fest, wie die Jet-Engine Speicher einsetzt. Die Option MaxBufferSize steuert die Maximalgröße des internen Cache der JetEngine. Standardmäßig ist sie so eingestellt, dass auf den meisten Rechnern die optimale Leistung erreicht wird. Die Daten werden in Seiten von 2 KB eingelesen und in einem Zwischenspeicher abgelegt. Die Daten im Cache sind für Formulare, Berichte, Tabellen und Abfragen mühelos erreichbar. Die Herabsetzung des Wertes von MaxBufferSize macht Speicher für andere Aufgaben frei. Das kann auf einem Rechner mit minimaler Speicherausstattung hilfreich sein. Die Option ReadAheadPages steuert die Anzahl der 2-KB-Datenseiten, welche die JetEngine bei sequentiellen Lesevorgängen im voraus liest. Sie kann von 0 bis 31 reichen; der Standard liegt bei 16. Je höher diese Zahl ist, desto effizienter liest Access im Voraus, so dass die Daten verfügbar sind, wenn Sie sie benötigen. Je niedriger diese Zahl ist, desto mehr Speicher steht für andere Aufgaben zur Verfügung. Denken Sie beim Konfigurieren dieser Einstellungen daran, dass Werte, die für einen Rechner günstig sind, für den nächsten nicht zwangsläufig auch gut sind. Die Einstellungen müssen für jeden Rechner mit Rücksicht auf die jeweilige Hardware-Konfiguration optimiert werden.
15.4
Was bringt Jet 4.0 für die Verbesserung der Leistung?
An der Jet 4.0-Engine wurden Verbesserungen vorgenommen, um die Leistung gegenüber den Vorgängern deutlich zu steigern. Einige davon gab es schon in der Jet 3.0-Engine von Access 95 oder in der Jet 3.5-Engine von Access 97, aber viele sind in Jet 4.0 neu hinzugekommen. Die gesamte Engine ist ein 32-Bit-Programm. Sie nutzt mehrere Ausführungs-Threads, was deutliche Leistungsvorteile bietet. Zu den Vorzügen, die mit Jet 3.5 (Access 97) kamen, gehört Folgendes:
Schnelleres Löschen. Teile einer Seite lassen sich als Ganzes löschen anstatt die Daten zeilenweise zu entfernen.
Verbesserte gleichzeitige Nutzung indizierter Spalten durch mehrere Benutzer. Indizierte Spalten lassen sich von mehreren Benutzern lesen und aktualisieren, ohne dass Sperrkonflikte auftreten. Indizierte Spalten enthalten keine Lesesperren mehr.
Implizite Transaktionsverarbeitung. Zwar haben viele Benutzer bereits in früheren Access-Versionen Verarbeitungsschleifen in das Konstrukt BeginTrans... CommitTrans verpackt, um die Anzahl der Schreibvorgänge zu begrenzen, aber Jet 3.5 handhabt dies auch von sich aus recht gut.
Was bringt Jet 4.0 für die Verbesserung der Leistung?
609
Umfangreiche Abfragen werden schneller erledigt. Ursache sind Verbesserungen am Transaktionsverhalten für SQL-Anweisungen in DML (Data Manipulation Language) sowie neue Einstellungen in der Registry, die den Commit von Transaktionen erzwingen, wenn eine bestimmte Sperrschwelle erreicht ist.
Abfragen mit dem Ungleichheitsoperator (<>) werden schneller abgearbeitet. Das sequentielle Lesen geht schneller. Es können bis zu 64 KB Speicherplatz auf der Platte auf einmal zugewiesen werden.
Temporäre Abfragen laufen schneller. Eine Tabelle lässt sich mit SQL DROP oder SQL DELETE schneller löschen. Indizes belegen weniger Speicherplatz. Beim Komprimieren einer Datenbank werden aus Gründen der Leistung alle Indizes optimiert.
Der Seitenzuweisungsmechanismus wurde verbessert. Dadurch wird eher gewährleistet, dass Tabellendaten auf nebeneinander liegenden Seiten abgelegt werden, und die Fähigkeit, im Voraus zu lesen, wird verbessert.
Der Cache wird dynamisch konfiguriert. Beim Start erfolgt die Konfiguration anhand des verfügbaren Systemspeichers. Der Cache enthält dann die zuletzt verwendeten Daten und das verbessert die Leistung.
Es gibt ISAM-Unterstützung für HTML-Dateien. Mit der Registry-Einstellung MaxLocksPerFile lässt sich ein Commit für Datensätze erzwingen, wenn eine bestimmte Sperrschwelle erreicht ist. Das beschleunigt den Abschluss umfangreicher Abfragen, wenn die Daten auf Windows NTund NetWare-Servern gespeichert werden. Folgende Verbesserungen sind in Jet 4.0 neu:
Die Datenseiten enthalten jetzt nicht mehr 2 KB sondern 4 KB. Dadurch erhöht sich die maximale Datenbankgröße von 1,07 auf 2,14 GB und für viele Operationen bringt es höhere Leistung, weil weniger Plattenzugriffe erforderlich sind.
Der native OLEDB Provider bietet im Vergleich zu ODBC-Daten höhere Leistung.
Die ersten 255 Zeichen von Memo-Feldern lassen sich indizieren. Das steigert die Leistung beim Durchsuchen und Sortieren von Memo-Feldern beträchtlich.
610
15.5
Kapitel 15: Optimieren Ihrer Anwendung
Mit Hilfe der Leistungsanalyse Problembereiche ermitteln
Sie können viel tun, um die Leistung einer Anwendung zu steigern. Die meisten Maßnahmen fordern von Ihnen viel Aufmerksamkeit und Fachwissen. Die Leistungsanalyse ist ein Werkzeug, das Ihnen einen Teil der Arbeit abnimmt. Sie analysiert die Architektur der Access-Anwendung und schlägt Techniken zur Steigerung der Leistung vor. Viele der vorgeschlagenen Techniken lassen sich automatisch implementieren. Um die Leistungsanalyse einzusetzen, wählen Sie EXTRAS|ANALYSE|LEISTUNG. Dann erscheint das Dialogfeld in Abbildung 15.1.
Abbildung 15.1: Das Dialogfeld Leistungsanalyse
Markieren Sie die einzelnen Tabellen, Abfragen, Formulare, Berichte, Makros, Module und Beziehungen, welche die Leistungsanalyse untersuchen soll. Wenn Access die Beziehungen untersuchen soll, müssen Sie auf die Registerkarte AKTUELLE DATENBANK klicken und dann BEZIEHUNGEN wählen. Nachdem Sie Ihre Wahl getroffen und auf OK geklickt haben, werden die markierten Objekte analysiert. Nach dem Abschluss des Analyseprozesses wird das Dialogfeld ASSISTENT ZUR LEISTUNGSANALYSE eingeblendet, das Sie in Abbildung 15.2 sehen. Es liefert Ihnen eine Liste von Verbesserungsvorschlägen für die markierten Objekte. Diese sind in Empfehlungen, Vorschläge, Ideen und automatisch behobene Dinge unterteilt. Zu den vorgeschlagenen Verbesserungen zählt beispielsweise das Hinzufügen eines Index oder die Konvertierung eines OLE-Objekts. Nach der Analyse der mit Access gelieferten Nordwind-Datenbank schlug die Leistungsanalyse beispielsweise vor, im Formular Personal weniger Steuerelemente unterzubringen.
611
Tabellen mit dem Ziel optimaler Leistung gestalten
Abbildung 15.2: Der zweite Teil des Dialogfeldes Assistent zur Leistungsanalyse
15.6
Tabellen mit dem Ziel optimaler Leistung gestalten
Nachdem Sie jetzt gesehen haben, welche Veränderungen Sie an Ihrer Umgebung vornehmen können, um die Leistung zu steigern, sollten Sie nun einen Blick auf die Veränderungen werfen, die Sie zu diesem Zweck an Ihren Datenstrukturen vornehmen können. Dazu gehört das Beseitigen redundanter Daten, die Verwendung von Indizes, die Auswahl geeigneter Datentypen für Felder und die Verwendung unterschiedlicher Abfragetechniken. Die Optimierung der Leistung durch ausgefeilte Datenstrukturen ist geboten. Schlechtes Daten-Design kann die Leistung Ihrer Anwendung erheblich verschlechtern, was Sie auch sonst zur Leistungsverbesserung tun mögen. Alle weiteren Optimierungsversuche sind ohne angemessene Berücksichtigung dieses Bereichs sinnlos. Die Optimierung Ihrer Daten kann Tage dauern. Derartige Veränderungen müssen gut durchdacht und sorgfältig analysiert werden. Veränderungen werden häufig im Lauf der Zeit vorgenommen, wenn sich Probleme zeigen. Dazu können auch die in den folgenden Abschnitten genannten gehören.
15.6.1
Warum »normal«?
Damit ist im Grunde gemeint: Bringen Sie Ihre Tabellen in die Normalform. Daten, die an mehreren Stellen vorkommen, können Ihre Anwendung deutlich verlangsamen. Ursache dafür ist sowohl die Menge der erzeugten Daten als auch die Notwendigkeit, bei Änderungen sämtliche Exemplare der Daten zu aktualisieren. Nehmen
612
Kapitel 15: Optimieren Ihrer Anwendung
wir an, eine Firmenadresse erscheint sowohl in der Tabelle Kunden als auch in der Tabelle Bestellungen. Wenn sich die Adresse ändert, muss sie in beiden Tabellen geändert werden. Die Information sollte nur in der Tabelle Kunden stehen. Adressund Bestelldaten sollten, falls erforderlich, mit Hilfe von Abfragen verknüpft werden.
15.6.2
Denormalisierung?
Wenn es um Leistung geht, gibt es leider keine schnellen, unumstößlichen Regeln. Obwohl Sie durch die Umstellung der Datenstruktur auf die Normalform meistens Leistung gewinnen, kann manchmal auch die Denormalisierung sinnvoll sein. Das gilt im Allgemeinen, wenn Sie feststellen, dass eine bestimmte Verknüpfung immer wieder erstellt wird. Ein weiteres Beispiel ist eine Buchhaltungsanwendung, in der die Gesamtschuld eines Kunden schnell erkennbar sein muss. Anstatt bei jedem Wechsel in einen Kundendatensatz alle offenen Rechnungen auszuwerten, können Sie die Gesamtschuld des Kunden im Kundendatensatz ablegen. Das setzt natürlich voraus, dass die Summe bei jeder Rechnungsausstellung oder Zahlung aktualisiert wird. Allgemein können Sie versuchen, die Daten zu denormalisieren, um zu sehen, ob sich deutliche Leistungsverbesserungen ergeben. Denken Sie daran, dass die Denormalisierung in Bezug auf Datenintegrität und -pflege deutliche Nachteile besitzt.
15.6.3
Index für gute Leistung
Es ist erstaunlich, in welchem Maß ein Index die Leistung verbessern kann. Alle Felder oder Feldkombinationen, anhand derer Sie suchen, sollten in einen Index aufgenommen werden. Sie sollten Indizes für alle Spalten anlegen, die in Abfrageverknüpfungen, Such- und Sortieroperationen verwendet werden. Primärschlüsselindizes sind gegenüber eindeutigen Indizes und eindeutige Indizes gegenüber nicht eindeutigen Indizes zu bevorzugen. Die Erstellung eines Index für das Fremdschlüsselfeld in einer 1:n-Beziehung ist nicht erforderlich. Dieser wird bei der Einrichtung der Beziehung von Access automatisch erstellt. Auch die Erstellung eines Index für ein Feld mit sich häufig wiederholenden Daten bringt keinen Vorteil. Ein Beispiel dafür ist ein Bundesstaatenfeld in einer Kundentabelle, in der alle Kunden in einem von zwei Staaten wohnen. Die Leistungssteigerungen durch Indizes sind gewaltig, obwohl sich Indizes auch überstrapazieren lassen. Obwohl Indizes die Leistung erheblich verbessern können, sollten Sie nicht für jedes Feld einer Tabelle einen Index anlegen. Indizes haben auch Nachteile. Neben dem Verbrauch von Speicherplatz verlangsamen sie das Hinzufügen, Bearbeiten und Löschen von Daten.
Abfragen mit dem Ziel optimaler Leistung gestalten
613
Indizieren Sie in einem Mehrfeldindex möglichst wenige Felder. Mehrfeldindizes können die Leistung erheblich beeinträchtigen.
Strategien für die Optimierung von Client-Server-Anwendungen werden in Kapitel 20 behandelt.
15.6.4
Wählen Sie den richtigen Datentyp
Wählen Sie bei der Definition eines Feldes den kürzesten Datentyp, den es für die Speicherung der Daten gibt. Wenn Sie beispielsweise einen Code zwischen 1 und 10 ablegen wollen, gibt es keinen Grund, für ein numerisches Feld den Typ Double zu wählen.
15.7
Abfragen mit dem Ziel optimaler Leistung gestalten
Die Optimierung Ihrer Abfragen erfordert ziemlich viel Übung und Experimente. Einige Abfragen, die eine 1:n-Beziehung betreffen, laufen beispielsweise effizienter, wenn das Kriterium auf die 1-Seite der Beziehung verlegt wird – bei anderen ist es umgekehrt. Wenn Sie einige grundlegende Dinge verstanden haben, sind Sie in bezug auf die Optimierung Ihrer Abfragen und Ihrer Anwendung insgesamt ein ganzes Stück weitergekommen, wie die folgende Liste zeigt:
Nehmen Sie möglichst wenige Spalten in die Ergebnismenge auf. Versuchen Sie, die Anzahl der komplexen Ausdrücke in der Abfrage zu reduzieren. Obwohl durch einen komplexen Ausdruck die Notwendigkeit entfällt, den Ausdruck in jedes einzelne Formular und jeden Bericht aufzunehmen, sind die Leistungsvorteile manchmal den Aufwand wert.
Verwenden Sie den Operator Zwischen anstelle von größer als (>) und kleiner als (<).
Verwenden Sie Anzahl(*) statt Anzahl([Spalte]). Fassen Sie Abfragen der Gesamtsumme anhand desjenigen Feldes in Gruppen zusammen, das sich in der Tabelle befindet, für die Sie die Gesamtsumme bilden. Anders gesagt: wenn Sie die Gesamtsumme aus Kosten mal Preis für alle Bestellungen in der Tabelle Bestelldetails bilden, sollten Sie Gruppen anhand der Bestell-ID in dieser Tabelle, aber nicht anhand der Bestell-ID in der Tabelle Bestellungen bilden.
614
Kapitel 15: Optimieren Ihrer Anwendung
Nachdem Sie gesehen haben, was Sie durch die Gestaltung Ihrer Abfragen für die Verbesserung der Leistung erreichen können, schauen Sie sich einige einfache Techniken an, mit deren Hilfe Sie die Leistung der Abfragen steigern können. Eine einfache, aber häufig vernachlässigte Methode der Abfrageoptimierung besteht in der Weitergabe der Abfragen in kompilierter Form. Eine Abfrage wird kompiliert, wenn Sie sie in der Datenblattansicht öffnen und dann einfach schließen. Wenn Sie eine Abfrage ändern und dann speichern, wird sie erst beim nächsten Start kompiliert. Wenn Sie die Datenbank komprimieren, werden alle Abfragen kompiliert. Die Auslieferung vorkompilierter Abfragen gewährleistet, dass diese möglichst schnell ausgeführt werden. Deshalb ist es günstig, eine Datenbank vor der Verteilung an Benutzer zu komprimieren. Schließlich ist es wichtig, Abfragen unter Verwendung derselben Datenmenge zu kompilieren, die Ihre Anwendung enthält. Das liegt daran, dass die Jet-Abfrageoptimierung die Abfrage in Abhängigkeit von der vorgefundenen Datenmenge auf unterschiedliche Weise optimiert. Wenn Sie eine Abfrage mit 100 Datensätzen erstellen, die auf eine reale Tabelle mit 100 000 Datensätzen angewendet werden soll, wird sie nicht korrekt optimiert. Sie müssen sie mit der richtigen Datenmenge erneut starten und sichern, wenn eine korrekte Optimierung stattfinden soll, oder die Datenbank komprimieren, nachdem die echten Daten eingegeben wurden.
15.8
Anders programmieren, um die Leistung zu optimieren
Was Sie auch tun, um die Betriebssystemumgebung zu optimieren und das DatenDesign zu verbessern – schlecht geschriebener Code kann Sie weiterhin ausbremsen. Richtige Optimierung schließt die Umgebung, das Daten-Design und den Code ein. Genauso wie schlecht gestaltete Tabellen die Leistung beeinträchtigen können, können sich auch ungeeignete Programmiertechniken negativ auswirken. Zu den Veränderungen am Code zählen die Beseitigung von Variant-Variablen und von überflüssigen Code-Bestandteilen sowie die Verwendung integrierter Auflistungen und bestimmter Objekttypen. Eine wichtige Optimierung in Bezug auf den Code ist die Auslieferung der Module in vorkompilierter Form. Die folgenden Änderungen und Techniken können zur Leistungssteigerung beitragen. Es ist wichtig zu erkennen, dass die einzelne Änderung nicht viel ausmacht. Die kombinierte Verwendung aller Änderungen kann sich jedoch beträchtlich auswirken, insbesondere an Stellen, an denen Schleifen ausgeführt werden.
Anders programmieren, um die Leistung zu optimieren
15.8.1
615
Variant-Variablen eliminieren und möglichst kleine Datentypen verwenden
Variant-Variablen sind die langsamsten. Sie verursachen hohen Aufwand, weil sie
erst zur Laufzeit aufgelöst werden. Denken Sie daran, dass die folgende Anweisung einen Variant-Datentyp deklariert: Dim intCounter
Um diese Variable beispielsweise streng als Variable vom Typ Integer zu deklarieren, muss Ihr Code folgendermaßen modifiziert werden: Dim intCounter As Integer
Sie sollten nicht nur Ihre Variablentypen genau angeben, sondern auch den kleinsten möglichen Datentyp verwenden. Denken Sie daran, dass Datentypen wie Boolean, Byte, Integer und Long die kleinsten und damit die schnellsten sind. Die übrigen folgen in der Reihenfolge Single – Double – Currency und (als letzter) Variant. Natürlich können Sie nicht den Datentyp Single wählen, wenn Sie sehr große Zahlen mit Dezimalpunkt in einer Variablen ablegen müssen. Denken Sie einfach daran, dass Sie klugerweise den kleinsten für die Verwendung der Variablen geeigneten Datentyp nehmen.
15.8.2
Verwenden Sie… spezielle Objekttypen
Genauso wie der allgemeine Variant-Datentyp ineffizient ist, gilt dies auch für allgemeine Objektvariablen. Die Unterroutine MakeItBold verwendet eine allgemeine Objektvariable, wie Sie in Listing 15.1 sehen. Listing 15.1:
Die Unterroutine MakeItBold
Private Sub cmdMakeBold_Click() Call MakeItBold(Screen.PreviousControl) End Sub Sub MakeItBold(ctlAny As Control) ctlAny.FontBold = True End Sub
Dagegen verwendet die Unterroutine SpecificBold eine bestimmte Objektvariable, wie Listing 15.2 zeigt. Listing 15.2:
Die Unterroutine SpecificBold
Private Sub cmdSpecificBold_Click() Call SpecificBold(Screen.PreviousControl) End Sub Sub SpecificBold(txtAny As TextBox)
616
Kapitel 15: Optimieren Ihrer Anwendung
txtAny.FontBold = True End Sub
Der Unterschied besteht darin, dass die Routine SpecificBold nur den Empfang von Textfeldern erwartet. Sie braucht den Typ des empfangenen Objekts nicht aufzulösen und ist deshalb effizienter. Dieser Code ist in der Datenbank CHAP15EX.MDB auf der Begleit-CD-ROM enthalten. Sie finden das Beispiel im Formular frmObjVar.
15.8.3
… Inline-Code
Es gibt eine Tendenz, alles und jedes in Form von Prozeduren aufzurufen. Das ist vom Standpunkt der Programmpflege günstig, aber nicht für die Effizienz. Jeder VBA-Prozeduraufruf erfordert zusätzliche Zeit für die Suche und Ausführung. Das zeigt sich besonders, wenn die Prozedur häufig aufgerufen wird. Die Alternative bietet Inline-Code. Dieser lässt sich effizienter ausführen, weil Access ihn nicht zu suchen braucht. Der Nachteil von Inline-Code ist die schwierigere Pflege. Sie müssen entscheiden, wie wichtig die Pflegbarkeit im Vergleich zur Geschwindigkeit ist.
15.8.4
Ändern Sie den Wert von Boolean-Variablen direkt
Der folgende Code ist ziemlich ineffizient: If bFlag = True Then bFlag = False Else bFlag = True End If
Er sollte folgendermaßen geändert werden: bFlag = Not bFlag
Das erfordert nicht nur weniger Code-Zeilen, sondern der Ausdruck lässt sich zur Laufzeit auch schneller auswerten.
15.8.5
Verwenden Sie… die integrierten Auflistungen
Die integrierten Auflistungen sind vorhanden – ob Sie sie verwenden oder nicht. Mit For Each...Next und einer Auflistung von Objekten können Sie sehr effizienten Code schreiben, wie Listing 15.3 zeigt.
Anders programmieren, um die Leistung zu optimieren
Listing 15.3:
617
Verwendung von For Each...Next
Sub FormCaption() Dim frm As Form For Each frm In Forms frm.Caption = frm.Caption & " – " & CurrentUser() Next End Sub
In diesem Beispiel verwenden Sie die Auflistung Forms, um schnell und effizient eine Schleife durch alle Formulare zu durchlaufen und die Beschriftung in der Titelleiste zu ändern.
15.8.6
… die Funktion Length
Es ist effizienter, die Funktion Length zu verwenden (wie in Listing 15.4), als auf eine Zeichenfolge der Länge Null zu prüfen (wie in Listing 15.5). Listing 15.4:
Verwendung der Funktion Length
Sub SayNameLen(strName As String) If Len(strName) Then MsgBox strName End If End Sub Listing 15.5:
Prüfen auf eine Zeichenfolge der Länge Null
Sub SayNameZero(strName As String) If strName <> "" Then MsgBox strName End If End Sub
Listing 15.4 ist für VBA einfacher auszuwerten und läuft daher schneller und effizienter.
15.8.7
… True und False anstelle von 0
Dieses Beispiel hat Ähnlichkeit mit dem vorigen. Die Auswertung auf True und False (wie in Listing 15.6) ist einfacher als die auf 0 (wie in Listing 15.7). Listing 15.6:
Auswertung auf True und False
Sub SaySalaryTrue(lngSalary As Long) If lngSalary Then MsgBox "Salary is " & lngSalary End If End Sub
618
Kapitel 15: Optimieren Ihrer Anwendung
Listing 15.7:
Auswertung auf 0
Sub SaySalaryZero(lngSalary As Long) If lngSalary <> 0 Then MsgBox "Salary is " & lngSalary End If End Sub
15.8.8
… Transaktionen – manchmal
In früheren Versionen als Access 95 ließ sich die Leistung durch Transaktionen erheblich steigern. Bei Verwendung expliziter Transaktionen werden die Daten nur einmal, nach einem CommitTrans, auf die Festplatte geschrieben. Alle Änderungen zwischen einem BeginTrans und einem CommitTrans werden in einem Zwischenspeicher abgelegt. Da der Festplattenzugriff auf einem Rechner den geringsten Durchsatz erzielt, lieferte diese Technik in Versionen vor Access 95 wesentliche Leistungsvorteile. Der Unterschied bei Access 95 und Access 2000 besteht darin, dass die JetEngines 3.0, 3.5, 3.6 und 4.0 Transaktionen implizit puffern. Meistens bietet die Jeteigene Transaktionshandhabung eine bessere Leistung als Ihre eigene. In anderen Fällen können Sie das, was Jet von sich aus macht, noch verbessern. Die einzige Möglichkeit, dies sicher festzustellen, sind eigene Benchmark-Tests. Jede Situation ist anders.
15.8.9
Beseitigen Sie nicht benutzte Dim- und Declare-Anweisungen
Beim Ändern Ihrer Subroutinen und Funktionen kommt es vor, daß Sie eine Variable deklarieren, aber nirgends Gebrauch von ihr machen. Jede Dim-Anweisung verbraucht aber selbst dann Speicher, wenn sie benutzt wird. Darüber hinaus trifft es auch zu, dass Declare-Anweisungen, die zum Aufrufen von Funktionen in externen Bibliotheken verwendet werden, Speicherplatz belegen. Sie sollten daher aller Vorkommen dieser Anweisungen entfernen, die nicht zum Einsatz kommen.
15.8.10 Nicht benutzten Code beseitigen Die meisten Programmierer experimentieren mit verschiedenen Alternativen, um eine Aufgabe zu erledigen. Das schließt häufig die Erstellung zahlreicher Unterroutinen und Funktionen zu Testzwecken ein. Das Problem liegt darin, dass die meisten diesen Code nicht löschen, wenn sie fertig sind. Der nutzlose Code wird zusammen mit der Anwendung geladen und belegt deshalb Arbeitsspeicher und Ressourcen. Es gibt einige Werkzeuge von Fremdanbietern, mit denen Sie überflüssigen Code und nicht benutzte Variablendeklarationen finden können. Viele Programmierer verwenden den Total Access Analyzer von FMS Inc.
Anders programmieren, um die Leistung zu optimieren
619
15.8.11 Setzen Sie Variablen zum Verweisen auf Eigenschaften, Steuerelemente und Datenzugriffsobjekte ein Wenn Sie vorhaben, wiederholt auf ein Objekt zu verweisen, sollten Sie ein Objekt deklarieren und auf die Objektvariable anstatt auf das eigentliche Steuerelement verweisen, wie in Listing 15.8 gezeigt wird. Listing 15.8:
Ein Objekt deklarieren und auf die Objektvariable verweisen
Forms!frmAny.txtHello.FontBold = True Forms!frmAny.txtHello.Enabled = True Forms!frmAny.txtHello.Left = 1 Forms!frmAny.txtHello.Top = 1
Das ist ein Beispiel mit sehr geringem Umfang. Wenn jedoch viele Eigenschaften zu ändern sind oder der Code rekursiv aufgerufen werden soll, kann er mit Hilfe einer Objektvariablen effizienter gestaltet werden, wie Listing 15.9 zeigt. Listing 15.9:
Den Code mit Hilfe einer Objektvariablen effizienter gestalten
Private Sub cmdChangeObject_Click() Dim txt As TextBox Set txt = Forms!frmHello!txtHello1 txt.FontBold = True txt.Enabled = True txt.Left = 100 txt.Top = 100 End Sub
15.8.12 Nehmen Sie… With...End With Eine weitere Möglichkeit, den Code im vorhergehenden Beispiel zu optimieren, besteht in der Verwendung eines With...End With-Konstrukts, wie in Listing 15.10 gezeigt. Listing 15.10: Verwendung von With...End With Private Sub cmdChangeObjectWith_Click() With Forms!frmHello!txtHello2 .FontBold = True .Enabled = True .Left = 100 .Top = 100 End With End Sub
620
Kapitel 15: Optimieren Ihrer Anwendung
15.8.13 … das Schlüsselwort Me Im vorhergehenden Beispiel haben Sie mit Forms!frmHello.txtHello auf ein Steuerelement im aktuellen Formular verwiesen. Es ist effizienter, dafür Me.txtHello zu verwenden. Die Ursache dafür ist, dass VBA nur im lokalen Namensraum sucht. Das macht Ihren Code zwar effizienter, aber der Nachteil liegt darin, dass das Schlüsselwort Me nur in Formular-, Berichts- und Klassenmodulen funktioniert, nicht aber in standardmäßigen Code-Modulen. Sie können es also nicht in allgemeinen Funktionen verwenden, auf die alle Formulare zugreifen.
15.8.14 … Funktionen mit Variablen des Typs String Viele Funktionen liegen in zwei Formen vor: einer mit einem Dollarzeichen ($) und einer ohne, z.B. Left(sName) und Left$(sName). Die Verwendung der Version mit dem Dollarzeichen ist, falls möglich, effizienter. Diese Funktionen geben Zeichenfolgen anstelle von Variant-Variablen zurück. Wenn eine Variable des Typs String zurückgegeben wird, ist keine Typkonvertierung erforderlich.
15.8.15 … dynamische Datenfelder Datenfeldelemente verbrauchen Arbeitsspeicher, gleich, ob sie verwendet werden oder nicht. Deshalb ist es manchmal vorzuziehen, dynamische Datenfelder einzusetzen. Die Größe eines dynamischen Datenfeldes lässt sich bei Bedarf erhöhen. Wenn Sie den Platz, der von den Elementen des Datenfeldes belegt wird, erneut nutzen wollen, können Sie das Schlüsselwort Erase verwenden, wie im folgenden Beispiel: Erase aNames
Falls Sie nur einen Teil des von dem Datenfeld belegten Platzes erneut nutzen wollen, ohne die Daten in den betreffenden Elementen zu zerstören, verwenden Sie Redim Preserve: Redim Preserve aNames(5)
Diese Anweisung legt die Größe des Datenfeldes auf sechs Elemente fest (sie beginnt die Zählung mit 0). Die Daten in diesen sechs Elementen bleiben erhalten. Bei der Verwendung dynamischer Datenfelder mit Redim Preserve müssen Sie sorgfältig vorgehen. Wenn Sie die Größe mit Redim Preserve verändern, wird das gesamte Datenfeld in den Arbeitsspeicher kopiert. Wenn in Ihrer Umgebung Arbeitsspeicher knapp ist, kann das bedeuten, dass virtueller Speicherplatz verwendet wird, was die Leistung senkt – oder noch schlimmer: die Anwendung kann abstürzen, falls physischer und virtueller Speicher nicht ausreichen.
Anders programmieren, um die Leistung zu optimieren
621
15.8.16 … nach Möglichkeit Konstanten Konstanten verbessern sowohl die Lesbarkeit als auch die Leistung. Der Wert einer Konstanten wird nach der Kompilierung aufgelöst. Der Wert, den die Konstante repräsentiert, wird im Code abgelegt. Eine normale Variable muss aufgelöst werden, während der Code ausgeführt wird, weil VBA den aktuellen Wert der Variablen benötigt.
15.8.17 … Lesezeichen Ein Lesezeichen bietet Ihnen den schnellsten Zugriff auf einen Datensatz. Wenn Sie vorhaben, zu einem Datensatz zurückzukehren, richten Sie eine Variable mit dem Wert dieses Lesezeichens ein. Es ist dann sehr einfach, zu einem beliebigen Zeitpunkt zu diesem Datensatz zurückzukehren. Listing 15.11 enthält ein Beispiel, das ein Lesezeichen verwendet. Listing 15.11: Verwendung eines Lesezeichens Sub BookMarkIt() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset Dim varBM As Variant rst.Open "tblProjects", CurrentProject.Connection, adOpenStatic varBM = rst.Bookmark Do Until rst.EOF Debug.Print rst!ProjectID rst.MoveNext Loop rst.Bookmark = varBM Debug.Print rst!ProjectID End Sub
Sie finden diesen Code im Modul basOptimize in CHAP15EX.MDB. Das Lesezeichen wird in einer Variablen abgelegt, bevor die Do Until-Schleife ausgeführt wird. Nach der Ausführung der Schleife wird das Lesezeichen des Datensatzes auf den in der Variablen enthaltenen Wert gesetzt.
15.8.18 Setzen Sie Objektvariablen auf Nothing Objektvariablen belegen Arbeitsspeicher und damit verknüpfte Ressourcen. Ihr Wert sollte auf Nothing gesetzt werden, wenn Sie mit der Verwendung fertig sind. Das spart Speicher und Ressourcen. Ein Beispiel: Set oObj = Nothing
622
Kapitel 15: Optimieren Ihrer Anwendung
15.8.19 Wählen Sie Aktionsabfragen, anstatt Datensatzgruppen zu durchlaufen Die Ausführung einer gespeicherten Abfrage ist nicht nur einfacher zu programmieren, sondern lässt sich auch effizienter ausführen als eine Schleife durch eine Datensatzgruppe, bei der für jeden Datensatz eine Aktion stattfindet. Listing 15.12 zeigt ein Beispiel für das Durchlaufen einer Datensatzgruppe. Listing 15.12: Durchlaufen einer Datensatzgruppe Sub LoopThrough() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.Open "tblProjects", CurrentProject.Connection, adOpenDynamic, _ adLockOptimistic Do Until rst.EOF rst!ProjectTotalEstimate = rst!ProjectTotalEstimate + 1 rst.UPDATE rst.MoveNext Loop End Sub
Dieser Code, den Sie im Modul basOptimize in CHAP15EX.MDB finden, durchläuft eine Datensatzgruppe ib Form einer Schleife und erhöht die Gesamtschätzung für jedes Projekt um 1. Vergleichen Sie mit dem Code in Listing 15.13!
Listing 15.13: Eine gespeicherte Abfrage ausführen Sub ExecuteQuery() Dim adoCat As ADOX.Catalog Dim cmd As ADODB.Command Set adoCat = New ADOX.Catalog Set cmd = New ADODB.Command Set adoCat.ActiveConnection = CurrentProject.Connection Set cmd = adoCat.Procedures("qupdLowerEstimate").Command cmd.Execute End Sub
Dieser Code verwendet ein Befehlsobjekt, um eine gespeicherte Abfrage mit dem Namen qupdLowerEstimate auszuführen. Die Abfrage verläuft wesentlich effizienter als die Do Until-Schleife in Listing 15.12.
Anders programmieren, um die Leistung zu optimieren
623
15.8.20 Liefern Sie Ihre Anwendung mit bereits kompilierten Modulen aus Anwendungen laufen langsamer, wenn sie nicht kompiliert sind. Formulare und Berichte werden langsamer geladen und die Anwendung benötigt mehr Arbeitsspeicher. Wenn Sie Ihre Anwendung mit bereits kompilierten Modulen ausliefern, brauchen diese nicht auf dem Rechner des Benutzers kompiliert zu werden, bevor er sie startet. Um ohne große Mühe alle Module erneut kompilieren zu können, wählen Sie DEBUGGEN|KOMPILIEREN, während der Visual Basic Editor (VBE) aktiv ist. Damit wird der gesamte Code der Anwendung geöffnet und kompiliert, auch derjenige, der hinter Formularen und Berichten liegt. Dann werden die Module in kompiliertem Zustand gespeichert. Damit bleibt der kompilierte Zustand der Anwendung erhalten.
15.8.21 Den kompilierten Zustand erhalten Haben Sie keine Angst, den Befehl DEBUGGEN|KOMPILIEREN zu verwenden, wenn Sie zusätzliche Änderungen an der Anwendung vorhaben. Eine Anwendung wird dekompiliert, sobald die Steuerelemente, Formulare, Berichte oder Module geändert werden. Selbst etwas so Einfaches wie das Einfügen eines einzigen Steuerelements in ein Formular veranlasst, dass die Anwendung den kompilierten Zustand verlässt. Deshalb ist es wichtig, unmittelbar vor der Weitergabe der Anwendung den Befehl DEBUGGEN|KOMPILIEREN zu benutzen. Die Umbenennung einer Datenbankdatei veranlasst die Dekompilierung des in der Datenbank enthaltenen Codes. Deshalb müssen Sie nach der Umbenennung einer Datenbank immer den Befehl ALLE MODULE KOMPILIEREN UND SPEICHERN anwenden.
15.8.22 Geben Sie Ihre Anwendung als MDE weiter Die Erstellung einer MDE-Datei kompiliert alle Module, löscht bearbeitbaren Quellcode und komprimiert die Zieldatenbank. Der gesamte VBA-Code lässt sich ausführen, kann aber nicht eingesehen oder bearbeitet werden. Das verbessert die Leistung, reduziert die Größe der Datenbank und schützt Ihr geistiges Eigentum. Auch die Speichernutzung wird verbessert. Das Speichern einer Anwendung als MDE-Datei und die damit verbundenen Implikationen werden in Kapitel 37 behandelt.
15.8.23 Organisieren Sie Ihre Module VBA-Code lässt sich theoretisch in jedes Modul innerhalb Ihrer Anwendung einfügen. Das Problem besteht darin, dass ein Modul erst geladen wird, wenn eine darin enthaltene Funktion aufgerufen wird. Wenn eine einzige Prozedur in einem Modul
624
Kapitel 15: Optimieren Ihrer Anwendung
aufgerufen wurde, wird das gesamte Modul in den Arbeitsspeicher geladen. Außerdem wird das gesamte Modul geladen, wenn eine einzige darin enthaltene Variable verwendet wird. Wie Sie sich vielleicht vorstellen können, wird jedes Modul Ihrer Anwendung geladen, wenn Sie die Anwendung nicht sehr durchdacht gestalten. Wenn Sie ähnliche Routinen in einem Modul zusammenfassen, wird dieses Modul geladen, andere aber nicht. Das bedeutet, dass Benutzer, welche die Funktionalität Ihrer Anwendung nur teilweise nutzen, niemals andere Module des Codes laden. Das spart Speicher und optimiert so die Anwendung.
15.9
Formulare und Berichte mit dem Ziel optimaler Leistung gestalten
Auch an Formularen und Berichten können Sie einiges zur Verbesserung der Leistung tun. Dazu gehören Techniken zum schnellen Laden von Formularen und Berichten, Tipps und Tricks in bezug auf OLE und spezielle Programmierverfahren, die nur für Formulare und Berichte relevant sind.
15.9.1
Formulargestaltung
Da Formulare die Hauptschnittstelle zum Benutzer darstellen, kann deren möglichst effiziente Gestaltung einen großen Teil zur Verbesserung des Eindrucks beitragen, den der Benutzer hinsichtlich der Leistung Ihrer Anwendung bekommt. Außerdem lassen sich viele Formulartechniken ausgesprochen einfach implementieren. Techniken zur Optimierung von Formularen lassen sich in zwei Kategorien unterteilen: in solche, die die Ladezeit verkürzen, und solche, mit denen sich Objekte im Formular effizienter bearbeiten lassen. Je umfangreicher ein Formular ist und je mehr Steuerelemente und Objekte Sie darauf untergebracht haben, desto geringer ist die Effizienz. Achten Sie darauf, dass sich die Steuerelemente nicht überschneiden. Außerdem ist es sehr vorteilhaft, Formulardaten auf logischen Seiten zusammenzufassen. Das ist besonders wichtig, wenn Ihre Benutzer nicht über ausreichend Bildschirmspeicher verfügen. Objekte auf Folgeseiten sollten erst mit Daten gefüllt werden, wenn sich der Benutzer zu der betreffenden Seite begibt. Formulare und deren Steuerelemente sollten auf gespeicherten Abfragen oder eingebetteten SQL-Anweisungen basieren. Nehmen Sie nur Felder auf, die das Formular in der zu Grunde liegenden Abfrage benötigt. Vermeiden Sie Abfragen mit Auswahl *. Da die interne Optimierung der Abfrage-Ergebnisse in Access so effizient ist, wird dadurch die Leistung Ihrer Formulare gesteigert. Reduzieren Sie, um die Leistungsfähigkeit von Abfragen noch stärker zu nutzen, die Anzahl der Datensätze, welche die Abfrage zurückgibt, indem Sie nur die zu einem bestimmten Zeitpunkt benötigten Datensätze laden.
Formulare und Berichte mit dem Ziel optimaler Leistung gestalten
625
Wenn Sie ein Formular lediglich benutzen wollen, um neue Datensätze hinzuzufügen, setzen Sie die Eigenschaft Daten eingeben des Formulars auf Ja, so dass es mit einem leeren Datensatz geöffnet wird. Das ist notwendig, weil Access sonst alle Datensätze einlesen muss, um am Ende der Datensatzgruppe den leeren Datensatz anzeigen zu können. Vermeiden Sie, falls möglich, Bitmap-Bilder und andere Grafikobjekte. Wenn Sie ein Bild anzeigen müssen, sollten Sie unbedingt daran denken, dass OLE-Objekte weit mehr Ressourcen beanspruchen als Bilder. Konvertieren Sie ein OLE-Objekt im Bitmap-Format, das nicht geändert werden muss, in ein Bild. Dazu klicken Sie mit der rechten Maustaste auf das Objekt und wählen ÄNDERN ZU|BILD. Vermeiden Sie, soweit möglich, die Verwendung untergeordneter Formulare. Access behandelt ein Unterformular wie ein eigenständiges Formular. Deshalb belegt es eine erhebliche Menge Speicher. Achten Sie darauf, dass alle Felder eines untergeordneten Formulars, die entweder mit dem Hauptformular verknüpft sind oder als Kriterium benutzt werden, einen Index besitzen. Stellen Sie sicher, dass nur die nötigen Felder in die Datensatzquelle des Unterformulars aufgenommen werden. Setzen Sie, wenn die Daten im Unterformular nicht bearbeitet zu werden brauchen, die Eigenschaften Bearbeitungen zulassen, Anfügen zulassen und Löschen zulassen auf Nein oder die Eigenschaft Recordsettyp auf Snapshot. Achten Sie darauf, dass die Datensatzherkunft für ein Kombinationsfeld nur die für dieses Feld erforderlichen Spalten enthält. Indizieren Sie nach dem ersten Feld, das im Kombinationsfeld erscheint. Das wirkt sich erheblich auf die Geschwindigkeit aus, mit der sich der Benutzer auf ein Element des Kombinationsfeldes bewegen kann. Außerdem sollten Sie, wo immer möglich, das erste sichtbare Feld eines Kombinationsfeldes zum Textfeld machen. Access konvertiert numerische Felder in Textfelder, wenn es das Kombinationsfeld nach einem passenden Wert durchsucht. Erstellen Sie schließlich Listen- oder Kombinationsfelder nicht auf der Grundlage von verknüpften Daten, falls diese nur selten oder überhaupt nicht geändert werden. Machen Sie stattdessen die statische Tabelle zur lokalen und aktualisieren Sie diese, wann immer es nötig ist. Eine allgemeine Regel im Hinblick auf die Leistung von Formularen besagt, dass alle Datenbankobjekte mit Ausnahme der Daten auf dem Rechner jedes Benutzers vorhanden sein sollten. Das beseitigt die Notwendigkeit, ständig Objektdefinitionen über das Netzwerk herbeischaffen zu müssen. Schließen Sie nicht mehr benötigte Formulare. Geöffnete Formulare belegen Arbeitsspeicher und Ressourcen und verringern damit die Leistung. Ein weiterer Tipp zur Leistungssteigerung ist die Verwendung der Standardformatierungen und -Eigenschaften für möglichst viele Steuerelemente. Damit steigt die Leistung deutlich, weil nur diejenigen Formular- und Steuerelementeigenschaften, die davon abweichen, zusammen mit dem Formular gespeichert werden.
626
Kapitel 15: Optimieren Ihrer Anwendung
Wenn die Mehrzahl der Steuerelemente Eigenschaften besitzt, die vom Standardsteuerelement des Formulars abweichen, sollten Sie das Standardsteuerelement wechseln und dann Steuerelemente auf der Basis des neuen Standards einfügen. Access speichert nur die Eigenschaften des Standardsteuerelements und braucht nicht die Eigenschaften jedes einzelnen Steuerelements im Formular zu speichern. Das kann zu erheblicher Leistungssteigerung führen. Der Wechsel des Standardsteuerelements wird in Kapitel 5 beschrieben. Beseitigen Sie schließlich das Code-Modul aus Formularen, die es nicht benötigen. Ein Formular ohne Formularmodul wird schneller geladen und belegt weniger Platz auf der Platte. Funktionsprozeduren aus einer Ereigniseigenschaft lassen sich mit Hilfe eines Ausdrucks trotzdem aufrufen. Sie können sich auch mit Hilfe von Hyperlinks vom Formular aus durch die Anwendung bewegen. Das mit einem Formular verknüpfte Modul lässt sich entfernen, indem Sie die Eigenschaft Enthält Modul auf Nein setzen.
15.9.2
Einen Bericht gestalten
Viele Techniken zur Optimierung von Formularen gelten auch für Berichte. Verringern der Anzahl der Steuerelemente, Vermeiden überlappender Steuerelemente, Abfragen als Grundlage von Berichten, Vermeiden von OLE-Objekten und Konvertieren nicht gebundener Objektrahmen mit Grafiken in Bildsteuerelemente verbessern die Leistung sowohl bei Formularen als auch bei Berichten. Um speziell die Leistung von Berichten zu steigern, gibt es ein paar zusätzliche Möglichkeiten. Beseitigen Sie alle nicht erforderlichen Sortier- und Gruppierungsausdrücke und indizieren Sie alle Felder, nach denen Sie sortieren oder gruppieren. Achten Sie darauf, dass die dem Bericht zu Grunde liegenden Abfragen optimiert und dass alle mit dem Hauptbericht verknüpften Felder im untergeordneten Bericht indiziert sind. Eine spezielle Technik, mit der sich die Leistung von Berichten steigern lässt, wurde mit Access 95 eingeführt. Sie umfasst das Ereignis Bei Ohne Daten und die Eigenschaft HasData. Das Ereignis Bei Ohne Daten wird ausgelöst, wenn ein Bericht geöffnet wird und seine Datensatzquelle keine Daten zurückgibt. Mit der Eigenschaft HasData wird ermittelt, ob ein Bericht an eine leere Datensatzgruppe gebunden ist. Wenn die Eigenschaft HasData für einen Unterbericht False ergibt, können Sie den Unterbericht verbergen und so die Leistung steigern.
15.9.3
Für die Praxis
Die Leistung des Zeit- und Abrechnungssystems verbessern Um sicherzustellen, dass unser exemplarisches Zeit- und Abrechnungssystem optimiert ist, können Sie Folgendes tun:
Achten Sie darauf, dass die Datenbank komprimiert wurde.
Formulare und Berichte mit dem Ziel optimaler Leistung gestalten
627
Analysieren Sie die Anwendung mit der Leistungsanalyse und empfehlen Sie Verbesserungen.
Wählen Sie im VBE DEBUGGEN|KOMPILIEREN, bevor Sie die Anwendung weitergeben.
Mehrbenutzer- und Unternehmensanwendungen entwickeln
Teil III
16 Eine Strategie für die Entwicklung von Access-Anwendungen 17 Mehrbenutzeranwendungen entwickeln 18 Externe Daten verwenden 19 Client-Server-Techniken 20 Client-Server-Strategien 21 Eine Client-Server-Anwendung in Aktion 22 Transaktionsverarbeitung 23 Replikation leichtgemacht
Eine Strategie für die Entwicklung von AccessAnwendungen
Kapitel
Hier lesen Sie:
Leistungssteigerungen Datenbanken in Tabellen und andere Objekte zerlegen Abfragen oder eingebettete SQL-Anweisungen als Grundlage für Formulare und Berichte
Die Laufzeit-Engine von Access Eine ausführbare Datei und eine Access-Datenbank im Vergleich Die Bedeutung der Absicherung der Datenbank Access als Front-End
16.1
Leistungssteigerungen
Sie sollten einige fachliche Tricks kennen, die Ihnen bei der Entwicklung viel Zeit sparen und dazu beitragen können, dass Ihre Anwendungen hinsichtlich der Leistung das Höchstmaß an Optimierung erreichen. Dieses Kapitel stellt diese Strategien dar und erläutert außerdem einige häufig mißverstandene Aspekte der Jet-Engine, der Laufzeit-Engine von Access und der Sicherheit. Alle hier behandelten Themen sollten Sie bei der Entwicklung Ihrer Access-Anwendungen im Kopf behalten. Achten Sie beim Lesen des Kapitels mehr auf die umrissene allgemeine Strategie als auf die Einzelheiten der jeweiligen Themen. Jedes davon wird in weiteren Kapiteln ausführlich dargestellt.
632
16.2
Kapitel 16: Eine Strategie für die Entwicklung von Access-Anwendungen
Datenbanken in Tabellen und andere Objekte zerlegen
In früheren Access-Versionen war es in einer Mehrbenutzerumgebung fast zwingend, die Tabellen, aus denen Ihr System bestand, in einer Datenbank und die übrigen Systemobjekte in einer anderen unterzubringen. Seit Access 95 und der Einführung der Replikation konnten Sie die Tabellen entweder von den anderen Objekten trennen oder Änderungen am Entwurf mit Hilfe der Replikation zum Einsatz bringen, ohne reale Daten zu berühren. Access 2000 führt diesen Schritt mit dem Access Data Project (ADP) noch ein Stück weiter, indem Tabellen, Ansichten, gespeicherte Prozeduren und Datendiagramme in einer SQL Server-Datenbank oder von der Microsoft Data Engine (MSDE), die anderen Objekte jedoch in der ADP-Datei gespeichert werden. Wie bereits erwähnt, stellt die Trennung von Tabellen und anderen Systemobjekten immer noch eine gangbare Lösung dar. Der Einfachheit halber nenne ich die Datenbank, welche die Tabellen enthält, Tabellen und die Datenbank mit den anderen Objekten Anwendung. Beide sind durch eine Verknüpfung von der Datenbank Anwendung zur Datenbank Tabellen verbunden. Das hat folgende Gründe:
Pflegbarkeit Leistung Skalierbarkeit Nehmen Sie für einen Augenblick an, Sie geben Ihre Anwendung in Form einer einzigen MDB-Datei weiter. Die Benutzer arbeiten eine oder zwei Wochen damit und notieren sich Probleme und Änderungen. Dann ist es Zeit, dass Sie Modifizierungen vornehmen. Inzwischen wurden zwei Wochen lang echte Daten in die Anwendung eingegeben. Sie legen eine Kopie der Datenbank an (welche die echten Daten enthält) und nehmen alle Fehlerkorrekturen und Änderungen vor. Das dauert eine Woche. Dann können Sie Ihr Exemplar der Datenbank im Netz installieren. Und nun? Die Benutzer haben die ganze Woche Datensätze hinzugefügt, bearbeitet und gelöscht. Datenreplikation (siehe Kapitel 23) könnte Ihnen bei der Behebung des Problems helfen, ist aber nicht immer machbar. Die einfachste Lösung besteht in der Trennung der Datenbankobjekte, so dass sich die Tabellen (Ihre Daten) in einer MDB-Datei und die übrigen Datenbankobjekte (Ihre Anwendung) in einer zweiten MDB-Datei befinden. Wenn Sie bereit sind, die Änderungen zu installieren, brauchen Sie nur noch die Anwendungsdatenbank auf den Server zu kopieren. Die neue Datenbank kann dann von dort aus auf jedem Client-Rechner installiert werden. Auf diese Weise können die Benutzer neue Exemplare der Anwendung von ihrem Rechner aus starten. Die Datenbank mit den Datentabellen bleibt unangetastet und wird von diesem Vorgang nicht berührt. (Das ist natürlich nur möglich, wenn Sie den Entwurf der Tabellenstruktur abgeschlossen haben, bevor Sie die Datenbank aufteilen.)
Datenbanken in Tabellen und andere Objekte zerlegen
633
Der zweite Vorteil bei der Aufteilung der Datenbankobjekte hat etwas mit der Geschwindigkeit zu tun. Die Tabellendatenbank muss natürlich auf dem Datei-Server des Netzwerks liegen, damit die Benutzer des Systems die Daten gemeinsam nutzen können; es gibt jedoch keinen guten Grund dafür, warum die anderen Datenbankbestandteile gemeinsam genutzt werden sollten. Access liefert Ihnen optimale Leistung, wenn die Anwendungsdatenbank auf allen lokalen Rechnern installiert ist. Dadurch wird nicht nur die Leistung gesteigert, sondern auch der Verkehr im Netzwerk erheblich reduziert. Wenn diese Datenbank auf dem Datei-Server liegt, müssen der Code und die Objekte der Anwendung jedesmal über das Netzwerk gesendet werden, wenn ein Objekt in der Datenbank geöffnet wird. Wenn sie auf allen lokalen Rechnern installiert ist, brauchen nur die Daten über das Netz gesendet zu werden. Die einzige Komplikation dieses Szenarios besteht darin, dass die Anwendungsdatenbank bei jeder Aktualisierung erneut an die Benutzer verteilt werden muss. In einem bereits überlasteten Netzwerk ist dies im Vergleich zu den Leistungsvorteilen der verteilten Struktur jedoch eine nur geringe Unbequemlichkeit. Der dritte Vorteil der Trennung der Tabellen von den anderen Datenbankobjekten hat etwas mit Skalierbarkeit zu tun. Da die Tabellen bereits verknüpft sind, ist der Wechsel von einer Verknüpfung mit einer im proprietären Access-Format gespeicherten Tabelle zu einer beliebigen ODBC-Datenbank, z.B. SQL Server, einfach. Diese Fähigkeit liefert Ihnen schnellen und unkomplizierten Zugriff auf Client-Server-Datenbanken. Wenn Sie die Gestaltung Ihres Systems bereits mit verknüpften Tabellen geplant haben, ist der Übergang noch einfacher. Lassen Sie sich dennoch nicht dadurch täuschen, dass es so einfach klingt. Mit der Verwendung von Access als Front-End für Client-Server-Daten sind viele Fragen verknüpft, die weit über die einfache Verknüpfung mit externen Tabellen hinausgehen. Einige davon werden in diesem Kapitel behandelt, andere in Kapitel 19. Einige besondere Tabellentypen sollten Sie lieber in der Anwendungsdatenbank als in der Tabellendatenbank ablegen. Tabellen, die sich selten ändern, sollten in der Anwendungsdatenbank auf dem lokalen Rechner des einzelnen Benutzers gespeichert werden. Beispielsweise ändert sich eine Tabelle Ort selten, wenn überhaupt, aber es wird ständig darauf zugegriffen, um Kombinationsfelder zu füllen, sie für Abfragen zu verwenden usw. Die Unterbringung auf jedem lokalen Rechner verbessert daher die Leistung und reduziert den Verkehr im Netzwerk. Nachschlagetabellen mit lokalspezifischen Informationen wie Abteilungs-Codes sollten ebenfalls in der Anwendungsdatenbank gespeichert werden. Auch temporäre Tabellen sollten auf den einzelnen lokalen Rechnern liegen – das ist sogar notwendig, nicht nur möglich. Falls zwei Benutzer gleichzeitig denselben Prozeß starten und dieser temporäre Tabellen verwendet, kommt es zum Konflikt, wenn der eine die temporären Tabellen des anderen überschreibt. Wenn sie auf den lokalen Rechnern gespeichert sind, steigt die Leistung und das Risiko potentiell katastrophaler Konflikte entfällt.
634
Kapitel 16: Eine Strategie für die Entwicklung von Access-Anwendungen
Wenn Sie Ihre Anwendung bereits entworfen und alle Tabellen in derselben Datenbank untergebracht haben wie die übrigen Datenbankobjekte, brauchen Sie nicht zu verzweifeln. Access 2000 enthält einen Assistenten zur Datenbankaufteilung. Sie finden dieses wertvolle Werkzeug unter EXTRAS|DATENBANK-DIENSTPROGRAMME|ASSISTENT ZUR DATENBANK-AUFTEILUNG. Er wird ebenso wie verknüpfte Tabellen in Kapitel 18 besprochen. Ich unterteile alle Anwendungen in zwei Datenbanken. Beim Untersuchen der Musterdatenbanken stellen Sie jedoch möglicherweise fest, dass bis Kapitel 18 keine einzige Anwendung in der empfohlenen Art aufgeteilt ist. Der Grund dafür ist, dass ich es nicht für hilfreich halte, die Musterdatenbanken zu unterteilen, bevor Sie alles gelernt haben, was zur Teilung von Datenbankobjekten erforderlich ist. Ab Kapitel 19 wird jedoch die hier empfohlene Strategie angewandt.
16.3
Abfragen oder eingebettete SQL-Anweisungen als Grundlage für Formulare und Berichte
Die Datensatzherkunft für ein Formular oder einen Bericht kann auf einem Tabellenobjekt, einem Abfrageobjekt oder einer SQL-Anweisung basieren. Durch gespeicherte Abfragen oder eingebettete SQL-Anweisungen als Grundlage lässt sich die Leistung und die Flexibilität Ihrer Anwendungen steigern. Meistens brauchen Sie nicht alle Felder und alle Datensätze in einem Formular oder Bericht anzuzeigen. Indem Sie eine Abfrage oder eine eingebettete SQL-Anweisung als Grundlage wählen, lassen sich die über das Netzwerk übertragenen Daten besser begrenzen. Diese Vorteile kommen am stärksten in einer Client-Server-Umgebung zum Tragen. Wenn ein Formular oder ein Bericht auf einem Tabellenobjekt basiert, sendet Access eine SQL-Anweisung, die alle Felder und alle Datensätze vom Datenbank-Server holt. Wenn dagegen die Datensatzherkunft für das Formular oder den Bericht eine Abfrage oder eine eingebettete SQL-Anweisung ist, werden nur die dort genannten Felder und Datensätze an die Arbeitsstation zurückgegeben. In Access 2.0 war ein Formular oder ein Bericht auf der Grundlage einer gespeicherten Abfrage effizienter als auf der Grundlage einer SQL-Anweisung. Das liegt daran, dass die Jet-Engine der Access-Datenbank beim Speichern einer Abfrage einen Abfrageplan erstellt, der Informationen über die effizientesten Methoden zur Ausführung der Abfrage enthält. Beim Speichern der Abfrage wirft die Jet-Engine einen Blick auf den Umfang der Daten und die verfügbaren Indizes, bestimmt die optimale Ausführungsmethode und speichert diese als Abfrageplan. Dieser wird bei jeder Ausführung eines Formulars oder Berichts auf der Grundlage dieser Abfrage angewandt. Wenn in Access 2.0 ein Formular oder Bericht auf einer SQL-Anweisung basierte, fand die Optimierung beim Öffnen des Formulars oder Berichts statt und der Abfrageplan wurde nebenbei ausgeführt. In Access 97 und Access 2000 wird eine
Die Laufzeit-Engine von Access
635
SQL-Anweisung genauso optimiert wie eine gespeicherte Abfrage. Deshalb haben Sie die Wahl, ob Sie lieber eine gespeicherte Abfrage oder eine eingebettete SQLAnweisung als Grundlage Ihrer Formulare oder Berichte wählen wollen. Wenn ein Formular dagegen auf Tabellendaten basiert, können Sie weder die Reihenfolge der Datensätze im Formular steuern noch mehr als eine Tabelle zur Grundlage machen. Sie können die im Formular angezeigten Datensätze erst einschränken, nachdem dieses geöffnet ist, es sei denn Sie verwenden die Access-Methode OpenForm mit einem Bedingungsargument. Wenn ein Formular auf einer Abfrage oder einer eingebetteten SQL-Anweisung basiert, können Sie sowohl die Kriterien für das Formular als auch die Standardreihenfolge für die Anzeige der Datensätze steuern. Alles gerade Gesagte gilt auch für Berichte, abgesehen von der Reihenfolge der Datensätze, die durch die Sortierung und Gruppierung des Berichts selbst bestimmt wird. Es stehen Ihnen viele weitere Techniken zur Verfügung, wenn Sie ein Formular anzeigen, das auf einer umfangreichen Datensatzgruppe basiert. Meine Lieblingstechnik besteht darin, als Grundlage für das Formular jeweils nur einen einzigen Datensatz zu nehmen und die Eigenschaft Datenherkunft des Formulars jedesmal zu ändern, wenn der Benutzer einen anderen Datensatz einsehen will. Diese und andere Techniken werden in den Kapiteln 9 und 20 ausführlich behandelt.
16.4
Die Laufzeit-Engine von Access
Viele Benutzer verstehen nicht richtig, was Access von sich aus zu bieten hat und was Microsoft Office Developer (MOD) darüber hinaus bringt. Sie erzählen mir häufig: »Ich kann in Access keine Anwendungen entwickeln, weil sich meine Firma weigert, für jeden Benutzer ein Exemplar von Access zu kaufen.« oder »Ich will mir MOD kaufen, damit ich meine Anwendungen mit den MOD-Werkzeugen kompilieren kann.« Das sind nur zwei der vielen Mißverständnisse hinsichtlich dessen, was die MOD-Werkzeuge genau können und was nicht.
16.4.1
MOD-Funktionen
Sie brauchen kein eigenes Produkt mehr zu kaufen, um Laufzeitversionen Ihrer Access-Anwendungen zu erstellen. Als Entwickler kaufen Sie wahrscheinlich MOD, welches Office Premium und alle Funktionen der alten ODE (Office Developer Environment) sowie viele neue Komponenten enthält. Eine wichtige Funktion von MOD ist eine lizenzgebührenfreie Auslieferungslizenz, welche die Weitergabe einer unbegrenzten Anzahl von Kopien Ihrer Access-Anwendungen erlaubt, ohne dass Ihre Benutzer selbst lizenzierte Kopien von Access besitzen müssen. Das bedeutet, dass Sie mit Hilfe der MOD-Werkzeuge Anwendungen erstellen und an Benutzer weitergeben können, welche diese dann mit der mitgelieferten Laufzeit-Engine betreiben können. Außerdem gehört Folgendes zu den MOD-Werkzeugen:
636
Kapitel 16: Eine Strategie für die Entwicklung von Access-Anwendungen
»The Microsoft Office Object Model Guide« und »The Office Programmer's Guide«; außerdem werden zahlreiche Code-Beispiele auf CD-ROM bereitgestellt.
Ein »Package and Deployment Wizard«, der Ihnen bei der Erstellung von Datenträgern hilft, die komprimierte Dateien mit allem enthalten, was zur Installation und zum Starten der Anwendung gebraucht wird. Dieser Assistent wird in Kapitel 37 behandelt und ist in Abbildung 16.1 zu sehen.
Abbildung 16.1: Der Package and Deployment Wizard, der für die Weitergabe von Anwendungen eingesetzt wird
Eine Menge datengebundener benutzerdefinierter ActiveX-Steuerelemente, die zur Erweiterung der Funktionen Ihrer Anwendung verwendet und als Teil Ihrer MOD-Lizenz an die Benutzer weitergegeben werden dürfen. Dazu gehören die Steuerelemente Enhanced FlexGrid und Data Repeater. Benutzerdefinierte ActiveX-Steuerelemente werden in Kapitel 25 vorgestellt.
Die »Microsoft Data Engine« (MSDE) stellt eine Alternative zur Jet-Engine dar. Sie bietet lokale Datenspeicherung, die mit dem SQL Server kompatibel ist und sich ohne Mühe auf diesen aufrüsten lässt. Sie wird nicht automatisch zusammen mit Microsoft Access installiert. Zu diesem Zweck starten Sie die Datei \Sql\x86\Setup\Setupsql.exe, die sich auf der Office 2000-CD-ROM 1 befindet.
Der »Microsoft Replication Manager« hilft Ihnen bei der Replikation, indem er Ihnen ermöglicht, Aktualisierungen zwischen Replikaten zeitlich zu planen, festzulegen, welche Objekte der Datenbank repliziert werden sollen, die Replikate in einer Replikatgruppe anzuzeigen und mehrere Replikatgruppen zu verwalten. Der Replikations-Manager wird in Kapitel 23 besprochen.
Die Laufzeit-Engine von Access
637
Mit dem »COM Add-in Designer« können Sie eigenständige COM-Add-Ins erstellen und testen. Es handelt sich dabei um DLLs, die von mehreren OfficeAnwendungen genutzt werden können.
Der »Code Librarian« bietet eine zentrale wiederverwendbare Datenbank mit vorgefertigten Standardroutinen, die von Entwicklungsteams gemeinsam genutzt werden kann.
Der »Data Environment Designer« ermöglicht Entwicklern die einfache Verbindung von VBA-Code mit externen Datenquellen. Man kann damit hierarchische Befehlsobjekte für Datensatzgruppen erstellen, ohne Code schreiben zu müssen.
»Visual Source Safe« und »VSS Integration« stellen Versions- und Teamverwaltung für Ihre Access-Anwendungen bereit. Nach der Integration von Visual Source Safe in die Anwendungen können die Teammitglieder u.a. die Anwendung mit und ohne bestimmte Objekte prüfen sowie sich die Unterschiede zwischen Versionen und das Protokoll eines Objekts ansehen.
Der »String Editor« stellt eine WYSIWYG-Schnittstelle dar, mit deren Hilfe sich SQL-Anweisungen schnell und ohne Mühe erstellen lassen. Er erleichtert die Einbettung von SQL-Anweisungen in VBA-Code.
Der »Code Commenter« fügt automatisch Kommentare und Kopfteile in Prozeduren ein. Dazu werden von Benutzern zu definierende Vorlagen verwendet.
Mit dem »Error Handler« können Sie ohne große Mühe eine standardmäßige Fehlerbehandlungsroutine für Ihre Anwendungen erstellen. Sie können mit Hilfe einer benutzerdefinierten Vorlage Code zur Fehlerbehandlung in Ihre Routinen integrieren.
Das Werkzeug »Multi-Code Import/Export« ermöglicht die Übertragung mehrerer Code-Module in und aus einer Anwendung. Das macht die gemeinsame Nutzung von Code-Bibliotheken zum Kinderspiel.
Der »Data Report Designer« stellt eine Drag&Drop-Schnittstelle für die Berichterstellung bereit, die in der gesamten Office-Suite verfügbar ist.
Der »Windows API Viewer« enthält alle Deklarationen, Konstanten und Typstrukturen, die in der Windows-32-Bit-Schnittstelle für die Anwendungsprogrammierung (API) verwendet werden. Die Funktions-, Konstanten- und Typdeklarationen lassen sich damit leicht in Code-Module kopieren.
16.4.2
Unterschiede zwischen der Standard- und der Laufzeitversion von Access
Es ist wichtig, die Unterschiede zwischen der Standard- und der Laufzeitversion von Access zu verstehen. Die folgenden Abweichungen haben deutliche Konsequenzen für die Entwicklung von Anwendungen, die mit der Laufzeitversion ausgeführt werden sollen:
638
Kapitel 16: Eine Strategie für die Entwicklung von Access-Anwendungen
In der Laufzeitumgebung stehen das Datenbank-, das Makro- und das Modulfenster nicht zur Verfügung.
In der Laufzeitumgebung stehen keine Entwurfsansichten zur Verfügung. In der Laufzeitumgebung stehen keine integrierten Symbolleisten zur Verfügung. Viele Fenster, Menüs und Befehle sind in der Laufzeitversion unsichtbar, u.a. die Befehle FENSTER|AUSBLENDEN und FENSTER|EINBLENDEN. Trotzdem sind die Funktionen normalerweise über Code verfügbar.
Sie müssen in Ihre Anwendungen eine Fehlerbehandlung aufnehmen. Falls Sie dies nicht tun, wird bei einem Fehler ein Access-Standarddialogfeld eingeblendet, das auf einen nicht behebbaren Fehler hinweist, und die Anwendung kehrt zum Arbeitsplatz zurück.
Für jede Laufzeitanwendung müssen benutzerdefinierte Hilfedateien erstellt werden.
Einige Tastenbelegungen sind in der Laufzeitversion nicht verfügbar. Die Deaktivierung bestimmter Funktionen schützt Ihre Anwendungen. Das Fehlen des Datenbank- und des Entwurfsfensters bedeutet beispielsweise, dass Ihre Anwendung nicht verändert werden kann, solange sie unter der Laufzeitversion von Access läuft. Andere nicht aktive Funktionen bringen zusätzliche Programmieraufgaben für Sie mit sich, z.B. das Fehlen von Befehlsleisten. Wenn Sie möchten, dass Ihre Anwendung Symbolleisten enthält, müssen Sie diese selbst erstellen und den Formularen und Berichten in Ihrer Datenbank zuweisen.
16.4.3
Vorbereitende Schritte für die Weitergabe einer Anwendung
Angesichts der in der Laufzeitversion von Access fehlenden Funktionen überrascht es nicht, dass Sie einige spezielle Schritte unternehmen müssen, um Ihre Anwendung für die Distribution vorzubereiten. Einige sind spezifisch für den Betrieb unter der Laufzeitversion, aber die meisten werden Sie wahrscheinlich vornehmen wollen, um Ihrer Anwendung ein professionelles Aussehen zu verleihen. Folgendes müssen Sie für die Distribution Ihrer Anwendung mit der Laufzeitversion unternehmen:
die Anwendung auf Formulare aufbauen Startoptionen in die Datenbank einbauen die Objekte in der Anwendung absichern die Fehlerbehandlung in die Anwendung integrieren ein gewisses Maß an benutzerdefinierten Hilfen bereitstellen benutzerdefinierte Befehlsleisten für die Formulare und Berichte der Anwendung erstellen
Die Laufzeit-Engine von Access
639
Die Anwendung auf Formularen aufbauen Ihre Anwendung sollte auf Formularen basieren und durch sie gesteuert werden. Sie sollte grundsätzlich mit einer Hauptübersicht starten, von der aus der Benutzer zu den anderen Komponenten der Anwendung gelangt. Alternativ wäre ein Hauptformular für die Dateneingabe denkbar, um das sich der Rest der Anwendung gruppiert. Wenn Sie sich für eine Anwendungsübersicht entscheiden, kann die Hauptübersicht den Benutzer zu weiteren Übersichten geleiten, z.B. einer Übersicht für die Dateneingabe, für Berichte oder für die Wartung. Übersichten lassen sich mit Hilfe eines Add-Ins mit dem Namen Übersichts-Manager oder in Form benutzerdefinierter Dialogfelder erstellen. Die Konstruktion einer Übersicht als benutzerdefiniertes Dialogfeld wird in Kapitel 9, der Einsatz des Übersichts-Managers in Kapitel 37 gezeigt. Der Hauptvorteil des Übersichts-Managers besteht darin, dass sich schnell und ohne große Mühe eine elegante Anwendungsschnittstelle aufbauen lässt. Der Hauptvorzug benutzerdefinierter Übersichten liegt in der Flexibilität und Freiheit, die sie bieten. Eine Alternative dazu stellt ein Dateneingabeformular als Herzstück der Anwendung dar. Ein Beispiel wäre eine Anwendung zur Verwaltung von Geschäftskontakten, die um das Kontaktformular herumkonstruiert ist. Alle anderen Formulare und Berichte, aus denen die Anwendung besteht, sind dann über dieses zu erreichen. Das geschieht mit Hilfe benutzerdefinierter Menü- und Symbolleisten. Startoptionen in die Datenbank einbauen Unabhängig vom gewählten Ansatz legen Sie ein Formular als Ausgangspunkt für die Anwendung fest, indem Sie die Startoptionen für Ihre Datenbank ändern. Das geschieht mit dem Befehl EXTRAS|START, der das Dialogfeld START einblendet (siehe Abbildung 16.2). Dort können Sie Startoptionen festlegen, wie z.B. ein Startformular, einen Titel für die Anwendung und ein Symbol, das erscheint, wenn Sie die Anwendung minimieren. Diese Optionen werden in Kapitel 37 ausführlich beschrieben.
Abbildung 16.2: Mit Hilfe des Dialogfeldes Start können Sie viele Aspekte der Anwendungsumgebung steuern
Die Anwendung absichern Wie Sie im nächsten Abschnitt erfahren werden, ist eine Datenbank nicht schon deshalb sicher, weil sie unter einer Laufzeitversion von Access läuft. Ohne Absicherung kann die Anwendung von jedem geändert werden, der eine vollständige Access-Ver-
640
Kapitel 16: Eine Strategie für die Entwicklung von Access-Anwendungen
sion besitzt. Daher ist die Absicherung Ihrer Datenbankobjekte ein wichtiger Vorbereitungsschritt für die Auslieferung Ihrer Anwendung. Mit diesem Thema befassen sich die Kapitel 33 und 34. Außer der Absicherung bietet Access 2000 noch die Möglichkeit, den Quellcode aus der Anwendung zu entfernen. Damit schützen Sie Ihr geistiges Eigentum und verbessern die Leistung der Anwendung. Die dabei entstehende Datenbank wird als MDE bezeichnet (siehe Kapitel 37). Fehlerbehandlung in die Anwendung integrieren Wenn Ihre Anwendung keine Fehlerbehandlung besitzt und ein Fehler auftritt, während sie unter der Laufzeitversion von Access läuft, wird der Benutzer brutal aus dem Programm geschubst. Es gibt keine angemessene Fehlermeldung und er fragt sich, was passiert ist. Daher ist der Einbau einer Fehlerbehandlung in die Prozeduren der Anwendung ein wesentliches Erfordernis. Das Thema wird in Kapitel 14 behandelt. Der in »Microsoft Office Developer« (MOD) enthaltene VBA-»Error Handler« kann ebenfalls bei der Integration von Fehlerbehandlung in Ihre Anwendung helfen. Benutzerdefinierte Hilfen bereitstellen In den meisten Fällen wollen Sie den Benutzern wenigstens ein gewisses Maß an benutzerdefinierten Hilfen an die Hand geben, die speziell auf Ihre Anwendung zugeschnitten sind. Mit Hilfe der Texteigenschaft SteuerelementTipp-Text für Steuerelemente und der Eigenschaft Beschreibung für Felder lassen sich einfachste Hilfehinweise einfügen. Mit der Texteigenschaft SteuerelementTipp-Text für Steuerelemente erhält der Benutzer eine Beschreibung des Steuerelements, wenn er mit dem Mauszeiger darüber hinwegfährt. Die Eigenschaft Beschreibung eines Feldes erscheint, wenn vorhanden, in der Statusleiste, wenn ein Steuerelement, das auf diesem Feld basiert, den Fokus besitzt. Wenn Sie mehr wollen und Umfang und Budget der Anwendung es hergeben, können Sie eine benutzerdefinierte Hilfedatei für Ihre Anwendung erstellen. Um benutzerdefinierte Hilfen in die Anwendung einzufügen, müssen Sie diesen Weg wählen und dann Teile davon mit Formularen und Steuerelementen der Anwendung verknüpfen. Der in »Microsoft Office Developer« (MOD) enthaltene »HTML Help Workshop« kann Ihnen beim Einbau benutzerdefinierter Hilfen in Ihre Anwendung helfen. Benutzerdefinierte Befehlsleisten erstellen Da in der Laufzeitversion keine integrierten Symbolleisten zur Verfügung stehen und die meisten Funktionen der Standardmenüs deaktiviert sind, sollten Sie schließlich eigene Befehlsleisten erstellen und mit bestimmten Formularen und Berichten verknüpfen. Damit verleihen Sie Ihrer Anwendung Eleganz und Funktionalität. Wenn Sie mit diesen Schritten fertig sind, können Sie in die Schlussphase der Vorbereitung Ihrer Anwendung für den Vertrieb starten, wozu Folgendes gehört:
Testen der Anwendung mit Hilfe des Schalters /Runtime (siehe Kapitel 37).
Die Laufzeit-Engine von Access
641
Erstellen von Einrichtungsdisketten oder Durchführen einer Netzwerkinstallation mit dem »Package and Deployment Wizard«.
Installieren der Anwendung auf einem Rechner, auf dem noch keine Standardoder Laufzeitversion von Access gelaufen ist.
Testen der Anwendung auf diesem Rechner. Achten Sie darauf, dass sie wie erwartet ausgeführt wird. Bevor Sie sich mit der Ausführung des »Package and Deployment Wizard« abmühen (einem etwas längeren Prozess), sollten Sie die Anwendung zunächst mit dem Schalter /Runtime starten. Dieser simuliert die Laufzeitumgebung und erlaubt Ihnen, Benutzeraktionen unter der Laufzeitversion von Access zu simulieren. Dieser Schritt erspart Ihnen viel Zeit und Energie. Sie entdecken die meisten, wenn nicht sogar alle Probleme, die den Betrieb unter der Laufzeitversion betreffen. Nach dem Test mit dem Schalter /Runtime können Sie den »Package and Deployment Wizard« starten (siehe Kapitel 37), mit dessen Hilfe Sie Einrichtungsdisketten erstellen oder eine Netzwerkinstallation durchführen können. Wenn Ihre Benutzer bereit sind, die Anwendung zu installieren, starten sie das Installationsprogramm mit Access:Setup (bzw. dem entsprechenden Netzlaufwerk und Pfad) und gelangen in ein professionell aussehendes, vertrautes Einrichtungsprogramm, das denen der meisten Microsoft-Produkte ähnelt. Nach dem Ausführen des »Package and Deployment Wizard« müssen Sie Ihre Anwendung durch Installation auf einem Rechner testen, auf dem sich noch keine Standard- oder Laufzeitversion von Access befunden hat. Ich schlage vor, alle Dateien im Windows-Systemverzeichnis des Testrechners mit einem Komprimierungsprogramm wie WinZip zu komprimieren oder eine Sicherungskopie des gesamten Windows-Verzeichnisses in einem anderen Verzeichnis anzulegen. Installieren Sie Ihre Anwendung und führen Sie einen vollständigen Test durch. Denken Sie daran, sämtliche Funktionen auszuprobieren. Löschen Sie, wenn Sie fertig sind, alles außer der komprimierten Datei. Entpacken Sie diese dann in das Windows-Systemverzeichnis (damit alle Dateien wieder vorhanden sind, die vor der Installation Ihrer Anwendung vorhanden waren). Hinter diesem Ansatz steckt ganz einfach das Bestreben, die Anwendung auf einem Rechner zu testen, der keine auf Access bezogenen Dateien enthält. Damit wird gewährleistet, dass Ihre Einrichtungsdisketten alle erforderlichen Dateien enthalten. Nach dem Testen versetzen Sie den Rechner wieder in den ursprünglichen Zustand, damit Sie ihn zum Testen der nächsten Anwendung einsetzen können. Dieses Vorgehen bereinigt zwar viel von dem, was infolge der Installation der Anwendung verändert wurde, aber der Originalzustand des Rechners wird nicht vollständig wiederhergestellt. Das liegt daran, dass die Registry während der Installation verändert wird. Wenn Sie eine vollständige Wiederherstellung des
642
Kapitel 16: Eine Strategie für die Entwicklung von Access-Anwendungen
ursprünglichen Zustandes wünschen, müssen Sie vor der Installation eine Kopie der Registry anlegen und auch diese nach dem Test wiederherstellen.
Sie können das Windows-Komprimierungsprogramm WinZip unter der Adresse http://www.winzip.com herunterladen.
16.4.4
Die Laufzeit-Engine von Access – alles in allem
Sie haben gerade einen Überblick über die Unterschiede zwischen der Vollversion und der Laufzeitversion von Access gelesen. Die Vorbereitung einer Anwendung für die Weitergabe mit der Laufzeitversion von Access wird in Kapitel 37 ausführlich beschrieben. Wenn Sie vorhaben, eine Anwendung mit der Laufzeitversion von Access zu vertreiben, sollten Sie daran denken, welche Funktionen Ihren Benutzern zur Verfügung stehen; andernfalls erleben Sie und die Benutzer einige Überraschungen.
16.5
Eine ausführbare Datei und eine Access-Datenbank im Vergleich
Viele Entwickler meinen zu Unrecht, dass die Verteilung einer Anwendung mit der Laufzeitversion von Access dasselbe sei wie die Weitergabe einer ausführbaren Datei. Eine mit der Laufzeitversion von Access verbreitete Datenbank ohne Absicherung lässt sich aber wie jede andere Datenbank verändern. Die Anwendung kann mit Hilfe der Laufzeitversion von Access gestartet werden und es gelten alle Regeln für den Betrieb einer Anwendung unter der Laufzeitversion. Das heißt, dass die Benutzer nicht in die Entwurfsansicht gelangen, keine eigenen Objekte erstellen können, keinen Zugriff auf integrierte Symbolleisten haben usw. Dieselben Benutzer können eigene Kopien der Standardversion von Access installieren und mit deren Hilfe dann dieselbe Datenbank öffnen. Wenn die Objekte in der Datenbank nicht abgesichert wurden, können sie die Anwendung beliebig verändern. Kurz gesagt: Eine mit dem »Package and Deployment Wizard« vorbereitete Datenbank unterscheidet sich in nichts von irgendeiner anderen Datenbank. Der »Package and Deployment Wizard« verändert die MDB-Datei in keiner Weise. Er komprimiert einfach alle für den Betrieb der Anwendung erforderlichen Dateien, darunter die Datenbank und die Laufzeit-Engine, und erstellt einen Ordner für die Netzwerkinstallation bzw. Vertriebsdatenträger mit den komprimierten Dateien. Zwei Methoden, den Entwurf Ihrer Anwendung zu schützen, sind die Einrichtung der Absicherung und die Verteilung als MDE-Datei.
Die Bedeutung der Absicherung der Datenbank
16.6
643
Die Bedeutung der Absicherung der Datenbank
Bis zu diesem Zeitpunkt sollten Sie die Bedeutung der Absicherung Ihrer Anwendung verstanden haben. Die Einrichtung von Sicherheit ist ein komplexer, aber lohnender Prozess, der entweder auf Gruppen- oder auf Benutzerebene stattfinden kann. Sie können Objekten Rechte zuweisen und diese Rechte können entweder einzelnen Benutzern oder einer Benutzergruppe gewährt werden. Abbildung 16.3 zeigt das Dialogfeld BENUTZER- UND GRUPPENBERECHTIGUNGEN. Wie Sie sehen können, lassen sich Rechte für jedes einzelne Objekt zuweisen. Für eine Tabelle kann der Benutzer oder die Gruppe Rechte zum Lesen, Einfügen, Aktualisieren und Löschen von Daten sowie zum Lesen, Ändern oder Verwalten des Tabellenentwurfs bekommen. Eine Gruppe kann beispielsweise das Recht des Hinzufügens, Bearbeitens und Löschens von Daten erhalten, eine andere nur das Recht zum Bearbeiten, eine weitere nur das Recht zum Einsehen und noch einer weiteren kann selbst dieses Recht verwehrt werden.
Abbildung 16.3: Mit Hilfe des Dialogfeldes Benutzerund Gruppenberechtigungen können Sie Benutzer- und Gruppenrechte für jedes Datenbankobjekt festlegen
Die verfügbaren Rechte sind für Tabellen, Abfragen, Formulare, Berichte, Makros und Module unterschiedlich. Die Berechtigungstypen hängen vom jeweiligen Objekttyp ab. Wenn die Absicherung korrekt aktiviert wurde, ist sie unverletzlich, unabhängig davon, wie jemand versucht, auf die Datenbankobjekte zuzugreifen (einschließlich der Verwendung der Laufzeit- oder Standardversion von Access, von Programm-Code oder sogar einer Visual Basic-Anwendung). Wenn die Datenbank korrekt abgesichert wurde, ist der illegale Zugriff genauso schwierig wie bei einer ausführbaren Datei.
644
16.7
Kapitel 16: Eine Strategie für die Entwicklung von Access-Anwendungen
Access als Front-End
Wenn Sie vorhaben, Access als Front-End zu anderen Datenbanken einzusetzen, müssen Sie einige Dinge beachten. Der gesamte Entwurf Ihres Systems variiert in Abhängigkeit davon, ob die Daten in einer Access-Datenbank oder auf einem BackEnd-Datenbank-Server gespeichert werden sollen. In einem System, in dem die Daten ausschließlich in Access-Tabellen abgelegt werden, stellt die Jet-Engine von Access alle Funktionen für die Suche und Verwaltung der Daten bereit. Sie ist auch für die Sicherheit, die Gültigkeitsprüfung der Daten und das Erzwingen referentieller Integrität zuständig. In einem System, in dem Access als Front-End für Client-Server-Daten fungiert, erledigt der Server die Datenverwaltung. Er ist für das Auffinden, Schützen und Aktualisieren der Daten auf dem Back-End-Datenbank-Server verantwortlich. Wenn Access als Front-End dient, ist die lokale Access-Kopie nur für das Senden von Anforderungen und den Empfang von Daten oder Zeigern auf Daten vom Datenbank-Server zuständig. Wenn Sie eine Anwendung schreiben, in der Access als Front-End fungiert, kann die Nutzung der Stärken sowohl von Access als auch des Servers eine anspruchsvolle Arbeit sein.
16.7.1
Dinge, die Sie bei der Umstellung auf eine Client-ServerUmgebung bedenken müssen
Der Übergang auf eine Client-Server-Umgebung verläuft nicht immer glatt. Sie müssen mehrere Faktoren berücksichtigen, wenn Sie eine Client-Server-Anwendung entwickeln oder vorhaben, Ihre Anwendung später von einer Access-Datenbank auf einen Back-End-Datenbank-Server mit SQL (Structured Query Language) umzustellen:
Nicht alle von Access unterstützten Feldtypen werden von jeder Back-EndDatenbank unterstützt.
Die gesamte in Access eingerichtete Sicherheit wird nicht in die Back-EndDatenbank übertragen.
In Access eingerichtete Regeln für die Gültigkeitsprüfung müssen auf dem BackEnd erneut eingerichtet werden.
Nicht alle Back-Ends unterstützen referentielle Integrität. Wenn es bei Ihnen der Fall ist, wird sie trotzdem von Access nicht automatisch übertragen.
Abfragen mit Verknüpfungen, die in Access aktualisiert werden können, lassen sich auf dem Back-End-Server nicht aktualisieren. Diese Liste enthält nur einen Überblick darüber, was Sie bedenken müssen, wenn Sie eine Anwendung von einer Access-Datenbank mit verknüpften Tabellen auf einen Back-End-Server umstellen oder eine spezielle Anwendung für ein Back-End
Access als Front-End
645
entwickeln wollen. Viele dieser Fragen besitzen weitreichende Implikationen. Wenn Sie beispielsweise Regeln für die Gültigkeitsprüfung aufstellen und Gültigkeitsmeldungen einfügen, müssen die Regeln für das Back-End in Trigger umgewandelt werden, aber das ist nicht das einzige Problem. Wenn auf dem Back-End eine Gültigkeitsregel verletzt wird, bekommen Sie einen Fehler-Code, der sich zurückgeben lässt. Diesen müssen Sie in Ihrer Anwendung mit Hilfe der Fehlerbehandlung verarbeiten und dem Benutzer die entsprechende Meldung anzeigen. Die Eigenschaft Gültigkeitsmeldung steht dafür nicht zur Verfügung. Einige der in diesem Kapitel behandelten Probleme kann der Upsizing-Assistent erledigen. Dieses zu Access gehörende Werkzeug automatisiert die Datenmigration aus dem nativen Access-Format in Microsoft SQL-Server. Es wird in Kapitel 19 behandelt.
16.7.2
Kosten und Nutzen der Client-Server-Technologie
Angesichts all der im vorigen Abschnitt behandelten Probleme fragen Sie vielleicht: »Warum soll ich mich mit einer Client-Server-Umgebung abmühen?« Die ClientServer-Technologie bietet wichtige Vorteile, erfordert aber in Bezug auf Zeit und Geld erheblichen Aufwand, wenn sie korrekt eingesetzt werden soll. Sie müssen in jedem Fall prüfen, ob der Nutzen der Technologie die Kosten aufwiegt. Zu den wesentlichen Vorteilen zählen folgende:
Bessere Kontrolle der Datenintegrität Bessere Kontrolle der Datensicherheit Höhere Fehlertoleranz Geringerer Verkehr im Netzwerk Höhere Leistung Zentrale Steuerung und Verwaltung der Daten Einige wesentliche Nachteile sind:
Höhere Entwicklungskosten Hardware-Kosten für den Server Einrichtungskosten für die Server-Datenbank Kosten für den Datenbankadministrator (Voll- oder Teilzeit) Diese Listen zeigen im Wesentlichen Kosten und Nutzen der Client-Server-Technologie auf. Sie sind lediglich als Warnung dafür gedacht, was Sie bei der Prüfung der Verlagerung Ihrer Daten auf einen Back-End-Datenbank-Server bedenken müssen. Diese und andere Fragen werden in Kapitel 19 ausführlicher behandelt.
646
16.7.3
Kapitel 16: Eine Strategie für die Entwicklung von Access-Anwendungen
Optionen beim Einsatz von Access als Front-End
Die Client-Server-Technologie ist keine Sache von Alles oder Nichts. Es gibt auch nicht nur eine Methode, sie mit Hilfe von Access als Front-End zu implementieren. Eine Möglichkeit besteht darin, Access als echtes Front-End zu nutzen, was bedeutet, dass alle Daten auf dem Server abgelegt und alle Abfragen auf diesem ausgeführt werden. Dazu werden Pass-Through-Abfragen anstelle gespeicherter Access-Abfragen verwendet. Mit deren Hilfe (siehe Kapitel 20) wird eine spezielle SQL-Anweisung für Back-Ends an das Back-End weitergeleitet anstatt von Access verarbeitet zu werden. Um Access zum echten Front-End zu machen, müssen Sie außerdem die natürliche Fähigkeit des Programms deaktivieren, Daten zu Formularen und Berichten zusammenzufügen. Nachdem Sie dies alles erledigt haben, haben Sie aber alle Funktionen beseitigt, durch die Access wesentlich zum leistungsfähigen Produkt wird. Leider haben Sie nicht den gesamten Zusatzaufwand beseitigt, der mit den gelöschten Funktionen verknüpft ist. Wollen Sie diesen Ansatz wählen, kommen Sie besser weg, wenn Sie die gesamte Anwendung in einer Umgebung mit geringerem Aufwand entwickeln, z.B. in Visual Basic. Ein weiterer Ansatz besteht in einer Mischmethode, bei der Sie eine Kombination aus verknüpften Tabellen, SQL-Pass-Through-Abfragen und lokalen Access-Tabellen verwenden. Die Vorstellung dabei ist, soweit wie möglich die Funktionen und Stärken von Access zu nutzen. Pass-Through-Abfragen werden eingesetzt, um Funktionen auszuführen, die durch direkte Kommunikation mit dem Back-End effizienter erledigt werden oder die in Access SQL gar nicht vorhanden sind. Um die Leistung weiter zu erhöhen, können viele Aufgaben lokal vollzogen und dann in einer einzigen Transaktion an den Server übertragen werden, nachdem die anfängliche Gültigkeitsprüfung stattgefunden hat. Ein neuer Dateityp mit der Bezeichnung »Projektdatei« erlaubt die Kommunikation mit der Back-End-Datenbank, ohne die Jet-Engine zu laden. Mit Access-Projekten, die häufig als ADP-Dateien bezeichnet werden, lassen sich sowohl die Leistung als auch die Funktionalität einer Client-Server-Anwendung steigern. ADP-Dateien werden in Kapitel 19 ausführlich dargestellt. Außer den gerade besprochenen Lösungen lassen sich Daten auch in größeren Mengen in Access herunterladen, so dass die zusätzliche Verarbeitung lokal stattfindet. Es gibt viele Möglichkeiten und jede ist für eine andere Situation geeignet. Es erfordert Erfahrung und Experimente, um diejenige Methodenkombination zu ermitteln, durch welche die Leistung in einer bestimmten Situation optimiert wird.
16.7.4
Welche Überlegungen sind für die Umstellung auf eine ClientServer-Umgebung von Bedeutung?
Die vorhergehenden Abschnitte haben Ihnen einen Überblick über die Probleme vermittelt, die Sie beim Schreiben einer Anwendung für eine Client-Server-Umgebung oder bei der Überlegung bedenken müssen, ob später auf eine Client-ServerUmgebung umgestellt werden soll. Detailliertere Informationen bekommen Sie in den Kapiteln 19 und 20. Die Fragen bei der Entwicklung von Client-Server-Anwen-
Access als Front-End
647
dungen werden aber schon hier beleuchtet, um das Risiko unerwarteten Ärgers zu einem späteren Zeitpunkt zu verringern. Wenn Sie dieses Buch lesen und dabei die Probleme im Gedächtnis behalten, werden Sie bei der Entwicklung glücklicher sein. Denken Sie beim Lesen des Buchs (insbesondere bei den späteren Kapiteln) daran, wenn Sie Access als Front-End einsetzen, besonders die Warnungen in Bezug auf die Entwicklung von Client-Server-Anwendungen zu beachten.
16.7.5
Für die Praxis
Anwendung dieser Strategie auf das Zeit- und Abrechnungssystem für das ConsultingUnternehmen Wenn das in Kapitel 1 vorgestellte Zeit- und Abrechnungssystem für das Consulting-Unternehmen fertig ist, besteht es aus zwei Datenbanken: einer, welche die meisten Tabellen enthält, und einer anderen, in der sich die übrigen Datenbankobjekte einschließlich der statischen und temporären Tabellen befinden. Die Anwendung wird mit der Vorstellung entwickelt, dass die Daten später vielleicht auf einen Back-End-Datenbank-Server übertragen und so gestaltet werden, dass diese Übertragung möglichst glatt vonstatten geht. Die Formulare und Berichte, aus denen die Anwendung besteht, basieren auf gespeicherten Abfragen oder eingebetteten SQLAnweisungen, um möglichst hohe Flexibilität und Effizienz zu erzielen. Schließlich wird die Anwendung so gestaltet, dass sie sich mühelos unter der Laufzeitversion von Access betreiben lässt, und so abgesichert, dass die Daten und die anderen Objekte nicht autorisierten Benutzern nicht zugänglich sind. Beim Durchlesen des Buchs werden diese Entwurfsstrategien in den einzelnen Kapiteln weiter ausgeführt.
Mehrbenutzeranwendungen entwickeln
Kapitel
Hier lesen Sie:
Anwendungsentwicklung unter Berücksichtigung der Probleme bei mehreren Benutzern
Strategien zum Sperren und Aktualisieren Sperrstrategien für Formulare Datensatzgruppen sperren Sperrkonflikte effizient erledigen Einen Datensatz auf seinen Sperrstatus prüfen Code zum Aktualisieren und erneuten Abfragen Die Benutzerliste Benutzerdefinierte Zähler erstellen Ungebundene Formulare Höhere Leistung durch Replikation
17.1
Anwendungsentwicklung unter Berücksichtigung der Ansprüche mehrerer Benutzer
Bei der Entwicklung von Anwendungen, auf die mehrere Benutzer über ein Netzwerk zugreifen, müssen Sie sicherstellen, dass die gemeinsame Nutzung von Daten und anderen Anwendungsobjekten effizient gehandhabt wird. Entwickler haben bei der Gestaltung von Mehrplatzanwendungen viele Möglichkeiten und dieses Kapitel behandelt deren Vor- und Nachteile.
650
Kapitel 17: Mehrbenutzeranwendungen entwickeln
Die Probleme bei mehreren Benutzern drehen sich rund um das Sperren von Daten. Dazu gehört die Entscheidung, wo die Datenbankobjekte gespeichert und wann und wie viele Daten gesperrt werden sollen. In einer Umgebung mit mehreren Benutzern kann es Konflikte verursachen, wenn mehrere Benutzer gleichzeitig versuchen, dieselben Daten zu ändern. Als Entwickler müssen Sie diese Konflikte regeln, sonst erleben die Benutzer unerklärliche Fehler.
17.1.1
Entwurfsstrategien für Mehrbenutzeranwendungen
Es gibt mehrere Möglichkeiten, den gleichzeitigen Zugriff mehrerer Benutzer auf Daten und andere Objekte der Anwendung zu regeln; jede bietet sowohl Lösungen als auch Grenzen. Die Auswahl der für die jeweilige Umgebung besten Lösung ist wichtig. Strategien für die Installation von Access Für die Installation von Access gibt es zwei Strategien:
Betrieb von Access auf einem Datei-Server über das Netzwerk Betrieb einer eigenen Access-Kopie auf jeder Arbeitsstation Beide Strategien haben Vor- und Nachteile. Der Betrieb von Access auf einem DateiServer bietet folgende Vorteile:
Er erlaubt die zentrale Verwaltung des Programms. Er reduziert möglicherweise die Lizenzerfordernisse. Das gilt deshalb, weil die Lizenzanforderungen bei Installation auf einem Datei-Server von gleichzeitigen Benutzern ausgehen. Wenn Access lokal installiert wird, muss jeder Benutzer eine eigene Lizenz haben, selbst wenn er nur selten Access-Anwendungen nutzt. Wenn nicht alle Benutzer gleichzeitig mit Access-Anwendungen arbeiten, kann es in Bezug auf die Kosten effizienter sein, eine LAN-Lizenz zu erwerben und Access auf dem Datei-Server zu installieren.
Er reduziert die Anforderungen an die Festplatte. Die Access-Software belegt ziemlich viel Platz auf der Festplatte. Obwohl sich der Platzbedarf durch die Verwendung der Laufzeitversion reduzieren lässt, kann der Platz auf den lokalen Festplatten zum erheblichen Problem werden. Die Installation auf dem DateiServer beseitigt dieses Problem jedenfalls teilweise. Es kann vollständig behoben werden, wenn auch die DLLs auf dem Datei-Server installiert werden.
Access-Anwendungen lassen sich auf Arbeitsstationen ohne Festplatte installieren. Auch wenn die Vorteile der Installation von Access auf einem Datei-Server zwingend erscheinen mögen, hat sie auch ernsthafte Nachteile, wie beispielsweise folgende:
Bei jedem Start einer Access-Anwendung durch einen Benutzer werden alle EXEDateien, die DLLs und die übrigen zum Betrieb von Access erforderlichen
Anwendungsentwicklung für mehrere Benutzer
651
Dateien über das Netzwerk an den lokalen Rechner gesendet. Das erzeugt natürlich Netzwerkverkehr in beträchtlicher Menge.
Die Leistung sinkt allgemein auf ein nicht akzeptables Niveau. Da die Nachteile des Betriebs von Access auf einem Datei-Server so deutlich sind, empfehle ich dringend, Access oder wenigstens die Laufzeit-Engine auf den Rechnern der einzelnen Benutzer zu installieren.
17.1.2
Strategien für die Installation Ihrer Anwendung
Genauso wie es für die Installation von Access verschiedene Strategien gibt, gilt dies auch für Ihre Anwendung. Es bestehen folgende Möglichkeiten:
Installation der Anwendung und der Daten auf einem Datei-Server Installation der Daten auf einem Datei-Server und der Anwendung auf allen Arbeitsstationen Anders gesagt: Nachdem Sie eine Anwendung geschrieben haben, können Sie diese als Ganzes im Netzwerk unterbringen. Das bedeutet, dass alle Tabellen, Abfragen, Formulare, Berichte, Makros und Module, aus denen das System besteht, auf dem Datei-Server liegen. Bei dieser Methode des gemeinsamen Zugriffs bleibt zwar alles zusammen, aber Sie werden feststellen, dass es viele Vorteile hat, nur die Datentabellen der Datenbank auf dem Datei-Server abzulegen. Die übrigen Objekte werden in einer Datenbank auf den Rechnern der einzelnen Benutzer untergebracht und jede lokale Anwendungsdatenbank wird mit den Tabellen im Netzwerk verknüpft. Auf diese Weise nutzen die Benutzer zwar die Daten gemeinsam, nicht aber die übrigen Anwendungsobjekte. Die Vorteile der Installation einer Datenbank mit Datentabellen auf dem Datei-Server und der lokalen Installation einer anderen Datenbank mit den übrigen Anwendungsobjekten sehen folgendermaßen aus:
Da jeder Benutzer eine Kopie der lokalen Datenbankobjekte (Abfragen, Formulare, Berichte, Makros und Module) besitzt, werden Ladezeit und Verkehr im Netzwerk reduziert.
Sicherungskopien der Daten lassen sich sehr einfach anlegen; die übrigen Anwendungsobjekte brauchen dabei nicht gesichert zu werden.
Bei der Verteilung neuer Versionen der Anwendung brauchen Sie keine Angst zu haben, dass die Anwendungsdaten überschrieben werden.
Mehrere Anwendungen lassen sich so gestalten, dass alle die zentral abgelegten Daten nutzen können.
Benutzer können eigene Objekte (z.B. eigene Abfragen) in die lokalen Exemplare der Datenbank einfügen.
652
Kapitel 17: Mehrbenutzeranwendungen entwickeln
Ich empfehle außer der Speicherung von Abfragen, Formularen, Berichten, Makros und Modulen, aus denen die Anwendung besteht, in einer lokalen Datenbank auch folgende Objekte abzulegen:
temporäre Tabellen statische Tabellen semistatische Tabellen Temporäre Tabellen sollten aus folgendem Grund in der Datenbank gespeichert werden, die sich auf der einzelnen Arbeitsstation befindet: Wenn zwei Benutzer Operationen vornehmen, die dieselben temporären Tabellen erstellen, soll der Prozess des einen Benutzers den des anderen nicht stören. Der potentielle Konflikt, dass die temporären Tabellen des einen Benutzers die des anderen überschreiben, lässt sich beseitigen, indem alle temporären Tabellen in den lokalen Kopien der Datenbank gespeichert werden. Auch statische Nachschlagetabellen, z.B. Tabellen der Bundesstaaten, sollten auf den einzelnen Arbeitsstationen gespeichert werden. Da sich die Daten nicht ändern, stellt die Wartung kein Problem dar. Der Vorteil besteht darin, dass Access die Daten nicht über das Netzwerk transportieren muss, wenn sie benötigt werden. Semistatische Tabellen – solche, die selten aktualisiert werden – lassen sich ebenfalls auf dem lokalen Rechner unterbringen. Wie bei statischen Tabellen besteht auch hier der wesentliche Vorteil darin, dass weniger Netzwerkverkehr höhere Leistung bedeutet und zwar nicht nur für denjenigen, der die Daten braucht, sondern auch für jeden, der dieselbe Leitung benutzt. Änderungen an semistatischen Tabellen lassen sich mittels Replikation an jede Arbeitsstation weitergeben (siehe Kapitel 23). Die in diesem ganzen Abschnitt beschriebene Konfiguration sehen Sie in Abbildung 17.1.
17.1.3
Grundlagen der Verknüpfung mit externen Daten
Die Verknüpfung mit externen Daten einschließlich solcher, die nicht in einer weiteren Access-Datenbank gespeichert sind, wird in Kapitel 18 ausführlich dargestellt. Sie haben drei Möglichkeiten:
die Datenbanken von vornherein separat zu entwerfen alle Objekte in einer Datenbank zusammenzufassen und sie manuell aufzuteilen, wenn Sie bereit sind, Ihre Anwendung zu verteilen
alle Objekte in einer Datenbank zusammenzufassen und sie dann mit Hilfe des Assistenten zur Datenbankaufteilung aufzuteilen
Anwendungsentwicklung für mehrere Benutzer
Arbeitsstation 1
Arbeitsstation 2
Formulare
Formulare
Berichte
Berichte
Makros
Makros
Module Abfragen Statische Tabellen Temp. Tabellen
Server Gemeinsame Tabellen System.mdt
Module Abfragen Statische Tabellen Temp. Tabellen
653
Abbildung 17.1: Ein Beispiel für eine Konfiguration mit Aufteilung von Datenbankobjekten: Lokale Speicherung temporärer und statischer Tabellen sowie Speicherung gemeinsam genutzter Tabellen auf dem Datei-Server
Die beiden ersten Möglichkeiten werden in Kapitel 18 behandelt. Die dritte, der Assistent für die Datenbankaufteilung, kommt hier zur Sprache. Um die Objekte in einer Datenbank auf zwei getrennte .MDB-Dateien zu verteilen, unternehmen Sie Folgendes: 1. Öffnen Sie die Datenbank, deren Objekte Sie aufteilen wollen. 2. Wählen Sie EXTRAS|DATENBANK-DIENSTPROGRAMME|ASSISTENT ZUR DATENBANKAUFTEILUNG, um das Dialogfeld ASSISTENT ZUR DATENBANKAUFTEILUNG einzublenden, das Sie in Abbildung 17.2 sehen.
Abbildung 17.2: Mit Hilfe des Assistenten zur Datenbankaufteilung können Sie die Datentabellen herauslösen, die auf dem Server untergebracht werden sollen
654
Kapitel 17: Mehrbenutzeranwendungen entwickeln
3. Klicken Sie auf DATENBANK AUFTEILEN. Damit öffnen Sie das Dialogfeld BACKEND-DATENBANK ERSTELLEN (siehe Abbildung 17.3). 4. Geben Sie einen Namen für die Datenbank ein, welche alle Tabellen enthalten soll. Klicken Sie auf AUFTEILEN. Der Assistent zur Datenbankaufteilung erstellt eine neue Datenbank, die alle Tabellen enthält, und es werden Verknüpfungen zwischen der aktuellen und der gerade erstellten Datenbank angelegt (siehe Abbildung 17.4).
Abbildung 17.3: Eingabe eines Namens für die neue, gemeinsam genutzte Datenbank
Abbildung 17.4: Die Datenbank, die aufgeteilt wurde
Die Sperrmechanismen von Access
655
Denken Sie daran, dass Sie bei der Verteilung einer Anwendung, die verknüpfte Tabellen verwendet, mit Hilfe von Code sicherstellen müssen, dass alle Anwendungsdatenbanken im Netzwerk diese Datentabellen finden können. Wenn jeder Benutzer denselben Pfad zum Datei-Server hat, ist das nicht problematisch. Wenn der Pfad zum Datei-Server jedoch unterschiedlich ist, müssen Sie eine Routine schreiben, die dafür sorgt, dass die Dateien gefunden werden. Falls das nicht klappt, fragt die Routine den Benutzer nach dem Speicherort der Daten (siehe Kapitel 18).
17.2
Die Sperrmechanismen von Access
Die genannten Tipps für die Gestaltung von Anwendungen für Netzwerke reduzieren zwar den Verkehr im Netzwerk, aber keineswegs Sperrkonflikte. Um gemeinsam genutzte Daten zu schützen, sperrt Access entweder einen Datensatz oder eine Datenseite, während ein Benutzer einen Datensatz bearbeitet. Auf diese Weise können die Daten von mehreren Benutzern gelesen werden, aber nur ein Benutzer kann Änderungen vornehmen. Daten können über ein Formular oder über eine Datensatzgruppe gesperrt werden, die nicht an ein Formular gebunden ist. Für eine Access-Anwendung gibt es folgende Sperrmethoden:
Sperren eines Datensatzes Sperren einer Seite Sperren einer Tabelle und einer Datensatzgruppe Öffnen einer ganzen Datenbank mit exklusivem Zugriff Beim Sperren eines Datensatzes wird nur der Datensatz gesperrt, den der Benutzer gerade bearbeitet. Beim Sperren einer Seite wird die 4-KB-Seite gesperrt, auf welcher der gerade bearbeitete Datensatz zu finden ist. Beim Sperren einer Tabelle oder einer Datensatzgruppe wird die ganze Tabelle oder Datensatzgruppe gesperrt, in welcher der gerade bearbeitete Datensatz steht. Beim Sperren einer Datenbank wird die gesamte Datenbank gesperrt, es sei denn, der Benutzer, der sie geöffnet hat, will nur Lesezugriffe vornehmen. In diesem Fall kann sie auch von anderen Benutzern für Lesezugriffe geöffnet werden. Die Möglichkeit, eine Datenbank exklusiv zu nutzen, kann durch Sicherheitsmaßnahmen eingeschränkt werden. Es muss darauf hingewiesen werden, dass das angewandte Sperrsystem von der Quelle der Daten abhängig ist. Wenn Sie Client-Server-Daten verwenden, erben Sie das Sperrsystem des verwendeten Back-Ends. Wenn Sie ISAM-Daten über ein Netzwerk bearbeiten, stehen Ihnen alle Datensatzsperren zur Verfügung, welche die konkrete ISAM-Datenbank unterstützt. Wenn Sie beispielsweise mit einer FoxProDatenbank arbeiten, können Sie Datensatzsperren oder alle anderen Sperrsysteme benutzen, die FoxPro unterstützt.
656
17.3
Kapitel 17: Mehrbenutzeranwendungen entwickeln
Strategien zum Sperren und Aktualisieren
Access verfügt über mehrere Werkzeuge, um die Sperrmethoden für Datenblätter, Formulare und Berichte zu steuern. Um die globalen Einstellungen für mehrere Benutzer zu konfigurieren, wählen Sie EXTRAS|OPTIONEN und klicken dann auf die Registerkarte WEITERE. Dann wird das Dialogfeld eingeblendet, das Sie in Abbildung 17.5 sehen.
Abbildung 17.5: Das Dialogfeld Optionen
Folgende Mehrbenutzereinstellungen lassen sich dort konfigurieren:
Standard bei Datensatzsperrung Sperren auf Datensatzebene Standardöffnungsmodus Anzahl der Datenaktualisierungsversuche Intervall für ODBC-Anzeigeaktualisierung Intervall für Anzeigeaktualisierung Intervall für Datenaktualisierung
Strategien zum Sperren und Aktualisieren
17.3.1
657
Standard bei Datensatzsperrung
Mit der Option STANDARD BEI DATENSATZSPERRUNG können Sie als Standardeinstellung KEINE SPERRUNGEN (optimistisch), ALLE DATENSÄTZE (sperrt die gesamte Tabelle oder das Dynaset) oder BEARBEITETE DATENSÄTZE (pessimistisch) festlegen. Dieses Dialogfeld wirkt sich auf alle Objekte in Ihrer Datenbank aus. Die Änderung dieser Option berührt zwar bestehende Abfragen, Formulare und Berichte nicht, wohl aber neue Abfragen, Formulare und Berichte. Die Optionen für das Sperren von Datensätzen werden später behandelt, weil sie für Formulare und Datensatzgruppen gelten. Den Sperrmechanismus für eine Abfrage festlegen Wenn Sie die Sperrmethode für eine bestimmte Abfrage festlegen wollen, können Sie dazu die Abfrage-Eigenschaft Datensätze sperren ändern. Die Optionen lauten wiederum Keine Sperrungen, Alle Datensätze und Bearbeiteter Datensatz. Die AbfrageEigenschaften lassen sich über einen Klick bei geöffnetem Eigenschaftsfenster in einen leeren Bereich im Abfrage-Entwurfsfenster einsehen und ändern. Das Fenster ABFRAGEEIGENSCHAFTEN sehen Sie in Abbildung 17.6.
Abbildung 17.6: Die Sperrmethode für eine Abfrage festlegen
Den Sperrmechanismus für ein Formular oder einen Bericht festlegen Wie für eine Abfrage lässt sich auch der Sperrmechanismus für ein Formular oder einen Bericht festlegen. Formulare und Berichte verfügen ebenfalls über Eigenschaften zum Sperren von Datensätzen (siehe Abbildung 17.7). Die Änderung dieser Eigenschaften ändert den Sperrmechanismus für das jeweilige Formular oder den Bericht.
658
Kapitel 17: Mehrbenutzeranwendungen entwickeln
Abbildung 17.7: Festlegen der Sperrmethode für ein Formular
Berichte enthalten keine Wahlmöglichkeiten für das Sperren, weil sich Berichtdaten nicht ändern lassen.
17.3.2
Sperren auf Datensatzebene
Unabhängig von der gewählten Standardsperrmethode für Datensätze ermöglicht das Kontrollkästchen DB MIT SPERRUNG AUF DATENSATZEBENE ÖFFNEN die Entscheidung, ob nur ein Datensatz oder eine ganze Datenseite gesperrt werden soll. Wenn Sie beispielsweise KEINE SPERRUNGEN wählen, wird die optimistische Sperrmethode verwendet, aber das Sperren findet auf Datensatzebene statt und nicht auf Seitenebene.
17.3.3
Standardöffnungsmodus
Mit der Option STANDARDÖFFNUNGSMODUS können Sie den standardmäßigen Öffnungsmodus für Datenbanken bestimmen. Indem Sie die Benutzer ermutigen, diese Option in ihrer Access-Kopie festzulegen, verhindern Sie, dass eine Datenbank versehentlich exklusiv geöffnet wird. Schauen Sie sich die Optionen, die im Access-Dialogfeld DATEI ÖFFNEN unter der Befehlsschaltfläche ÖFFNEN liegen, gut an. Sie sehen sie in Abbildung 17.8. Dort können Sie den standardmäßigen Öffnungsmodus überschreiben und eine Datenbank mit der von Ihnen gewünschten Sperrmethode öffnen.
17.3.4
Anzahl der Datenaktualisierungsversuche
Die Anzahl der Versuche zur Datenaktualisierung gibt an, wie oft Access versucht, Daten in einen gesperrten Datensatz zu schreiben. Je höher diese Zahl ist, desto größer ist die Chance, dass der Versuch gelingt. Der Nachteil liegt darin, dass der Benutzer warten muss, während Access weiter versucht die Daten zu aktualisieren, auch
Strategien zum Sperren und Aktualisieren
659
wenn keine Hoffnung besteht, dass die Aktualisierung gelingt. Die Standardeinstellung ist 2, der Wert kann zwischen 0 und 10 liegen.
Abbildung 17.8: Die Befehlsschaltfläche Öffnen im Access-Dialogfeld Datei Öffnen ermöglicht, einen Öffnungsmodus für die Datenbank anzugeben
17.3.5
Intervall für ODBC-Anzeigeaktualisierung
Das ODBC-Anzeigeaktualisierungs-Intervall bestimmt, wie häufig Ihr Formular oder Ihr Datenblatt mit den Änderungen an Daten aktualisiert wird, die in ODBC-Datenquellen gespeichert sind. Nehmen Sie beispielsweise an, dass zwei Benutzer dieselben Daten in einer Microsoft SQL-Server-Datenbank auf einem Back-End ansehen. Benutzer 1 nimmt eine Änderung vor und das ODBC-Anzeigeaktualisierungs-Intervall bestimmt, wie lange es dauert, bis Benutzer 2 die Änderung sieht. Je höher die Zahl liegt, desto unwahrscheinlicher ist es, dass Benutzer 2 die aktuellen Daten zu sehen bekommt. Je niedriger die Zahl liegt, desto mehr Netzwerkverkehr wird erzeugt. Die Standardeinstellung beträgt 1 500 Sekunden (25 Minuten); der Wert kann 1 bis 32 766 Sekunden betragen.
17.3.6
Das Intervall für Anzeigeaktualisierung
Das Anzeigeaktualisierungs-Intervall bestimmt, wie lange es dauert, bis Ihr Formular oder Ihr Datenblatt mit den Änderungen an Daten aus einer Access-Datenbank aktualisiert wird. Das ist ähnlich wie beim ODBC-Anzeigeaktualisierungs-Intervall, aber das ODBC-Anzeigeaktualisierungs-Intervall gilt nur für ODBC-Datenquellen, das Anzeigeaktualisierungs-Intervall hingegen für Access-Datenquellen. Wie beim ODBC-Anzeigeaktualisierungs-Intervall ist bei höherer Zahl die Chance geringer, dass der Benutzer wirklich aktuelle Daten sieht. Je kleiner der Wert, desto mehr
660
Kapitel 17: Mehrbenutzeranwendungen entwickeln
Netzwerkverkehr wird erzeugt. Die Standardeinstellung beträgt hier 60 Sekunden; der Wert kann 1 bis 32 766 Sekunden betragen. Access aktualisiert die Daten eines Datensatzes automatisch, wenn ein Benutzer versucht, den Datensatz zu bearbeiten. Der Vorteil eines kürzeren Anzeigeaktualisierungs-Intervalls liegt darin, dass der Benutzer sieht, ob der Datensatz von einem anderen Benutzer geändert oder gesperrt wurde, bevor er versucht, ihn zu bearbeiten.
17.3.7
Das Intervall für Datenaktualisierung
Das Datenaktualisierungs-Intervall bestimmt, wie viele Sekunden Access wartet, bevor es erneut versucht, einen gesperrten Datensatz zu aktualisieren. Die Standardeinstellung beträgt hier 250 Millisekunden und der Wert kann zwischen 0 und 1 000 Millisekunden liegen.
17.3.8
Aktualisieren und erneutes Abfragen im Vergleich
Dem Unterschied zwischen der Aktualisierung und dem erneuten Abfragen einer Datensatzgruppe kommt große Bedeutung zu. Das Aktualisieren einer Datensatzgruppe bringt geänderte Daten auf den neuesten Stand und weist auf gelöschte Datensätze hin. Es versucht nicht, eine neue Datensatzgruppe über das Netzwerk heranzuschaffen, sondern »aktualisiert« die Daten in der bestehenden Datensatzgruppe, d.h. die Datensätze werden nicht neu geordnet, es erscheinen keine neuen Datensätze und gelöschte Datensätze werden nicht vom Bildschirm entfernt. Der Datensatzzeiger bleibt auf demselben Datensatz stehen. Nicht alle Arten von Datensatzgruppen lassen sich so aktualisieren. »Erneutes Abfragen« holt dagegen eine neue Datensatzgruppe, d.h., die Abfrage wird erneut gestartet und alle sich ergebenden Daten werden über das Netzwerk geschickt. Die Daten werden neu geordnet, es erscheinen neue Datensätze und gelöschte Datensätze werden nicht mehr angezeigt. Der Datensatzzeiger wandert zum ersten Datensatz der Datensatzgruppe.
17.4
Sperrstrategien für Formulare
Weiter vorn in diesem Kapitel haben Sie die Sperrstrategien für Formulare bereits kennengelernt: keine Sperrungen, alle Datensätze und bearbeiteter Datensatz. Wenn Sie diese korrekt verwenden, können Sie eine Mehrbenutzeranwendung mit geringem oder sogar ohne zusätzlichen Aufwand für die Mehrbenutzerfähigkeit entwickeln. Sie bekommen zwar nicht dieselbe Leistungsfähigkeit, Flexibilität und Steuermöglichkeit wie bei Datensatzgruppen, aber Sie können schnell und ohne große
Sperrstrategien für Formulare
661
Mühe Mehrbenutzertechniken implementieren. In diesem Abschnitt werden Sie sehen, wie die drei Strategien die gebundenen Formulare in Ihrer Anwendung beeinflussen.
17.4.1
Keine Sperrungen
Die Option Keine Sperrungen sorgt dafür, dass die Datenseite mit dem bearbeiteten Datensatz erst gesperrt wird, wenn Access versucht, die geänderten Daten auf die Platte zu schreiben. Das geschieht, wenn zu einem anderen Datensatz gewechselt wird oder eine explizite Speicherung des Datensatzes erfolgt. Wenn die Seitensperre aktiv ist, stellt die Option KEINE SPERRUNGEN die am wenigsten restriktive Sperroption für Formulare dar. Die Daten auf einer 4-KB-Seite lassen sich gleichzeitig von mehreren Benutzern bearbeiten, aber es kommt zum Konflikt, wenn zwei Benutzer versuchen, auf denselben Datensatz einzuwirken. Nehmen wir beispielsweise an, dass Benutzer 1 versucht den Datensatz des Kunden ABCDE zu ändern, und Benutzer 2 versucht denselben Datensatz zu bearbeiten. Es tritt kein Fehler auf, weil für das Formular, auf das die beiden zugreifen, die Option KEINE SPERRUNGEN gesetzt wurde. Dann nimmt Benutzer 1 eine Änderung an der Adresse vor, während Benutzer 2 den Titel der Person überarbeitet. Benutzer 1 verlässt den Datensatz und speichert seine Änderungen. Es tritt kein Fehler auf, weil Access nicht wissen kann, dass Benutzer 2 denselben Datensatz ändert. Jetzt versucht Benutzer 2, den Datensatz zu verlassen, woraufhin das Dialogfeld SCHREIBKONFLIKT (siehe Abbildung 17.9) eingeblendet wird. Benutzer 2 hat nun die Wahl, seine Änderungen zu speichern und dadurch die Änderungen zu überschreiben, die Benutzer 1 gemacht hat oder die Änderungen von Benutzer 1 in die Zwischenablage zu kopieren, so dass eine kluge Entscheidung darüber möglich ist, was geschehen soll, oder die eigenen Änderungen zu verwerfen und die Änderungen von Benutzer 1 zu akzeptieren.
Abbildung 17.9: Das Dialogfeld Schreibkonflikt wird eingeblendet, wenn zwei Benutzer denselben Datensatz bearbeiten.
662
17.4.2
Kapitel 17: Mehrbenutzeranwendungen entwickeln
Alle Datensätze
Die Sperroption Alle Datensätze ist die restriktivste. Wenn sie gilt, können andere Benutzer die Daten in den Tabellen, die dem Formular zu Grunde liegen, nur ansehen, aber unabhängig von ihren eigenen Sperroptionen keine Änderungen an diesen vornehmen. Wenn sie das Formular öffnen, sehen sie eine schnelle Meldung in der Statusleiste, die besagt, dass die Daten nicht aktualisiert werden können. Wenn sie versuchen, Daten im Formular zu ändern, piept der Rechner und in der Statusleiste wird eine Meldung angezeigt.
17.4.3
Bearbeiteter Datensatz
Diese Option wird verwendet, wenn Sie die Konflikte vermeiden wollen, die auftreten, während die Option Keine Sperrungen aktiv ist. Beim Sperren auf Seitenebene sind Sperrkonflikte erheblich wahrscheinlicher als Konflikte wegen geänderter Daten, weil jedesmal, wenn jemand beginnt, einen Datensatz zu bearbeiten, die gesamte 4-KB-Seite gesperrt wird, auf welcher der Satz steht. Beim Sperren auf Zeilenebene ist das kein Problem, weil nur der gerade bearbeitete Datensatz gesperrt wird. Stellen Sie sich dieses Szenario beim Sperren auf Seitenebene vor. Benutzer 1 beginnt einen Datensatz zu bearbeiten, und Benutzer 2 versucht denselben Datensatz zu ändern. Der Rechner piept und im Datensatzmarkierer des Formulars erscheint ein Sperrsymbol (siehe Abbildung 17.10). Dann wechselt Benutzer 2 zu einem anderen Datensatz. Wenn dieser auf derselben 4-KB-Seite steht wie derjenige, den Benutzer 1 gesperrt hat, erscheint das Sperrsymbol und Benutzer 2 kann auch diesen Datensatz erst bearbeiten, wenn Benutzer 1 den Datensatz, an dem er gearbeitet hat, gespeichert und damit die Sperre aufgehoben hat.
Abbildung 17.10: Das Sperrsymbol für einen Datensatz in Bearbeitung
Datensatzgruppen sperren
663
Wenn Sie eines der Standarddialogfelder für Sperrfehler überschreiben wollen, müssen Sie für das Error-Ereignis des Formulars eine Routine schreiben. Mit dieser Methode lässt sich zwar jede Fehlermeldung ersetzen, die erscheint, aber Sie können die Situation einer pessimistischen Sperre nicht abfangen, wenn ein anderer Benutzer für die Sperrung des Datensatzes verantwortlich zeichnet. Als Hinweise, dass der Datensatz gesperrt wurde, dienen nur das Sperrsymbol und der Piepton beim Versuch, den Datensatz zu bearbeiten. Wenn Sie die Benutzer vor dem Bearbeitungsversuch über die Sperrung informieren wollen, müssen Sie Code in das Timer-Ereignis des Formulars einfügen, der prüft, ob der Datensatz gesperrt ist. Diese Technik wird in Abschnitt »Einen Datensatz auf seinen Sperrstatus prüfen« dieses Kapitels behandelt.
17.5
Datensatzgruppen sperren
Das Sperren von Datensatzgruppen gilt für die Datenseiten, die in einer Datensatzgruppe zusammengefasst sind. Sie können damit steuern, wann und für welche Zeitspanne die Daten gesperrt werden. Das unterscheidet dieses Verfahren vom Sperren mit Hilfe gebundener Formulare, bei dem Sie nur geringen Einfluss auf die Einzelheiten des Sperrvorgangs haben. Wenn Sie sich durch eine Datensatzgruppe bewegen und Daten bearbeiten und aktualisieren, erfolgt das Sperren unabhängig davon, ob Sie eingreifen oder nicht. Deshalb müssen Sie verstehen, wann gesperrt wird und ob Sie einschreiten müssen, um das Standardverhalten zu unterbrechen. Wenn Sie nichts tun, wird jedesmal, wenn Sie aus Ihrem VBA-Code heraus mit der Bearbeitung von Daten beginnen, ein Datensatz oder eine ganze Seite mit Datensätzen gesperrt.
17.5.1
Pessimistisches Sperren
VBA lässt Sie bestimmen, wann und für wie lange eine Seite gesperrt wird. Das Standardverhalten wird als »pessimistisches Sperren« bezeichnet, d.h. der Datensatz oder die Seite wird gesperrt, wenn das erste Feld aktualisiert wird. Listing 17.1 veranschaulicht diesen Prozess. Listing 17.1:
Pessimistisches Sperren
Sub PessimisticLock(strAuthorID As String) Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim strCriteria As String Set cnn = New ADODB.Connection cnn.ConnectionString = "Provider=sqloledb;" & _ "Data Source=(local);Initial Catalog=pubs;uid=sa;pwd=" cnn.Open
664
Kapitel 17: Mehrbenutzeranwendungen entwickeln
Set rst = New ADODB.Recordset rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.LockType = adLockPessimistic 'Pessimistisches Sperren aktivieren rst.CursorLocation = adUseServer rst.Open "Select * from Authors Where Au_ID = '" _ & strAuthorID & "'", _ Options:=adCmdText rst!City = "Thousand Oaks" 'Die Sperre tritt an dieser Stelle auf rst.Update 'Hier wird die Sperre wieder aufgehoben End Sub
Diesen und den weiteren in diesem Kapitel abgedruckten Code finden Sie in der Datei CHAP17EX.MDB auf der Begleit-CD-ROM dieses Buchs.
Nicht alle Datenbank-Provider unterstützen alle Arten von Sperren. Um zu ermitteln, welche Funktionen für das jeweilige Recordset-Objekt zur Verfügung stehen, verwenden Sie die Methode Supports mit adUpdate und adUpdateBatch. Außerdem wird die Einstellung adLockPessimistic nicht unterstützt, wenn die Eigenschaft CursorLocation auf adUseClient gesetzt ist. Ob nun der Lieferant oder die Cursor-Position Ursache dafür sind, dass der Sperrentyp nicht unterstützt wird – ein Fehler tritt nicht auf, es wird vielmehr der verfügbare nächste Sperrentyp benutzt. Obwohl die Sperre in diesem Szenario nur für sehr kurze Zeit gilt, wird sie beim Beginn der Bearbeitung verhängt und bei der Aktualisierung aufgehoben. Der Vorteil dieser Sperrmethode besteht darin, dass gewährleistet werden kann, dass zwischen dem Beginn des Bearbeitungsvorgangs und dem Aufruf der Methode Update keine Änderungen an den Daten vorgenommen werden. Außerdem bekommen Sie, wenn der Bearbeitungsvorgang erfolgreich beginnt, Schreibzugriff auf den Datensatz. Der Nachteil liegt darin, dass die Zeitspanne zwischen Bearbeitungsbeginn und Aktualisierung dazu führen könnte, dass die Sperre eine längere Zeit besteht und andere Benutzer nicht nur von diesem Datensatz, sondern – wegen der Seitensperre – auch von der gesamten Datenseite aussperrt, auf welcher der gerade bearbeitete Datensatz steht. Dieses Phänomen verschlimmert sich noch, wenn Transaktionsverarbeitung (siehe Kapitel 22) dazukommt. Im Grunde stellt Transaktionsverarbeitung sicher, dass bei mehreren Änderungen an Daten entweder alle Änderungen erfolgreich durchgeführt werden oder keine. Listing 17.2 veranschaulicht, wie sich pessimistisches Sperren auf die Transaktionsverarbeitung auswirkt:
Datensatzgruppen sperren
Listing 17.2:
665
Pessimistisches Sperren und seine Auswirkung auf die Transaktionsverarbeitung
Sub PessimisticTrans(strOldCity As String, strNewCity As String) Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim strCriteria As String Set cnn = New ADODB.Connection cnn.ConnectionString = "Provider=sqloledb;" & _ "Data Source=(local);Initial Catalog=pubs;uid=sa;pwd=" cnn.Open Set rst = New ADODB.Recordset rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.LockType = adLockPessimistic 'Sperrentyp: pessimistisch rst.CursorLocation = adUseServer rst.Open "SELECT * FROM Authors WHERE City = '" & strOldCity & "'", _ Options:=adCmdText cnn.BeginTrans Do Until rst.EOF rst!City = strNewCity 'Sperre wird verhängt rst.Update rst.MoveNext Loop cnn.CommitTrans 'Sperre wird aufgehoben End Sub
Sie können hier sehen, dass die Sperre von der Bearbeitung des Feldes City im allerersten Datensatz bis zum CommitTrans gilt. Das bedeutet, dass niemand Datensätze oder möglicherweise Datenseiten mit den bearbeiteten Datensätzen aktualisieren kann, bevor die Methode CommitTrans aufgerufen wird. Bei einem längeren Vorgang kann dies untragbar lange sein.
17.5.2
Optimistisches Sperren
»Optimistisches« Sperren schiebt den Zeitpunkt hinaus, zu dem der Datensatz gesperrt wird. Die Sperre wird erst bei der Aktualisierung ausgesprochen, nicht schon bei der Bearbeitung des ersten Feldes. Den Code sehen Sie in Listing 17.3. Listing 17.3:
Optimistisches Sperren
Sub OptimisticLock(strAuthorID As String) Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim strCriteria As String
666
Kapitel 17: Mehrbenutzeranwendungen entwickeln
Set cnn = New ADODB.Connection cnn.ConnectionString = "Provider=sqloledb;" & _ "Data Source=(local);Initial Catalog=pubs;uid=sa;pwd=" cnn.Open Set rst = New ADODB.Recordset rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.LockType = adLockOptimistic 'Sperrentyp: optimistisch rst.CursorLocation = adUseServer rst.Open "Select * from Authors Where au_ID = '" & _ strAuthorID & "'", _ Options:=adCmdText rst!City = "Thousand Oaks" rst.Update 'Sperre wird hier verhängt und wieder aufgehoben End Sub
Wie Sie sehen können, tritt die Sperre erst in Aktion, wenn die Methode Update aufgerufen wird. Der Vorteil dieser Methode besteht darin, dass die Seite bzw. der Datensatz nur sehr kurze Zeit gesperrt ist. Der Nachteil macht sich jedoch bemerkbar, wenn zwei Benutzer gleichzeitig nach dem Datensatz greifen, um ihn zu bearbeiten. Wenn einer davon einen Aktualisierungsversuch unternimmt, tritt kein Fehler auf. Wenn der andere eine Aktualisierung versucht, bekommt er eine Fehlermeldung, die darauf hinweist, dass sich die Daten seit dem Beginn der Bearbeitung geändert haben. Die Behandlung dieser Fehlermeldung wird in »Lösungen für Konflikte beim optimistischen Sperren programmieren« weiter hinten in diesem Kapitel besprochen. Optimistisches Sperren mit Transaktionsverarbeitung unterscheidet sich nicht sehr vom pessimistischen Sperren. Wenn der Code die Methode Update für den jeweiligen Datensatz erreicht, wird die Seite mit diesem Datensatz gesperrt und bleibt gesperrt, bis ein Commit für die Transaktion ausgeführt ist. Den Code sehen Sie in Listing 17.4. Listing 17.4:
Optimistisches Sperren auf Datensatzebene und seine Auswirkung auf die Transaktionsverarbeitung
Sub OptimisticTrans(strOldCity As String, strNewCity As String) Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim strCriteria As String Set cnn = New ADODB.Connection cnn.ConnectionString = "Provider=sqloledb;" & _ "Data Source=(local);Initial Catalog=pubs;uid=sa;pwd=" cnn.Open Set rst = New ADODB.Recordset
Sperrkonflikte effizient erledigen
667
rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.LockType = adLockOptimistic 'Sperrentyp: Optimistisches Batch-Sperren rst.CursorLocation = adUseServer rst.Open "SELECT * FROM Authors WHERE City = '" & strOldCity & "'", _ Options:=adCmdText cnn.BeginTrans Do Until rst.EOF rst!City = strNewCity rst.Update 'Sperre wird verhängt rst.MoveNext Loop cnn.CommitTrans 'Sperre wird aufgehoben End Sub
Die Konstante adLockBatchOptimistic wird verwendet, wenn anstelle von unmittelbaren Aktualisierungen stapelweise so genannte Batch-Aktualisierungen gewünscht werden. Diese werden erst ausgeführt, wenn die Methode UpdateBatch des Objekts Recordset eingesetzt wird. Bei optimistischen Batch-Sperrungen werden die Datensätze erst gesperrt, wenn die Methode UpdateBatch aufgerufen wird.
17.6
Sperrkonflikte effizient erledigen
Wenn ein Benutzer eine Seite oder einen Datensatz gesperrt hat und ein anderer versucht, die Daten dieses Datensatzes oder dieser Seite einzusehen, kommt es nicht zum Konflikt. Wenn jedoch andere Benutzer versuchen, Daten auf der betreffenden Seite zu verändern, tritt ein Fehler auf. Sie wollen vermutlich nicht, dass die Access-Fehlerbehandlung bei jedem Sperrkonflikt zum Einsatz kommt. Anstelle der allgemeinen Access-Fehlermeldung, die besagt, dass ein Datensatz gesperrt ist, wollen Sie vielleicht eine eigene Meldung anzeigen und dann noch ein paarmal versuchen, den Datensatz zu sperren. Um etwas derartiges zu erreichen, müssen Sie jeden von VBA erzeugten Fehler beim Sperren interpretieren lernen, damit Sie eine Entscheidung treffen können, wie Sie reagieren wollen. Sperrkonflikte treten in folgenden Situationen auf:
Ein Benutzer versucht, einen Datensatz zu bearbeiten, der bereits gesperrt ist. Ein Datensatz wurde geändert oder gelöscht, nachdem der Benutzer mit der Bearbeitung begonnen hat. Diese Fehler können unabhängig davon auftreten, ob Sie gebundene Daten über ein Formular bearbeiten oder über VBA-Code auf die Datensätze zugreifen.
668
Kapitel 17: Mehrbenutzeranwendungen entwickeln
17.6.1
Fehler beim pessimistischen Sperren
Werfen Sie zu Beginn der Behandlung von Sperrkonflikten einen Blick darauf, welche Arten von Fehlern bei pessimistischem Sperren auftreten. Sie müssen im Allgemeinen Maßnahmen für die folgenden Fehler vorsehen:
Der aktuelle Datensatz wurde von einem anderen Benutzer gesperrt. Normalerweise brauchen Sie nur ein wenig zu warten und es dann erneut zu versuchen.
Der Datensatz wurde gelöscht, nachdem die Datensatzgruppe geholt wurde. In diesem Fall ist es am günstigsten, die Daten zu aktualisieren. Die Fehlernummern unterscheiden sich in Abhängigkeit vom benutzten Provider. Deshalb verwenden die Beispiele in diesem Kapitel nur exemplarische Fehlernummern. In der Online-Hilfe finden Sie abfangbare Microsoft Jet-Fehler, ADO-Fehler-Codes und ADO-Provider-Fehler. Als Alternative zum VBA-Fehler-Code können Sie sich mit Hilfe der Auflistung Errors die Eigenschaften des Verbindungsobjektes eines aufgetretenen Fehlers ansehen.
17.6.2
Lösungen für Konflikte beim pessimistischen Sperren programmieren
Code zur Handhabung von Konflikten beim pessimistischen Sperren ist recht einfach zu schreiben. Er sollte so aussehen wie in Listing 17.5. Listing 17.5:
Handhabung von Fehlern beim pessimistischen Sperren
Sub PessimisticRS(strAuthorID As String) On Error GoTo PessimisticRS_Err Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim strCriteria As String Dim intChoice As Integer Set cnn = New ADODB.Connection cnn.ConnectionString = "Provider=sqloledb;" & _ "Data Source=(local);Initial Catalog=pubs;uid=sa;pwd=" cnn.Open Set rst = New ADODB.Recordset rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.LockType = adLockPessimistic 'Sperrtyp: pessimistisch rst.CursorLocation = adUseServer rst.Open "Select * from Authors Where Au_ID = '" & _ strAuthorID & "'", _ Options:=adCmdText
Sperrkonflikte effizient erledigen
669
rst!City = "Thousand Oaks" 'Sperre wird verhängt rst.Update 'Sperre wird aufgehoben Exit Sub PessimisticRS_Err: Select Case Err.Number Case 3197 rst.Move 0 Resume Case -2147217887 intChoice = MsgBox(Err.Description, vbRetryCancel + vbCritical) Select Case intChoice Case vbRetry Resume Case Else MsgBox "Couldn't Lock" End Select Case 3021 MsgBox "Record Has Been Deleted" Case Else MsgBox Err.Number & ": " & Err.Decription End Select End Sub
Der Fehlerbehandlungs-Code für diese Routine fängt die Fehler ab, die beim pessimistischen Sperren auftreten können. Tritt ein Fehler auf, der die Nummer -2147217887: Record Is Locked hat, wird der Benutzer gefragt, ob er es noch einmal versuchen möchte. Wenn dies zutrifft, wird der Bearbeitungsvorgang wieder aufgenommen; andernfalls wird der Benutzer darüber informiert, dass die Sperre fehlgeschlagen ist. Wenn der bearbeitete Datensatz gelöscht wurde, tritt ein Fehler mit der Nummer 3021 auf und der Benutzer wird über die Löschung des Datensatzes in Kenntnis gesetzt. Die Situation sieht aus wie in Listing 17.6, in dem auch Transaktionsverarbeitung realisiert wird. Listing 17.6:
Handhabung von Fehlern in Transaktionen beim pessimistischen Sperren
Sub PessimisticRSTrans() On Error GoTo PessimisticRSTrans_Err Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim strCriteria As String Dim intCounter As Integer Dim intTry As Integer Dim intChoice As Integer Set cnn = CurrentProject.Connection Set rst = New ADODB.Recordset
670
Kapitel 17: Mehrbenutzeranwendungen entwickeln
rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.CursorLocation = adUseServer rst.LockType = adLockPessimistic 'Sperrtyp: pessimistisch rst.Open "tblCustomers", _ Options:=adCmdTable cnn.BeginTrans Do Until rst.EOF rst!CompanyName = rst!CompanyName & 1 'Sperre wird verhängt rst.Update rst.MoveNext Loop cnn.CommitTrans 'Sperre wird aufgehoben PessimisticRSTrans_Exit: Exit Sub PessimisticRSTrans_Err: Select Case Err.Number Case 3197 rst.Move 0 Resume Case -2147217887 intCounter = intCounter + 1 If intCounter > 2 Then intChoice = MsgBox(Err.Description, vbRetryCancel + vbCritical) Select Case intChoice Case vbRetry intCounter = 1 Case vbCancel Resume CantLock End Select End If DoEvents For intTry = 1 To 100: Next intTry Resume Case Else MsgBox "Error: " & Err.Number & ": " & Err.Description End Select CantLock: cnn.RollbackTrans Exit Sub End Sub
Dieser Code versucht, den Datensatz zu sperren. Falls das erfolglos bleibt (weil ein Fehler mit der Nummer -2147217887 auftritt), wird der Benutzer um eine Reaktion
Sperrkonflikte effizient erledigen
671
gebeten. Wenn dieser WIEDERHOLEN wählt, wird der Vorgang wiederholt. Andernfalls erfolgt ein Rollback und die Routine wird verlassen. Falls irgendein anderer Fehler auftritt, kommt es ebenfalls zum Rollback und es wird keine der Aktualisierungen akzeptiert. Listing 17.6 öffnet die Tabelle tblCustomers direkt. Das ist nur für dieses Beispiel gedacht. Sie sollten eine Basistabelle niemals direkt öffnen, weil Sie damit alle Zeilen und deren Spalteneigenschaften vom Server herunterladen, sondern stattdessen die Zahl der zurückgegebenen Zeilen auf diejenigen beschränken, mit denen Sie wirklich arbeiten müssen. Letztlich lässt sich, wenn Sie einen Datenbank-Server wie Microsoft SQL Server einsetzen, das Aktualisieren von Datensätzen mit Hilfe einer gespeicherten Prozedur wesentlich effizienter erledigen.
17.6.3
Fehler beim optimistischen Sperren
Nachdem Sie jetzt gesehen haben, was sich abspielt, wenn es beim pessimistischen Sperren zu einem Konflikt kommt, sollten Sie sich ansehen, was beim optimistischen Sperren geschieht. Die beiden folgenden Fehler-Codes sind diejenigen, die beim optimistischen Sperren am häufigsten vorkommen:
Es kommt zu einem Fehler, wenn die Methode Update verwendet wird, um einen gesperrten Datensatz bzw. einen Datensatz auf einer gesperrten Seite zu speichern. Das kann passieren, wenn optimistisches Sperren in Kraft ist und jemand versucht, einen Datensatz auf der Seite zu sperren, auf der ein Datensatz steht, der von einem anderen Rechner gesperrt wurde. Normalerweise können Sie ein wenig warten und es dann erneut versuchen.
Beim optimistischen Sperren tritt ein Fehler auf, wenn jemand anderes einen Datensatz in der Zeit aktualisiert hat, die verstrichen ist, seit Sie begonnen haben, ihn sich anzusehen.
17.6.4
Lösungen für Konflikte beim optimistischen Sperren programmieren
Denken Sie daran, dass VBA beim optimistischen Sperren versucht, die Seite zu sperren, wenn die Methode Update aktiviert wird. In diesem Augenblick besteht das Risiko, dass ein Datenänderungsfehler auftritt, der in Ihrem Code behandelt werden muss. Sie sollten daher die zuvor gezeigte Unterroutine für optimistisches Sperren mit Hilfe des Codes in Listing 17.7 ändern. Listing 17.7:
Handhabung von Fehlern beim optimistischen Sperren
Sub OptimisticRS(strAuthorID) On Error GoTo OptimisticRS_Err Dim cnn As ADODB.Connection
672
Kapitel 17: Mehrbenutzeranwendungen entwickeln
Dim rst As ADODB.Recordset Dim strCriteria As String Dim intChoice As Integer Set cnn = New ADODB.Connection cnn.ConnectionString = "Provider=sqloledb;" & _ "Data Source=(local);Initial Catalog=pubs;uid=sa;pwd=" cnn.Open Set rst = New ADODB.Recordset rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.LockType = adLockOptimistic 'Sperrtyp: optimistisch rst.CursorLocation = adUseServer rst.Open "Select * from Authors Where Au_ID = '" & _ strAuthorID & "'", _ Options:=adCmdText rst!City = "Thousand Oaks" rst.Update 'Sperre wird verhängt und aufgehoben OptimisticRS_Exit: Exit Sub OptimisticRS_Err: Select Case Err.Number Case -2147217885 'Daten haben sich geändert If rst.EditMode = adEditInProgress Then MsgBox "Another User has Edited Record Since You Began Modifying It" End If Case -2147217871 'Gesperrt oder ODBC-Zeitüberschreitung intChoice = MsgBox(Err.Description, vbRetryCancel + vbCritical) Select Case intChoice Case vbRetry Resume Case vbCancel MsgBox "Update Cancelled" End Select Case Else MsgBox "Error: " & Err.Number & ": " & Err.Description End Select Resume OptimisticRS_Exit End Sub
Wie bei der pessimistischen Fehlerbehandlung fängt diese Routine alle potentiellen Fehler ab, die beim optimistischen Sperren auftreten können. Im Fall eines Datenänderungskonflikts erhält der Benutzer eine problembezogene Warnung. Bei einem Sperrkonflikt wird der Benutzer gefragt, ob er es erneut versuchen möchte. Listing 17.8 zeigt, wie das Ganze aussieht, wenn Transaktionsverarbeitung einbezogen wird.
Sperrkonflikte effizient erledigen
Listing 17.8:
673
Handhabung von Fehlern in Transaktionen beim optimistischen Sperren
Sub OptimisticRSTrans() On Error GoTo OptimisticRSTrans_Err Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim strCriteria As String Dim intChoice As Integer Dim boolInTrans As Boolean Set cnn = New ADODB.Connection cnn.ConnectionString = "Provider=sqloledb;" & _ "Data Source=(local);Initial Catalog=pubs;uid=sa;pwd=" cnn.Open Set rst = New ADODB.Recordset rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.LockType = adLockOptimistic 'Sperrtyp: optimistisch rst.CursorLocation = adUseServer rst.Open "tblCustomers", _ Options:=adCmdTable cnn.BeginTrans boolInTrans = True Do Until rst.EOF rst!CompanyName = rst!CompanyName & 1 'Sperre wird verhängt rst.Update rst.MoveNext Loop cnn.CommitTrans 'Sperre wird aufgehoben OptimisticRSTrans_Exit: Exit Sub OptimisticRSTrans_Err: Select Case Err.Number Case -2147217885 'Data has Changed If rst.EditMode = adEditInProgress Then MsgBox "Another User has Edited Record Since You Began Modifying It" End If Case -2147217871 'Gesperrt oder ODBC-Zeitablauf intChoice = MsgBox(Err.Description, vbRetryCancel + vbCritical) Select Case intChoice Case vbRetry Resume Case vbCancel MsgBox "Update Cancelled"
674
Kapitel 17: Mehrbenutzeranwendungen entwickeln
End Select Case Else MsgBox "Error: " & Err.Number & ": " & Err.Description End Select If boolInTrans Then cnn.RollbackTrans End If Resume OptimisticRSTrans_Exit End Sub
Wenn ein Datenänderungsfehler auftritt, wird die gesamte Verarbeitungsschleife abgebrochen (und es kommt zum Rollback). Bei einem Sperrkonflikt werden mehrere neue Versuche gestartet. Wenn das erfolglos bleibt, erfolgt ein Rollback der gesamten Transaktion.
17.7
Einen Datensatz auf seinen Sperrstatus prüfen
Häufig wollen Sie den Sperrstatus eines Datensatzes ermitteln, bevor Sie eine Operation beginnen. Mit Hilfe pessimistischen Sperrens und eines Versuchs, den Datensatz zu ändern, können Sie bestimmen, ob die aktuelle Zeile gesperrt ist. Der Code sieht aus wie in Listing 17.9. Listing 17.9:
Vor der Bearbeitung ermitteln, ob ein Datensatz gesperrt ist
Sub TestLocking() Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim boolLocked As Boolean Set cnn = New ADODB.Connection cnn.ConnectionString = "Provider=sqloledb;" & _ "Data Source=(local);Initial Catalog=pubs;uid=sa;pwd=" cnn.Open Set rst = New ADODB.Recordset rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.LockType = adLockPessimistic 'Sperrtyp: pessimistisch rst.CursorLocation = adUseServer rst.Open "Authors", Options:=adCmdTable boolLocked = IsItLocked(rst) MsgBox boolLocked
Code zum Aktualisieren oder erneuten Abfragen
675
End Sub Function IsItLocked(rstAny As ADODB.Recordset) As Boolean On Error GoTo IsItLocked_Err IsItLocked = False With rstAny .Update End With Exit Function IsItLocked_Err: If Err = -2147467259 Then IsItLocked = True Exit Function End If End Function
Die Routine TestLocking sendet ihre Datensatzgruppe an die Funktion IsItLokked(),welche die Datensatzgruppe als Parameter übernimmt. Dann ruft IsItLokked() die Methode Update für die Datensatzgruppe auf. Wenn ein Fehler auftritt, ist der Datensatz gesperrt und die Fehlerbehandlungsroutine setzt den Rückgabewert der Funktion auf True.
17.8
Code zum Aktualisieren oder erneuten Abfragen
In diesem Abschnitt werden Sie sehen, wie man mit Hilfe von Code eine erneute Abfrage startet. Die Methode Requery gewährleistet, dass der Benutzer alle Änderungen an vorhandenen Datensätzen sowie alle hinzugekommenen Datensätze zu sehen bekommt. Außerdem wird sichergestellt, dass gelöschte Datensätze aus der Datensatzgruppe entfernt werden. Die Methode Requery ist am einfachsten zu verstehen, wenn man sich die einem Formular zugrunde liegenden Daten ansieht: Private Sub cmdRequery_Click() If Me.RecordsetClone.Restartable Then Me.RecordsetClone.Requery Else MsgBox "Requery Method Not Supported on this Recordset" End If End Sub
Dieser Code prüft zunächst die Eigenschaft Restartable der Datensatzgruppe, welche dem Formular zu Grunde liegt. Wenn diese den Wert True hat, unterstützt die Datensatzgruppe die Methode Requery, die für die Datensatzgruppe des Formulars
676
Kapitel 17: Mehrbenutzeranwendungen entwickeln
ausgeführt wird. Natürlich funktionieren die Eigenschaft Restartable und die Methode Requery für jede beliebige Datensatzgruppe und nicht nur für die, die einem Formular zu Grunde liegt. Der einzige Grund, weshalb eine Datensatzgruppe nicht erneut startfähig sein könnte, wäre der Umstand, dass sich einige Back-End-Abfragen nicht erneut starten lassen. Bevor dieser Code ausgeführt wird, erscheinen keine neuen Datensätze in der Datensatzgruppe und gelöschte Datensätze sind mit #Gelöscht gekennzeichnet (siehe Abbildung 17.11). Nach dem Ausführen der Methode Requery erscheinen alle neuen Datensätze und die gelöschten sind entfernt.
Abbildung 17.11: Eine Datensatzgruppe, die noch nicht aktualisiert wurde
17.9
Die .LDB-Datei
Jede für gemeinsame Nutzung geöffnete Datenbank besitzt eine entsprechende .LDBDatei, eine Sperrdatei, die angelegt wurde, um Rechner- und Sicherheitsnamen aufzunehmen und Byte-Bereichssperren für die Datensatzgruppe zu verhängen. Sie hat immer denselben Namen und denselben Speicherort wie die Datenbanken, deren Sperren sie verfolgt, und sie wird automatisch gelöscht, wenn der letzte Benutzer die Datenbankdatei verlässt. In zwei Fällen wird sie jedoch nicht gelöscht:
Die Datenbank wird als beschädigt markiert (fachlich korrekter Begriff). Der letzte Benutzer besitzt keine Löschberechtigung in dem Ordner mit der Datenbank und den .LDB-Dateien.
Die Benutzerliste
677
Die Jet-Engine trägt jeden, der die Datenbank öffnet, in die .LDB-Datei ein. Der Eintrag ist 64 Bytes lang. Die ersten 32 Bytes enthalten den Namen des Rechners, die zweiten 32 Bytes den Sicherheitsnamen des Benutzers. Da die maximale Benutzeranzahl für eine Access-Datenbank bei 255 liegt, kann die .LDB-Datei nicht größer als 16 KB werden. Die dort gespeicherten Informationen verhindern, dass Benutzer Daten in Datensätze auf Seiten schreiben, die von anderen Benutzern gesperrt wurden, und ermittelt, wer für das Sperren der Datensätze oder Seiten verantwortlich zeichnet.
17.10
Die Benutzerliste
Neu in Access 2000 ist die Benutzerliste. Sie ermöglicht, per Programm zu ermitteln, wer sich bei einer Datenbank angemeldet hat. Diese Informationen werden mit Hilfe der Methode OpenSchema des Objekts Connection bereitgestellt. Die Methode OpenSchema übernimmt drei Parameter: den Abfragetyp, die Beschränkungen und eine Schema-ID. Listing 17.10 veranschaulicht die Verwendung der Methode OpenSchema zur Ermittlung der Benutzerliste. Listing 17.10: Ermitteln, wer eine Datenbank benutzt Public Const JET_SCHEMA_USERROSTER = _ "{947bb102-5d43-11d1-bdbf-00c04fb92675}" Sub UserRoster() Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Set cnn = New ADODB.Connection cnn.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=C:\My Documents\Test.mdb" cnn.Open Set rst = cnn.OpenSchema(adSchemaProviderSpecific, _ , JET_SCHEMA_USERROSTER) Debug.Print rst.GetString End Sub
Der Code beginnt mit der Deklaration und der Erstellung eines Connection-Objekts. Dieses wird mit Hilfe einer Zeichenfolge für die Anbindung an die Datenbank geöffnet, deren Benutzerliste Sie ermitteln wollen. Dann wird die Methode OpenSchema für das Connection-Objekt ausgeführt. Die der Methode übergebenen Parameter geben an, dass Sie eine Benutzerliste erhalten möchten. Diese wird an das Recordset-Objekt zurückgegeben.
678
17.11
Kapitel 17: Mehrbenutzeranwendungen entwickeln
Benutzerdefinierte Zähler erstellen
Access stellt einen Feldtyp AutoWert bereit, der sich so einstellen lässt, dass er automatisch sequentielle oder zufällige Werte erzeugt. Dieser Feldtyp eignet sich zwar für die meisten Situationen, aber möglicherweise wollen Sie aus einem der folgenden Gründe eigene Felder des Typs AutoWert anlegen:
Es gefällt Ihnen nicht, dass das Feld des Typs AutoWert Werte aus gelöschten Datensätzen verwirft.
Der Primärschlüsselwert muss ein Algorithmus der anderen Felder der Tabelle sein (z.B. die ersten Zeichen mehrerer Felder).
Der Primärschlüsselwert muss eine alphanumerische Zeichenfolge enthalten. Um einen eigenen automatisch mit einer Nummer versehenen sequentiellen Wert zu erhalten, müssen Sie wahrscheinlich eine Systemtabelle anlegen, die den nächst verfügbaren Wert für Ihr benutzerdefiniertes Feld des Typs AutoWert enthält. Diese muss gesperrt sein, während jemand auf den nächsten verfügbaren sequentiellen Wert zugreift, weil sonst zwei Benutzer denselben Wert zugewiesen bekommen könnten.
17.12
Ungebundene Formulare
Eine Lösung für Sperrkonflikte ist die Verwendung ungebundener Formulare. Dadurch lässt sich die Zeit wesentlich verringern, für die ein Datensatz gesperrt bleibt, und Sie können vollständig steuern, wann Access versuchen soll, die Sperre abzusichern. Ungebundene Formulare erfordern deutlich mehr Programmieraufwand als gebundene. Daher sollten Sie sicherstellen, dass die Vorteile die damit verbundene Programmierung und Pflege aufwiegen. Angesichts der Verbesserungen sowohl an Formularen als auch an der Jet-Engine in Access 2000 sind die Gründe weniger zwingend geworden, für Access-Daten ungebundene Formulare zu verwenden. Ungebundene Formulare werden in Kapitel 19 ausführlicher behandelt.
17.13
Höhere Leistung durch Replikation
Zur Leistungssteigerung in einer Mehrbenutzerumgebung lässt sich auch Replikation (siehe Kapitel 23) einsetzen. Sie können damit mehrere Kopien der Datenbank mit den Tabellen im Netzwerk verteilen, jede auf einem anderen Datei-Server. Unterschiedliche Benutzer bekommen über unterschiedliche Datei-Server Zugriff auf die Daten, so dass sich der Netzwerkverkehr besser verteilt. Mit Hilfe des Replication Managers, der in der Microsoft Office Developer Edition (ODE) enthalten ist, lassen sich die Datenbanken in regelmäßigen Abständen synchronisieren. Das ist zwar keine gangbare Lösung, wenn die Benutzer der Datenbank vollständige Aktua-
Höhere Leistung durch Replikation
679
lität benötigen, aber sie reicht in vielen Fällen aus. Wenn beschränkte Ressourcen den Umstieg auf eine Client-Server-Datenbank nicht zulassen, stellt dieser Weg häufig die einzige Lösung dar. Der Replication Manager wird nur mit Office 2000 Developer Edition ausgeliefert.
17.13.1
Für die Praxis
Eine Anwendung für Multiuser fähig machen Das Zeit- und Abrechnungssystem baut im Wesentlichen auf Formularen auf. Da es unwahrscheinlich ist, dass zwei Benutzer die Daten eines Datensatzes gleichzeitig aktualisieren, können Sie sich für optimistisches Sperren entscheiden. Das reduziert das Risiko, dass eine Seite mit Datensätzen versehentlich für längere Zeit gesperrt wird. Alternativ können Sie auf Zeilenebene sperren. Das Beispiel in Listing 17.11 veranschaulicht, wie Sie mit Hilfe des Error-Ereignisses des Formulars die Standardmeldungen für Sperrfehler überschreiben können, wenn optimistisches Sperren in Kraft ist. Listing 17.11: Standardfehlerbehandlung in einem Formular überschreiben 'Datenänderungsfehler Private Sub Form_Error(DataErr As Integer, Response As Integer) On Error GoTo Form_Error_Err: Dim intAnswer As Integer If DataErr = 7787 Then 'Data Has Changed Error intAnswer = MsgBox("Another User Has Modified This Record " & vbCrLf & _ "Since You Began Editing It. " & vbCrLf & vbCrLf & _ "Click OK to Cancel Your Changes", _ vbOK, "Locking Conflict") End If Response = acDataErrContinue Exit Sub Form_Error_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description Exit Sub End Sub
Dieser Code wird in das Error-Ereignis des Formulars frmClients in der Datenbank CHAP17EX.MDB eingefügt. Zuerst prüft er, ob DataErr gleich 7787 ist. Das ist der Fehler-Code für DataErr, wenn in einem Formular ein Datenänderungsfehler aufgetreten ist. In diesem Fall bekommt der Benutzer ein Meldungsfeld zu sehen, das ihn über den Konflikt informiert. Response wird auf acDataErrContinue gesetzt, so dass die normale Fehlermeldung unterdrückt wird.
Externe Daten verwenden
Kapitel
Hier lesen Sie:
Daten importieren, verknüpfen und öffnen: wann und warum Externe Daten importieren Eine Verknüpfung mit externen Daten erstellen Eine externe Tabelle öffnen Mit Kennwörtern arbeiten Verknüpfungen aktualisieren und löschen Spezielle Überlegungen Problemlösung Leistungsaspekte und Verknüpfungen Mit HTML-Dokumenten arbeiten
18.1
Verbindung mit externen Datenquellen
Microsoft Access besitzt ausgeprägte Fähigkeiten, Schnittstellen zu Daten aus anderen Quellen zu bilden. Es kann Daten aus beliebigen ODBC-Datenquellen sowie Daten aus FoxPro, dBase, Paradox, Lotus, Excel und vielen anderen Quellen nutzen. In diesem Kapitel werden Sie erfahren, wie Sie die Verbindung mit externen Datenquellen mit Hilfe der Benutzerschnittstelle und durch Verwendung von Code herstellen. Externe Daten sind außerhalb der aktuellen Datenbank gespeichert. Damit können Daten gemeint sein, die in einer anderen Microsoft Access-Datenbank abgelegt sind, aber auch Daten, die in zahlreichen anderen Dateiformaten vorliegen – in einem ISAM-, Tabellenkalkulations-, ASCII- oder noch einem anderen Format. Dieses Kapitel stellt den Zugriff auf andere Datenquellen als ODBC in den Mittelpunkt. ODBC-Datenquellen werden in den Kapiteln 19, 20 und 21 ausführlich behandelt.
682
Kapitel 18: Externe Daten verwenden
Access ist ein hervorragendes »Front-End«-Programm, d.h., es stellt ein leistungsfähiges und effizientes Werkzeug zur Präsentation von Daten dar – selbst von Daten aus externen Quellen. Daten werden aus den verschiedensten Gründen nicht in Access gespeichert. Umfangreiche Datenmengen lassen sich beispielsweise auf einem Back-End-Datenbank-Server wie Microsoft SQL-Server effizienter verwalten. Daten werden auch häufig im FoxPro-, dBase- oder Paradox-Dateiformat gespeichert, weil sie von einer älteren Anwendung stammen, die in einer dieser Umgebungen geschrieben wurde. Textdaten sind häufig von einem Großrechner heruntergeladen worden. Unabhängig davon, warum die Daten in einem anderen Format gespeichert sind, ist es wichtig, dass Sie verstehen, wie Sie in Ihren VBA-Modulen mit diesen externen Daten umzugehen haben. Mit Hilfe der Fähigkeit, auf Daten aus anderen Quellen zuzugreifen, können Sie Abfragen, Formulare und Berichte erstellen. Beim Zugriff auf externe Daten haben Sie drei Auswahlmöglichkeiten: Sie können die Daten in eine Access-Datenbank importieren, über eine Verknüpfung von Ihrer Access-Datenbank aus auf die Daten zugreifen oder eine Datenquelle direkt öffnen. Der Import der Daten ist der optimale Weg (außer bei ODBC-Datenquellen) aber nicht immer möglich. Wenn Sie die externen Daten nicht importieren können, sollten Sie eine Verknüpfung zu ihnen herstellen, weil Microsoft Access eine Menge Informationen über diese verknüpften Dateien unterhält. Dadurch wird die Leistung bei der Bearbeitung externer Dateien optimiert. Manchmal rechtfertigt eine bestimmte Situation den direkten Zugriff auf die Daten. Deshalb sollten Sie sowohl wissen, wie man mit verknüpften Dateien umgeht, als auch, wie man Dateien direkt öffnet und bearbeitet.
18.2
Daten importieren, verknüpfen und öffnen: wann und warum
Beim Importieren von Daten in eine Access-Tabelle wird eine Kopie der Daten angelegt und in eine Access-Tabelle eingefügt. Nach dem Importieren werden die Daten ebenso behandelt wie jede andere native Access-Tabelle. Genau genommen können weder Sie noch Access erkennen, woher die Daten stammen. Infolgedessen bieten importierte Daten dieselbe Leistung und Flexibilität wie alle anderen Access-Tabellen. Die Verknüpfung mit externen Daten ist etwas völlig anderes. Die verknüpften Daten verbleiben in ihrem nativen Format. Durch Einrichten einer solchen Verknüpfung können Sie Abfragen, Formulare und Berichte erstellen, welche die externen Daten aufbereiten. Die Verknüpfung bleibt dauerhaft bestehen, bis Sie sie explizit löschen. Die verknüpfte Tabelle erscheint im Datenbankfenster wie jede andere Access-Tabelle, abgesehen davon, dass sie ein anderes Symbol besitzt. Ein weiterer Unterschied besteht darin, dass sich die Tabellenstruktur nicht von Access aus verändern lässt. Wenn die Datenquelle Mehrbenutzerzugriff erlaubt, können die Benut-
Daten importieren, verknüpfen und öffnen: wann und warum
683
zer Ihrer Anwendung genau genommen die Daten ebenso ändern wie die Benutzer von Anwendungen, die im nativen Datenformat der Datenquelle (z.B. FoxPro, dBase oder Paradox) geschrieben sind. Das Öffnen einer externen Tabelle entspricht der Verknüpfung mit dieser Tabelle, abgesehen davon, dass keine permanente Beziehung eingerichtet wird. Wenn Sie eine »Verknüpfung« mit einer externen Tabelle einrichten, bleiben die Verbindungsinformationen von einer Sitzung zur nächsten erhalten. Wenn Sie eine Tabelle öffnen, erstellen Sie aus dieser eine Datensatzgruppe. Es wird keine permanente Verknüpfung angelegt.
18.2.1
Auswahl einer Möglichkeit
Sie müssen unbedingt verstehen, wann man externe Daten importiert, wann man eine Verknüpfung einrichtet und wann man eine externe Tabelle direkt öffnet. Unter folgenden Umständen sollten Sie externe Daten importieren:
Sie stellen ein vorhandenes System auf Access um. Sie wollen externe Daten für eine Vielzahl von Abfragen und Berichten verwenden, ohne die Daten zu aktualisieren. Sie wollen die höhere Leistung haben, die native Access-Daten bieten. Wenn Sie ein vorhandenes System auf Access umstellen und bereit sind, Test- oder Produktionsdaten dauerhaft in Ihre Anwendung zu übernehmen, importieren Sie die Tabellen in Access. Ein weiterer guter Grund für den Import externer Daten besteht darin, wenn regelmäßig Daten im ASCII-Format von einem Großrechner heruntergeladen und für Berichte verwendet werden sollen. Anstatt eine Verknüpfung mit den Daten aufzubauen und die damit verbundenen Leistungseinbußen hinzunehmen, können Sie die Daten jeweils beim Herunterladen vom Großrechner importieren. Unter folgenden Umständen sollten Sie eine Verknüpfung mit externen Daten einrichten:
Die Daten werden von einer älteren Anwendung benutzt, die das native Dateiformat benötigt.
Die Daten befinden sich auf einem ODBC-kompatiblen Datenbank-Server. Sie wollen regelmäßig auf die Daten zugreifen (was es unmöglich macht, die Daten aktuell zu halten, wenn sie nicht verknüpft sind). Häufig fehlen Ihnen Zeit oder Ressourcen, um eine in FoxPro, Paradox oder einer anderen Sprache geschriebene Anwendung neu zu schreiben. Möglicherweise entwickeln Sie zusätzliche Anwendungen, welche die Daten gemeinsam mit der älteren Anwendung nutzen, oder wollen vielleicht die leistungsfähigen Abfrage- und Berichtsfähigkeiten von Access einsetzen, anstatt Abfragen und Berichte in der nativen Umgebung zu entwickeln.
684
Kapitel 18: Externe Daten verwenden
Mit Hilfe einer Verknüpfung mit den externen Daten können die Benutzer vorhandener Anwendungen weiter mit diesen Anwendungen und ihren Daten arbeiten. Ihre Access-Anwendungen können die Daten holen und ändern, ohne sich Sorgen über eine Beschädigung oder sonstige Beeinträchtigung der Daten machen zu müssen. Wenn sich die Daten in einer ODBC-Datenbank wie z.B. Microsoft SQL-Server befinden, wollen Sie von den Vorteilen beim Auffinden der Daten profitieren, die ein Datenbank-Server bietet. Durch eine Verknüpfung mit einer ODBC-Datenquelle können Sie die einfache Bedienbarkeit von Access als Front-End-Werkzeug und die Client-Server-Technologie gleichzeitig nutzen. Schließlich bietet die Verknüpfung mit einer externen Tabelle anstelle des temporären direkten Öffnens eine einfache Benutzung und Leistungsvorteile, wenn Sie vorhaben, die Daten regelmäßig einzusetzen. Nach dem Erstellen der Verknüpfung behandelt Access die Tabelle meistens genauso wie jede andere Access-Tabelle. Unter folgenden Umständen sollten Sie eine externe Tabelle direkt öffnen:
Sie müssen nur selten eine Verbindung mit der externen Datenquelle einrichten. Sie haben festgestellt, dass sich die Leistung tatsächlich verbessert, wenn Sie die Datenquelle direkt öffnen. Wenn Sie nur selten auf die externen Daten zuzugreifen brauchen, ist es vielleicht angemessen, sie direkt zu öffnen. Verknüpfungen vergrößern Ihre MDB-Datei. Dies ist nicht notwendig, wenn Sie nur selten auf die Daten zugreifen. Außerdem stellen Sie möglicherweise in manchen Fällen beim Zugriff auf ISAM-Daten (auf Indizes aufbauende sequentielle Zugriffsmethode) fest, dass das direkte Öffnen der Tabelle eine bessere Leistung erbringt als das Verknüpfen. Dieses Kapitel stellt zwar den Vorgang des Importierens externer Daten dar, aber das ist im Grunde ein einmaliger Vorgang und erfordert nicht viel Beschreibung. Wichtig ist jedoch, dass die Anwendung nach dem Import der Daten in eine Access-Tabelle nicht mehr im nativen Format auf die Daten zugreift. Der Großteil des Kapitels befasst sich mit dem Verknüpfen oder direkten Öffnen von externen Datentabellen.
18.2.2
Unterstützte Dateiformate
Microsoft Access ermöglicht das Importieren, Verknüpfen und Öffnen von Dateien in folgenden Formaten:
Microsoft Jet-Datenbanken (auch aus älteren Jet-Versionen) ODBC-Datenbanken HTML-Dokumente Microsoft Exchange/Outlook
685
Externe Daten importieren
dBase III, dBase IV, dBase 5.0 Paradox 3.x, 4.x und 5.x Microsoft Excel-Arbeitsblätter der Version 3.0, 4.0, 5.0 und 8.0 Lotus WKS-, WK1-, WK3- und WK4-Arbeitsblätter ASCII-Textdateien im Tabellenformat
18.3
Externe Daten importieren
Der Import externer Daten ist recht einfach. Sie können dazu die Benutzerschnittstelle oder VBA-Code verwenden. Wenn Sie vorhaben, nur ein- oder zweimal Daten zu importieren, sollten Sie die Benutzerschnittstelle wählen. Wenn Sie regelmäßig Daten importieren (z.B. aus einer heruntergeladenen Großrechnerdatei), sollten Sie eine Routine schreiben, die diese Aufgabe in einer für den Benutzer transparenten Weise erledigt.
18.3.1
Daten mit Hilfe der Benutzerschnittstelle importieren
Um eine externe Datendatei mit Hilfe der Benutzerschnittstelle zu importieren, unternehmen Sie Folgendes: 1. Klicken Sie irgendwo im Datenbankfenster mit der rechten Maustaste. 2. Wählen Sie IMPORTIEREN (oder DATEI|EXTERNE DATEN|IMPORTIEREN). Das ruft das Dialogfeld IMPORTIEREN auf, das Sie in Abbildung 18.1 sehen.
Abbildung 18.1: Das Dialogfeld Importieren
686
Kapitel 18: Externe Daten verwenden
3. Markieren Sie im aufklappbaren Listenfeld DATEITYP den Dateityp, den Sie importieren wollen. 4. Wählen Sie die Datei aus, die Sie importieren wollen und klicken Sie auf IMPORTIEREN. 5. Je nachdem, welchen Dateityp Sie gewählt haben, wird der Importvorgang abgeschlossen oder es werden weitere Dialogfelder eingeblendet. Wenn Sie beispielsweise MICROSOFT EXCEL (*.XLS) wählen, erscheint der Import-Assistent für Kalkulationstabellen, wie in Abbildung 18.2 gezeigt. Dieser führt Sie durch den Vorgang des Importierens von Arbeitsblattdaten.
Abbildung 18.2: Der Import-Assistent für Kalkulationstabellen
Wenn Sie feststellen, dass sich eine Textdatei nicht direkt in eine große AccessDatenbank (4-5 MB) importieren lässt, konvertieren Sie die Datei zunächst in ein Excel-Arbeitsblatt und importieren dieses.
18.3.2
Daten mit Hilfe von Code importieren
Das Objekt DoCmd besitzt drei Methoden, die Ihnen beim Import externer Daten helfen: TransferDatabase, TransferText und TransferSpreadsheet. Alle drei werden in diesem Abschnitt behandelt. Daten aus Datenbanken mit Hilfe von Code importieren Um Daten aus einer Datenbank wie z.B. FoxPro, dBase, Paradox oder aus einer anderen Access-Datenbank zu importieren, setzen Sie die Methode TransferDatabase
Externe Daten importieren
687
ein. Im Modul basImport wurde im Abschnitt ALLGEMEINE DEKLARATIONEN eine öffentliche Konstante mit dem Namen ADDPATH deklariert. Sie müssen den Wert dieser Konstanten ändern, wenn Sie den Beispiel-Code aus diesem Kapitel in einem anderen Verzeichnis starten wollen. Listing 18.1, zu finden im Modul basImport, zeigt ein Beispiel, das die Methode TransferDatabase verwendet. Listing 18.1:
Die Methode TransferDatabase
Sub ImportDatabase() DoCmd.TransferDatabase _ TransferType:=acImport, _ DatabaseType:="dBase III", _ DatabaseName:=APPPATH, _ ObjectType:=acTable, _ Source:="Customer", _ Destination:="tblCustomers", _ StructureOnly:=False End Sub
Diesen und den gesamten Code dieses Kapitels finden Sie in der Datei CHAP18EX.MDB auf der CD-ROM.
Tabelle 18.1 listet die Argumente für die Methode TransferDatabase auf. Argument
Inhalt
TransferType
Typ der durchzuführenden Übertragung
DatabaseType
Typ der zu importierenden Datenbank
DatabaseName
Name der Datenbank. Wenn es sich um eine separate Datei handelt (wie bei dBase, Paradox und den früheren Versionen von FoxPro), ist der Name der Datenbank das Verzeichnis, welches die Tabellendatei enthält. Setzen Sie hinter den Verzeichnisnamen keinen umgekehrten Schrägstrich!
ObjectType
Typ des zu importierenden Objekts. Dieses Argument wird bei Objekten ignoriert, die keine Access-Objekte sind.
Source
Name des zu importierenden Objekts. Geben Sie keine Dateierweiterung ein!
Destination
Name des importierten Objekts
Tabelle 18.1: Argumente für TransferDatabase
688
Kapitel 18: Externe Daten verwenden
Argument
Inhalt
StructureOnly
Soll nur die Tabellenstruktur oder die Tabellenstruktur samt den Daten importiert werden?
SaveLoginID
Sollen Anmelde-ID und Kennwort für eine ODBC-Datenbank in der Verbindungszeichenfolge für verknüpfte Tabellen gespeichert werden?
Tabelle 18.1: Argumente für TransferDatabase (Forts.)
Textdaten mit Hilfe von Code importieren Um Text aus einer Textdatei zu importieren, benutzen Sie die Methode TransferText des Objekts DoCmd. Listing 18.2 zeigt ein Beispiel für diese Methode. Listing 18.2:
Die Methode TransferText
Sub ImportText() DoCmd.TransferText _ TransferType:=acImportDelim, _ TableName:="tblCustomerText", _ filename:=APPPATH & "\Customer.Txt" End Sub
Tabelle 18.2 listet die Argumente für die Methode TransferText auf. Argument
Inhalt
TransferType
Typ der gewünschten Übertragung
SpecificationName
Name für die Gruppe von Optionen, die bestimmt, wie die Datei importiert wird
TableName
Name der Access-Tabelle, welche die importierten Daten aufnehmen soll
FileName
Name der Textdatei, aus der Daten importiert werden sollen
HasFieldHeadings
Enthält die erste Zeile der Textdatei Feldüberschriften?
Tabelle 18.2: Argumente für TransferText
Daten aus Kalkulationstabellen mit Hilfe von Code importieren Um Daten aus einer Kalkulationstabellendatei zu importieren, benutzen Sie die Methode TransferSpreadsheet des Objekts DoCmd. Listing 18.3 zeigt ein Beispiel für diese Methode.
Eine Verknüpfung zu externen Daten erstellen
Listing 18.3:
689
Die Methode TransferSpreadsheet
Sub ImportSpreadsheet() DoCmd.TransferSpreadsheet _ TransferType:=acImport, _ SpreadsheetType:=acSpreadsheetTypeExcel9, _ TableName:="tblCustomerSpread", _ filename:=APPPATH & "\Customer.Xls", _ HasFieldNames:=True End Sub
Tabelle 18.3 listet die Argumente für die Methode TransferSpreadsheet auf. Argument
Inhalt
TransferType
Typ der gewünschten Übertragung
SpreadsheetType
Typ des Arbeitsblatts, aus dem importiert werden soll. Standardeinstellung ist Excel 3.0
TableName
Name der Access-Tabelle, welche die importierten Daten aufnehmen soll
FileName
Name der Arbeitsblattdatei, aus der Daten importiert werden sollen
HasFieldNames
Enthält die erste Zeile des Arbeitsblatts Feldüberschriften?
Range
Bereich der zu importierenden Zellen
Tabelle 18.3: Argumente für TransferSpreadsheet
18.4
Eine Verknüpfung zu externen Daten erstellen
Wenn die Daten im Originalformat erhalten bleiben müssen, aber genauso behandelt werden sollen wie eine andere Access-Tabelle, stellt eine Verknüpfung die beste Lösung dar. Alle zur Einrichtung und Pflege der Verbindung mit der entfernten Datenquelle erforderlichen Informationen werden in der Definition der verknüpften Tabelle gespeichert. Verknüpfungen lassen sich mit Hilfe der Benutzerschnittstelle oder über Code anlegen. Beide Alternativen werden in diesem Abschnitt vorgestellt. Eine der häufigsten Verknüpfungsarten ist die Verknüpfung mit einer anderen Access-Tabelle. Diese wird angelegt, damit die Anwendungsobjekte (Abfragen, Formulare, Berichte, Makros und Module) in einer lokalen Datenbank und die Tabellen in einer Datenbank auf dem Datei-Server abgelegt werden können. Mit einer solchen Konfiguration sind zahlreiche Vorteile verbunden, die in Kapitel 17 ausführlich dargelegt werden.
690
18.4.1
Kapitel 18: Externe Daten verwenden
Verknüpfungen mit Hilfe der Benutzerschnittstelle einrichten
Das Einrichten einer Verknüpfung mit Hilfe der Benutzerschnittstelle ist sehr beliebt. Wenn Sie schon beim Entwurf wissen, welche Verknüpfungen Sie anlegen wollen, ist es vermutlich die einfachste Möglichkeit. Sie können dazu den Assistenten zur Datenbankaufteilung einsetzen oder es manuell erledigen. Verknüpfungen mit Hilfe des Assistenten zur Datenbankaufteilung erstellen Der Assistent zur Datenbankaufteilung wurde entworfen, um Datenbanken aufzuteilen, die Tabellen und andere Datenbankobjekte in einer einzigen physischen MDB-Datenbankdatei vereinigen. Sie automatisiert das Verschieben der Datentabellen in eine andere Datenbank. Kapitel 17 beschreibt dies ausführlich. Verknüpfungen mit Tabellen lassen sich nur von einer Access-Datenbank, nicht aber von einem Access-Projekt aus erstellen.
Verknüpfungen mit Access-Tabellen anlegen Um eine Verknüpfung mit einer Access-Tabelle anzulegen, unternehmen Sie Folgendes: 1. Klicken Sie mit der rechten Maustaste an einer beliebigen Stelle im Datenbankfenster. 2. Wählen Sie TABELLEN VERKNÜPFEN. Hier wird das Dialogfeld VERKNÜPFEN eingeblendet, das Sie in Abbildung 18.3 sehen.
Abbildung 18.3: Das Dialogfeld Verknüpfen
691
Eine Verknüpfung zu externen Daten erstellen
3. Markieren Sie den Namen der Datenbank, welche die Tabelle enthält, mit der Sie eine Verknüpfung anlegen wollen. 4. Klicken Sie auf die Schaltfläche VERKNÜPFEN. Nun erscheint das Dialogfeld TABELLEN VERKNÜPFEN, das in Abbildung 18.4 zu sehen ist.
Abbildung 18.4: Das Dialogfeld Tabellen verknüpfen
5. Markieren Sie die Tabellen, für die Sie eine Verknüpfung anlegen wollen. 6. Klicken Sie auf OK. Der Verknüpfungsprozess wird durchgeführt. Beachten Sie die Pfeile in Abbildung 18.5, die darauf hinweisen, dass die Tabellen tblCustomer, tblOrders und tblOrderDetails verknüpfte Tabellen sind, jedoch keine in der aktuellen Datenbank gespeicherten Tabellen.
Abbildung 18.5: Verknüpfte Tabellen im Datenbankfenster
692
Kapitel 18: Externe Daten verwenden
Verknüpfungen mit Tabellen anderen Typs erstellen Das Erstellen von Verknüpfungen mit Datenbankdateien anderen Typs verläuft ein wenig anders, und zwar folgendermaßen: 1. Klicken Sie mit der rechten Maustaste an einer beliebigen Stelle im Datenbankfenster. 2. Wählen Sie TABELLEN fen.
VERKNÜPFEN,
um das Dialogfeld VERKNÜPFEN aufzuru-
3. Wählen Sie im Listenfeld DATEITYP den Typ der zu verknüpfenden Tabelle aus. 4. Markieren Sie die externe Datei mit den zu verknüpfenden Daten. 5. Klicken Sie auf die Schaltfläche VERKNÜPFEN. Das nächste Dialogfeld richtet sich nach dem Typ der Tabelle, für die Sie eine Verknüpfung erstellen wollen. Bei einer dBase-Datei erscheint beispielsweise das Dialogfeld INDEXDATEI AUSWÄHLEN, wie in Abbildung 18.6 gezeigt. Es ist wichtig, alle Indexdateien zu markieren, die mit der Datendatei verknüpft sind. Die Indizes werden von Access beim Hinzufügen, Ändern und Löschen von Tabellendaten in Access automatisch aktualisiert. 6. Sie bekommen eine Meldung, dass der Index erfolgreich hinzugefügt wurde und Sie bei Bedarf weitere Indizes hinzufügen können. Klicken Sie auf OK. 7. Fügen Sie weitere Indizes hinzu und klicken Sie auf SCHLIESSEN. 8. Es erscheint das Dialogfeld EINDEUTIGEN DATENSATZBEZEICHNER AUSWÄHLEN, das in Abbildung 18.7 gezeigt wird. Dort können Sie für jeden Datensatz in der Tabelle einen eindeutigen Bezeichner wählen. Markieren Sie ein eindeutiges Feld und klicken Sie auf OK.
Abbildung 18.6: Das Dialogfeld Indexdateien auswählen
Eine Verknüpfung zu externen Daten erstellen
693
Abbildung 18.7: Das Dialogfeld Eindeutigen Datensatzbezeichner auswählen
Beachten Sie das Symbol, das anzeigt, mit welchem Dateityp verknüpft wurde (siehe Abbildung 18.8).
Abbildung 18.8: Ein Symbol, welches besagt, dass die Datenbank mit einer dBaseDatenbankdatei verknüpft ist
Frühere Access-Versionen unterstützten Verknüpfungen mit FoxPro-Dateien über den ISAM-Treiber von FoxPro. Bei Access 2000 und Jet 4.0 müssen Sie die Verknüpfung mit Hilfe des ODBC-Treibers von Visual FoxPro einrichten.
18.4.2
Verknüpfungen mit Hilfe von Code einrichten
Das Einrichten einer Verknüpfung mit einer externen Tabelle per Programm umfasst die folgenden sechs Schritte: 1. Erstellen Sie einen Verweis auf die Microsoft-Bibliothek ADO Extension 2.1 for DDL and Security (ADOX). 2. Legen Sie ein Catalog-Objekt an.
694
Kapitel 18: Externe Daten verwenden
3. Setzen Sie die Eigenschaft Connection des Catalog-Objekts auf die Datenbank, welche die verknüpfte Tabelle enthält. 4. Erstellen Sie ein neues Table-Objekt. 5. Legen Sie die Eigenschaften dieses Objekts fest. 6. Fügen Sie das Table-Objekt an das Ende des Catalog-Objekts an. Listing 18.4 enthält den Code für die Verknüpfung mit einer externen Tabelle, welche sich in diesem Fall in einer anderen Microsoft Access-Datenbank befindet. Listing 18.4:
Verknüpfung zu einer externen Tabelle
Sub LinkToAccessTableProps() Dim cat As ADOX.Catalog Dim tbl As ADOX.Table Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection Set tbl = New ADOX.Table tbl.Name = "tblLinkedTable" Set tbl.ParentCatalog = cat tbl.Properties("Jet tbl.Properties("Jet tbl.Properties("Jet tbl.Properties("Jet
OLEDB:Create Link") = True OLEDB:Link Datasource") = APPPATH & "\Chap18Data.mdb" OLEDB:Link Provider String") = ";pwd=password" OLEDB:Remote Table Name") = "tblClients"
cat.Tables.Append tbl End Sub
In Listing 18.4 wird ein Catalog-Objekt angelegt. Die Eigenschaft ActiveConnection dieses Objekts zeigt auf das Verbindungsobjekt, das mit der aktuellen Datenbank verknüpft ist. Als nächstes wird ein Table-Objekt erstellt. Die Eigenschaft Name dieses Objekts wird auf tblLinkedTable gesetzt und die Eigenschaft ParentCatalog des TableObjekts wird so eingerichtet, dass sie auf das Catalog-Objekt zeigt. Vier Eigenschaften der Eigenschaftenauflistung des Table-Objekts werden auf die passenden Werte gesetzt und das Objekt wird an den Katalog angehängt. Dieser Vorgang wird in den folgenden Abschnitten weiter ausgeführt. Verbindungsinformationen bereitstellen Wenn Sie eine Verknüpfung mit einer externen Tabelle einrichten, müssen Sie Informationen über Typ, Namen und Speicherort der externen Datenbank bereitstellen. Dazu dienen die folgenden Eigenschaften der Eigenschaftenauflistung des Table-Objekts:
Eine Verknüpfung zu externen Daten erstellen
695
Jet OLEDB:Link Provider String Jet OLEDB:Remote Table Name Jet OLEDB:Link Datasource Wie man den Verbindungsanbieter, den Namen und den Speicherort der Datenquelle angibt, veranschaulichen die folgenden drei Code-Zeilen: tbl.Properties("Jet OLEDB:Link Provider String") = ";pwd=password" tbl.Properties("Jet OLEDB:Remote Table Name") = "tblClients" tbl.Properties("Jet OLEDB:Link Datasource") = ADDPATH & "\Chap18Data.mdb"
Die Eigenschaft Jet OLEDB:Link Provider ist das ISAM-Format, das für die Verknüpfung benutzt werden soll. Jeder Datenbanktyp einer Quelle ist ein eigener Ordner in der Windows-Registry (im Abschnitt HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\ISAM Formats). Es folgen die gültigen Quelldatenbanktypen: dBase
dBase III, dBase IV und dBase 5.0
Excel
Excel 3.0, Excel 4.0, Excel 5.0 und Excel 8.0
HTML
HTML Export und HTML Import
Jet
Jet 2.x, Jet 3.x
Lotus
Lotus WK1, Lotus WK3, Lotus WK4, Lotus WJ2 und Lotus WJ3
Exchange
Exchange 4.0
Outlook
Outlook 9.0
Paradox
Paradox 3.x, Paradox 4.x, Paradox 5.x und Paradox 7.x
Text Die Eigenschaft Jet OLEDB:Link Datasource muss einen vollständigen Dateipfad enthalten. Sie können diesen mit Laufwerksbuchstaben und Verzeichnispfad oder durch Verwendung »allgemeiner Namenskonventionen« (UNCs) angeben. Für eine lokale Datenbank müssen Sie den Pfad folgendermaßen benennen: tbl.Properties("Jet OLEDB:Link Datasource") = "c:\Databases\Chap18Data"
Für einen Datei-Server können Sie den UNC-Pfad oder die Angabe mit dem Laufwerksbuchstaben wählen. Der UNC-Pfad sieht folgendermaßen aus: tbl.Properties("Jet OLEDB:Link Datasource") = _ "\\FILESERVERNAME\Databases\Chap18Data"
In diesem Fall ist die Datenbank Chap18Data im Datenbankteil eines bestimmten Datei-Servers abgelegt. Die Verknüpfung einrichten Listing 18.5 zeigt, wie man die Verbindungsinformationen zusammenfügt, um eine Verknüpfung mit einer externen Tabelle einzurichten.
696
Kapitel 18: Externe Daten verwenden
Listing 18.5:
Eine Verknüpfung mit einer externen Tabelle einrichten
Sub LinkToDBase(strDirName As String, strTableName As String, strAccessTable) Dim cat As ADOX.Catalog Dim tbl As ADOX.Table Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection Set tbl = New ADOX.Table tbl.Name = strAccessTable Set tbl.ParentCatalog = cat tbl.Properties("Jet tbl.Properties("Jet tbl.Properties("Jet tbl.Properties("Jet
OLEDB:Create Link") = True OLEDB:Link Datasource") = strDirName OLEDB:Link Provider String") = "dBase III;HDR=NO;IMEX=2;" OLEDB:Remote Table Name") = strTableName
cat.Tables.Append tbl End Sub
Es folgt ein Beispiel für den Aufruf dieser Unterroutine: Call LinkToDBase("c:\customer\data","customer","tblCustomers")
Die Unterroutine LinkToDBase übernimmt drei Parameter:
den Namen des Verzeichnisses, in dem die dBase-Datei gespeichert ist den Namen der zu verknüpfenden Datei (den Tabellennamen ohne die Erweiterung DBF)
den Namen der Access-Tabelle, die Sie erstellen Die Unterroutine legt zwei Objektvariablen an, eine Catalog -Objektvariable und eine Table-Objektvariable, lässt die Eigenschaft ActiveConnection der Catalog -Objektvariablen auf die mit der aktuellen Datenbank verknüpfte Verbindung zeigen und legt dann die Eigenschaften des Table-Objekts fest. Die Eigenschaft Link Datasource enthält den Namen des Verzeichnisses, in dem die dBase-Datei abgelegt ist. Die Eigenschaft Link Provider String gibt an, dass es sich beim Tabellentyp um eine dBase-IIIDatei handelt. Die Eigenschaft Remote Table Name schließlich nennt den Namen der dBase-Datei, die Sie anbinden. Danach sind Sie in der Lage, die Tabellendefinition in die Datenbank aufzunehmen. Sie haben gesehen, wie man eine Verknüpfung mit einer dBase-Tabelle einrichtet. Listing 18.6 fasst alles zusammen, was Sie in diesem Kapitel gelernt haben: es richtet eine Verknüpfung mit einer Access-Tabelle ein, die in einer anderen Datenbank gespeichert ist.
Eine externe Tabelle öffnen
Listing 18.6:
697
Eine Verknüpfung mit einer Access-Tabelle einrichten, die in einer anderen Datenbank gespeichert ist
Sub LinkToAccess(strDBName As String, strTableName As String, strAccessTable) Dim cat As ADOX.Catalog Dim tbl As ADOX.Table Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection Set tbl = New ADOX.Table tbl.Name = strAccessTable Set tbl.ParentCatalog = cat tbl.Properties("Jet tbl.Properties("Jet tbl.Properties("Jet tbl.Properties("Jet
OLEDB:Create Link") = True OLEDB:Link Datasource") = strDBName OLEDB:Link Provider String") = ";pwd=password" OLEDB:Remote Table Name") = strTableName
cat.Tables.Append tbl End Sub
Beachten Sie, dass der Jet OLEDB Link Provider String nicht mehr den Typ der Datenbank angibt, mit der verknüpft wird. Alles andere ist genauso wie in der Routine, die eine Verknüpfung mit dBase aufgebaut hat. Beachten Sie außerdem die Parameter, die dieser Routine übergeben werden: Call LinkToAccess("C:\datenbanken\nordwind","Kunden","tblCustomers")
Die übergebene Datenbank ist eine echte Access-Datenbank (kein Verzeichnis) und der Tabellenname ist der Name der Access-Tabelle in der anderen Datenbank (nicht der DBF-Dateiname). Unabhängig davon, ob Sie eine externe Tabelle mit Hilfe der Benutzerschnittstelle oder mittels Code verknüpfen – Sie sollten grundsätzlich den UNC-Pfad benutzen, nicht den Pfad mit dem Laufwerksbuchstaben. Dadurch wird gewährleistet, dass alle, die Zugriff auf das Netzlaufwerk haben, die Daten sehen können – ohne Rücksicht auf die Zuordnung von Laufwerksbuchstaben.
18.5
Eine externe Tabelle öffnen
Im Allgemeinen ist die Verknüpfung mit einer externen Tabelle günstiger als das direkte Öffnen. Es bietet höhere Leistung und leichtere Benutzbarkeit. Nach dem Einrichten der Verknüpfung wird die Tabelle genauso behandelt wie jede andere Access-Tabelle. Gelegentlich ist es jedoch erforderlich, eine externe Tabelle zu öff-
698
Kapitel 18: Externe Daten verwenden
nen, ohne eine Verknüpfung zu erstellen. Das Öffnen einer externen Tabelle erfolgt in zwei Schritten: 1. Einrichten einer Verbindung mit der externen Datenquelle 2. Versehen eines Datensatzobjekts mit einem Zeiger auf das Ergebnis der Ausführung einer SQL-Anweisung für das Verbindungsobjekt
18.5.1
Verbindungsinformationen liefern
Die Verbindungsinformationen, die Sie beim Öffnen einer externen Tabelle liefern, entsprechen denen beim Verknüpfen mit der Tabelle. Sie werden in Form des Arguments ConnectionString der Methode Open oder des Objekts Connection bereitgestellt. Es folgt ein Beispiel: cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _ "c:\Eigene Dateien\tblCustomers.xls;" & _ _ "Extended Properties=Excel 8.0;"
Hier führt die Verbindungszeichenfolge zum Arbeitsblatt c:\Eigene Dateien \tblCustomers.xls mit ISAM Version 8.0.
18.5.2
Die Tabelle öffnen
Das Recordset-Objekt wird so gesetzt, dass es auf das Ergebnis der Ausführung einer Select-Anweisung für das Connection-Objekt verweist: Set rst = cnn.E XE cute("Select * from tblCustomers")
Listing 18.7 zeigt, wie dieser Vorgang als Code aussieht. Listing 18.7:
Die Methode OpenDatabase
Sub OpenExternalExcel(strDBName As String, strTableName As String) Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Set cnn = New ADODB.Connection Set rst = New ADODB.Recordset cnn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" & _ strDBName & "\" & strTableName & _ ";Extended Properties=Excel 8.0;" Set rst = cnn.Execute("Select * from tblCustomers") Do Until rst.EOF Debug.Print rst.Fields(0).Value rst.MoveNext Loop
Die Einstellungen in der Windows-Registry
699
cnn.Close End Sub
Es wird mit folgender Zeile aufgerufen: Call OpenExternalExcel("c:\Eigene Dateien","tblCustomers.xls")
Beachten Sie, dass hier keine Tabellendefinition angehängt, sondern eine temporäre Datensatzgruppe erstellt wird, welche auf die externen Daten verweist. Nach dem Öffnen der externen Tabelle als Datensatzgruppe durchläuft der Code alle Datensätze der Tabelle und gibt den Wert des ersten Feldes aus. Die Datensatzgruppe lässt sich natürlich beliebig bearbeiten, nachdem sie geöffnet wurde. Die Tabelle wird im Datenbankfenster nicht als verknüpfte Tabelle gekennzeichnet. Wenn die Routine abgeschlossen ist und die lokale Variable ungültig wird, existiert die Datensatzgruppe im Grunde nicht mehr. Nachdem Sie jetzt gesehen haben, wie man eine Verknüpfung zu einer externen Tabelle herstellt und wie man die Tabelle öffnet, sind Sie bereit, einen Blick darauf zu werfen, wie sich diese beiden Vorgänge verfeinern lassen. Das umfasst folgende Lerninhalte: die Einstellungen in der Windows-Registry, welche den Verknüpfungsvorgang betreffen, die Parameter, die bei der Angabe der Verbindungsinformationen zur Verfügung stehen, die Angabe von Kennwörtern, das Aktualisieren und Löschen von Verknüpfungen und das Erstellen einer externen Tabelle mit Hilfe von VBACode.
18.6
Die Einstellungen in der Windows-Registry
Jeder ISAM-Treiber besitzt in der Windows-Registry einen eigenen Schlüssel. Diese Schlüssel befinden sich unter dem jeweiligen ISAM-Treiber im Abschnitt HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\ISAM Formats der Windows-Registry. Sie werden dazu verwendet, den ISAM-Treiber nach der Initialisierung zu konfigurieren. Wie Sie in Abbildung 18.9 sehen können, hat das Einrichtungsprogramm Schlüssel für mehrere Datenquellen erstellt. Wenn Sie sich eine bestimmte Datenquelle ansehen (in diesem Fall dBase III), finden Sie alle für den dBase-Treiber vorhandenen Einstellungen. Die Eigenschaft IndexFilter ist zum Beispiel auf dBaseIndex(*.ndx) gesetzt. Manchmal müssen Sie eine der Registry-Einstellungen verändern, um das Verhalten des ISAM-Treibers anzupassen, was weiter hinten in diesem Kapitel im Abschnitt »Spezielle Überlegungen« behandelt wird.
700
Kapitel 18: Externe Daten verwenden
Abbildung 18.9: Die WindowsRegistry mit Schlüsseln für ISAM-Treiber
18.7
Die Eigenschaft Jet OLEDB:Link Provider String
Die Eigenschaft Jet OLEDB:Link Provider String umfasst den Typ der Quelldatenbank, die Benutzer-ID und das Kennwort. Jeder Bestandteil dieser Verbindungszeichenfolge muss durch ein Semikolon abgetrennt werden. Jeder Quelldatenbanktyp verfügt über einen gültigen Namen. Das ist der Name, der beim Zugriff auf Daten dieses Typs verwendet werden muss. Es handelt sich um die Typen, die unter HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\ISAM Formats in der Windows-Registry stehen. Der Typ der Quelldatenbank muss korrekt angegeben werden, sonst ist der Zugriff auf die externen Daten nicht möglich. Die Benutzer-ID wird immer dann verwendet, wenn ein Benutzername angegeben werden muss, um sich erfolgreich bei der Datenquelle anzumelden. Dies kommt am häufigsten vor, wenn es um Back-End-Datenbanken wie Oracle, Sybase oder Microsoft SQL Server geht. Dieser Bestandteil der so genannten Anbieterzeichenfolge kann zur Anmeldung des Benutzers bei dem System erforderlich sein, auf dem die Quelldaten liegen. Das Schlüsselwort UID verweist auf die Benutzer-ID. Wie die Benutzer-ID wird das Kennwort meistens im Zusammenhang mit BackEnd-Daten genannt. Es kann auch für andere Datenbanktypen, die Kennwörter unterstützen, z.B. Paradox, oder beim Verknüpfen mit einer externen Access-Tabelle verwendet werden. Bei der Angabe des Kennworts wird das Schlüsselwort PWD benutzt. Der Name der Datengruppe wird schließlich verwendet, um eine definierte ODBCDatenquelle zu bezeichnen. Die Kommunikation mit einer solchen wird in Kapitel 19 ausführlich besprochen. Das Schlüsselwort DSN in der Verbindungszeichenfolge
Mit Kennwörtern arbeiten
701
verweist auf den Namen der Datengruppe. Es folgt ein Beispiel für die Eigenschaft Jet OLEDB:Link Provider String: tblProperties("Jet OLEDB:Link Provider String") = "ODBC" & _ ";DATABASE=Pubs" & _ ";UID=Alison" & _ ";PWD=MyPass" & _ ";DSN=PublisherData"
In diesem Beispiel lautet der Name der SQL Server-Datenbank, auf die zugegriffen wird, Pubs, die Benutzer-ID Alison, das Kennwort MyPass und der Name der Datenquelle PublisherData.
18.8
Mit Kennwörtern arbeiten
Bei der Arbeit mit Kennwörtern bietet es sich nicht an, diese fest in den Code aufzunehmen, weil damit der Zweck der Maßnahme, die Datenbank mit einem Kennwort zu versehen, nicht erreicht wird. In Listing 18.8 ist das Kennwort für die Datenbank im Code enthalten. Damit kann die Verknüpfung zu der abgesicherten Tabelle ohne Kennwortauswertung hergestellt werden. Listing 18.8:
Ein Kennwort für eine Datenbank in den Code einbetten
Sub LinkToSecured() Dim cat As ADOX.Catalog Dim tbl As ADOX.Table Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection Set tbl = New ADOX.Table tbl.Name = "tblLinkedTable" Set tbl.ParentCatalog = cat tbl.Properties("Jet OLEDB:Create Link") = True tbl.Properties("Jet OLEDB:Link Provider String") = "ODBC" & _ ";DATABASE=Pubs" & _ ";UID=SA" & _ ";PWD=" & _ ";DSN=PubsData" tbl.Properties("Jet OLEDB:Remote Table Name") = "Authors" cat.Tables.Append tbl End Sub
Ein ungültiges Kennwort führt zu einer Meldung, die eine Anmeldung des Benutzers fordert. Wenn Sie sich nicht unter Verwendung der integrierten Sicherheit von
702
Kapitel 18: Externe Daten verwenden
Windows NT bei Ihrem Datenbank-Server anmelden, ist es am günstigsten, den Benutzer während der Laufzeit zur Angabe seines Kennwortes aufzufordern. In Listing 18.9 wurde das Kennwortargument leer gelassen. Das führt dazu, dass der Benutzer nach einem Kennwort gefragt wird. Listing 18.9:
Kennwortauswertung fordern
Sub ReallySecure() Dim cat As ADOX.Catalog Dim tbl As ADOX.Table Dim strPassword As String Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection Set tbl = New ADOX.Table tbl.Name = "tblLinkedTable" Set tbl.ParentCatalog = cat strPassword = InputBox("Please Enter Your Password", "Database Security!!!") tbl.Properties("Jet OLEDB:Create Link") = True tbl.Properties("Jet OLEDB:Link Provider String") = "ODBC" & _ ";DATABASE=Pubs" & _ ";UID=SA" & _ ";PWD=" & strPassword & _ ";DSN=PubsData" tbl.Properties("Jet OLEDB:Remote Table Name") = "Authors" cat.Tables.Append tbl End Sub
Der Benutzer gibt das Kennwort ein, das dann in einer Variablen mit dem Namen strPassword gespeichert wird. Diese Variable wird zur Laufzeit in die Verbindungszeichenfolge eingefügt.
18.9
Verknüpfungen aktualisieren und löschen
Das »Aktualisieren von Verknüpfungen« findet statt, wenn sich der Speicherort einer externen Tabelle geändert hat. Mit dem »Löschen von Verknüpfungen« wird die dauerhafte Entfernung einer Verknüpfung mit einer externen Tabelle bezeichnet. Access kann externe Tabellen nicht finden, wenn sich ihr Speicherort geändert hat. Für diesen Fall müssen Sie in Ihrem VBA-Code Vorkehrungen treffen. Außerdem könnte es vorkommen, dass Sie eine Verknüpfung mit externen Daten löschen möchten – wenn diese nicht mehr gebraucht werden oder permanent in Access importiert wurden.
Verknüpfungen aktualisieren und löschen
18.9.1
703
Verknüpfungen aktualisieren, die verschoben wurden
Um eine Verknüpfung mit Hilfe von VBA-Code zu aktualisieren, definieren Sie lediglich die Eigenschaft Jet OLEDB:Link Datasource neu. Listing 18.10 zeigt den dazu nötigen Code. Listing 18.10: Eine Verknüpfung aktualisieren Sub RefreshLink() Dim cat As ADOX.Catalog Dim tdf As ADOX.Table Set cat = New ADOX.Catalog Set cat.ActiveConnection = CurrentProject.Connection tdf.Properties("Jet OLEDB:LinkDatasource") = _ strNewLocation End Sub
Diese Routine lässt sich so verändern, dass der Benutzer nach dem Verzeichnis gefragt wird, das die Datentabellen enthält, wie Listing 18.11 zeigt. Listing 18.11: Den Benutzer nach dem Pfad und dem Namen der Datenbank fragen Sub RefreshLink() On Error GoTo RefreshLink_Err Dim cat As ADOX.Catalog Dim tdf As ADOX.Table Dim strNewLocation As String Dim strTemp As String Set cat = New ADOX.Catalog Set cat.ActiveConnection = CurrentProject.Connection Set tdf = cat.Tables("tblClients") strTemp = tdf.Columns(0).Name Exit Sub RefreshLink_Err: strNewLocation = InputBox("Please Enter Database Path and Name") tdf.Properties("Jet OLEDB:Link Datasource") = _ strNewLocation Set cat.ActiveConnection = CurrentProject.Connection Set tdf = cat.Tables("tblClients") Resume End Sub
Diese Routine versieht ein Table-Objekt mit einem Zeiger auf die Tabelle tblClients. Dann versucht sie, auf den Namen der ersten Tabellenspalte zuzugreifen. Wenn ein Fehler auftritt, fragt ein Eingabefeld den Benutzer nach dem neuen Speicherort der Datenbank. Die Eigenschaft Jet OLEDB:Link Datasource für die Datenbank wird auf
704
Kapitel 18: Externe Daten verwenden
den neuen Namen geändert. Dann wird die Ausführung des Codes in der zunächst fehlerhaften Zeile wieder aufgenommen. Sie sollten diese Routine so ändern, dass der Benutzer eine Möglichkeit erhält, sie zu verlassen. Die Anweisung Resume versetzt ihn in eine Endlosschleife, falls die Datenbank nicht zu finden ist. Eine erweiterte Routine (Listing 18.13) wird später im Abschnitt »Praktische Beispiele« dieses Kapitels vorgestellt.
18.9.2
Verknüpfungen löschen
Um eine Verknüpfung mit Hilfe von VBA-Code zu löschen, führen Sie einfach die Methode Delete der Auflistung Tables eines mit der Datenbank verknüpften CatalogObjekts aus, wie in Listing 18.12 gezeigt. Listing 18.12: Eine Verknüpfung löschen Sub RemoveLink() Dim cat As Catalog Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection cat.Tables.Delete ("tblClients") End Sub
18.10
Spezielle Überlegungen
Im Zusammenhang mit unterschiedlichen Typen externer Dateien zeigen sich verschiedene Fragen und Probleme. Wenn Sie diese Stolpersteine verstehen, bevor Sie darauf stoßen, haben Sie beim Umgang mit diesen potentiellen Hindernissen einen gewaltigen Vorsprung.
18.10.1 dBase Die meisten Sorgen im Umgang mit dBase-Dateien kreisen um gelöschte Datensätze, Indizes, Datentypen und Memo-Felder. Wenn Sie einen Datensatz aus einer dBase-Tabelle löschen, wird er nicht wirklich entfernt, sondern nur zum Löschen markiert. Um die Datensätze tatsächlich aus der Tabelle zu löschen, muss ein PackProzess stattfinden. Wenn Datensätze mit Hilfe einer Access-Anwendung aus einer dBase-Tabelle gelöscht werden, werden sie ebenfalls nicht entfernt. Da sich eine dBase-Datenbank aber nicht aus einer Access-Anwendung heraus packen lässt, verbleiben die Datensätze noch in der Tabelle. Sie werden im Grunde nicht automatisch aus der Access-Tabelle herausgefiltert. Um gelöschte Datensätze herauszufiltern, damit sie innerhalb der Access-Anwendung nicht mehr sichtbar sind, muss der Wert
Spezielle Überlegungen
705
Gelöscht im Abschnitt \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Xbase auf 01 (True) gesetzt werden.
Access kann die dBase-Indizes zur Verbesserung der Leistung einsetzen. Nachdem Sie eine Verknüpfung zu einer dBase-Tabelle erstellt und einen Index gewählt haben, wird eine INF-Datei angelegt. Diese trägt denselben Namen wie Ihre dBase-Datenbank und die Erweiterung INF. Sie enthält Informationen über alle verwendeten Indizes. Es folgt ein Beispiel für eine solche Datei: [dBase III] NDX1=CUSTID.NDX UNDX1=CUSTID.NDX
dBase III ist die Bezeichnung für den Datenbanktyp, NDX1 eine Indexnummer für den ersten Index und der Eintrag UNDX1 bezeichnet einen eindeutigen Index.
Die in dBase-Dateien zur Verfügung stehenden Datentypen sind andere als in AccessDateien. Es ist wichtig, die Zuordnung der Feldtypen zu verstehen. Tabelle 18.4 zeigt, wie die einzelnen dBase-Datentypen einem Jet-Datentyp zuzuordnen sind. dBase-Datentyp
Jet-Datentyp
Character
Text
Numeric, float
Double
Logical
Boolean
Date
Date/Time
Memo
Memo
OLE
OLE Object
Tabelle 18.4: Zuordnung der dBase-Datentypen
Schließlich ist es noch wichtig, sicherzustellen, dass die dBase-Memo-Dateien im gleichen Verzeichnis wie die Tabelle abgelegt werden, da Access die Daten in der Memo-Datei sonst nicht lesen kann.
18.10.2 Textdaten Beim Verknüpfen mit einer ASCII-Textdatei kann Jet das Format dieser Datei direkt ermitteln oder eine Schemainformationsdatei nutzen, die sich im gleichen Verzeichnis wie die Textdatei befindet. Sie heißt immer SCHEMA.INI und enthält Informationen über Format, Spaltennamen und Datentypen der Datei. Diese Datei ist für Dateien mit Begrenzern optional, für Dateien mit fester Länge jedoch erforderlich. Sie müssen unbedingt wissen, dass sich ASCII-Dateien nicht für die gemeinsame Nutzung öffnen lassen.
706
Kapitel 18: Externe Daten verwenden
18.11
Problemlösung
Leider verläuft die Arbeit mit externen Dateien nicht immer glatt. Vieles kann schiefgehen und außerdem gibt es Verbindungsprobleme und temporären Speicherplatzmangel.
18.11.1 Verbindungsprobleme Schwierigkeiten beim Zugriff auf externe Daten können durch folgende Umstände ausgelöst werden:
Der Server, auf dem die externen Daten abgelegt sind, ist nicht in Betrieb. Der Benutzer besitzt keine Berechtigung für das Verzeichnis, in dem die externen Daten abgelegt sind.
Der Benutzer besitzt keine Rechte für die externe Datenquelle. Die externe Datenquelle wurde verschoben. Der UNC-Pfad oder der Name des Netzlaufwerks wurde verändert. Die Verbindungszeichenfolge ist nicht korrekt. Der installierbare ISAM-Treiber ist nicht installiert.
18.11.2 Temporärer Speicherplatz Access benötigt eine beträchtliche Menge Speicherplatz auf der Festplatte, um komplexe Abfragen an umfangreichen Tabellen auszuführen. Dieser ist sowohl für verknüpfte Tabellen, die in einem anderen Format entfernt gespeichert sind, als auch für Tabellen auf dem lokalen Rechner erforderlich. Wenn für eine Abfrage nicht genug Speicherplatz zur Verfügung steht, ist das Verhalten der Anwendung nicht vorhersehbar. Deshalb muss unbedingt sichergestellt werden, dass allen Benutzern genügend Speicherplatz für die beabsichtigen Abfragen zur Verfügung steht.
18.12
Leistung und Verknüpfungen
Da Ihre Anwendung eine zusätzliche Übersetzungsschicht durchqueren muss (den installierbaren ISAM-Treiber), ist die Leistung bei ISAM-Dateien längst nicht so hoch wie bei nativen Jet-Daten. Es ist immer am günstigsten, ISAM-Daten nach Möglichkeit zu importieren. Wenn das nicht möglich ist, müssen Sie sich mit der Leistung zufrieden geben, die Verknüpfungen bieten, oder das Verknüpfen als beste Lösung für ein sonst nicht lösbares Problem betrachten.
Mit HTML-Dokumenten arbeiten
18.13
707
Mit HTML-Dokumenten arbeiten
Access 2000 ermöglicht das Importieren, Exportieren und Verknüpfen von bzw. mit HTML-Dokumenten. Obwohl die Arbeit mit HTML-Dokumenten der Arbeit mit anderen Datentypen entspricht, verdient sie besondere Erwähnung. Um ein HTMLDokument zu importieren, ist Folgendes erforderlich: 1. Klicken Sie mit der rechten Maustaste auf eine beliebige Stelle im Datenbankfenster und wählen Sie IMPORTIEREN. 2. Markieren Sie im aufklappbaren Listenfeld DATEITYP den Eintrag HTMLDOKUMENTE (*.HTML; *.HTM). 3. Markieren Sie das zu importierende Dokument und klicken Sie auf IMPORTIEREN. Daraufhin erscheint der Assistent für den HTML-Import, den Sie in Abbildung 18.10 sehen.
Abbildung 18.10: Der erste Schritt des HTML-Import-Assistenten
4. Der erste Schritt des Assistenten versucht, das HTML-Dokument in Felder zu zerlegen. Sie können die Arbeit des Assistenten akzeptieren oder auf WEITERE klicken. Im Dialogfeld IMPORTSPEZIFIKATIONEN, das jetzt eingeblendet wird, können Sie Feldnamen, Datentyp und Index für jedes Feld angeben und Felder markieren, die Sie aus der importierten Datei entfernen wollen (siehe Abbildung 18.11). Sie können dort auch die Datumsreihenfolge, die Trennzeichen und anderes ändern.
708
Kapitel 18: Externe Daten verwenden
5. Nach den erforderlichen Änderungen an den Importspezifikationen klicken Sie auf OK, um zum Assistenten für den HTML-Import zurückzukehren. Klicken Sie auf WEITER, um zum nächsten Schritt zu kommen, in dem Sie wählen können, ob die importierten Daten in einer neuen oder einer vorhandenen Tabelle gespeichert werden sollen. Treffen Sie Ihre Wahl und klicken Sie auf WEITER. 6. Der dritte Schritt des Assistenten ermöglicht die Angabe eines Feldnamens, eines Datentyps und eines Index für jedes Feld, wie in Abbildung 18.12 gezeigt wird. Nehmen Sie die gewünschten Änderungen vor und klicken Sie auf WEITER.
Abbildung 18.11: Im Dialogfeld Importspezifikationen können Sie die Einzelheiten für den Import angeben
7. Der vierte Schritt ermöglicht die Angabe, ob Sie einen Primärschlüssel für die Datei wünschen, die Auswahl eines eigenen Primärschlüssels oder den Verzicht auf einen solchen. Treffen Sie Ihre Wahl und klicken Sie auf WEITER. 8. Im letzten Schritt können Sie der Tabelle einen Namen zuweisen. Außerdem können Sie durch den Assistenten die Tabelle nach dem Import analysieren lassen. Klicken Sie auf FERTIG STELLEN, nachdem Sie Ihre Wahl getroffen haben. Sie können ein HTML-Dokument nicht nur importieren, sondern auch eine Verknüpfung mit diesem einrichten. Dazu unternehmen Sie Folgendes: 1. Klicken Sie mit der rechten Maustaste auf eine beliebige Stelle im Datenbankfenster und wählen Sie TABELLEN VERKNÜPFEN. 2. Markieren Sie im Listenfeld DATEITYP den Eintrag HTML-DOKUMENTE (*.HTML; *.HTM).
Mit HTML-Dokumenten arbeiten
709
Abbildung 18.12: Anpassung der Eigenschaften der importierten Felder
3. Markieren Sie die zu verknüpfende Tabelle und klicken Sie auf VERKNÜPFEN. Daraufhin erscheint der HTML-Verknüpfungs-Assistent. 4. Klicken Sie auf die Schaltfläche WEITERE, um Verknüpfungsspezifikationen zu ändern, und kehren Sie zum ersten Schritt des Assistenten zurück. Klicken Sie auf WEITER, um zum zweiten Schritt zu gelangen. 5. Im zweiten Schritt können Sie Informationen über die einzelnen Felder angeben, die an der Verknüpfung beteiligt sein sollen. Nehmen Sie die gewünschten Änderungen vor und klicken Sie auf WEITER. 6. Geben Sie einen Namen für die verknüpfte Tabelle ein und klicken Sie auf FERTIG STELLEN. Während sich ein importiertes HTML-Dokument genauso verhält wie jede andere Access-Tabelle, lassen sich die Daten in einem verknüpften HTML-Dokument von Access aus nicht ändern. Sie können das verknüpfte Dokument verwenden, um Abfragen, Berichte und Formulare zu erstellen.
18.13.1 Für die Praxis Aus einer Anwendung heraus mit externen Daten arbeiten Es ist Zeit, die Datentabellen von den übrigen Anwendungsobjekten zu trennen. Das lässt sich mit dem Assistenten zur Datenbankaufteilung mühelos erledigen. Danach müssen Sie Code schreiben, der die Verknüpfungen aktualisiert. Beide Themen kommen in diesem Abschnitt zur Sprache.
710
Kapitel 18: Externe Daten verwenden
18.13.2 Die Datenbank mit Hilfe des Assistenten zur Datenbankaufteilung trennen
Verwenden Sie zuerst den Assistenten zur Datenbankaufteilung (beschrieben in Kapitel 17), um die Tabellen von den übrigen Datenbankobjekten zu trennen. Die Dateien CHAP18.MDB und CHAP18DATA.MDB finden Sie auf der CD-ROM mit dem Beispiel-Code. Die Datei CHAP18DATA.MDB enthält alle Tabellen, die Datei CHAP18.MDB die übrigen Datenbankobjekte.
18.13.3 Verknüpfungen aktualisieren Wenn Sie die Beispielanwendung »Time and Billing« verteilt installiert hätten und nicht für alle Benutzer derselbe Pfad zur Datei CHAP18DATA.MDB korrekt gewesen wäre, wäre die Anwendung nicht erfolgreich geladen worden. Die Routine LinkTables im anfänglichen Übersichtsformular stellt sicher, dass die Tabellen erfolgreich verknüpft sind, wie Listing 18.13 zeigt. Listing 18.13: Die Anwendung laden und Tabellenanlagen überprüfen Sub LinkTables() On Error GoTo LinkTables_Err:
DoCmd.Hourglass True If Not VerifyLink Then If Not ReLink(CurrentProject.FullName, True) Then MsgBox "You Must Locate Tables to Proceed" Me.dlgCommon.ShowOpen If Not ReLink(Me.dlgCommon.FileName, False) Then MsgBox "You Cannot Run This App Without Locating Data Tables" DoCmd.Close acForm, "frmSplash" DoCmd.Quit End If End If End If Call GetCompanyInfo DoCmd.Hourglass False Exit Sub LinkTables_Err: DoCmd.Hourglass False MsgBox "Error # " & Err.Number & ": " & Err.Description
Mit HTML-Dokumenten arbeiten
711
Exit Sub End Sub
Beachten Sie, dass die Routine LinkTables die Routine VerifyLink aufruft. Diese finden Sie in Listing 18.14. Listing 18.14: Die Routine VerifyLink prüft, ob Tabellenverknüpfungen ungültig geworden sind. Function VerifyLink() As Boolean 'Verbindungsinformationen in verknüpften Tabellen überprüfen. 'Erforderliche Variablen deklarieren. Dim cat As ADOX.Catalog Dim tdf As ADOX.Table Dim strTemp As String 'Objektvariable der Datenbank mit Zeiger auf die aktuelle Datenbank versehen. Set cat = New ADOX.Catalog With cat Set .ActiveConnection = CurrentProject.Connection 'Fortsetzen, falls Verknüpfungen ungültig sind. On Error Resume Next 'Eine verknüpfte Tabelle öffnen, um zu prüfen, 'ob die Verbindungsinformationen korrekt sind. For Each tdf In .Tables If tdf.Type = "LINK" Then strTemp = tdf.Columns(0).Name Exit For End If Next tdf
End With VerifyLink = (Err.Number = 0) End Function
Die Routine setzt zuerst die Eigenschaft ActiveConnection des Catalog-Objekts auf die Verbindung, die mit der aktuellen Datenbank verknüpft ist. Dann durchläuft sie alle Tabellen in der Auflistung Tables dieses Objekts in einer Schleife. Wenn sie auf eine verknüpfte Tabelle trifft, versucht sie, auf den Namen der ersten Tabellenzeile zuzugreifen. Bei ungültigen Verknüpfungen tritt ein Fehler auf und die For...Each-
712
Kapitel 18: Externe Daten verwenden
Schleife wird verlassen. Wenn kein Fehler vorkommt, gibt die Funktion True zurück, sonst False. Wenn die Routine VerifyLink den Wert False zurückgibt, wird die Routine ReLink aufgerufen, die in Listing 18.15 abgedruckt ist. Listing 18.15: Die Routine ReLink versucht, ungültig gewordene Tabellenverknüpfungen neu einzurichten Function ReLink(strDir As String, DefaultData As Boolean) _ As Boolean 'Eine ungültig gewordene Verknüpfung mit einer Access-Tabelle erneut einrichten. Dim Dim Dim Dim Dim Dim Dim
cat As ADOX.Catalog tdfRelink As ADOX.Table oDBInfo As DBInfo strPath As String strName As String intCounter As Integer vntStatus As Variant
vntStatus = SysCmd(acSysCmdSetStatus, "Updating Links") Set cat = New ADOX.Catalog Set oDBInfo = New DBInfo With cat .ActiveConnection = CurrentProject.Connection oDBInfo.FullName = strDir strPath = oDBInfo.FilePathOnly strName = Left(oDBInfo.FileName, InStr(oDBInfo.FileName, ".") – 1) On Error Resume Next Call SysCmd(acSysCmdInitMeter, "Linking Data Tables", .Tables.Count) For Each tdfRelink In .Tables intCounter = intCounter + 1 Call SysCmd(acSysCmdUpdateMeter, intCounter) If .Tables(tdfRelink.Name).Type = "LINK" Then tdfRelink.Properties("Jet OLEDB:Link Datasource") = strPath & _ strName & IIf(DefaultData, "Data.Mdb", ".mdb") End If If Err.Number Then Exit For End If Next tdfRelink
Mit HTML-Dokumenten arbeiten
713
End With Call SysCmd(acSysCmdRemoveMeter) vntStatus = SysCmd(acSysCmdClearStatus) ReLink = (Err = 0) End Function
Die Funktion ReLink übernimmt zwei Parameter: den Namen der Datenbank, mit der eine Verknüpfung eingerichtet werden soll, und eine Variable des Typs Boolean, mit deren Hilfe festgelegt wird, ob es sich um die Standarddatenbank handeln soll. Die Funktion beginnt mit einer Veränderung der Statusleiste. Dann werden ein Catalog-Objekt und eine Instanz einer benutzerdefinierten Klasse mit dem Namen DBInfo erstellt. Diese Klasse wird in Kapitel 37 ausführlich beschrieben und Klassenmodule werden in Kapitel 28 behandelt. Die Eigenschaft ActiveConnection des Catalog-Objekts wird auf die Eigenschaft Connection des aktuellen Projekts gesetzt. Als nächstes wird die Eigenschaft FullName der Klasse DBInfo auf den Namen der Datei festgelegt, die der Funktion als Parameter übergeben wurde. Die Klasse extrahiert aus dem vollständigen Namen der Datei den Pfad und den Dateinamen. Genauso wie die Funktion VerifyLink verwendet die Funktion ReLink eine For...Next-Schleife, um alle Tabellen der Datenbank durchzugehen. Dabei versucht sie, eine Verknüpfung mit einer Datenbank mit dem Namen einzurichten, den sie als Parameter bekommen hat. Die in Listing 18.13 vorgestellte Routine LinkTables ruft die Funktion ReLink zweimal auf. Beim ersten Mal haben die Eigenschaft FullName des Objekts CurrentProject und die Variable des Typs Boolean den Wert True, d.h. die Routine versucht, die Tabelle in einer Datenbank am selben Speicherort wie die Anwendungsdatenbank zu finden. Wenn das keinen Erfolg hat, blendet sie das vertraute Dialogfeld DATEI ÖFFNEN ein, das dem Benutzer ermöglicht, die Datenbank zu suchen. Wenn auch das erfolglos bleibt, wird die Anwendung abgebrochen.
Client-Server-Techniken
Kapitel
Hier lesen Sie:
Entscheiden, ob das Client-Server-Modell eingesetzt werden soll Die Rollen, die Access im Anwendungsentwurfsmodell spielt Die Client-Server-Schlagworte Upsizing: Was zu bedenken ist Der Upsizing-Assistent Eine ODBC-Datenquelle definieren Mit verknüpften Tabellen arbeiten Pass-Through-Abfragen Gespeicherte Prozeduren ausführen und erstellen Mit Hilfe eines Microsoft Access-Datenprojekts auf Client-Server-Daten zugreifen
19.1
Das Client-Server-Modell
»Client-Server« ist einer der »heißen« Begriffe der Computerwelt der neunziger Jahre. Er bezeichnet die verteilte Verarbeitung von Informationen. Das umfasst die Speicherung von Daten auf Datenbank-Servern, die für die Aufgaben der Verarbeitung und Speicherung der Daten reserviert sind. Sie werden als »Back-Ends« bezeichnet. Ein Front-End-Werkzeug wie Microsoft Access ist für die Präsentation der Daten zuständig. Microsoft Access stellt in Verbindung mit seinen Werkzeugen, die zur schnellen Entwicklung von Abfragen, Formularen und Berichten beitragen, ein hervorragendes Front-End für die Präsentation von Back-End-Daten dar. Da immer mehr Anwendungen von Großrechnern und von PCs auf Server portiert werden, müssen immer mehr Benutzer die Einzelheiten der Client-Server-Technologie verstehen.
716
Kapitel 19: Client-Server-Techniken
Jahrelang haben die meisten EDV-Fachleute mit herkömmlichen Programmiersprachen gearbeitet. Diese sind sowohl für die Verarbeitung der Daten als auch für die Erhaltung der Datenintegrität innerhalb der Anwendung zuständig. Das bedeutet, dass die Regeln für die Gültigkeitsprüfung der Daten in den Programm-Code eingebettet werden müssen. Außerdem arbeiten Anwendungen dieser Art datensatzorientiert. Alle Datensätze werden in den Arbeitsspeicher gelesen und verarbeitet. Dieses Verfahren besitzt einige Nachteile:
Wenn sich die zu Grunde liegende Datenstruktur ändert, muss jede Anwendung geändert werden, die mit ihr arbeitet.
Die Regeln für die Prüfung der Daten auf Gültigkeit müssen in jede Anwendung integriert werden, die auf eine Datentabelle zugreift.
Präsentation, Verarbeitung und Speicherung werden von einem einzigen Programm erledigt.
Datensatzorientierte Verarbeitung führt zu außergewöhnlich hohem, überflüssigem Netzwerkverkehr. Das Client-Server-Modell führt eine Funktionstrennung ein. Der »Client« bzw. das Front-End ist für die Präsentation der Daten und ein gewisses Maß an Verarbeitung zuständig, während der »Server« bzw. das Back-End die Speicherung, den Schutz und den wesentlichen Teil der Verarbeitung der Daten übernimmt.
19.2
Soll das Client-Server-Modell eingesetzt werden?
Die Client-Server-Technologie war weniger notwendig, als es eine deutliche Trennlinie zwischen Anwendungen für Großrechner und für PCs gab. Heute hat sich diese Grenze verwischt. PC-Anwendungen übernehmen viele Aufgaben, die in der Vergangenheit Großrechnern übertragen wurden. Das Problem liegt darin, dass die Benutzer immer noch durch die Bandbreite der Netzwerke eingeschränkt sind. Das ist eine Stelle, an der die Client-Server-Technologie wirklich helfen kann. Viele Entwickler wissen nicht wirklich, was die Client-Server-Technologie eigentlich ist. (Ich habe tatsächlich an vielen Diskussionen teilgenommen, in denen andere Entwickler darauf bestanden, Access sei eine Anwendung für Datenbank-Server. Das stimmt aber nicht.) Access ist eine Front-End-Anwendung, die auf einem BackEnd-Server gespeicherte Daten verarbeiten kann. In diesem Szenario läuft die Access-Anwendung auf einem Client-Rechner, der auf Daten auf einem DatenbankServer mit Software wie Microsoft SQL Server zugreift. Access arbeitet als FrontEnd-Software auf der Client-Seite hervorragend. Die Verwirrung ergibt sich aus der Fähigkeit von Access, auch als Datenbank-Server zu fungieren.
Soll das Client-Server-Modell eingesetzt werden?
717
Viele Leute meinen zu Unrecht, eine auf einem Datei-Server gespeicherte AccessMDB-Datenbankdatei fungiere als Datenbank-Server. Das ist nicht der Fall. Der Unterschied liegt in der Art und Weise, wie Daten geholt werden, wenn Access als Front-End für einen Datenbank-Server fungiert bzw. wenn die Daten in einer MDBDatei gespeichert sind. Nehmen Sie an, Sie haben eine Tabelle mit 500 000 Datensätzen. Ein Benutzer startet eine Abfrage auf der Grundlage dieser Tabelle, die in einer Access-Datenbank auf einem Datei-Server abgelegt ist. Er will eine Liste aller Deutschen mit einem Jahreseinkommen von mehr als 75 000 DM haben. Da die Daten im Access MDB-Dateiformat auf einem Datei-Server abgelegt sind, werden alle Datensätze über das Netzwerk an die Arbeitsstation gesendet, und die Abfrage wird auf der Arbeitsstation durchgeführt (siehe Abbildung 19.1). Das führt zu erheblichem Verkehr im Netzwerk.
Abbildung 19.1: Access als Front-End und Back-End
Nehmen Sie nun an, dass diese 500 000 Datensätze auf einem Datenbank-Server wie Microsoft SQL Server liegen. Der Benutzer startet dieselbe Abfrage. In diesem Fall werden nur die Namen der Deutschen mit einem Jahreseinkommen von mehr als 75 000 DM über das Netzwerk gesendet. Im Grunde werden nur spezielle Felder angefordert und nur diese werden dann auch übertragen (siehe Abbildung 19.2).
718
Kapitel 19: Client-Server-Techniken
Abbildung 19.2: Access als FrontEnd mit einem echten Back-End
Was bedeutet das für Sie? Wann sollten Sie sich um Client-Server-Technologie kümmern und was kann sie Ihnen bieten? Die folgenden Abschnitte stellen einige Richtlinien dafür vor, warum Sie möglicherweise ein so genanntes Upsizing auf Client-Server in Betracht ziehen sollten.
19.2.1
Umgang mit großen Datenmengen
Mit dem Anstieg des Datenvolumens in einer Access-Datenbank geht mit großer Wahrscheinlichkeit ein Leistungsverlust einher. Häufig wird gesagt, 100 MB sei die magische Zahl für die Maximalgröße einer Access-Datenbank, aber viele Back-EndDatenbank-Server kommen mit Datenbanken zurecht, die mehrere Gigabyte Daten enthalten. Eine Maximalgröße von 100 MB ist zwar für eine Access-Datenbank ein guter allgemeiner Anhaltspunkt, aber es ist keine feste Regel. Möglicherweise stellen Sie fest, dass die Notwendigkeit des Upsizing eintritt, wenn Ihre Datenbank deutlich größer oder kleiner als 100 MB ist. Die für Sie magische Zahl hängt von all den Faktoren, die in den folgenden Abschnitten zur Sprache kommen, und von der Zahl der
Soll das Client-Server-Modell eingesetzt werden?
719
Tabellen in der Datenbank ab. Im Allgemeinen ist die Leistung von Access bei großen Datenmengen höher, wenn diese in einer einzigen Tabelle statt in mehreren gespeichert sind.
19.2.2
Viele gleichzeitige Benutzer
Genauso wie große Datenmengen können auch viele gleichzeitige Benutzer ein Problem darstellen. Wenn mehr als zehn Benutzer zur gleichen Zeit auf eine AccessDatenbank zugreifen, kann die Leistung sinken. Wie bei den Datenmengen handelt es sich aber nicht um eine magische Zahl. Ich habe gleichermaßen Anwendungen mit weniger als zehn Benutzern und schrecklicher Leistung wie Anwendungen mit deutlich mehr als zehn Benutzern und vernünftiger Leistung erlebt. Häufig hängt es vom Entwurf der Anwendung sowie von der Art der Aufgaben ab, welche erledigt werden.
19.2.3
Die Notwendigkeit höherer Leistung
Bestimmte Anwendungen erfordern höhere Leistung als andere. Ein System für Online-Transaktionsverarbeitung (OLTP) beispielsweise benötigt im Allgemeinen deutlich höhere Leistung als ein System zur Entscheidungsunterstützung (DSS). Nehmen Sie an, 100 Benutzer nehmen gleichzeitig telefonische Bestellungen entgegen. Es wäre nicht angemessen, wenn sie ihre Kunden bitten müssten, zwischen der Eingabe der einzelnen Artikel jeweils 15 Sekunden zu warten. Dagegen ist es nicht übertrieben, Kunden um 60 Sekunden Wartezeit zu bitten, um einen Geschäftsbericht zu erstellen, der einmal im Monat angefertigt wird (auch wenn sich viele trotzdem beschweren werden). Nicht nur die Client-Server-Architektur als solche führt zu höherer Leistung, sondern die meisten Back-End-Datenbank-Server können außerdem – im Gegensatz zu Access – Multithreading-Betriebssysteme mit mehreren Prozessoren einsetzen.
19.2.4
Was ist bei höherem Netzwerkverkehr zu tun?
Wenn ein Datei-Server einer Organisation mit steigenden Anforderungen konfrontiert wird, verschärft die Access-Anwendung möglicherweise ein bereits bestehendes Problem. Durch Verlagerung der Anwendungsdaten auf einen Datenbank-Server könnten die insgesamt geringeren Anforderungen an das Netzwerk allen Benutzern höhere Leistung bringen und zwar unabhängig davon, ob sie gerade mit der AccessAnwendung arbeiten oder nicht. Wahrscheinlich eine der schlimmsten Situationen, die ich erlebt habe, spielte sich in einer Anlage ab, in der keine Arbeitsstation über eine eigene Festplatte verfügte. Windows und die gesamte Anwendungs-Software waren auf einem Datei-Server installiert. Alle Benutzer luden gleichzeitig Microsoft Word, Microsoft Excel und Microsoft PowerPoint über das Netz. Außerdem arbeiteten sie mit umfangreichen Access-
720
Kapitel 19: Client-Server-Techniken
Anwendungen mit vielen Datenbankobjekten und großen Datenmengen. All das lag ebenfalls auf dem Datei-Server. Ein Hinweis auf die bodenlos miserable Leistung erübrigt sich. Man kann nicht erwarten, dass ein bereits überlasteter Datei-Server es schafft, bei geringer Bandbreite große Datenmengen zu übertragen. Die Vorzüge der Client-Server-Technologie können zur Verbesserung dieser Problemsituation beitragen.
19.2.5
Sicherung und Wiederherstellung implementieren
Die angebotenen Optionen zur Sicherung und Wiederherstellung von AccessDatenbanken, die auf einem Datei-Server gespeichert sind, können einfach nicht mit denen für Datenbanken auf einem Datenbank-Server konkurrieren. Jeder Datenbank-Server, der sein Geld wert ist, bietet zum Beispiel sehr leistungsfähige unterbrechungsfreie Stromversorgungen (USVs). Viele besitzen Plattenlaufwerke, die im laufenden Betrieb ausgetauscht werden können, und Spiegelung, Duplexing oder Stripe Sets mit Parität (RAID-Stufe 5) unterstützen. Bei Festplattenspiegelung und -Duplexing können die Daten gleichzeitig auf mehrere Laufwerke geschrieben werden, was unmittelbare Sicherungskopien liefert. Außerdem ermöglichen einige Bandsicherungsprogramme für Datenbank-Server die Sicherung auf Band, während Benutzer auf das System zugreifen. Viele bieten auch automatische Protokollierung von Transaktionen. Alle diese Optionen bedeuten ein geringeres Risiko von Datenverlust oder Ausfallzeiten. Bei bestimmten Anwendungen sind Sicherung und Wiederherstellung dieser Art übertrieben, bei anderen sind sie jedoch absolut notwendig. Obwohl sich einiges von dem, was Back-Ends in Bezug auf Sicherung und Wiederherstellung zu bieten haben, mit Hilfe von Code und Replikation nachbilden lässt, ist es so gut wie unmöglich, bei einer auf einem Datei-Server gespeicherten AccessDatenbank dasselbe Sicherheitsniveau zu erreichen wie bei einer auf einem Datenbank-Server gespeicherten Datenbank.
19.2.6
Absicherung im Mittelpunkt
Access bietet für Einzelplatzdatenbanken Absicherung auf höchstem Niveau. Trotzdem ist die Absicherung, die eine Access-Datenbank bietet, nicht mit der von den meisten Datenbank-Servern gebotenen zu vergleichen. Diese funktioniert häufig in Verbindung mit dem Netzwerkbetriebssystem. Das gilt beispielsweise für Microsoft SQL Server und Windows NT Server. Der Benutzer erhält keinen direkten Zugriff auf die physische Datenbankdatei, sondern diese ist nur über eine ODBC-Datenquelle oder eine ADO-Verbindung zugänglich. Denken Sie daran, dass der Benutzer unabhängig davon, wieviel Absicherung Sie in eine Access-Datenbank einbauen, nicht daran gehindert wird, die gesamte MDB-Datei anzuschauen oder sie vom Netzlaufwerk zu löschen. Ein Datenbank-Server kann sehr einfach vor diesem und anderen potentiellen Problemen schützen. Außerdem stellen viele Programme für Back-End-Anwendungsdatenbank-Server Absicherung auf Feldebene bereit, die es
Soll das Client-Server-Modell eingesetzt werden?
721
in einer MDB-Datei von Acess nicht gibt. Schließlich bieten viele Back-Ends integrierte Absicherung mit einer gemeinsamen Anmeldung für Netzwerk und Datenbank.
19.2.7
Daten in mehreren Front-End-Werkzeugen gemeinsam nutzen
Das MDB-Dateiformat von Access ist proprietär. Nur wenige andere Programme können die im Access-Datenbankformat gespeicherten Daten lesen. Wenn ein BackEnd-Datenbank-Server vorhanden ist, der ODBC (Open Database Connectivity) unterstützt, lassen sich Anwendungen in zahlreichen Front-End-Anwendungsprogrammen schreiben, die gleichzeitig auf dieselben Back-End-Daten zugreifen.
19.2.8
Beurteilung
Sie müssen die konkrete Umgebung beurteilen, in der Ihre Anwendung laufen soll:
Wie viele Benutzer gibt es? Wie viele Daten sind vorhanden? Wie sieht der Verkehr im Netzwerk jetzt schon aus? Welche Leistung ist erforderlich? Wie schlimm sind Ausfallzeiten? Wie vertraulich sind die Daten? Welche anderen Anwendungen sollen die Daten verwenden? Wenn Sie diese und weitere Fragen beantwortet haben, können Sie Entscheidungen darüber treffen, ob der Nutzen der Client-Server-Architektur die damit verbundenen Kosten aufwiegt. Die gute Nachricht lautet, dass es nicht um Alles oder Nichts geht. Für Client-Server-Anwendungen, die Access als Front-End einsetzen, gibt es verschiedene Möglichkeiten. Wenn Sie Ihre Anwendung gleich mit der Möglichkeit des Upsizing im Blick entwerfen, verlangt die Client-Server-Technologie auch nicht, dass Sie alles wegwerfen, was Sie entwickelt haben, und von vorn anfangen. Microsoft stellt einen Upsizing-Assistenten bereit, der den Aufstieg auf eine SQL ServerDatenbank eigentlich relativ problemlos gestaltet. Wie problemlos es wirklich wird, ist von zahlreichen Faktoren abhängig, wie zum Beispiel davon, wie komplex Ihre Abfragen sind, ob die Abfragen VBA-Funktionen enthalten, und von anderen Dingen, die an späterer Stelle in diesem Kapitel behandelt werden.
722
19.3
Kapitel 19: Client-Server-Techniken
Die Rollen, die Access im Anwendungsentwurfsmodell spielt
Sie sollten, bevor Sie weiterlesen, um mehr über die Client-Server-Technologie zu erfahren, einen Blick auf die unterschiedlichen Rollen werfen, die Access im Entwurf einer Anwendung spielen kann. Es gibt mehrere Möglichkeiten, die in diesem Abschnitt erläutert werden.
19.3.1
Front-End und Back-End als Access-MDB-Dateien
Weiter vorn in diesem Buch haben Sie etwas über die Verwendung von Access als Front-End und Back-End gleichzeitig gelesen. Die Access-Datenbank fungiert nicht als echtes Back-End, weil sie keine Verarbeitung leistet. Abbildung 19.3 zeigt die Architektur dieses Szenarios. Die Access-Anwendung befindet sich auf der Arbeitsstation. Access kommuniziert mit Hilfe der Jet-Engine mit den Daten, die in einer MDB-Datenbankdatei auf dem Datei-Server gespeichert sind.
Abbildung 19.3: Access als Front-End, das für die Speicherung der Daten eine MDB-Datei verwendet
19.3.2
Das Front-End als MDB-Datei, die über Verknüpfungen mit einem Back-End kommuniziert
Im zweiten Szenario lassen sich Back-End-Tabellen mit der Front-End-Anwendungsdatenbank verknüpfen. Die Verknüpfung mit den Back-End-Tabellen ist fast mit der Verknüpfung mit Tabellen in anderen Access-Datenbanken oder mit externen Tabellen im FoxPro-, Paradox- oder dBase-Format identisch. Nach dem Einrichten der Verknüpfung der Back-End-Tabellen mit der Front-End-Anwendungsdatenbank lassen sich diese wie jede andere verknüpfte Tabelle behandeln. Access kommuniziert mit den Back-End-Tabellen über ODBC (siehe Abbildung 19.4). Ihre Anwendung sendet eine Access SQL-Anweisung an die Access-Jet-Engine. Jet übersetzt die Anweisung in ODBC SQL. Die ODBC SQL-Anweisung wird dann an den ODBC Manager gesendet. Dieser sucht den richtigen ODBC-Treiber und übergibt
Die Rollen, die Access im Anwendungsentwurfsmodell spielt
723
ihm die ODBC SQL-Anweisung. Der vom Anbieter des Back-Ends gelieferte ODBC-Treiber übersetzt die ODBC SQL-Anweisung in den jeweiligen Dialekt des Back-Ends. Die Back-End-spezifische Abfrage wird an den SQL Server und die entsprechende Datenbank gesendet. Wie Sie sich vielleicht denken können, erfordert diese Übersetzung insgesamt ein wenig Zeit. Außerdem wird ODBC allmählich zur Technologie der Vergangenheit, die bald durch die ADO/OLEDB-Technologie abgelöst sein wird. Deshalb stellt eine der folgenden Alternativen möglicherweise die bessere Lösung dar.
Abbildung 19.4: Access als Front-End, das Verknüpfungen zu Back-End-Tabellen benutzt
19.3.3
Das Front-End, das mittels SQL Pass-Through mit einem Back-End kommuniziert
Ein Engpass verknüpfter Tabellen liegt in der von Jet vorgenommenen Übersetzung der Access SQL-Anweisung in ODBC SQL, welche dann vom ODBC-Treiber in eine allgemeine SQL-Anweisung übertragen wird. Die Übersetzung ist nicht nur langsam, sondern es gibt möglicherweise noch andere Gründe für eine Umgehung des Übersetzungsvorgangs:
Möglicherweise unterstützt Access eine Operation nicht, die von der nativen Abfragesprache des Back-Ends unterstützt wird.
Die Jet-Engine oder der ODBC-Treiber erzeugt eine SQL-Anweisung, die nicht für das Back-End optimiert ist.
Sie wollen, dass ein Prozess vollständig auf dem Back-End ausgeführt wird.
724
Kapitel 19: Client-Server-Techniken
Pass-Through-Abfragen werden im Abschnitt »Pass-Through-Abfragen« dieses Kapitels ausführlicher beschrieben. Schauen Sie sich zunächst an, was passiert, wenn eine Pass-Through-Abfrage ausgeführt wird. Eine Abfrage dieses Typs ist in der speziellen Syntax des Back-End-Datenbank-Servers geschrieben. Obwohl die Abfrage die Jet-Engine passiert, wird sie von dieser nicht übersetzt. Anders gesagt: Die SQLDatenbank empfängt genau das, was Access gesendet hat. Abbildung 19.5 veranschaulicht dieses Szenario. Beachten Sie, dass die Jet-Engine, der ODBC Manager und der ODBC-Treiber nicht vollständig beseitigt sind. Sie sind noch vorhanden, haben aber wesentlich weniger Einfluss auf den Prozess als bei verknüpften Tabellen. Wie Sie später in diesem Kapitel sehen werden, stellen Pass-Through-Abfragen kein Patentrezept dar, auch wenn sie sehr nützlich sind. Die Ergebnisse einer PassThrough-Abfrage lassen sich zum Beispiel nicht aktualisieren. Außerdem müssen Sie, weil Pass-Through-Abfragen im speziellen SQL-Dialekt des Back-Ends geschrieben sind, diese neu schreiben, wenn Sie sie vom Back-End an eine andere Stelle verschieben. Aus diesen und anderen Gründen werden Pass-Through-Abfragen. Im Allgemeinen im Zusammenhang mit anderen Lösungen eingesetzt.
Abbildung 19.5: Access beim Senden einer Pass-Through-Abfrage an eine BackEnd-Datenbank
19.3.4
Das Front-End als Access-Datenprojekt, das direkt mit einem Back-End kommuniziert
Bei der Arbeit mit einem Back-End-Datenbank-Server steht eine weitere, sehr vitale Lösung zur Verfügung. Dabei wird ein Access-Datenprojekt (.adp) eingesetzt, welches mit Access 2000 neu eingeführt wurde. Dadurch umgehen Sie die Jet-Engine völlig. Ein Access-Projekt enthält ausschließlich Objekte auf Code-Basis, z.B. Formulare, Berichte, Datenzugriffsseiten, Makros und Module. Alle Tabellen, Sichten,
Die Client-Server-Schlagworte
725
Datenbankdiagramme und gespeicherten Prozeduren sind in einer SQL ServerDatenbank abgelegt. Nachdem Sie mit einer SQL Server-Datenbank Verbindung aufgenommen haben, lassen sich SQL Server-Objekte mühelos erstellen, ansehen, verändern und löschen. Abbildung 19.6 veranschaulicht dieses Szenario. Beachten Sie, dass weder die Jet-Engine noch ODBC vorkommen.
Abbildung 19.6: Access verwendet ein Access-Datenprojekt zur Kommunikation mit einem Back-End
19.4
Die Client-Server-Schlagworte
Wenn man über Client-Server-Technologie spricht, werden viele Begriffe verwendet, die dem durchschnittlichen Datenbankentwickler nicht geläufig sind. Um die ClientServer-Technologie und das, was sie zu bieten hat, umfassend einschätzen zu können, brauchen Sie zumindest ein allgemeines Verständnis der Terminologie. Tabelle 19.1 fasst die häufigsten Begriffe zusammen. Begriff
Definition
Spalte
Ein Feld
DDL (Data Definition Eine Datendefinitionssprache, die zur Definition und Beschreibung Language) der Datenbankstruktur verwendet wird Fremdschlüssel
Ein Wert in einer Tabelle, der in einer anderen Tabelle zum Zweck der Gültigkeitsprüfung nachgeschlagen werden muss
Jet
Die von Microsoft Access verwendete native Datenbank-Engine
ODBC (Open Database Connectivity)
Ein von Microsoft vorgeschlagener Standard, der über eine gemeinsame Schnittstelle Zugriff auf verschiedene Back-End-Datenbanken bietet. Im Wesentlichen ist ODBC ein Übersetzer.
OLE DB
Ein neuer Standard für die Verbindung zu relationalen und nicht relationalen Datenquellen
DAO
Data Access Objects (Datenzugriffsobjekte) stellen eine Methode der Datenbearbeitung dar. Sie wird gerade durch ADO ersetzt und war für den Zugriff auf Jet-Datenbanken optimiert.
Tabelle 19.1: Die Terminologie
726
Kapitel 19: Client-Server-Techniken
Begriff
Definition
ADO
ActiveX Data Objects (ActiveX-Datenobjekte) sind ein Objektmodell auf COM-Basis, das die einfache Bearbeitung von OLE-DBDatenquellen ermöglicht. ADO ist die Datenzugriffsmethodik, die DAO ersetzt.
Primärschlüssel
Eine Gruppe von Feldern, die eine Spalte eindeutig kennzeichnet
Zeile
Ein Datensatz
Schema
Ein Plan der gesamten Datenbank mit Tabellendefinitionen, Beziehungen, Absicherung und anderen wichtigen Informationen über die Datenbank
SQL (Structured Query Language)
Eine Datenbearbeitungssprache, die im Allgemeinen zur Kommunikation mit Tabellen verwendet wird, die auf einem Server liegen
Gespeicherte Prozeduren
Kompilierte SQL-Anweisungen, z.B. Abfragen, die auf einem Datenbank-Server gespeichert sind. Lassen sich von einer Anwendung aufrufen
Transaktion
Eine Reihe von Aktionen, die an einer Datenbank vorgenommen werden müssen. Wenn eine dieser Aktionen missglückt, werden alle Aktionen verworfen.
Trigger
Code-Teile, die in Reaktion auf eine Aktion an einer Tabelle (Einfügen, Bearbeiten oder Löschen) ausgeführt werden
Tabelle 19.1: Die Terminologie (Forts.)
Eine ausgezeichnete Informationsquelle ist die MSDN-CD-ROM (MSDN – Microsoft Developer Network). Von Microsoft als Abonnement angeboten, enthält sie zahlreiche Artikel und Texte über die Client-Server-Technologie, ODBC und den Einsatz von Access als Front-End für einen Datenbank-Server.
19.5
Upsizing: Was dabei zu bedenken ist
Nehmen Sie an, Ihre Datenbank verwendet Access als Front-End und als Back-End. Eine Access-Datenbank auf einem Datei-Server hat möglicherweise eine Zeitlang ausgereicht, aber die Notwendigkeit höherer Leistung, erweiterter Absicherung oder eines der weiteren Vorteile einer Back-End-Datenbank zwingt Ihre Firma (oder die Ihres Kunden) zum Umstieg auf eine Client-Server-Architektur. Die Access-Tabellen liegen bereits vor und enthalten sogar umfangreiche Datenmengen. In diesem Szenario könnte Upsizing vernünftig sein.
Upsizing: Was dabei zu bedenken ist
727
Da alle Tabellen als Access-Tabellen entworfen wurden, müssen sie auf den BackEnd-Datenbank-Server portiert werden. Dazu gehört das Verschieben der Tabellen von einer lokalen Access-Datenbank (oder einer beliebigen PC-Datenbank) auf einen Back-End-Datenbank-Server, der normalerweise unter UNIX, Windows NT Server oder OS/2 LAN Server bzw. als Novell NetWare NLM läuft. Ein weiterer Grund für das Upsizing von Tabellen von Access auf einen DatenbankServer liegt darin, dass es viele Entwickler vorziehen, ihre Tabellen in der AccessUmgebung zu entwerfen. Access bietet für die Tabellenerstellung mehr Benutzerfreundlichkeit als die meisten Server-Anwendungen. Unabhängig von den Gründen für das Upsizing müssen Sie einige Probleme im Zusammenhang mit dem Verschieben bzw. Portieren von Access-Tabellen auf einen Datenbank-Server verstehen. Wegen der vielen damit verbundenen Warnungen entscheiden sich tatsächlich viele Entwickler dafür, die Tabellen direkt auf dem BackEnd zu entwerfen. Wenn Sie Ihre Tabellen jedoch in Access entwerfen, können Sie sie auf das Back-End exportieren und dann eine Verknüpfung zu Ihrer lokalen Datenbank einrichten, oder Sie setzen zur wesentlichen Vereinfachung des Prozesses den Upsizing-Assistenten ein. Beim Export Ihrer Tabellen auf den Datenbank-Server müssen Sie sich jedoch ungeachtet der gewählten Methode der in den folgenden Abschnitten behandelten Probleme bewusst sein. Wenn Sie auf eine SQL Server-Datenbank umsteigen, erledigt der UpsizingAssistent von Microsoft Access 2000 die meisten der damit verbundenen Probleme.
19.5.1
Indizes
Beim Exportieren einer Tabelle auf einen Server werden keine Indizes erstellt. Alle Indizes müssen auf dem Back-End-Datenbank-Server neu angelegt werden. Wenn auf Ihrem Datenbank-Server Microsoft SQL Server läuft, können Sie den UpsizingWizard für Access 2000 einsetzen. Dieser erstellt Indizes für Server-Tabellen an den Stellen, an denen sie in den Access-Tabellen stehen.
19.5.2
Felder vom Typ AutoWert
Felder vom Typ AutoWert werden als Werte des Typs Long Integer exportiert. Da einige Datenbank-Server die automatische Nummerierung nicht unterstützen, müssen Sie auf dem Server einen Einfüge-Trigger erstellen, der den nächsten Schlüsselwert liefert. Automatisches Nummerieren lässt sich auch durch Ereignisse auf Formularebene erreichen, aber das ist nicht wünschenswert, da die Nummerierung nicht erzwungen wird, wenn andere Anwendungen auf die Daten zugreifen. Wenn Sie auf Microsoft SQL Server umsteigen, konvertiert der Upsizing-Assistent für Access 2000 alle Felder des Typs AutoWert in Identitätsfelder.
728
19.5.3
Kapitel 19: Client-Server-Techniken
Standardwerte
Standardwerte werden nicht automatisch auf den Server verschoben, selbst wenn sie von diesem unterstützt werden. Sie können Standardwerte direkt auf dem Server einrichten, aber sie erscheinen nicht automatisch, wenn neue Datensätze in die Tabelle eingefügt werden, es sei denn, der Datensatz wird gespeichert, ohne dass Daten in das Feld mit dem Standardwert eingefügt werden. Wie die automatische Nummerierung lassen sich auch Standardwerte – mit denselben Nachteilen – auf Formularebene implementieren. Wenn zum Verschieben der Daten auf Microsoft SQL Server der Upsizing-Assistent verwendet wird, werden Standardwerte in Ihre Server-Datenbank exportiert.
19.5.4
Gültigkeitsregeln
Gültigkeitsregeln werden nicht auf den Server exportiert. Sie müssen mit Hilfe von Triggern auf dem Server neu erstellt werden. Es werden keine in Access definierten Fehlermeldungen angezeigt, wenn eine Server-Gültigkeitsregel verletzt wird. Die entsprechenden Fehlermeldungen sollten von Ihrer Anwendung über Code bereitgestellt werden. Sie können auch auf Formularebene Gültigkeitsregeln ausführen, aber diese werden nicht verwendet, wenn anderweitig auf die Daten zugegriffen wird. Wenn zum Portieren der Daten auf Microsoft SQL Server der Upsizing-Assistent verwendet wird, werden Gültigkeitsregeln in Ihre Server-Datenbank exportiert.
19.5.5
Beziehungen
Beziehungen müssen mit Hilfe von Triggern auf Server-Basis eingerichtet werden. Die Standardfehlermeldungen von Access werden nicht angezeigt, wenn die referentielle Integrität verletzt ist. Sie müssen diese Fehlermeldungen in Ihre Anwendung integrieren und auf sie reagieren. Beziehungen lassen sich auf Formularebene erzwingen, aber diese Methode schützt – wie andere Gültigkeitsregeln auf Formularebene – Ihre Daten nicht adäquat. Wenn zum Verschieben der Daten auf Microsoft SQL Server der Upsizing-Assistent für Access 2000 verwendet wird, werden alle Beziehungen und die in Ihrer Access-Datenbank eingerichtete referentielle Integrität in die Server-Datenbank übernommen.
19.5.6
Absicherung
Absicherungsfunktionen, die Sie in Access eingerichtet haben, werden nicht auf den Server übertragen. Sie müssen auf dem Server die Absicherung von Tabellen neu einrichten. Wenn Sie das getan haben, weiß Access erst dann vom Vorhandensein der Absicherung, wenn eine Access-Anwendung versucht, die Absicherung des Servers zu verletzen. Dann werden Fehlertexte an die Anwendung zurückgegeben. Sie müssen diese Fehler mit Hilfe von Code behandeln und entsprechende Fehlermeldungen ausgeben.
Upsizing: Was dabei zu bedenken ist
19.5.7
729
Tabellen- und Feldnamen
Hinsichtlich der Benennung von Feldern sind die Regeln von Servern häufig wesentlich strenger als in Access. Beim Exportieren einer Tabelle werden alle nicht alphanumerischen Zeichen in Unterstriche umgewandelt. Die meisten Back-Ends lassen keine Leerzeichen in Feldnamen zu. Außerdem begrenzen die meisten Back-Ends die Länge von Objektnamen auf 30 Zeichen oder weniger. Wenn Sie bereits Abfragen, Formulare, Berichte, Makros und Module erstellt haben, die Leerzeichen und sehr lange Feld- und Tabellennamen verwenden, können diese Datenbankobjekte möglicherweise unbrauchbar werden, wenn Sie sie auf einen Back-End-DatenbankServer verschieben.
19.5.8
Reservierte Begriffe
Auf den meisten Back-Ends gibt es zahlreiche reservierte Begriffe, die unbedingt beachtet werden müssen. Es ist ein schlimmer Schock, wenn Sie eine Tabelle portieren und feststellen, dass die von Ihnen verwendeten Feldnamen auf Ihrem Datenbank-Server reservierte Wörter sind. In diesem Fall müssen Sie alle Felder umbenennen, in denen ein Konflikt auftritt. Das bedeutet wiederum, dass alle Abfragen, Formulare, Berichte, Makros und Module, die auf die ursprünglichen Feldnamen verweisen, geändert werden müssen
19.5.9
Groß- und Kleinschreibung
Viele Back-End-Datenbanken unterscheiden nach Groß- und Kleinbuchstaben. Wenn dies auf Ihr Back-End zutrifft, stellen Sie möglicherweise fest, dass Ihre Abfragen und Ihr Anwendungs-Code nicht erwartungsgemäß ausgeführt werden. Abfragen oder Code, die in der falschen Schreibweise auf einen Feld- oder Tabellennamen verweisen, werden von der Back-End-Datenbank nicht erkannt und nicht korrekt verarbeitet.
19.5.10 Eigenschaften Die meisten Eigenschaften in entfernten Tabellen lassen sich nicht verändern. Alle veränderbaren Eigenschaften gehen beim Export verloren und müssen nach dem Export neu eingerichtet werden.
19.5.11 Visual Basic-Code Bestimmte Methoden und Eigenschaften, die bei Access-Tabellen funktionieren, funktionieren bei entfernten Tabellen möglicherweise nicht. Das könnte Veränderungen im Code erforderlich machen, nachdem Sie die Tabellen exportiert haben.
730
19.6
Kapitel 19: Client-Server-Techniken
Das Upsizing aktiv vorbereiten
Wenn Sie bei der Einrichtung Ihrer Tabellen und Code-Module bereits das Upsizing im Blick haben, können Sie viele der genannten Fallen beseitigen. Trotz der Probleme, welche das Upsizing mit sich bringen kann, stellt die Skalierbarkeit von Access eines seiner leistungsfähigen Merkmale dar. Manchmal sind die Ressourcen nicht verfügbar, um im Frühstadium einer Anwendung die Client-Server-Technologie zu implementieren. Wenn Sie beim Durchdenken des Entwurfs die Möglichkeit des Upsizing im Auge behalten, werden Sie angenehm überrascht sein, wie relativ einfach sich der Umstieg auf die Client-Server-Technologie gestaltet, wenn die Zeit gekommen ist. Mit dem Upsizing-Assistenten von Access 2000, der dazu gedacht ist, eine Access-Anwendung auf Microsoft SQL Server zu portieren, ist der Vorgang relativ unkompliziert. Der Assistent übernimmt mit nur wenigen Klicks auf Schaltflächen einen großen Teil der mit dem Upsizing einer Datenbank verbundenen Arbeit.
19.7
Der Upsizing-Assistent
Wie im vorigen Abschnitt erwähnt, vereinfacht der Upsizing-Assistent von Access 2000 das Portieren auf eine SQL Server-Datenbank erheblich. Um ihn aufzurufen, unternehmen Sie Folgendes: 1. Wählen Sie EXTRAS|DATENBANK-DIENSTPROGRAMME|UPSIZING-ASSISTENT. Der Upsizing-Assistent erscheint (siehe Abbildung 19.7). Hier können Sie sich entscheiden, auf eine vorhandene SQL Server-Datenbank zu portieren oder eine neue Datenbank anzulegen.
Abbildung 19.7: Der erste Schritt des Upsizing-Assistenten ermöglicht das Anlegen einer neuen SQL Server-Datenbank oder die Verwendung einer vorhandenen Datenbank
Der Upsizing-Assistent
731
2. Treffen Sie Ihre Wahl und klicken Sie auf WEITER. Wenn Sie sich für eine neue Datenbank entscheiden, erscheint der Upsizing-Assistent so wie in Abbildung 19.8.
Abbildung 19.8: Der zweite Schritt des Upsizing-Assistenten ermöglicht die Angabe des Servers, einer Anmelde-ID, eines Kennworts und weiterer wichtiger Informationen, die zum Erstellen einer neuen Datenbank benötigt werden
3. Wählen Sie den Server, auf dem die Datenbank untergebracht werden soll. 4. Geben Sie eine Anmelde-ID und ein Kennwort mit Rechten zum Erstellen einer Datenbank ein. 5. Geben Sie einen Namen für die neue Datenbank ein. Klicken Sie auf WEITER. Der Upsizing-Assistent sieht nun so aus wie in Abbildung 19.9.
Abbildung 19.9: Der dritte Schritt des Upsizing-Assistenten ermöglicht die Auswahl der zu verschiebenden Tabellen
732
Kapitel 19: Client-Server-Techniken
6. Markieren Sie die Tabellen, die Sie in SQL Server exportieren wollen und klicken Sie auf WEITER. 7. Im nächsten Schritt des Upsizing-Assistenten, gezeigt in Abbildung 19.10, können Sie wichtige Informationen darüber eingeben, was in den portierten Tabellen enthalten ist. Sie können bestimmen, ob Indizes, Gültigkeitsregeln, Standardwerte und Tabellenbeziehungen portiert und Timestamps in Tabellen eingefügt werden sollen. Schließlich müssen Sie entscheiden, ob nur Tabellenstrukturen oder Tabellenstrukturen und Daten zu übernehmen sind. Treffen Sie Ihre Wahl und klicken Sie auf WEITER.
Abbildung 19.10: Im vierten Schritt des Upsizing-Assistenten wird festgelegt, ob Indizes, Gültigkeitsregeln, Standardwerte und Tabellenbeziehungen übernommen werden
8. Im nächsten Schritt des Upsizing-Assistenten, den Sie in Abbildung 19.11 sehen, können Sie entscheiden, ob Access Ihre Datenbank so ändern soll, dass Verknüpfungen mit den neuen Tabellen angelegt werden. Wenn Sie es wünschen, erstellt Access ein Access-Datenprojekt. Sie können auch festlegen, dass die Anwendung nicht verändert wird. Wenn Sie festlegen, dass eine neue AccessClient-Server-Anwendung (ADP) erstellt werden soll, müssen Sie den ADPDateinamen angeben. Klicken Sie anschließend auf WEITER. 9. Klicken Sie auf FERTIG STELLEN. Die Datenbank wird daraufhin portiert und der Upsizing-Assistent erstellt einen Bericht (siehe Abbildung 19.12). Sie sollten diesen Bericht lesen, denn er enthält wichtige Informationen über den Stand des Upsizing. Abbildung 19.13 zeigt das Ergebnis der Datenbankportierung von Chap18Data.
Der Upsizing-Assistent
733
Abbildung 19.11: Im fünften Schritt des Upsizing-Assistenten geben Sie an, ob der Assistent als Teil des Upsizing Verknüpfungen mit Tabellen oder eine Access-Datenprojektdatei erstellen soll
Abbildung 19.12: Der Bericht über das Upsizing liefert wichtige Informationen über den Verlauf der Portierung
734
Kapitel 19: Client-Server-Techniken
Abbildung 19.13: Die Datenbank Chap18DataSQL nach der Portierung
19.8
Eine ODBC-Datenquelle definieren
Wenn Sie Verknüpfungen mit ODBC-Tabellen planen, müssen Sie die entsprechenden ODBC-Treiber laden. Diese werden zusammen mit Access geliefert und mit dem Programm installiert. Sie müssen auch Treiber für die Back-End-DatenbankServer laden, mit denen Sie Verbindung aufnehmen wollen. Sie erwerben diese normalerweise beim Anbieter der Back-End-Datenbank, wobei die Lizenzierung häufig in Abhängigkeit von der Anzahl der Arbeitsplätze erfolgt. Das bedeutet, dass Sie für jeden Benutzer eine Client-Lizenz erwerben müssen, der mit den entfernten Daten arbeiten soll. Eine ODBC-Datenquelle ist ein benutzerdefinierter Name, der auf eine entfernte Datenquelle zeigt. Er enthält alle Eigenschaften der Datenquelle, die zur Kommunikation mit den auf einem Datenbank-Server gespeicherten Daten notwendig sind. Bevor Sie aus Access auf eine entfernte Tabelle zugreifen können, müssen Sie diese mit Hilfe des ODBC-Datenquellen-Administrators definieren. Wenn Sie die Datenquelle nicht oder nicht korrekt definieren, können Sie nicht auf die Daten zugreifen. Die ODBC-Datenquellen werden im ODBC-Datenquellen-Administrator eingerichtet (siehe Abbildung 19.14). In Abhängigkeit von Ihrer Installation könnte der ODBC-Datenquellen-Administrator eine eigenständige Anwendung sein oder als Symbol in der Systemsteuerung erscheinen. Standardmäßig wird dieses Symbol als ODBC-DATENQUELLEN angezeigt. Sie können damit Datenquellen erstellen, verän-
Eine ODBC-Datenquelle definieren
735
dern und löschen sowie Informationen über vorhandene Treiber abfragen. Denken Sie daran, dass eine Datenquelle lediglich ein benutzerdefinierbarer Name ist, der Einstellungen speichert, welche zum Zugriff auf ein Back-End auf einem bestimmten Server mit Hilfe eines angegebenen Treibers verwendet werden können.
Abbildung 19.14: Der Abschnitt Benutzerdatenquellen im ODBCDatenquellen-Administrator
Der ODBC-Datenquellen-Administrator ist ein Dialogfeld mit Registerkarten. Tabelle 19.2 beschreibt, wie diese verwendet werden. Registerkarte
Funktion
BENUTZER-DSN
Ermöglicht das Hinzufügen, Löschen und Einrichten von Datenquellen, die für einen Rechner lokal sind und nur vom aktuellen Benutzer verwendet werden können
SYSTEM-DSN
Ermöglicht das Hinzufügen, Löschen und Einrichten von Datenquellen, die für einen Rechner lokal vorliegen, aber nicht auf einen bestimmten Benutzer beschränkt sind
DATEI-DSN
Ermöglicht das Hinzufügen, Löschen und Einrichten von Datenquellen auf Dateibasis, die von allen Benutzern gemeinsam genutzt werden können, welche denselben Treiber installiert haben. DateiDSNs sind nicht auf einen bestimmten Rechner beschränkt.
TREIBER
Liefert Informationen über installierte ODBC-Treiber
Tabelle 19.2: Der ODBC-Datenquellen-Administrator
736
Kapitel 19: Client-Server-Techniken
Registerkarte
Funktion
VERFOLGUNG
Ermöglicht die Angabe, wie der ODBC Driver Manager Aufrufe von ODBC-Funktionen verfolgen soll. Als Optionen sind der Zeitpunkt der Verfolgung, der Pfad der Protokolldatei und die benutzerdefinierte Verfolgungs-DLL verfügbar.
VERBINDUNGS-POOL
Ermöglicht Einstellungen für die Wiederverwendung offener _Verbindungszugriffsnummern, was Wege zum Server erspart
INFO
Liefert Informationen über Kernbestandteile wie den Speicherort von Dateien und Versionsnummern.
Tabelle 19.2: Der ODBC-Datenquellen-Administrator (Forts.)
Nachdem Sie sich in den ODBC-Datenquellen-Administrator begeben haben, sollten Sie eine neue Datenquelle einrichten. Dazu klicken Sie auf die Schaltfläche HINZUFÜGEN auf der Registerkarte BENUTZER-DSN oder SYSTEM-DSN oder Sie klicken auf HINZUFÜGEN auf der Registerkarte DATEI-DSN des Dialogfeldes. Das Dialogfeld NEUE DATENQUELLE ERSTELLEN wird eingeblendet, in dem Sie den Namen des Treibers wählen müssen, den die Datenquelle verwenden soll (siehe Abbildung 19.15).
Abbildung 19.15: Das Dialogfeld Neue Datenquelle erstellen
Die Liste der verfügbaren Treiber ist unterschiedlich, je nachdem, welche ClientTreiber auf dem Rechner installiert sind. Nachdem Sie eine Datenquelle ausgewählt und auf FERTIG STELLEN geklickt haben, erscheint ein Assistent, der von dem gewählten Treiber abhängig ist. Sie verwenden ihn zur Definition spezieller Informationen über die Datenquelle, die Sie erstellen wollen. Als Beispiel sehen Sie in Abbildung 19.16 den Assistenten zur Erstellung einer neuen Datenquelle für SQL Server.
Eine ODBC-Datenquelle definieren
737
Abbildung 19.16: Der erste Schritt des Assistenten zur Erstellung einer neuen Datenquelle für SQL Server ermöglicht die Angabe des Namens der Datenquelle, einer Beschreibung und des Namens des DatenbankServers
1. Der erste Schritt des Assistenten (siehe Abbildung 19.16) ermöglicht die Angabe des Namens der Datenquelle, einer Beschreibung der Datenquelle und des Namens des SQL-Servers, zu dem Sie Verbindung aufnehmen wollen. Klicken Sie auf WEITER, wenn Sie mit der Auswahl fertig sind. 2. Im zweiten Schritt des Assistenten zur Erstellung einer neuen Datenquelle für SQL Server, den Sie in Abbildung 19.17 sehen, können Sie Anmeldeinformationen für die ODBC-Datenquelle angeben. Treffen Sie Ihre Wahl und klicken Sie auf WEITER.
Abbildung 19.17: Im zweiten Schritt des Assistenten geben Sie Anmeldeinformationen für die ODBC-Datenquelle an
3. Im dritten Schritt des Assistenten (siehe Abbildung 19.18) liefern Sie Informationen über die Datenbank, zu der Sie verknüpfen. In Abbildung 19.18 heißt sie Nordwind. Klicken Sie auf WEITER, wenn Sie fortfahren wollen.
738
Kapitel 19: Client-Server-Techniken
Abbildung 19.18: Im dritten Schritt des Assistenten liefern Sie Informationen über die Datenbank, zu der Sie verknüpfen
4. Im vierten und letzten Schritt des Assistenten zur Erstellung einer neuen Datenquelle für SQL Server können Sie die Verbindung zu der SQL Server-Datenquelle weiter verfeinern (siehe Abbildung 19.19). Wenn Sie fertig sind, klicken Sie auf WEITER.
Abbildung 19.19: Im vierten Schritt des Assistenten können Sie weitere Attribute der Datenquelle angeben
5. Es erscheint das Dialogfeld ODBC MICROSOFT SQL SERVER-SETUP (siehe Abbildung 19.20). Es liefert Ihnen Informationen über die Datenquelle und ermöglicht, diese zu prüfen. Das ist empfehlenswert, um bestätigt zu bekommen, dass alle angegebenen Einstellungen gültig sind. Eine erfolgreiche Prüfung sehen Sie in Abbildung 19.21. Klicken Sie auf OK, wenn Sie fertig sind.
Eine ODBC-Datenquelle definieren
739
Abbildung 19.20: Das Dialogfeld ODBC Microsoft SQL ServerSetup liefert Ihnen Informationen über die Datenquelle und ermöglicht, diese zu prüfen
Abbildung 19.21: Ein Beispiel für eine erfolgreiche Prüfung einer ODBC-Datenquelle
Sie fragen sich vielleicht, wie Sie die Definition von Datenquellen in einer umfangreichen Installation mit mehreren tausend Rechnern schaffen sollen. Glücklicherweise lässt sich dieser Vorgang mit Hilfe von DLL-Funktionen automatisieren. Die Datenquellen werden über DLL-Funktionsaufrufe des ODBC-DatenquellenAdministrators mittels Code eingerichtet. Die Alternative stellen Datei-DSNs dar, die allen Benutzern zur Verfügung stehen.
740
Kapitel 19: Client-Server-Techniken
19.9
Mit einem Datenbank-Server Verbindung aufnehmen
Nachdem Sie eine Datenquelle definiert haben, können Sie zu dieser Verbindung aufnehmen. Für den Zugriff auf die Daten stehen folgende Methoden zur Verfügung:
Eine Verknüpfung mit Tabellen auf dem Server einrichten Eine Verknüpfung mit Server-Sichten einrichten SQL-Anweisungen mit Hilfe von Pass-Through-Abfragen direkt an den Server senden
Die Server-Tabellen mit Hilfe von VBA-Code direkt öffnen Ein Access-Datenprojekt erstellen (dann brauchen Sie keine ODBC-Datenquelle zu definieren)
19.10
Mit verknüpften Tabellen arbeiten
Die einfachste Methode, auf Daten auf dem Server zuzugreifen, ist eine Verknüpfung mit den externen Tabellen. Diese verhalten sich nahezu genauso wie native Access-Tabellen. Wenn Sie eine Verknüpfung nutzen, analysiert Access die in den Tabellen enthaltenen Felder und Indizes, um optimale Leistung zu erzielen. Wenn sich die Struktur der entfernten Tabellen ändert, müssen neue Verknüpfungen eingerichtet werden. Dieser Abschnitt beschäftigt sich damit, wie man mit Hilfe der Benutzerschnittstelle und mittels Code eine Verknüpfung mit entfernten Tabellen einrichten kann.
19.10.1 Mit Hilfe der Benutzerschnittstelle Verbindungen zu entfernten Tabellen herstellen Um mit Hilfe der Benutzerschnittstelle Verbindungen zu entfernten Tabellen aufzubauen, klicken Sie mit der rechten Maustaste im Datenbankfenster und wählen dann TABELLEN VERKNÜPFEN. Wählen Sie im aufklappbaren Listenfeld DATEITYP den Eintrag ODBC-DATENBANKEN. Daraufhin erscheint das in Abbildung 19.22 gezeigte Dialogfeld DATENQUELLE AUSWÄHLEN, das zwei Registerkarten besitzt: DATEIDATENQUELLE und COMPUTERDATENQUELLE. Auf der Registerkarte DATEIDATENQUELLE wählen Sie einen der definierten Datei-DSNs aus. Das sind die Datenquellen, die allen Benutzern an allen Rechnern zur Verfügung stehen. Auf der Registerkarte COMPUTERDATENQUELLE wählen Sie unter den definierten Benutzerund Systemdatenquellen. Diese sind nur für einen Benutzer und einen Rechner verfügbar.
Mit verknüpften Tabellen arbeiten
741
Abbildung 19.22: Das Dialogfeld Datenquelle auswählen
Sie können direkt im Dialogfeld DATENQUELLE AUSWÄHLEN eine vorhandene Datenquelle auswählen oder eine neue Datenquelle definieren. Nachdem Sie eine Datenquelle gewählt haben, wird Ihnen ein Dialogfeld zum Anmelden präsentiert. Sie bekommen erst dann Zugriff auf die Server-Daten, wenn Sie eine gültige Anmelde-ID und ein Kennwort haben. Abbildung 19.23 zeigt das Dialogfeld SQL SERVER-LOGIN.
Abbildung 19.23: Das Dialogfeld SQL Server-Login
Wenn Sie sich erfolgreich beim Server angemeldet haben, wird eine Liste mit Tabellen angezeigt, die in der Datenbank enthalten sind, auf welche die Datenquelle verweist. Hier müssen Sie die Tabelle markieren, die Sie in die Verknüpfung einbeziehen möchten. Abbildung 19.24 zeigt das Dialogfeld TABELLEN VERKNÜPFEN. Nachdem Sie eine oder mehrere Tabellen markiert und auf OK geklickt haben, bekommen Sie vielleicht das Dialogfeld EINDEUTIGEN DATENSATZBEZEICHNER AUSWÄHLEN zu Gesicht. Die Auswahl eines eindeutigen Bezeichners für die Tabelle ermöglicht das Aktualisieren von Datensätzen auf der Back-End-Datenquelle. Wäh-
742
Kapitel 19: Client-Server-Techniken
Abbildung 19.24: Das Dialogfeld Tabellen verknüpfen
len Sie einen Bezeichner und klicken Sie auf OK. Die verknüpften Tabellen erscheinen im Datenbankfenster, wie in Abbildung 19.25 gezeigt. Sie können wie jede andere Tabelle behandelt werden (von einigen Ausnahmen abgesehen, die weiter hinten in diesem Kapitel besprochen werden).
Abbildung 19.25: Das Datenbankfenster mit verknüpften ODBC-Tabellen
19.10.2 VBA-Code verwenden, um Verknüpfungen mit externen Tabellen zu erstellen Sie haben gerade gelernt, wie Sie mit Hilfe der Benutzerschnittstelle von Access eine Verknüpfung mit einer entfernten Tabelle aufbauen können. Sehen Sie sich nun an, wie Sie dasselbe mit Hilfe von Code erreichen. Die Unterroutine in Listing 19.1 übernimmt sechs Parameter: den Namen für die Access-Tabelle, den Namen der Server-Datenbank, den Namen der Server-Tabelle, den Namen der Datenquelle, die Benutzer-ID und das Kennwort. Listing 19.1:
VBA-Code zum Verknüpfen mit einer externen Tabelle
Sub LinkToSQL(strAccessTable, strDBName, strTableName, _ strDataSourceName, strUserID, strPassWord)
Mit verknüpften Tabellen arbeiten
743
Dim cat As ADOX.Catalog Dim tbl As ADOX.Table Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection Set tbl = New ADOX.Table tbl.Name = strAccessTable Set tbl.ParentCatalog = cat tbl.Properties("Jet OLEDB:Create Link") = True tbl.Properties("Jet OLEDB:Link Provider String") = "ODBC" & _ ";DATABASE=" & strDBName & _ ";UID=" & strUserID & _ ";PWD=" & strPassWord & _ ";DSN=" & strDataSourceName tbl.Properties("Jet OLEDB:Remote Table Name") = strTableName cat.Tables.Append tbl End Sub
Dieses Beispiel benötigt einen Verweis auf die Microsoft-Bibliothek ADO Ext. 2.1 for DDL and Security.
Es folgt ein Beispiel dafür, wie Sie die Unterroutine aufrufen können. Die AccessTabelle, die Sie erstellen, bekommt den Namen tblStores. Der Name der ServerDatenbank lautet Pubs, die Tabelle, die an der Verknüpfung beteiligt ist, heißt Stores und die Datenquelle ist PublisherData. Sie melden sich als SA (Datenbanksystemadministrator) ohne Kennwort an. Benutzer-ID und Kennwort sind möglicherweise schon bei der Anmeldung Ihrer Anwendung genannt und in Variablen abgelegt worden, bis sie für die Anmeldung beim Server gebraucht wurden, wie dieser Code zeigt: Call LinkToSQL("tblStores", "Pubs", "Stores", "PublisherData", "SA", "")
Dieser und der größte Teil des weiteren Codes dieses Kapitels befindet sich in der Datenbank CHAP19EX.MDB auf der CD-ROM mit dem Beispiel-Code.
19.10.3 Mit Sichten anstelle von Tabellen verknüpfen Sichten auf einem Datenbank-Server entsprechen Access-Abfragen. Sie liefern eine gewisse Form von Sicherheit, indem sie die Zeilen und Spalten einschränken, die der Benutzer sehen kann. Es wird Zugriff auf die Sicht gewährt und nicht direkt auf die
744
Kapitel 19: Client-Server-Techniken
zu Grunde liegende Tabelle. Standardmäßig lassen sich Sichten nicht aktualisieren. Sie können eine Sicht aktualisierbar machen, indem Sie alle Felder, aus denen der Primärschlüssel besteht, in die Sicht aufnehmen und einen eindeutigen Index auf der Basis des Primärschlüssels erstellen. Sichten lassen sich auf drei Arten erstellen:
mit Hilfe des SQL Server Enterprise Managers für SQL 6.5 oder SQL 7.0 (bzw. der entsprechenden Option für den Back-End-Datenbank-Server)
mit der Anweisung Create View von Access mit Hilfe der Registerkarte SICHT einer ADP-Datei Um von einer Access-Standarddatenbank (.MDB) aus eine entfernte Sicht zu erstellen, unternehmen Sie Folgendes: 1. Erstellen Sie eine neue Abfrage. 2. Klicken Sie im Dialogfeld TABELLE ANZEIGEN auf SCHLIESSEN, ohne eine Tabelle zu markieren. 3. Wählen Sie ABFRAGE|SQL SPEZIFISCH|PASS-THROUGH. 4. Geben Sie die Create View-Anweisung ein, wie in Abbildung 19.26 gezeigt.
Abbildung 19.26: Eine Abfrage für eine entfernte Sicht erstellen
5. Klicken Sie auf AUSFÜHREN. 6. Wählen Sie eine SQL-Datenquelle und klicken Sie auf OK. 7. Geben Sie die Anmeldeinformationen ein und klicken Sie auf OK. Möglicherweise bekommen Sie die in Abbildung 19.27 gezeigte Meldung angezeigt. Diese wird im Abschnitt »Gespeicherte Prozeduren ausführen und erstellen« weiter hinten in diesem Kapitel erläutert und dort erfahren Sie auch, wie Sie sie verhindern können.
745
Mit verknüpften Tabellen arbeiten
Abbildung 19.27: Die Fehlermeldung, die Sie beim Erstellen einer entfernten Sicht bekommen
Nachdem Sie mit dieser Technik eine entfernte Sicht erstellt haben, können Sie eine Verknüpfung mit dieser wie mit jeder anderen Tabelle einrichten. Sie werden dann mit dem Dialogfeld EINDEUTIGEN DATENSATZBEZEICHNER AUSWÄHLEN konfrontiert, wie in Abbildung 19.28 gezeigt. Es ist sehr wichtig, Access einen eindeutigen Index zu liefern, da sich die Ergebnisse der Sicht sonst nicht aktualisieren lassen. Die Sicht lässt sich dann behandeln, als wäre sie eine Verknüpfung mit einer Tabelle.
Abbildung 19.28: Das Dialogfeld Eindeutigen Datensatzbezeichner auswählen nach der Auswahl einer Sicht
Access-Datenprojekte werden im Abschnitt »Über ein Microsoft Access-Datenprojekt auf Client-Server-Daten zugreifen« dieses Kapitels ausführlich vorgestellt. Um von einer Access-Datenprojektdatei (.ADP) aus eine entfernte Sicht zu erstellen, unternehmen Sie Folgendes: 1. Klicken Sie im Datenbankfenster in der Liste der Objekte auf SICHTEN. 2. Doppelklicken Sie auf das Symbol ERSTELLT EINE SICHT UNTER VERWENDUNG DES DESIGNERS. Es erscheint eine NEUE SICHT (siehe Abbildung 19.29). 3. Klicken Sie auf das Werkzeug TABELLE ANZEIGEN in der Symbolleiste. Das Fenster TABELLE ANZEIGEN wird eingeblendet. Sehen Sie sich mit Hilfe der Pluszeichen (+) die Tabellen und Sichten in der Datenbank an, die mit der AccessDatenprojektdatei verknüpft sind (siehe Abbildung 19.30). 4. Ziehen Sie die Tabellen, die in der Sicht erscheinen sollen, in das Sicht-Fenster und legen Sie sie dort ab. In dem Beispiel in Abbildung 19.31 wurden die Tabellen tblClients und tblProjects in die Sicht aufgenommen.
746
Kapitel 19: Client-Server-Techniken
Abbildung 19.29: Ein Beispiel für eine neue Sicht
Abbildung 19.30: Das Fenster Tabelle anzeigen zeigt alle Tabellen und Sichten in der Datenbank, die mit dem Access-Datenprojekt verknüpft sind
5. Klicken Sie in die Kontrollkästchen links von den Feldnamen, um die Felder auszuwählen, die Sie in die Sicht aufnehmen wollen. Wenn Sie wollen, können Sie die Felder auch in die Spaltenliste im Abfragebereich ziehen und dort ablegen. Abbildung 19.32 zeigt eine Sicht mit den Feldern ClientID, CompanyID, ProjectName, ProjectDescription und City.
Mit verknüpften Tabellen arbeiten
747
Abbildung 19.31: Die Tabellen tblClients und tblProjects erscheinen in der Sicht verknüpft
Abbildung 19.32: Eine Sicht mit ausgewählten Feldern und Kriterien
6. Geben Sie alle Kriterien an, die Sie auf die Sicht anwenden wollen. Sie müssen die gewünschten Kriterien in die Spalte KRITERIEN des entsprechenden Feldes im Abfragebereich eingeben. Damit schränken Sie die Datensätze ein, die beim Ausführen der Abfrage zurückgegeben werden. Abbildung 19.32 zeigt Kriterien, welche die zurückgegebenen Datensätze auf diejenigen in Boston und Los Angeles beschränken.
748
Kapitel 19: Client-Server-Techniken
7. Testen Sie die Sicht mit Hilfe der Schaltfläche AUSFÜHREN. Sie werden aufgefordert, Änderungen an der Sicht zu speichern. 8. Die Sicht erscheint im Datenbankfenster und kann weitgehend wie eine Tabelle behandelt werden.
19.11
Pass-Through-Abfragen
Wenn Sie eine Abfrage in Access speichern und ausführen, wird diese normalerweise, auch wenn sie entfernte Daten verwendet, von Access kompiliert und optimiert. Häufig entspricht das genau Ihren Wünschen. Bei anderen Gelegenheiten könnte es jedoch günstiger sein, eine Pass-Through-Abfrage auszuführen, da diese nicht von der Jet-Engine von Access analysiert, sondern direkt an den Server weitergegeben wird. Dies reduziert die Zeit, die Jet für die Analyse der Abfrage benötigt, und versetzt Sie in die Lage, dem Back-End Server-spezifische Syntax zu liefern. Außerdem können Pass-Through-Abfragen Informationsmeldungen protokollieren, die der Server zurückgibt. Schließlich laufen Aktualisierungs-, Lösch- und Anhängeabfragen auf großen Datenmengen als Pass-Through-Abfragen schneller als in Form von Access-Aktionsabfragen auf der Basis entfernter Tabellen. Pass-Through-Abfragen haben aber auch einen Nachteil: sie geben immer eine Momentaufnahme zurück, was sie unaktualisierbar macht. Außerdem müssen Sie die genaue Syntax kennen, die der Server verlangt, und Sie müssen die Anweisung in das Abfragefenster eingeben, anstatt sie grafisch darzustellen. Schließlich können Sie die Abfrage nicht mit Parametern versehen, damit sie den Benutzer nach einem Wert fragt.
19.11.1
Mit Hilfe der Benutzerschnittstelle in einer MDB-Datei eine PassThrough-Abfrage erstellen
Um eine Pass-Through-Abfrage zu erstellen, können Sie die Abfrage im AbfrageEditor von Access schreiben. Wählen Sie dazu ABFRAGE|SQL SPEZIFISCH|PASSTHROUGH. Sie sehen dann ein Textbearbeitungsfenster, in das Sie die Abfrageanweisung schreiben können. Die eingegebene SQL-Anweisung muss in dem SQL-Dialekt formuliert werden, der für Ihr Back-End gilt.
19.11.2 Eine Pass-Through-Abfrage mit Hilfe von Code ausführen Sie können eine Pass-Through-Abfrage auch mit Hilfe von VBA-Code ausführen. Genau genommen müssen Sie die Pass-Through-Abfrage mittels VBA-Code abfassen, wenn sie Parameter enthalten soll, die Sie dem Server übergeben wollen. Sie sehen jetzt eine Möglichkeit, wie Sie mit Hilfe von VBA-Code eine Pass-ThroughAbfrage erstellen können:
Pass-Through-Abfragen
749
1. Richten Sie eine Verbindung zu der SQL Server-Datenbank ein. 2. Führen Sie die SQL-Anweisung auf dem Back-End-Datenbank-Server mit Hilfe der Methode Execute des Objekts Connection aus. Wie eine SQL-Anweisung, die mit ABFRAGE|SQL SPEZIFISCH|PASS-THROUGH-ABFRAGE erstellt wurde, muss auch diese Anweisung in der für Ihr Back-End geltenden Syntax abgefasst werden. Listing 19.2 zeigt den Code für diese Prozedur. Listing 19.2:
Eine Pass-Through-Abfrage mit Hilfe von Code ausführen
Sub PassThroughQuery(strDBName As String, _ strDataSourceName As String, _ strUserID As String, _ strPassWord As String) Dim cnn As ADODB.Connection Dim strConnectString As String strConnectString = "ODBC" & _ ";DATABASE=" & strDBName & _ ";UID=" & strUserID & _ ";PWD=" & strPassWord & _ ";DSN=" & strDataSourceName Set cnn = New ADODB.Connection cnn.ConnectionString = strConnectString cnn.Open cnn.Execute "Update dbo.Sales Set Qty = Qty + 1", _ Options:=adCmdText End Sub
Die Routine wird so aufgerufen, wie es der Code zeigt: Call PassThroughQuery("Pubs", "PublisherData", "SA", "")
Diese Unterroutine verwendet eine Verbindungszeichenfolge, die eine Verbindung zu einer Datenbank mit dem Namen Pubs mit einer Datenquelle namens PublisherData, der Benutzer-ID SA und ohne Kennwort herstellt. Dann führt sie eine PassThrough-Abfrage aus, die das Feld Qty jedes Datensatzes auf Qty +1 aktualisiert. Wie Sie gesehen haben, besteht eine Möglichkeit, eine Pass-Through-Abfrage auszuführen, darin, mit Hilfe der Methode Open des Objekts Connection eine Verbindung zur Datenbank aufzubauen und anschließend die Abfrage mit Hilfe der Methode Execute des Datenbankobjekts auszuführen. Die Beschränkung dieser Vorgehensweise liegt darin, dass die Methode Execute keine Abfragen ausführen kann, die Daten zurückgeben. Wenn Sie Datensätze zurückgeben wollen, können Sie eine
750
Kapitel 19: Client-Server-Techniken
andere Art der Ausführung einer Pass-Through-Abfrage wählen. Dabei wird das Ergebnis der Pass-Through-Abfrage in ein Objekt des Typs Recordset zurückgegeben. Dies wird in Listing 19.3 gezeigt. Listing 19.3:
Eine Pass-Through-Abfrage ausführen, die Datensätze zurückgibt
Sub PassThroughQueryResults(strDBName As String, _ strDataSourceName As String, _ strUserID As String, _ strPassWord As String) Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim strConnectString As String strConnectString = "ODBC" & _ ";DATABASE=" & strDBName & _ ";UID=" & strUserID & _ ";PWD=" & strPassWord & _ ";DSN=" & strDataSourceName Set cnn = New ADODB.Connection cnn.ConnectionString = strConnectString cnn.Open Set rst = cnn.Execute("Select * from dbo.Sales Where Qty >5", _ Options:=adCmdText) Do Until rst.EOF Debug.Print rst!Stor_id, rst!Qty rst.MoveNext Loop End Sub
19.12
Gespeicherte Prozeduren erstellen und ausführen
Auf einem Back-End-Datenbank-Server lassen sich auch gespeicherte Prozeduren ausführen. Eine gespeicherte Prozedur entspricht einer Abfrage oder einem Programm, das auf dem Back-End gespeichert ist, und führt eine Aktion aus. Ein Beispiel ist die in SQL Server 7.0 gespeicherte Prozedur sp_columns, die Informationen über die Felder einer bestimmten Tabelle zurückgibt. Abbildung 19.33 zeigt, wie Sie diese gespeicherte Prozedur vom Abfrage-Entwurfsfenster aus ausführen würden. Sie geben einfach den Namen der gespeicherten Prozedur und die erforderlichen Parameter ein. Sehen Sie sich das Fenster ABFRAGEEIGENSCHAFTEN in Abbildung 19.33 genau an. Wenn Sie eine gültige Verbindungszeichenfolge eingeben, wird der
Gespeicherte Prozeduren erstellen und ausführen
751
Benutzer zur Laufzeit nicht aufgefordert, sich anzumelden. Die Eigenschaft Liefert Datensätze ist ebenfalls wichtig. In diesem Fall setzen Sie den Wert der Eigenschaft auf Ja, damit Sie die Ergebnisse der gespeicherten Prozedur sehen können. Wenn diese keine Datensätze zurückgibt, wie es bei der im Abschnitt »Mit Sichten anstelle von Tabellen verknüpfen« erstellten Create-View-Pass-Through-Abfrage der Fall ist, ist es wichtig, die Eigenschaft auf Nein zu setzen; sonst bekommen Sie eine Fehlermeldung, die besagt, dass keine Zeilen zurückgegeben wurden. Abbildung 19.34 zeigt die Ergebnisse der Ausführung der gespeicherten Prozedur.
Abbildung 19.33: Ausführung einer gespeicherten Prozedur durch Eingabe des Prozedurnamens und der erforderlichen Parameter vom Abfragefenster aus
Abbildung 19.34: Die Ergebnisse der Ausführung der gespeicherten Prozedur sp_columns
Listing 19.4 zeigt eine Prozedur, welche mittels Code die gespeicherte Prozedur sp_columns ausführt. Listing 19.4:
Ausführen der gespeicherten Prozedur sp_columns
Sub StoredProcedure() Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim strConnectString As String strConnectString = "ODBC" & _ ";DATABASE=Pubs" & _ ";UID=SA" & _ ";PWD=" & _ ";DSN=PubsData"
752
Kapitel 19: Client-Server-Techniken
Set cnn = New ADODB.Connection cnn.ConnectionString = strConnectString cnn.Open Set rst = cnn.Execute("sp_columns('sales')", _ Options:=adCmdStoredProc) Do While Not rst.EOF Debug.Print rst!Column_Name rst.MoveNext Loop End Sub
Und so funktioniert sie: Zunächst wird ein Connection-Objekt angelegt und geöffnet, dann wird ein Recordset-Objekt erstellt, das die Ergebnisse der Ausführung der gespeicherten Prozedur aufnehmen soll. Beachten Sie, dass die gespeicherte Prozedur sp_columns einen Parameter übernimmt, der in Klammern steht. Die Konstante adCmdStoredProc teilt, wenn sie als Parameter Options übergeben wird, ADO mit, dass der Befehlstext für die Anweisung Execute der Name einer gespeicherten Prozedur ist.
19.12.1 Eine gespeicherte Prozedur schreiben Wenn Ihre Anwendung eine ADP-Datei ist, können Sie direkt aus der AccessUmgebung gespeicherte Prozeduren schreiben. Folgende Schritte sind dazu erforderlich: 1. Wählen Sie in der Objektliste des Datenbankfensters die Option GESPEICHERTE PROZEDUREN. 2. Doppelklicken Sie auf ERSTELLT EINE GESPEICHERTE PROZEDUR UNTER VERWENDUNG DES DESIGNERS. Dies ruft das Fenster GESPEICHERTE PROZEDUR auf (siehe Abbildung 19.35). 3. Geben Sie den Text für die gespeicherte Prozedur ein. 4. Klicken Sie auf das Werkzeug SPEICHERN in der Symbolleiste. 5. Geben Sie den Namen für die gespeicherte Prozedur ein und klicken Sie auf OK.
753
Über ein Microsoft Access-Datenprojekt auf Client-Server-Daten zugreifen
Abbildung 19.35: Im Dialogfeld Gespeicherte Prozedur können Sie auf einem DatenbankServer eine gespeicherte Prozedur erstellen
19.13
Über ein Microsoft Access-Datenprojekt auf Client-Server-Daten zugreifen
Wie in diesem Kapitel bereits erwähnt, können Sie mit Hilfe von Access-Projekten (ADP-Dateien) mit SQL Server-Datenbanken arbeiten, ohne die Microsoft JetDatenbank-Engine zu laden. Access-Projekte besitzen gegenüber den anderen in diesem Kapitel behandelten Zugriffsmethoden für Client-Server-Daten folgende Vorteile:
Sie bieten Ihnen direkten Zugriff auf eine Microsoft SQL Server-Datenbank. Sie können mühelos SQL Server-Tabellen, -Sichten, -Datenbankdiagramme und gespeicherte Prozeduren erstellen und zwar in der Access-Entwicklungsumgebung.
Sie können Formulare, Berichte, Datenzugriffsseiten und Module entwickeln, die auf SQL Server zugreifen, ohne Jet zu benutzen.
Auf der Client-Seite sind geringere Ressourcen erforderlich. Der Server ist für die gesamte Abfrageverarbeitung zuständig. Sie können auf Funktionen zugreifen, die beim Zugriff auf ODBC über Jet nicht verfügbar sind.
Sie können asynchrone Abfragen ausführen, d.h. Sie brauchen nicht darauf zu warten, dass die Ausführung einer Abfrage abgeschlossen ist, bevor Sie eine andere Operation beginnen.
754
Kapitel 19: Client-Server-Techniken
Sie können Batch-Aktualisierungen durchführen, d.h. Sie haben die Möglichkeit, Änderungen lokal zwischenzuspeichern und sie dem Server dann als Stapel zu liefern.
Sie können Abfragen ausführen, die mehrere Ergebnisgruppen liefern. Die Anzahl der Datensätze, die in einer Ergebnisgruppe zurückgegeben wird, lässt sich mühelos begrenzen.
Meldungen und Fehler, die von der entfernten Datenquelle erzeugt werden, lassen sich einfach überwachen. Nun die Nachteile der Access-Datenprojektdateien:
Sie können keine lokalen Tabellen anlegen. Sie können keine lokalen Abfragen erstellen. Das Erstellen von Tabellen, Sichten, Datenbankdiagrammen und gespeicherten Prozeduren erfordert Lernaufwand.
19.13.1 Ein Access-Datenprojekt (ADP) erstellen Mit Access 2000 werden Access-Datenprojekte (ADPs) eingeführt. Während eine Access-Datenbank über die Jet-Engine und ODBC auf Client-Server-Daten zugreift, verwenden ADPs zu diesem Zweck OLE DB. Dadurch bekommen Sie bei der Nutzung von Client-Server-Daten deutlich mehr Funktionen und höhere Leistung. Der einzige Nachteil liegt darin, dass die Client-Server-Daten in einer Microsoft SQL Server 7.0-Datenbank, in der MSDE oder in einer Microsoft SQL Server 6.5-Datenbank mit installiertem Service Pack 5 gespeichert werden müssen. Die
MSDE
finden
Sie
auf
der
Office-2000-CD-ROM
im
Ordner
\sql\x86\setup.
Wenn Sie mit Hilfe einer Access-Datenbank auf Client-Server-Daten zugreifen, müssen Sie verknüpfte Tabellen, Pass-Through-Abfragen und ODBC zur Bearbeitung der Daten benutzen. Wenn Sie die Strukturen der Client-Server-Tabellen verändern wollen, muss das in der SQL Server-Umgebung stattfinden. Bei einem Access-Datenprojekt können Sie Tabellen, Sichten, Datenbankdiagramme und gespeicherte Prozeduren direkt aus der Access-Umgebung erstellen und modifizieren.
Über ein Microsoft Access-Datenprojekt auf Client-Server-Daten zugreifen
755
Um ein Access-Datenprojekt zu erstellen, ist Folgendes erforderlich: 1. Klicken Sie auf die Schaltfläche NEU in der Symbolleiste.
Abbildung 19.36: Im Dialogfeld Neu können Sie auf der Basis einer neuen oder bereits vorhandenen SQL Server-Datenbank ein ADP erstellen
2. Es gibt zwei Optionen, um ein ADP zu erstellen. Mit der ersten können Sie eine vorhandene SQL Server-Datenbank als Grundlage für das ADP verwenden, mit der zweiten eine neue SQL Server-Datenbank. Wenn Sie doppelklicken, um ein Projekt auf der Basis einer vorhandenen Datenbank zu erstellen, wird das Dialogfeld NEUE DATENBANKDATEI eingeblendet. Geben Sie Namen und Speicherort der ADP-Datei ein und klicken Sie auf ERSTELLEN. Daraufhin erscheint das Dialogfeld DATENLINKEIGENSCHAFTEN (siehe Abbildung 19.37). 3. Geben Sie den Namen des Servers, Sicherheitsinformationen und den Namen der Datenbank ein, mit der Sie Verbindung aufnehmen wollen. 4. Klicken Sie auf die Registerkarte WEITERE, um weitere Optionen einzugeben, oder auf die Registerkarte ALLE, um Verbindungsoptionen einzusehen oder zu ändern. 5. Wenn Sie mit der Angabe von Optionen fertig sind, klicken Sie auf die Registerkarte VERBINDUNG und dann auf VERBINDUNG TESTEN, um sicherzustellen, dass alle Einstellungen korrekt vorgenommen wurden. 6. Klicken Sie auf OK, um das Access-Datenprojekt zu erstellen. Abbildung 19.38 zeigt eine ADP-Datei auf der Grundlage des Zeit- und Abrechnungssystems. Beachten Sie, dass die Tabellen so erscheinen, als wären sie in der ADP-Datei enthalten. Tatsächlich sind sie aber in der SQL Server-Datenbank gespeichert. Wichtig ist hier, dass die Tabellen nicht verknüpft sind! Deshalb sehen sie aus, als ob sie Teil des ADP wären, und lassen sich entsprechend bearbeiten.
756
Kapitel 19: Client-Server-Techniken
Abbildung 19.37: Im Dialogfeld Datenlinkeigenschaften können Sie Verbindungsinformationen in Bezug auf die SQL Server-Datenbank eingeben, mit der die ADP-Datei verknüpft ist
Abbildung 19.38: Die ADP-Datei zeigt Ihnen die in der SQL ServerDatenbank enthaltenen Tabellen, Sichten, Datenbankdiagramme und gespeicherten Prozeduren
Wie Sie in Abbildung 19.38 sehen können, sieht das Datenbankfenster für eine ADP-Datei anders aus als das für eine MDB-Datei. Die Objektliste enthält Tabellen,
757
Über ein Microsoft Access-Datenprojekt auf Client-Server-Daten zugreifen
Sichten, Datenbankdiagramme und gespeicherte Prozeduren statt Tabellen und Abfragen. Tatsächlich lassen sich weder lokale Tabellen noch Abfragen in einer ADP-Datei speichern.
19.13.2 Mit SQL Server-Tabellen arbeiten Einer der wesentlichen Vorteile eines ADP besteht darin, dass man SQL ServerTabellen direkt aus der Access-Umgebung erstellen, verändern, umbenennen und löschen kann. Es ist wichtig, daran zu denken, dass alle Änderungen, die aus Access heraus vorgenommen werden, in der verknüpften SQL Server-Datenbank unmittelbar zum Tragen kommen. Eine SQL Server-Tabelle anlegen Mit dem SQL Server Table Designer können Sie aus Access heraus SQL ServerTabellen anlegen. Dazu unternehmen Sie Folgendes: 1. Wählen Sie in der Objektliste den Eintrag TABELLEN. 2. Doppelklicken Sie auf ERSTELLT EINE TABELLE IN DER ENTWURFSANSICHT. 3. Geben Sie einen Namen für die SQL Server-Tabelle ein und klicken Sie auf OK. Sie gelangen in den SQL Server-Tabellen-Designer, wo Sie die Felder und Attribute definieren können (siehe Abbildung 19.39).
Abbildung 19.39: Im SQL ServerTabellenDesigner können Sie Namen und Attribute der Spalten eingeben
4. Geben Sie im SQL Server-Tabellen-Designer die Namen und Attribute der Spalten ein. 5. Schließen Sie das Fenster und speichern Sie Ihre Änderungen, wenn Sie fertig sind.
758
Kapitel 19: Client-Server-Techniken
Eine SQL Server-Tabelle verändern Um die Struktur einer vorhandenen SQL Server-Tabelle zu verändern, unternehmen Sie Folgendes: 1. Wählen Sie in der Objektliste den Eintrag TABELLEN. 2. Markieren Sie die Tabelle, deren Struktur Sie verändern wollen. 3. Klicken Sie auf ENTWURF. Die Struktur der Tabelle wird eingeblendet. Abbildung 19.40 zeigt die Tabelle tblClients in der Entwurfsansicht.
Abbildung 19.40: Die Tabelle tblClients in der Entwurfsansicht
4. Verändern Sie Namen und Attribute der gewünschten Spalten. 5. Schließen Sie das Fenster und speichern Sie Ihre Änderungen, wenn Sie fertig sind. Das Erstellen von und die Arbeit mit Tabellen, Sichten, Datenbankdiagrammen und gespeicherten Prozeduren in SQL Server wird in »Microsoft SQL Server 7.0 in 21 Tagen« oder »Microsoft SQL Server 7.0 Kompendium«, beide als Markt&Technik-Bücher erschienen, ausführlich behandelt. Eine SQL Server-Tabelle löschen Das Löschen einer SQL Server-Tabelle ist ganz einfach: 1. Wählen Sie in der Objektliste den Eintrag TABELLEN. 2. Klicken Sie mit der rechten Maustaste auf die zu löschende Tabelle.
759
Über ein Microsoft Access-Datenprojekt auf Client-Server-Daten zugreifen
3. Wählen Sie im Kontextmenü LÖSCHEN. Sie müssen daran denken, dass die Tabelle durch das Löschen über den ADP aus der SQL Server-Datenbank entfernt wird. Die Einfachheit des Löschens einer SQL Server-Tabelle über ein ADP macht es außerdem notwendig, dass für die SQL ServerDatenbank eine angemessene Absicherung eingerichtet ist.
19.13.3 Mit SQL Server-Sichten arbeiten SQL Server-Sichten entsprechen Access-Auswahlabfragen. Der wesentliche Unterschied besteht darin, dass SQL Server-Sichten die Verwendung von Parametern nicht unterstützen. Eine SQL Server-Sicht erstellen 1. Wählen Sie in der Objektliste den Eintrag SICHTEN. 2. Doppelklicken Sie auf ERSTELLT EINE SICHT UNTER VERWENDUNG NERS. Danach wird das Sichtenfenster eingeblendet.
DES
DESIG-
3. Definieren Sie die Spalten, Kriterien und die übrigen Attribute der Sicht, wie im Abschnitt »Mit Sichten anstelle von Tabellen verknüpfen« dieses Kapitels beschrieben. Eine SQL Server-Sicht modifizieren Das Modifizieren einer Sicht verläuft ähnlich wie das Modifizieren einer Tabelle: 1. Wählen Sie in der Objektliste den Eintrag SICHTEN. 2. Markieren Sie die Sicht, deren Attribute Sie verändern wollen. 3. Klicken Sie auf ENTWURF. Der Entwurf der vorliegenden Sicht erscheint. 4. Modifizieren Sie die Attribute der Sicht. 5. Schließen Sie das Fenster und speichern Sie Ihre Änderungen, wenn Sie fertig sind. Eine SQL Server-Sicht löschen Das Löschen einer SQL Server-Sicht ist sehr einfach: 1. Wählen Sie in der Objektliste den Eintrag SICHTEN. 2. Klicken Sie mit der rechten Maustaste auf die zu löschende Sicht. 3. Wählen Sie im Kontextmenü LÖSCHEN. Wie bei Tabellen müssen Sie daran denken, dass die Sicht mit dem Löschen aus dem ADP auch aus der SQL Server-Datenbank entfernt wird. Dies unterstreicht wiederum, dass für die SQL Server-Datenbank eine angemessene Absicherung erforderlich ist.
760
Kapitel 19: Client-Server-Techniken
19.13.4 Mit Datenbankdiagrammen arbeiten Datenbankdiagramme bieten Ihnen eine visuelle Methode zum Entwerfen und Verwalten Ihrer Datenbanktabellen. Mit Hilfe eines Datenbankdiagramms lassen sich Tabellenbeziehungen einrichten und ändern und Tabellenstrukturen bearbeiten. Ein Datenbankdiagramm erstellen Um ein Datenbankdiagramm zu erstellen, unternehmen Sie Folgendes: 1. Wählen Sie in der Objektliste den Punkt DATENBANKDIAGRAMME. 2. Doppelklicken Sie auf EIN DATENBANKDIAGRAMM UNTER VERWENDUNG DESIGNERS ERSTELLEN. Ein leeres Diagrammfenster erscheint.
DES
3. Klicken Sie auf TABELLE ANZEIGEN, um die Tabellen zu sehen, die in der mit dem ADP verknüpften SQL Server-Datenbank enthalten sind (siehe Abbildung 19.41).
Abbildung 19.41: Beim Anlegen eines Datenbankdiagramms beginnen Sie mit dem Einfügen von Tabellen in das leere Diagrammfenster
4. Klicken Sie auf die gewünschten Tabellen und ziehen Sie sie in das Datenbankdiagramm. 5. Um die Struktur einer Tabelle zu ändern, klicken Sie im Designer mit der rechten Maustaste auf die Tabelle und wählen SPALTENEIGENSCHAFTEN. Die im Datenbank-Designer geänderten Eigenschaften werden unmittelbar in der SQL Server-Datenbank geändert.
Über ein Microsoft Access-Datenprojekt auf Client-Server-Daten zugreifen
761
6. Um eine Beziehung zu verändern, klicken Sie mit der rechten Maustaste auf die Beziehungslinie und wählen EIGENSCHAFTEN. Dies ruft das Dialogfeld EIGENSCHAFTEN auf (siehe Abbildung 19.42). Dort können Sie alle Attribute einer bestehenden Beziehung verändern. 7. Um eine Beziehung hinzuzufügen, klicken Sie auf den Feldmarkierer und ziehen diesen von der einen Tabelle in die andere. Im Anschluss daran wird das Dialogfeld BEZIEHUNG ERSTELLEN eingeblendet (siehe Abbildung 19.43).
Abbildung 19.42: Im Fenster Eigenschaften können Sie die Attribute einer bestehenden Beziehung verändern
Ein Datenbankdiagramm verändern Um ein vorhandenes Datenbankdiagramm zu verändern, unternehmen Sie Folgendes: 1. Wählen Sie in der Objektliste den Eintrag DATENBANKDIAGRAMME. 2. Markieren Sie das Datenbankdiagramm, dessen Attribute Sie verändern wollen. Abbildung 19.44 zeigt das mit dem Datenprojekt NorthwindCS verknüpfte Datenbankdiagramm, das zusammen mit Microsoft Access geliefert wurde. 3. Klicken Sie auf ENTWURF. Der Entwurf des Datenbankdiagramms erscheint. 4. Verändern Sie die Attribute des Datenbankdiagramms.
762
Kapitel 19: Client-Server-Techniken
Abbildung 19.43: Im Dialogfeld Beziehung erstellen können Sie die Eigenschaften einer neuen Beziehung festlegen
Abbildung 19.44: Im Datenbankdiagrammfenster können Sie Beziehungen zwischen Tabellen einrichten und die Struktur von Tabellen verändern
5. Schließen Sie das Fenster und speichern Sie Ihre Änderungen, wenn Sie fertig sind.
19.13.5 Mit gespeicherten Prozeduren arbeiten Das Erstellen und Verändern gespeicherter Prozeduren wird im Abschnitt »Gespeicherte Prozeduren erstellen und ausführen« dieses Kapitels erläutert. Sie sollten unbedingt beachten, dass gespeicherte Prozeduren zwar Sichten ähnlich sind, aber
Über ein Microsoft Access-Datenprojekt auf Client-Server-Daten zugreifen
763
zwei weitere Funktionsmerkmale besitzen, die in Sichten nicht zur Verfügung stehen: Gespeicherte Prozeduren können Parameter enthalten und deshalb zur Laufzeit Kriterien übernehmen und außerdem lassen sie sich so entwerfen, dass sie Tabellendaten bearbeiten können. Zwischen dem Ausführen einer Access-Aktionsabfrage für eine verknüpfte Tabelle und dem Ausführen einer gespeicherten Prozedur besteht ein wichtiger Unterschied. Bei einer Aktionsabfrage müssen alle von der Abfrage betroffenen Daten über die Netzwerkleitung transportiert werden, um mit Hilfe der Abfrage auf der Arbeitsstation aktualisiert zu werden. Eine gespeicherte Prozedur aktualisiert Daten dagegen direkt auf dem Server, ohne dass ein Transport der Daten über das Netzwerk erforderlich ist. Das kann zu größeren Leistungsunterschieden führen, insbesondere wenn es um große Datenmengen geht.
19.13.6 Formulare, Berichte, Makros und Module erstellen und damit arbeiten Das Erstellen von und die Arbeit mit Formularen, Berichten, Makros und Modulen in einer ADP-Datei ist der Arbeit mit entsprechenden Objekten in einer AccessDatenbank sehr ähnlich. Wichtig ist jedoch Folgendes: während die Tabellen, Sichten, Datenbankdiagramme und gespeicherten Prozeduren auf dem Server gespeichert sind, werden die Formulare, Berichte, Makros und Module als OLE-Dokumentteil in der ADP-Datei abgelegt. ADP-Dateien sind im Allgemeinen kleiner als MDB-Dateien und weniger anfällig für Beschädigungen!
19.13.7 Andere im Zusammenhang mit Access-Datenprojekten verfügbare Funktionen Neben der Möglichkeit, SQL Server-Tabellen, -Sichten, -Datenbankdiagramme und gespeicherte SQL Server-Prozeduren aus der Access-Umgebung heraus zu pflegen, bringen ADP-Dateien Ihnen weitere Vorteile. Von einer ADP-Datei aus lassen sich folgende Aufgaben erledigen:
Anlegen von Sicherungskopien der SQL Server-Datenbank Wiederherstellen der SQL Server-Datenbank Replikation der SQL Server-Datenbank einschließlich der Möglichkeit, neue SQL Server-Publikationen zu erstellen, Replikate zu synchronisieren und Konflikte zu lösen.
Pflege der SQL Server-Sicherheit
Client-Server-Strategien
Kapitel
Hier lesen Sie:
Effizientes Vorgehen Den günstigsten Typ für eine Datensatzgruppe wählen Pass-Through-Abfragen und gespeicherte Prozeduren Access-Datenprojekte Den Umgang mit Daten optimieren Abfragen und Formulare optimieren
20.1
Effizientes Vorgehen
Wie Sie im vorigen Kapitel gesehen haben, passiert es leicht, Client-Server-Strategien ineffizient zu implementieren. Das kann dazu führen, dass die Leistung schlechter statt besser wird. Es ist die Aufgabe des Entwicklers, die Techniken intelligent anzuwenden, mit der Client-Server-Systeme wirkungsvoll zum Einsatz kommen. Dieses Kapitel behandelt Strategien, die Ihnen bei der Entwicklung eleganter ClientServer-Anwendungen helfen.
20.2
Den günstigsten Typ für eine Datensatzgruppe wählen
Welchen Typ Sie für eine Datensatzgruppe wählen, wirkt sich deutlich auf die Leistung aus. Sowohl die Eigenschaften CursorType und LockType als auch der Parameter Options der Methode Open des Objekts Recordset bestimmen, welcher Typ Datensatzgruppe zurückgegeben wird.
766
20.2.1
Kapitel 20: Client-Server-Strategien
Die Eigenschaft CursorType
Die Eigenschaft CursorType bestimmt, welcher Cursor-Typ vom Objekt Recordset zurückgegeben wird. Folgende Optionen stehen zur Verfügung:
adOpenForwardOnly adOpenStatic adOpenKeyset adOpenDynamic Jeder dieser Cursor-Typen bietet eine andere Funktionalität und unterschiedliche Leistung. Was die Leistung betrifft, ist der Vorwärts-Cursor am besten geeignet, bietet jedoch die geringste Funktionalität. Es folgen der statische Cursor, der KeysetCursor und der dynamische Cursor. Was die Funktionalität betrifft, liegt der Vorwärts-Cursor auf dem letzten Platz. Es folgen der statische, der Keyset- und der dynamische Cursor. Wie bereits erwähnt, bietet der Vorwärts-Cursor die beste Leistung, aber die geringste Funktionalität. Wie der Name schon sagt, erlaubt er nur Vorwärtsbewegungen durch die Datensätze der Datensatzgruppe. Er eignet sich nur für Situationen, in der ein einziger Durchgang durch die Datensätze angemessen ist. Ein statischer Cursor erlaubt sowohl Vorwärts- als auch Rückwärtsbewegungen durch die Datensätze der Datensatzgruppe. Seine größte Einschränkung liegt darin, dass Änderungen durch andere Benutzer im Netzwerk (einschließlich Hinzufügen, Bearbeiten und Löschen) in der Datensatzgruppe nicht wiedergegeben werden. Obwohl ein statischer Cursor weniger effizient ist als ein Vorwärts-Cursor, liegt seine Effizienz deutlich über der eines Keyset- oder eines dynamischen Cursors. Das liegt daran, dass er sich nicht um die ständige Aktualisierung der Datenanzeige vom Server kümmern muss. Ein Keyset-Cursor bietet alles, was der statische Cursor auch hat. Außerdem sind Änderungen durch andere Benutzer in der Datensatzgruppe sichtbar. Von anderen Benutzern hinzugefügte Datensätze stehen aber in der Datensatzgruppe nicht zur Verfügung. Von anderen Benutzern gelöschte Datensätze erscheinen als »Löcher« in der Datensatzgruppe und der Zugriff ist nicht mehr möglich. Ein dynamischer Cursor bietet die größte Funktionalität, aber die niedrigste Leistung. Der Datensatzgruppe stehen nicht nur die Änderungen zur Verfügung, die andere Benutzer an den Daten vorgenommen haben, sondern auch hinzugefügte Datensätze und Löschungen. Es gibt eine sehr einfache Regel, die man bei der Auswahl eines Cursor-Typs befolgen sollte: Sie sollten den Cursor-Typ mit der höchsten Leistung wählen, der die benötigte Funktionalität bietet. Sie müssen sich wirklich überlegen, wie wichtig es ist, dass Sie die Änderungen sehen, die andere Benutzer vornehmen, und ob es erforderlich ist, sich vorwärts und rückwärts durch die Datensatzgruppe zu bewegen.
Den günstigsten Typ für eine Datensatzgruppe wählen
20.2.2
767
Die Eigenschaft LockType
Auch die Eigenschaft LockType kann die Leistung beeinflussen. Sie bestimmt, ob und wie sich die Daten der Datensatzgruppe aktualisieren lassen. Die Optionen lauten:
adLockReadOnly adLockPessimistic adLockOptimistic adLockBatchOptimistic Die wichtigste Differenzierung besteht zwischen der Schreibschutz-Option und den übrigen Optionen. Standardmäßig wird ein Datensatz nur zum Lesen geöffnet. Diese Option liefert die beste Leistung, weil die Aktualisierbarkeit der Datensatzgruppe kein Problem darstellt. Als wichtigstes müssen Sie sich merken, dass Sie die Schreibschutz-Option wählen sollten, wenn die Datensatzgruppe nicht aktualisiert werden muss.
20.2.3
Der Parameter Options der Methode Open
Der Parameter Options der Methode Open bestimmt, wie der Provider das Argument Source der Methode Open des Objekts Recordset auswerten soll. Folgende Wahlmöglichkeiten stehen für den Parameter Options zur Verfügung:
adCmdText adCmdTable adCmdTableDirect adCmdStoredProc adCmdUnknown adCmdFile adAsyncExecute adAsyncFetch adAsyncFetchNonBlocking Es ist wichtig, dass schon die Angabe des Parameters Options Leistungsverbesserungen bewirkt. Das liegt daran, dass ADO nicht ermitteln muss, was im Argument Source steht. Bei der Auswahl des Parameters Options haben die Werte adCmdTable, adCmdTableDirect, adCmdStoredProc, adAsyncExecute, adAsyncFetch und adAsyncFetchNonBlokking den größten Einfluss auf die Leistung. Die Optionen adCmdTable und adCmdTableDirect wirken sich negativ aus, weil beide alle Zeilen der im Argument Source genannten Tabelle zurückgeben. Das kann bei umfangreichen Tabellen in einer Client-Server-Umgebung direkte Konsequenzen haben. Diese Werte unterminieren genau
768
Kapitel 20: Client-Server-Strategien
genommen den wesentlichen Grund dafür, warum eine Anwendung in einer ClientServer-Umgebung installiert wurde. Die Option adCmdStoredProc stellt einfach deshalb eine ausgezeichnete Wahl dar, weil sie vorschreibt, dass die Quelle ausgewertet und als gespeicherte Prozedur auf dem Server ausgeführt wird. Die Option adAsyncExecute gibt an, dass die Quelle asynchron ausgeführt wird, d.h. dass andere Operationen weiterlaufen können, während die Datensätze geholt werden. Die Option adAsyncFetch kann je nach Situation die Leistung steigern oder verringern. Sie legt fest, dass Zeilen, die verbleiben, nachdem die in der Eigenschaft Initial Fetch Size angegebene Anzahl Datensätze geholt wurde, asynchron geholt werden. Das Problem liegt darin, dass der Haupt-Thread, wenn eine angeforderte Zeile nicht verfügbar ist, blockiert wird, bis diese Zeile geholt ist. Die Option adAsyncFetchNonBlocking schließlich stellt sicher, dass der Haupt-Thread in keinem Fall blockiert wird. Wenn die angeforderte Zeile nicht verfügbar ist, rückt die aktuelle Zeile an das Dateiende.
20.3
Pass-Through-Abfragen und gespeicherte Prozeduren
Sie sollten unbedingt daran denken, dass die Ausführung von Pass-Through-Abfragen und gespeicherten Prozeduren erheblich effizienter ist als die Rückgabe einer Datensatzgruppe zur Verarbeitung in Access. Pass-Through-Abfragen und die Einzelheiten ihrer Implementierung werden in Kapitel 19 behandelt. Pass-ThroughAbfragen unterscheiden sich durch den Ort der Verarbeitung. Bei Pass-ThroughAbfragen und gespeicherten Prozeduren findet die gesamte Verarbeitung auf dem Server statt. Wenn Operationen mit Hilfe von VBA-Code ausgeführt werden, müssen alle von diesem Vorgang betroffenen Datensätze auf die Arbeitsstation des Benutzers übertragen, verändert und dann an den Server zurückgegeben werden. Dadurch wird eine erhebliche Menge Netzwerkverkehr erzeugt und die Verarbeitung gewaltig gebremst.
20.4
Access-Datenprojekte
»Access-Datenprojekte« (.ADP-Dateien) ermöglichen den Zugriff auf Microsoft SQL Server-Daten, ohne die Jet-Datenbank-Engine von Microsoft Jet zu laden. Sie liefern durch Beseitigung der Engpässe, welche die Jet-Engine verursacht, eindrucksvolle Leistungssteigerungen. Datenanforderungen gehen direkt an Microsoft SQL Server, anstatt von Jet analysiert und übersetzt zu werden. Access-Datenprojekte werden in Kapitel 19 ausführlich beschrieben. Die durch sie gewonnene Leistung ist möglicherweise erforderlich, damit Sie in einer Anwendung, die Microsoft SQL ServerDaten verwendet, eine zufriedenstellende Leistung erzielen. Außerdem können Sie mit Hilfe von Access-Datenprojekten die mit einer Microsoft SQL Server-Datenbank verknüpften Tabellen, Ansichten, Datenbankdiagramme und gespeicherten
Den Umgang mit Daten optimieren
769
Prozeduren mühelos verwalten. Der wesentliche Nachteil der Datenprojekte liegt darin, dass sie nur zum Zugriff auf Microsoft SQL Server-Datenbanken eingesetzt werden können.
20.5
Den Umgang mit Daten optimieren
Das beste, was Sie zur Optimierung des Umgangs mit Daten – z.B. Bearbeiten, Einfügen und Löschen – tun können, ist das Einfügen eines Versionsfeldes (einer Zeitmarke) in jede entfernte Tabelle. Dieses Versionsfeld wird genutzt, wenn Benutzer die Daten der entfernten Tabelle aktualisieren, um Überschreibkonflikte zu vermeiden. Wenn es nicht vorhanden ist, vergleicht der Server alle Felder, um festzustellen, ob sie sich verändert haben, nachdem der Benutzer mit der Bearbeitung des Datensatzes begonnen hat. Das ist ziemlich ineffizient und wesentlich langsamer als die Auswertung einer Zeitmarke.
20.6
Abfragen und Formulare optimieren
Im Großen und Ganzen verbessert der Umstieg auf die Client-Server-Technologie die Leistung. Wenn Sie beim Entwurf Ihrer Abfragen, Formulare und Berichte nicht sorgfältig arbeiten, kann er die Leistung jedoch vermindern. Sie können einiges tun, um sicherzustellen, dass der Umstieg vorteilhaft ausfällt. Die zur Verfügung stehenden Techniken gliedern sich in abfragebezogene und formularbezogene Verfahrensweisen.
20.6.1
Abfragen optimieren
Server können viele der Funktionen, die der Access-Abfrage-Editor bietet, nicht ausführen. Die Funktionen, die auf dem Server nicht verfügbar sind, werden auf der Arbeitsstation erledigt. Das führt häufig dazu, dass große Datenmengen über das Netzwerk transportiert werden. Sie können diesen zusätzlichen Verkehr ausschalten, indem Sie Ihre Abfragen so gestalten, dass sie vom Server allein bewältigt werden. Es folgen einige Beispiele für problematische Abfragen, die sich auf dem Server nicht ausführen lassen:
Top-N-Prozentabfragen Abfragen mit benutzerdefinierten oder Access-Funktionen Abfragen, die Tabellen aus zwei unterschiedlichen Datenquellen betreffen – z.B. eine Abfrage, die Tabellen von zwei Servern oder eine Access- und eine ServerTabelle verknüpft (einen Join aus diesen Tabellen bildet)
770
Kapitel 20: Client-Server-Strategien
Sowohl Top-N-Abfragen als auch heterogene Verknüpfungen werden von Microsoft SQL Server 7.0 unterstützt.
20.6.2
Formulare optimieren
Sie können die Techniken dieses Abschnitts verwenden, um Formulare zu entwerfen, die die Vorteile der Client-Server-Architektur nutzen. Die Idee besteht darin, Formulare so zu entwerfen, dass sie die minimal erforderliche Datenmenge vom Server anfordern und nur dann zusätzliche Daten bekommen, wenn der Benutzer dies verlangt. Das bedeutet, dass Sie möglichst wenige Datensätze und Felder vom Server anfordern. Sie können das erreichen, indem Sie als Grundlage für Formulare Abfragen anstelle der Tabellen selbst verwenden. Außerdem lässt sich der Prozess dadurch weiter verfeinern, dass Sie Ihre Formulare mit einem speziellen Blick auf die Datenbeschaffung entwerfen. Ein Formular lässt sich beispielsweise zunächst auch ohne Datenquelle öffnen. Es kann verlangen, dass der Benutzer die Kriterien einschränkt, bevor überhaupt Datensätze angezeigt werden. Statische Tabellen, wie zum Beispiel eine Tabelle der Bundesstaaten, sollten lokal gespeichert werden. Dadurch werden Netzwerkverkehr und Anforderungen beim Server reduziert. Außerdem sollten Sie Kombinations- und Listenfelder nicht auf der Grundlage von Server-Daten einrichten. Die Zeilenquelle für Kombinations- und Listenfelder sollte, wo immer möglich, auf lokalen statischen Tabellen basieren. Wenn dies nicht möglich ist, können Sie ein Textfeld mit einem Kombinationsfeld verwenden. Die Zeilenquelle des Kombinationsfeldes bleibt zunächst leer. Der Benutzer muss die ersten Buchstaben in das Textfeld eingeben. Dann wird die Zeilenquelle des Kombinationsfeldes auf eine Select-Anweisung aufgebaut, welche die eingegebenen Zeichen verwendet. Auch OLE-Objekt- und Memo-Felder sind umfangreich und vermehren den Netzwerkverkehr deshalb beträchtlich. Am besten wird der Inhalt dieser Felder nur angezeigt, wenn er vom Benutzer ausdrücklich verlangt wird. Sie erreichen dies, indem Sie die Eigenschaft Sichtbar von OLE- und Memo-Feldern auf False setzen oder diese Felder auf eine andere Seite des Formulars verlegen. Sie können eine Schaltfläche hinzufügen, über die die Benutzer die Anzeige der zusätzlichen Daten erreichen können. Abbildung 20.1 zeigt ein Formular, das die Implementierung einiger der genannten Methoden veranschaulicht. Der Detailbereich des Formulars ist zunächst nicht sichtbar. Das Formular hat keine Datenherkunft und die Daten, die dem im Formular angezeigten Kombinationsfeld zu Grunde liegen, sind in einer lokalen Tabelle gespeichert.
771
Abfragen und Formulare optimieren
Das Ereignis AfterUpdate des Kombinationsfeldes sieht folgendermaßen aus: Private Sub cboBookType_AfterUpdate() Me.RecordSource = "Select * From dbo_titles Where Type Like '" & _ cboBookType.Value & "*';" Me.Detail.Visible = True End Sub
Abbildung 20.1: Ein Formular, das mit Hilfe des Ereignisses AfterUpdate des Kombinationsfeldes die Datenherkunft (RecordSource) festlegt und Details sichtbar macht
Die Eigenschaft Sichtbar (Visible) des Detailbereichs des Formulars ist auf False gesetzt. Nachdem der Benutzer im Kombinationsfeld einen Eintrag ausgewählt hat, wird die Eigenschaft RecordSource des Formulars auf eine Select-Anweisung gesetzt, die aus der Datenbanktabelle dbo_titles bestimmte Titel auswählt. Dann wird der Detailbereich des Formulars sichtbar gemacht, wie in Abbildung 20.2 gezeigt. Schließlich wollen Sie möglicherweise ungebundene Formulare verwenden. Das schließt das Erstellen eines Formulars ein, dessen RecordSource-Eigenschaft dann gelöscht wird. Die Benutzer sehen ein Kombinationsfeld, in dem sie einen Datensatz auswählen können. Aus den Client-Server-Daten wird eine Datensatzgruppe mit dem ausgewählten Datensatz erstellt. Bei dieser Methode des Formularentwurfs muss alles im Code festgelegt werden. Ihr Formular muss alle Hinzufüge-, Bearbeitungs- und Löschoperationen erledigen. Abbildung 20.3 zeigt ein Beispiel eines solchen Formulars. Bei keinem der dort vorhandenen Steuerelemente ist die Steuerelementquelle ausgefüllt. Der Name der einzelnen Steuerelemente entspricht einem Feld in der Datenbanktabelle auf dem Server.
772
Kapitel 20: Client-Server-Strategien
Abbildung 20.2: Ein Formular, das bei sichtbarem Detailbereich mit Hilfe des Ereignisses AfterUpdate des Kombinationsfeldes die Datenherkunft festlegt
Abbildung 20.3: Ein ungebundenes Formular
Das Ereignis Open des Formulars sieht folgendermaßen aus: Private Sub Form_Open(Cancel As Integer) Set mrst = New ADODB.Recordset Me.txtTitle.SetFocus End Sub
Abfragen und Formulare optimieren
773
Dieser Code setzt eine Datenbankvariable auf Modulebene auf die aktuelle Datenbank und übergibt den Fokus an das Textfeld txtTitle. Das Ereignis AfterUpdate des Textfeldes sieht folgendermaßen aus: Private Sub txtTitle_AfterUpdate() Me!cboTitle.RowSource = "SELECT DISTINCTROW [dbo_titles].[title_id] " _ & "FROM [dbo_titles] " _ & "WHERE [dbo_titles].[title_id] Like '" & Me!txtTitle.Text & "*';" End Sub
Dieser Code setzt die Eigenschaft RowSource des Kombinationsfeldes auf eine SelectAnweisung, die alle Datensätze der Titeltabelle auswählt, deren Feld Title_ID mit den Buchstaben beginnt, die der Benutzer eingegeben hat. Auf diese Weise erscheinen im Kombinationsfeld nicht alle Titel vom Server. Das Ereignis AfterUpdate des Kombinationsfeldes sieht folgendermaßen aus: Private Sub cboTitle_AfterUpdate() Dim boolSuccess As Boolean mrst.ActiveConnection = CurrentProject.Connection mrst.Open "Select * From dbo_Titles " _ & "WHERE Title_ID = '" & Me!cboTitle.Value & "';" boolSuccess = PopulateForm(Me, mrst) If Not boolSuccess Then MsgBox "Record Not Found" End If End Sub
Mit Hilfe der Methode Open wird eine Datensatzgruppe auf der Grundlage der verknüpften Tabelle dbo_titles geöffnet. Beachten Sie, dass nur die Datensätze mit der passenden Title_ID geholt werden. Da dieses Feld den Primärschlüssel darstellt, wird nur ein Datensatz zurückgegeben. Dann wird die Funktion PopulateForm aufgerufen, wie Sie hier sehen: Function PopulateForm(frmAny As Form, rstAny As ADODB.Recordset) Dim fld As ADODB.Field If rstAny.EOF Then PopulateForm = False Else For Each fld In rstAny.Fields frmAny(fld.Name) = fld Next fld PopulateForm = True End If End Function
774
Kapitel 20: Client-Server-Strategien
Die Funktion PopulateForm prüft, ob die übergebene Datensatzgruppe Datensätze enthält. Dann geht sie jedes Feld des Formulars durch und vergleicht die Feldnamen mit den Steuerelementen im Formular. Der Wert der einzelnen Steuerelemente wird auf den Wert des Feldes in der Datensatzgruppe gesetzt, das denselben Namen wie das Steuerelement trägt. Beachten Sie, dass diese Änderungen an den Daten des Formulars nicht die Daten auf dem Datenbank-Server aktualisieren. Außerdem sieht das Formular weder Einfügungen noch Löschungen vor. Sie müssen Code schreiben, um aktualisieren, einfügen und löschen zu können, und Sie müssen Schaltflächen bereitstellen, um Ihren Benutzern Zugriff auf diese Funktionalität zu gewähren. Beide Techniken lassen sich sowohl in Verbindung mit verknüpften Tabellen als auch in Verbindung mit Access-Datenprojekten einsetzen. Die Vorteile sind bei Access-Datenprojekten am größten.
20.6.3
Für die Praxis
Client-Server-Strategien anwenden Nehmen Sie an, dass die Tabelle Employees voraussichtlich in Kürze auf einen Datenbank-Server verschoben werden soll, weil sie vertrauliche Daten enthält. Deshalb müssen Sie das Formular Employees mit Rücksicht auf die Client-Server-Architektur entwerfen. Das Formular beschränkt die darin angezeigten Daten. Es wird mit nur einer Optionsgruppe geöffnet, welche die Buchstaben des Alphabets enthält, wie in Abbildung 20.4 gezeigt. Nachdem der Benutzer einen Buchstaben ausgewählt hat, wird der Detailbereich des Formulars eingeblendet und die RecordSource-Eigenschaft des Formulars mit einer Select-Anweisung gefüllt, wie Abbildung 20.5 zeigt.
Das Ereignis Open des Formulars sieht folgendermaßen aus: Private Sub Form_Open(Cancel As Integer) Me.Detail.Visible = False End Sub
Abbildung 20.4: Das Formular Employees mit einer Optionsgruppe zur Auswahl des Nachnamens des Beschäftigten
775
Abfragen und Formulare optimieren
Abbildung 20.5: Die Vollansicht des Formulars Employees
Die Eigenschaft VISIBLE des Detailbereichs des Formulars wird auf False gesetzt. Das Ereignis AfterUpdate der Optionsgrupe sieht folgendermaßen aus: Private Sub optEmpName_AfterUpdate() Me.RecordSource = "Select * from tblEmployees Where LastName Like '" _ & Chr$(Me![optEmpName].Value) & "*';" Me.NavigationButtons = True Me.Detail.Visible = True DoCmd.DoMenuItem acFormBar, 7, 6, , acMenuVer70 End Sub
Dieser Code legt die RecordSource-Eigenschaft des Formulars mit Hilfe einer SelectAnweisung fest und macht die Schaltflächen zum Bewegen und den Detailbereich des Formulars sichtbar. Schließlich passt es die Fenstergröße der Formulargröße an.
Eine Client-ServerAnwendung in Aktion
Kapitel
Hier lesen Sie:
Zum Gesamtzusammenhang Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen Eine Client-Server-Anwendung mit Hilfe eines Access-Datenprojekts erstellen
21.1
Zum Gesamtzusammenhang
Häufig ist es schwierig, die in einem Buch dargestellten Techniken in einem Gesamtzusammenhang zu sehen. Dieses Kapitel zeigt Ihnen, wie viele der in Kapitel 19 und Kapitel 20 behandelten Client-Server-Techniken angewandt werden.
21.2
Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen
Eine Möglichkeit für die Erstellung einer Client-Server-Anwendung ist die Verwendung verknüpfter Tabellen. Dies kann, wenn es richtig gemacht wird, eine sehr gute Lösung sein. Ein Überblick über die zum Aufbau einer Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erforderlichen Schritte enthält folgende Punkte: 1. Stellen Sie eine Verknüpfung mit den in der SQL Server-Datenbank enthaltenen Tabellen her. 2. Erstellen Sie ein Formular, welches Registerkarten für Kunden, Bestellungen und Bestelldetails enthält. 3. Fügen Sie ein Kombinationsfeld hinzu, mit dem der Benutzer Daten einer bestimmten Firma suchen kann.
778
Kapitel 21: Eine Client-Server-Anwendung in Aktion
4. Erstellen Sie eine Abfrage, mit deren Hilfe der Detailbereich des Formulars ausgefüllt wird. Die Abfrage holt nur Daten für den ausgewählten Kunden. 5. Erstellen Sie eine Abfrage, mit deren Hilfe der Detailbereich des Unterformulars für Bestellungen ausgefüllt wird. 6. Erstellen Sie eine Abfrage, mit deren Hilfe der Detailbereich des Unterformulars für Bestelldetails ausgefüllt wird. 7. Blenden Sie die Unterformulare für Bestellungen und Bestelldetails aus, bis die entsprechende Registerkarte ausgewählt wird. 8. Geben Sie für die Unterformulare leere Datenquellen an. 9. Bestimmen Sie die Datensatzquelle für die Unterformulare und machen Sie die Unterformulare nur dann sichtbar, wenn die entsprechende Registerkarte gewählt wird. Die folgenden Abschnitte liefern Ihnen die Einzelheiten der einzelnen Schritte zur Erstellung der Anwendung.
21.2.1
Eine Verknüpfung mit Dateien in der SQL Server-Datenbank erstellen
Da diese Version der Anwendung verknüpfte Tabellen enthält, besteht der erste Schritt darin, eine Verknüpfung zu den Tabellen einzurichten, welche die Anwendung verwendet. Das Beispiel benutzt die SQL Server-Version der Datenbank Northwind. (In Access liegt diese Datenbank in der deutschen Version vor.) Unternehmen Sie Folgendes, um Verknüpfungen mit den Tabellen der Datenbank Northwind einzurichten: 1. Klicken Sie mit der rechten Maustaste im Datenbankfenster und wählen Sie TABELLEN VERKNÜPFEN. Dadurch wird das Dialogfeld VERKNÜPFEN aufgerufen. 2. Wählen Sie in der Liste DATEITYP den Eintrag ODBC-DATABASES (). Sie gelangen in das Dialogfeld DATENQUELLE AUSWÄHLEN. 3. Klicken Sie auf die Registerkarte COMPUTERDATENQUELLE (siehe Abbildung 21.1). 4. Klicken Sie auf NEU, um eine neue Datenquelle zu erstellen. Es erscheint das Dialogfeld NEUE DATENQUELLE ERSTELLEN (siehe Abbildung 21.2). 5. Wählen Sie SYSTEMDATENQUELLE und klicken Sie auf WEITER. 6. Wählen Sie in der Treiberliste den Treiber für SQL Server (siehe Abbildung 21.3). Klicken Sie auf WEITER. 7. Klicken Sie auf FERTIG STELLEN. Sie gelangen jetzt in das Dialogfeld NEUE DATENQUELLE FÜR SQL SERVER ERSTELLEN (siehe Abbildung 21.4).
Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen
779
Abbildung 21.1: Auf der Registerkarte Computerdatenquelle können Sie eine Datenquelle für den Rechner wählen
Abbildung 21.2: Der Assistent zum Erstellen neuer Datenquellen führt Sie durch die einzelnen Schritte der Erstellung
8. Geben Sie einen Namen und optional eine Beschreibung für die Datenquelle ein. 9. Wählen Sie den SQL-Server aus, zu dem Sie eine Verbindung erstellen wollen. Klicken Sie auf WEITER. 10. Markieren Sie die gewünschten Sicherheitsoptionen und klicken Sie auf WEITER (siehe Abbildung 21.5).
780
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Abbildung 21.3: Wählen Sie in der Liste der verfügbaren Treiber den Treiber für SQL Server
Abbildung 21.4: Das Dialogfeld Neue Datenquelle für SQL Server erstellen führt Sie durch die einzelnen Schritte der Erstellung einer neuen SQL Server-Datenquelle
11. Wählen Sie die passenden Datenbankoptionen. Dazu gehört, wie gespeicherte Prozeduren ausgeführt und wie Anführungszeichen und Nullwerte behandelt werden sollen. Klicken Sie auf WEITER (siehe Abbildung 21.6). 12. Ändern Sie die übrigen Optionen und klicken Sie auf FERTIG STELLEN. 13. Eine Liste der gewählten Optionen wird angezeigt (siehe Abbildung 21.7). Klicken Sie auf DATENQUELLE TESTEN, um die neue Datenquelle zu testen. Sie sollten die Meldung bekommen, dass der Test erfolgreich abgeschlossen wurde. 14. Klicken Sie auf OK, um das Testdialogfeld zu schließen. Klicken Sie noch einmal auf OK, um das Dialogfeld ODBC MICROSOFT SQL SERVER-SETUP zu schließen. Damit kehren Sie zum Dialogfeld DATENQUELLE AUSWÄHLEN zurück.
Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen
781
Abbildung 21.5: Geben Sie die gewünschten Absicherungsoptionen für die Datenbank ein
15. Markieren Sie die Datenquelle, die Sie gerade erstellt haben, und klicken Sie auf OK. Sie werden aufgefordert, sich beim SQL-Server anzumelden (siehe Abbildung 21.8). Geben Sie eine gültige Anmelde-ID und ein Kennwort ein, und klicken Sie auf OK. Daraufhin wird das Dialogfeld TABELLEN VERKNÜPFEN eingeblendet (siehe Abbildung 21.9).
Abbildung 21.6: Wählen Sie die passenden Datenbankoptionen
16. Klicken Sie auf jede Tabelle, die Sie in die Verknüpfung einbeziehen wollen, um sie zu markieren. Wenn Sie fertig sind, klicken Sie auf OK. Das Datenbankfenster wird mitsamt den eingerichteten Verknüpfungen eingeblendet, wie Sie in Abbildung 21.10 sehen.
782
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Abbildung 21.7: Klicken Sie auf Datenquelle testen, um die Datenquelle mit den aufgeführten Optionen zu testen
Abbildung 21.8: Im Dialogfeld SQL Server-Login können Sie sich beim SQL-Server anmelden
Abbildung 21.9: Im Dialogfeld Tabellen verknüpfen können Sie die SQL ServerTabellen bestimmen, zu denen eine Verknüpfung eingerichtet werden soll
Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen
783
Abbildung 21.10: Das Datenbankfenster mit Verknüpfungen zur Datenbank Northwind
21.2.2
Das Kundenformular
Das Formular, das Sie aufbauen sollen, sehen Sie in Abbildung 21.11. Beachten Sie, dass zunächst keine Daten erscheinen. Das Formular wurde so gestaltet, dass es nur jeweils einen Datensatz anzeigt. Dies wird dadurch erreicht, dass es auf einer Abfrage basiert, die nur Daten für den Kunden holt, der im Kombinationsfeld SELECT A COMPANY ausgewählt wurde. Außerdem werden die Daten für die Registerkarten ORDERS und ORDER DETAILS erst geholt, wenn diese gewählt werden. Dadurch wird gewährleistet, dass Datensätze auf der n-Seite der 1:n-Beziehung erst geholt werden, wenn dies tatsächlich erforderlich wird.
Abbildung 21.11: Das vollständige Kundenformular erscheint zunächst ohne Daten
784
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Um mit dem Entwurf des Formulars frmCustomer zu beginnen, unternehmen Sie Folgendes: 1. Wählen Sie in der Objektliste des Datenbankfensters den Eintrag FORMULARE. 2. Doppelklicken Sie auf ERSTELLT EIN FORMULAR IN DER ENTWURFSANSICHT. 3. Wählen Sie ANSICHT|FORMULARKOPF/-FUSS, um eine Kopf- und eine Fußzeile in das Formular einzufügen. Ein Kombinationsfeld zum Suchen in das Formular einfügen Der erste zum Aufbau des Formulars erforderliche Schritt ist das Einfügen eines Kombinationsfeldes, mit dessen Hilfe der Benutzer die Firma auswählen kann, deren Informationen er einsehen möchte. Dieses wird mit der CustomerID und dem CompanyName aller Firmen aus der Firmentabelle gefüllt. Wenn im Kombinationsfeld eine Firma markiert wird, wird das Formular durch eine neue Abfrage aktualisiert, so dass es die Daten für den gewählten Kunden anzeigt. Erstellen Sie das Kombinationsfeld mit Hilfe des Assistenten für Kombinationsfelder, indem Sie wie folgt vorgehen: 1. Achten Sie darauf, dass das Werkzeug STEUERELEMENT-ASSISTENTEN in der Toolbox aktiviert ist. 2. Wählen sie in der Toolbox das Werkzeug KOMBINATIONSFELD und klicken Sie dann auf die Stelle in der Kopfzeile des Formulars, an der das Kombinationsfeld erscheinen soll. Dies startet den Kombinationsfeld-Assistenten. 3. Markieren Sie die Option DAS KOMBINATIONSFELD SOLL DIE WERTE EINER TABELLE ODER ABFRAGE ENTNEHMEN. Klicken Sie anschließend auf WEITER. 4. Wählen Sie in der Liste der Tabellen die (verknüpfte) Tabelle dbo_Customers (siehe Abbildung 21.12). Klicken Sie auf WEITER.
Abbildung 21.12: Wählen Sie in der Liste der verfügbaren Tabellen die Tabelle dbo_Customers aus
Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen
785
5. Wählen Sie aus der Liste der verfügbaren Felder die Felder CustomerID und CompanyName aus (siehe Abbildung 21.13). Klicken Sie dann auf WEITER.
Abbildung 21.13: Wählen Sie die Felder CustomerID und CompanyName als Felder für das Kombinationsfeld aus
6. Doppelklicken Sie an der rechten Seite der Spalte CompanyName, um die Spalte an den längsten Eintrag anzupassen (siehe Abbildung 21.14). Lassen Sie die Option SCHLÜSSELSPALTE AUSBLENDEN aktiviert. Klicken Sie auf WEITER.
Abbildung 21.14: Doppelklicken Sie an der rechten Seite der Spalte CompanyName, um die Spalte an den längsten Eintrag anzupassen
7. Geben Sie als Beschriftung für das Kombinationsfeld »Select a Company« ein. Klicken Sie auf FERTIG STELLEN. Das Kombinationsfeld wird in das Formular eingefügt (siehe Abbildung 21.15).
786
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Abbildung 21.15: Das Kombinationsfeld wird in das Formular eingefügt
8. Wählen Sie das hinzugefügte Kombinationsfeld aus, indem Sie es anklicken. 9. Ändern Sie den Namen des Kombinationsfeldes in cboSelectCompany. 10. Speichern Sie das Formular als frmCustomer. 11. Testen Sie das Formular, um sicherzustellen, dass das Kombinationsfeld eine Liste aller Kunden anzeigt (siehe Abbildung 21.16). Die Abfrage für das Kundenformular erstellen Der nächste Schritt ist der Entwurf der Abfrage, die dem Formular frmCustomer zu Grunde liegt. Die Abfrage verweist auf das Feld CustomerID des Kunden, der im Kombinationsfeld cboSelectCompany ausgewählt ist. Es folgen die einzelnen Schritte: 1. Kehren Sie in die Entwurfsansicht zurück, falls nötig. 2. Markieren Sie das Formular. 3. Klicken Sie im Eigenschaftenfenster auf die Registerkarte DATEN. 4. Klicken Sie in das Eigenschaftsfeld DATENHERKUNFT (siehe Abbildung 21.17). 5. Klicken Sie auf die Schaltfläche mit den drei Punkten. Dadurch wird das Dialogfeld TABELLE ANZEIGEN eingeblendet. 6. Markieren Sie in der Liste der Tabellen die Tabelle dbo_Customers (siehe Abbildung 21.18). Klicken Sie auf HINZUFÜGEN. 7. Klicken Sie auf SCHLIESSEN.
Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen
787
Abbildung 21.16: Das vollständige Kombinationsfeld zeigt eine Liste aller Kunden an
8. Fügen Sie die Felder CustomerID, CompanyName, ContactName, ContactTitle, Address, City, Region, PostalCode, Phone und Fax in die Abfrage ein (siehe Abbildung 21.19).
Abbildung 21.17: Die Eigenschaft Datenherkunft ermöglicht das Festlegen der Datensatzquelle für das Formular
788
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Abbildung 21.18: Markieren Sie im Dialogfeld Tabellen anzeigen die Tabelle dbo_Customers
Abbildung 21.19: Fügen Sie die gewünschten Felder in die Abfragetabelle ein
9. Geben
Sie
für
das
Feld
CUSTOMERID
als
Kriterium
Forms!frmCusto-
mer!CBOSELECTCOMPANY ein (siehe Abbildung 21.20).
Abbildung 21.20: Auswahlkriterien für das Feld CustomerID
10. Schließen Sie den SQL-Anweisungseditor.
789
Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen
11. Klicken Sie auf Ja, weil Sie die Änderungen an der SQL-Anweisung speichern und die Eigenschaft aktualisieren wollen. Bevor Sie die Felder in das Formular einfügen können, müssen Sie die Registerkarten für das Formular entwerfen. Unternehmen Sie dazu Folgendes: 1. Klicken Sie auf das Registersteuerelement in der Toolbox. 2. Klicken Sie auf die Stelle im Formular frmCustomers, an der das Steuerelement erscheinen soll, um es einzufügen. 3. Ändern Sie die Eigenschaft Beschriftung der ersten Registerkarte auf Customers. 4. Ändern Sie die Eigenschaft Name der ersten Registerkarte auf pagCustomers. 5. Ändern Sie die Eigenschaft Beschriftung der zweiten Registerkarte auf Orders. 6. Ändern Sie die Eigenschaft Name der zweiten Registerkarte auf pagOrders. 7. Klicken Sie mit der rechten Maustaste auf das Registersteuerelement und wählen Sie SEITE EINFÜGEN. Eine dritte Seite erscheint. 8. Ändern Sie die Eigenschaft Beschriftung der dritten Registerkarte auf Order Details. 9. Ändern Sie die Eigenschaft Name der dritten Registerkarte auf pagOrderDetails. 10. Ändern Sie die Eigenschaft Name des Registersteuerelements auf tabDataEntry. 11. Fügen Sie die Felder wie in Abbildung 21.21 gezeigt in die Registerkarte CUSTOMERS des Formulars ein. Die Abfrage für das Unterformular Orders erstellen Der nächste Schritt ist die Erstellung der Abfrage, die dem Unterformular Orders zu Grunde liegt. Diese wählt alle Bestellungen aus, bei denen die CustomerID die des Kunden ist, der im Kombinationsfeld cboSelectCompany markiert ist. Um die Abfrage zu erstellen, unternehmen Sie Folgendes: 1. Wählen Sie in der Objektliste des Datenbankfensters den Eintrag ABFRAGEN. 2. Doppelklicken Sie auf ERSTELLT EINE NEUE ABFRAGE IN DER SICHT. Das Dialogfeld TABELLEN ANZEIGEN wird eingeblendet.
ENTWURFSAN-
3. Markieren Sie in der Liste der Tabellen die Tabelle dbo_Orders und klicken Sie auf HINZUFÜGEN. 4. Klicken Sie auf SCHLIESSEN. 5. Fügen Sie die Felder OrderID, CustomerID, EmployeeID, OrderDate, RequiredDate, ShippedDate, ShipVia und Freight in die Abfrage ein. 6. Geben Sie für das Feld CustomerID als Kriterium Forms!frmCustomer!cboSelectCompany ein.
790
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Abbildung 21.21: Die Registerkarte Customers nach dem Einfügen der ausgewählten Felder
7. Speichern Sie die Abfrage unter dem Namen qryOrders. Die vollständige Abfrage erscheint in Abbildung 21.22.
Abbildung 21.22: Die vollständige Abfrage qryOrders
Die Abfrage für das Unterformular OrderDetails erstellen Der nächste Schritt ist die Erstellung der Abfrage, die dem Unterformular OrderDetails zu Grunde liegt. Diese wählt alle Bestelldetails aus, bei denen die OrderID die ID der Bestellung ist, die im Unterformular fsubOrders markiert wurde. Um die Abfrage zu erstellen, unternehmen Sie Folgendes: 1. Wählen Sie in der Objektliste des Datenbankfensters den Eintrag ABFRAGEN. 2. Doppelklicken Sie auf ERSTELLT EINE NEUE ABFRAGE IN DER SICHT. Das Dialogfeld TABELLEN ANZEIGEN wird eingeblendet.
ENTWURFSAN-
3. Markieren Sie in der Liste der Tabellen die Tabelle dbo_OrderDetails und klicken Sie auf HINZUFÜGEN.
791
Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen
4. Klicken Sie auf SCHLIESSEN. 5. Fügen Sie die Felder OrderID, ProductID, UnitPrice, Quantity und Discount in die Abfrage ein. 6. Geben Sie für das Feld ORDERID als Kriterium Forms!frmCustomer.Form!fsubOrders!OrderID ein. 7. Speichern Sie die Abfrage unter dem Namen qryOrderDetails. Die vollständige Abfrage erscheint in Abbildung 21.23.
Abbildung 21.23: Die vollständige Abfrage qryOrderDetails
Das Unterformular fsubOrders erstellen Das Unterformular fsubOrders dient zur Anzeige der mit den ausgewählten Kunden verknüpften Bestellungen. Unternehmen Sie Folgendes, um das Unterformular zu erstellen und es in die Seite ORDERS des Registerkartensteuerelements einzufügen: 1. Aktivieren Sie das Formular frmCustomer in der Entwurfsansicht. 2. Markieren Sie mit einem Klick die Seite ORDERS des Registersteuerelements. 3. Vergewissern Sie sich, dass das Werkzeug STEUERELEMENT-ASSISTENTEN aktiv ist. 4. Wählen Sie das Steuerelement UNTERFORMULAR/UNTERBERICHT. 5. Klicken Sie an der Stelle auf die Registerkarte ORDERS, an der Sie das Steuerelement einfügen möchten. Dadurch gelangen Sie in den Unterformular-Assistenten (siehe Abbildung 21.24). 6. Markieren Sie BEREITS VORHANDENE TABELLEN und klicken Sie auf WEITER.
UND
ABFRAGEN
VERWENDEN
7. Markieren Sie im aufklappbaren Listenfeld TABELLEN/ABFRAGEN den Eintrag qryOrders. 8. Fügen Sie alle Felder der Abfrage in die Liste AUSGEWÄHLTE FELDER ein (siehe Abbildung 21.25). 9. Klicken Sie auf WEITER.
792
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Abbildung 21.24: Der Unterformular-Assistent hilft Ihnen beim Einfügen des Unterformulars Orders in die Registerkarte Orders
10. Wählen Sie KEINE als Verknüpfung zwischen Haupt- und Unterformular (siehe Abbildung 21.26) und klicken Sie auf WEITER. 11. Geben Sie fsubOrders als Namen des Unterformulars ein und klicken Sie auf FERTIG STELLEN. 12. Legen Sie die Größe des Unterformulars so fest, dass es aussieht wie in Abbildung 21.27. Das Unterformular fsubOrderDetail erstellen Das Unterformular fsubOrderDetails wird verwendet, um die mit der markierten Bestellung verknüpften Bestelldetails anzuzeigen. Unternehmen Sie Folgendes, um das Unterformular fsubOrderDetails zu erstellen und es in die Seite ORDER DETAILS der damit verknüpften Registerkarte einzufügen: 1. Aktivieren Sie das Formular frmCustomer in der Entwurfsansicht. 2. Markieren Sie mit einem Klick die Seite ORDER DETAILS des Registerkartensteuerelements. 3. Vergewissern Sie sich, dass das Werkzeug STEUERELEMENT-ASSISTENTEN aktiv ist. 4. Klicken sie auf das Steuerelement UNTERFORMULAR/UNTERBERICHT. 5. Klicken Sie auf die Stelle auf der Registerkarte ORDER DETAILS, an der das Unterformular erscheinen soll, um es einzufügen. Der Assistent für Unterformulare erscheint.
793
Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen
Abbildung 21.25: Fügen Sie alle Felder von qryOrders in die Liste der ausgewählten Felder ein
Abbildung 21.26: Wählen Sie als Verknüpfung zwischen dem übergeordneten und dem Unterformular Keine
6. Markieren Sie BEREITS VORHANDENE TABELLEN und klicken Sie auf WEITER.
UND
ABFRAGEN
VERWENDEN
7. Markieren Sie in der Dropdown-Liste TABELLEN/ABFRAGEN den Eintrag qryOrderDetails. 8. Fügen Sie alle Felder der Abfrage in die Liste AUSGEWÄHLTE FELDER ein. 9. Klicken Sie auf WEITER.
794
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Abbildung 21.27: Das Unterformular fsubOrders nach dem Einfügen in die Registerkarte Orders
10. Sie werden aufgefordert, Verknüpfungen zwischen Haupt- und Unterformular zu definieren (siehe Abbildung 21.28). Klicken Sie auf WEITER, ohne Verknüpfungen zu definieren.
Abbildung 21.28: Es werden keine Verknüpfungen zwischen Haupt- und Unterformular erstellt
11. Geben Sie fsubOrderDetails als Namen des Unterformulars ein und klicken Sie auf FERTIG STELLEN.
Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen
795
12. Wählen Sie die Größe des Unterformularsteuerelements so, dass es aussieht wie in Abbildung 21.29.
Abbildung 21.29: Das Unterformular fsubOrderDetails nach dem Einfügen in die Registerkarte Order Details
Die Unterformulare Order und OrderDetails verbergen, bis die entsprechende Registerkarte gewählt wurde Wahrscheinlich das wichtigste Ziel der Entwicklung von Client-Server-Anwendungen ist die Begrenzung der Daten, die vom Datenbank-Server zur Arbeitsstation übertragen werden. Häufig muss der Benutzer die Hauptinformationen eines Kunden sehen, ohne dass er Informationen über Bestellungen oder Bestelldetails braucht. Deshalb ist es unnötig, diese Informationen zu holen, wenn der Benutzer sie nicht ausdrücklich durch einen Klick auf die Registerkarte ORDER bzw. ORDER DETAILS anfordert. Der in Listing 21.1 abgedruckte Code erledigt das Verbergen und Anzeigen des jeweiligen Unterformulars, wenn der Benutzer auf die verschiedenen Registerkarten im Formular klickt. Wenn die Unterformulare angezeigt werden, wird die Eigenschaft RecordSource des Unterformulars mit den passenden Daten gefüllt. Listing 21.1:
Das Change-Ereignis des Steuerelements tabDataEntry erledigt das Verbergen und Anzeigen des jeweiligen Unterformulars
Private Sub tabDataEntry_Change() Select Case Me.tabDataEntry.Pages. _ Item(Me.tabDataEntry.Value).Name Case "pagCustomers" Me.fsubOrders.Visible = False Me.fsubOrderDetails.Visible = False
796
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Case "pagOrders" Me.fsubOrders.Form.RecordSource = "qryOrders" Me.fsubOrders.Visible = True Me.fsubOrderDetails.Visible = False
Case "pagOrderDetails" Me.fsubOrderDetails.Form.RecordSource = "qryOrderDetails" Me.fsubOrders.Visible = False Me.fsubOrderDetails.Visible = True
End Select End Sub
Der Code wertet zunächst aus, welche Seite ausgewählt wurde. Wenn es sich um die Seite pagCustomers handelt, wird die Eigenschaft Visible (bzw. Sichtbar) der Unterformularsteuerelemente fsubOrders und fsubOrderDetails auf False gesetzt. Wenn die Seite pagOrders ausgewählt wurde, wird die Eigenschaft RecordSource des Unterformulars (die Datenherkunft) auf die Abfrage qryOrders gesetzt. Die Eigenschaft Visible des Unterformularsteuerelements fsubOrders wird auf True, die Eigenschaft VISIBLE des Unterformularsteuerelements fsubOrderDetails auf False festgelegt. Wenn die Seite pagOrderDetails ausgewählt wurde, wird die Eigenschaft RecordSource des Unterformulars auf die Abfrage qryOrderDetails gesetzt. Die Eigenschaft Visible des Unterformularsteuerelements fsubOrders wird auf False, die Eigenschaft Visible des Unterformularsteuerelements fsubOrderDetails auf True festgelegt. Die Datenherkunft der Unterformulare leer lassen Alles trifft zusammen, wenn der Benutzer im Kombinationsfeld cboSelectCompany eine Firma auswählt. Dann wird das Ereignis AfterUpdate des Kombinationsfeldes behandelt. Die entsprechende Routine finden Sie in Listing 21.2. Listing 21.2:
Die Behandlungsroutine für das Ereignis AfterUpdate des Kombinationsfeldes cboSelectCompany legt die Datenherkunft der Unterformulare korrekt fest und aktualisiert das Hauptformular
Private Sub cboSelectCompany_AfterUpdate() Select Case Me.tabDataEntry.Pages. _ Item(Me.tabDataEntry.Value).Name Case "pagCustomers" Me.fsubOrders.Form.RecordSource = "" Me.fsubOrderDetails.Form.RecordSource = ""
Eine Client-Server-Anwendung mit Hilfe verknüpfter Tabellen erstellen
797
Case "pagOrders" Me.fsubOrderDetails.Form.RecordSource = "" End Select Me.Requery End Sub
Die Routine wertet zunächst aus, welche Seite ausgewählt wurde. Wenn es sich um die Seite pagCustomers handelt, wird die Eigenschaft RecordSource der Unterformulare fsubOrders und fsubOrderDetails auf eine leere Zeichenfolge gesetzt. Wenn die Seite pagOrders heißt, wird die Eigenschaft RecordSource der Seite fsubOrderDetails auf eine leere Zeichenfolge gesetzt. Im Grunde gewährleistet der Code, dass bei der Auswahl eines anderen Kunden der Bestell- und der Bestelldetaildatensatz erst geholt werden, wenn die jeweilige Seite angeklickt wurde. Das dient dazu, eine große Menge unnötigen Netzwerkverkehr zu verhindern. Die Datenherkunft für die Unterformulare festlegen Da die Datenquellen der Unterformulare auf eine leere Zeichenfolge gesetzt werden, wenn ein anderer Kunde ausgewählt wird, muss die Eigenschaft RecordSource neu ausgefüllt werden, wenn die Seite aktiviert wird. Die in Listing 21.3 gezeigte Behandlungsroutine für das Ereignis Change des Registerkartensteuerelements tabDataEntry erledigt dies. Listing 21.3:
Die Behandlungsroutine für das Ereignis Change des Registerkartensteuerelements tabDataEntry legt die Eigenschaft RecordSource neu fest, wenn eine Seite aktiviert wird
Private Sub tabDataEntry_Change() Select Case Me.tabDataEntry.Pages. _ Item(Me.tabDataEntry.Value).Name Case "pagCustomers" Me.fsubOrders.Visible = False Me.fsubOrderDetails.Visible = False Case "pagOrders" Me.fsubOrders.Form.RecordSource = "qryOrders" Me.fsubOrders.Visible = True Me.fsubOrderDetails.Visible = False
Case "pagOrderDetails" Me.fsubOrderDetails.Form.RecordSource = "qryOrderDetails" Me.fsubOrders.Visible = False Me.fsubOrderDetails.Visible = True
798
Kapitel 21: Eine Client-Server-Anwendung in Aktion
End Select End Sub
Beachten Sie, dass die Datenherkunft des Unterformulars fsubOrders festgelegt wird, wenn die Seite pagOrders ausgewählt wird, und die Datenherkunft des Unterformulars fsubOrderDetails, wenn die Seite pagOrderDetails ausgewählt wird.
21.3
Eine Client-Server-Anwendung mit Hilfe eines Access-Datenprojekts erstellen
Die eine Alternative für unsere Client-Server-Lösung stellen verknüpfte Tabellen, die andere ein Access-Datenprojekt dar. Wiederum wird die Anwendung um die Client-Server-Datenbank Northwind herum konstruiert. Um die ADP-Datei zu erstellen, unternehmen Sie Folgendes: 1. Klicken Sie auf DATEI|NEU. 2. Wählen Sie PROJEKT (VORHANDENE DATENBANK) und klicken Sie auf OK. 3. Wählen Sie einen Namen und einen Speicherort für das Access-Datenprojekt (.ADP). Klicken Sie auf ERSTELLEN und Sie gelangen in das Dialogfeld DATENLINKEIGENSCHAFTEN. 4. Geben Sie im Textfeld GEBEN SIE EINEN SERVERNAMEN EIN ODER WÄHLEN SIE EINEN AUS den Namen des Servers ein, auf dem sich die Datenbank Northwind befindet. 5. Geben Sie an, wie Sie sich beim Server anmelden wollen. 6. Markieren Sie die Datenbank Northwind als Datenbank auf dem Server. Das vollständige Dialogfeld sollte aussehen wie in Abbildung 21.30. 7. Klicken Sie auf VERBINDUNG TESTEN, um die Verbindung zu Server und Datenbank zu testen. Dann sollte ein Dialogfeld eingeblendet werden, das besagt, dass die Testverbindung erfolgreich war. Klicken Sie auf OK, um fortzufahren. 8. Klicken Sie auf OK, um das Dialogfeld DATENLINKEIGENSCHAFTEN zu schließen. Die ADP-Datei ist jetzt erstellt. Das Datenbankfenster sollte aussehen wie in Abbildung 21.31.
Eine Client-Server-Anwendung mit Hilfe eines Access-Datenprojekts erstellen
799
Abbildung 21.30: Geben Sie im Dialogfeld Datenlinkeigenschaften Informationen über den Speicherort der Daten an
Abbildung 21.31: Das Datenbankfenster nach dem Erstellen der ADP-Datei
800
21.3.1
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Das Kundenformular entwerfen
Das Formular, welches Sie erstellen sollen, sehen Sie in Abbildung 21.32. Um mit dem Entwurf des Formulars frmCustomer zu beginnen, unternehmen Sie Folgendes: 1. Wählen Sie in der Objektliste den Eintrag FORMULARE. 2. Doppelklicken Sie auf ERSTELLT EIN FORMULAR IN DER ENTWURFSANSICHT. 3. Wählen Sie ANSICHT|FORMULARKOPF/-FUSS, um eine Kopf- und eine Fußzeile in das Formular einzufügen.
Abbildung 21.32: Das vollständige Formular frmCustomer
Ein Kombinationsfeld zum Suchen in das Formular einfügen Wie bei der Anwendung mit verknüpften Tabellen ist der erste Schritt das Einfügen eines Kombinationsfeldes in das Formular, mit dessen Hilfe der Benutzer die Firma auswählen kann, deren Informationen er einsehen möchte. Dieses wird mit den Feldern CustomerID und CompanyName aller Firmen aus der Firmentabelle gefüllt. Erstellen Sie das Kombinationsfeld mit Hilfe des Kombinationsfeld-Assistenten. Unternehmen Sie dazu Folgendes: 1. Klicken Sie, falls erforderlich, auf das Werkzeug STEUERELEMENT-ASSISTENT in der Toolbox, um die Steuerelementassistenten zu aktivieren. 2. Klicken Sie in der Toolbox auf KOMBINATIONSFELD und dann auf die Stelle im Formularkopf, an der das Steuerelement eingefügt werden soll. Dies startet den Kombinationsfeld-Assistenten (siehe Abbildung 21.33). 3. Markieren Sie DAS KOMBINATIONSFELD SOLL SICHT ENTNEHMEN. Klicken Sie auf WEITER.
DIE
WERTE
EINER
TABELLE
ODER
Eine Client-Server-Anwendung mit Hilfe eines Access-Datenprojekts erstellen
801
Abbildung 21.33: Mit Hilfe des Kombinationsfeld-Assistenten wird ein Kombinationsfeld in das Formular eingefügt
4. Markieren Sie die Tabelle Customers und klicken Sie auf WEITER. 5. Markieren Sie die Felder CustomerID und CompanyName und klicken Sie auf WEITER (siehe Abbildung 21.34). 6. Passen Sie die Spalte für das Feld CompanyName falls nötig, in der Größe an und klicken Sie auf WEITER. 7. Geben Sie als Beschriftung für das Kombinationsfeld »Select a Company« ein und klicken Sie auf FERTIG STELLEN. 8. Nennen Sie das Kombinationsfeld cboSelectCompany. Seiten und Steuerelemente in das Formular einfügen Bevor Sie die Felder in das Formular einfügen können, müssen Sie die Registerkarten für das Formular entwerfen. Unternehmen Sie dazu Folgendes: 1. Klicken Sie auf das Registersteuerelement in der Toolbox. 2. Klicken Sie auf die Stelle im Formular frmCustomer, an der das Steuerelement erscheinen soll, um es einzufügen. 3. Ändern Sie die Eigenschaft Beschriftung der ersten Registerkarte auf Customers. 4. Ändern Sie die Eigenschaft Name der ersten Registerkarte auf pagCustomers. 5. Ändern Sie die Eigenschaft Beschriftung der zweiten Registerkarte auf Orders. 6. Ändern Sie die Eigenschaft Name der zweiten Registerkarte auf pagOrders. 7. Klicken Sie mit der rechten Maustaste auf das Seitensteuerelement und wählen Sie SEITE EINFÜGEN. Eine dritte Seite erscheint.
802
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Abbildung 21.34: Die Felder CustomerID und CompanyName werden in das Kombinationsfeld eingefügt
8. Ändern Sie die Eigenschaft Beschriftung der dritten Registerkarte auf Order Details. 9. Ändern Sie die Eigenschaft Name der dritten Registerkarte auf pagOrderDetails. 10. Ändern Sie die Eigenschaft Name des Registersteuerelements auf tabDataEntry. 11. Ändern Sie die Eigenschaft RecordSource des Formulars (die Datenherkunft) vorübergehend auf die Tabelle Customers. Damit können Sie Steuerelemente in das Formular einfügen. 12. Fügen Sie die Felder wie in Abbildung 21.35 gezeigt in die Registerkarte CUSTOMERS des Formulars ein. 13. Löschen Sie die Datenherkunft aus dem Formular. Die Datenherkunft des Formulars festlegen Dann ist es Zeit, die Datenherkunft für das Formular einzurichten. Das wird am Anfang innerhalb der Behandlungsroutine zum Ereignis Load des Formulars erledigt. Den Code sehen Sie in Listing 21.4. Listing 21.4:
Die Behandlungsroutine für das Ereignis Load des Formulars legt die Datenherkunft für das Formular fest
Private Sub Form_Load() Set mrstCustomers = New ADODB.Recordset With mrstCustomers .ActiveConnection = CurrentProject.Connection .CursorLocation = adUseClient
Eine Client-Server-Anwendung mit Hilfe eines Access-Datenprojekts erstellen
803
Abbildung 21.35: Die Registerkarte Customers nach dem Einfügen der markierten Felder .CursorType = adOpenDynamic .LockType = adLockOptimistic .Source = "Select * from Customers Where CustomerID = '" & _ Me.cboSelectCompany & "'" .Open End With Set Me.Recordset = mrstCustomers End Sub
Der Code instanziiert zunächst eine ADODB-Datensatzgruppe, die im Abschnitt Allgemeine Deklarationen als privat deklariert wurde. Dann legt er einige Eigenschaften der Datensatzgruppe fest. Beachten Sie, dass als CursorType die Option adOpenDynamic und als LockType die Option adLockOptimistic gewählt wurde. Die Kombination dieser Eigenschaften macht das Formular aktualisierbar. Die Eigenschaft Source der Datensatzgruppe wird auf eine SQL-Anweisung gesetzt, die auf dem im Kombinationsfeld cboSelectCompany gewählten Kunden basiert. Dann wird die Datensatzgruppe geöffnet. Zum Schluss wird die mit dem Formular frmCustomer verknüpfte Datensatzgruppe auf der Grundlage der Datensatzgruppe eingerichtet, die den einen Kundendatensatz enthält. Das Ereignis AfterUpdate des Kombinationsfeldes cboSelectCompany Wenn im Kombinationsfeld cboSelectCompany ein neuer Kunde ausgewählt wird, muss die dem Formular zu Grunde liegende Datensatzgruppe mit den Informationen dieses Kunden neu erstellt werden. Sie sehen die Behandlungsroutine für das Ereignis AfterUpdate des Kombinationsfeldes in Listing 21.5.
804
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Listing 21.5:
Die Routine für das Ereignis AfterUpdate des Kombinationsfeldes cboSelectCompany erstellt die mit dem Formular frmCustomers verknüpfte Datensatzgruppe
Private Sub cboSelectCompany_AfterUpdate() mrstCustomers.Close mrstCustomers.Source = "Select * from Customers Where CustomerID = '" & _ Me.cboSelectCompany & "'" mrstCustomers.Open Set Me.Recordset = mrstCustomers Select Case Me.tabDataEntry.Pages. _ Item(Me.tabDataEntry.Value).Name Case "pagCustomers" Set Me.fsubOrders.Form.Recordset = Nothing Set Me.fsubOrderDetails.Form.Recordset = Nothing Case "pagOrders" Set Me.fsubOrderDetails.Form.Recordset = Nothing Call CreateOrdersRecordset Case "pagOrderDetails" Call CreateOrdersRecordset Call CreateOrderDetailsRecordset End Select End Sub
Zuerst schließt der Code die Datensatzgruppe mrstCustomers. Das ist nötig, damit die Eigenschaften der Datensatzgruppe geändert werden können. Die Herkunft der Datensatzgruppe wird so geändert, dass sie jetzt auf dem gerade im Kombinationsfeld ausgewählten Kunden basiert. Dann wird die Datensatzgruppe geöffnet und die Datensatzgruppeneigenschaft des Formulars wird mit einem Zeiger auf die gerade erstellte Datensatzgruppe versehen. Die case-Anweisung wertet aus, welche Registerkarte des Formulars ausgewählt wurde. Wenn es die Registerkarte CUSTOMERS ist, werden die mit den Unterformularen Order und OrderDetails verknüpften Datensatzgruppen entfernt. Wenn es die Registerkarte ORDERS ist, wird die mit dem Unterformular OrderDetails verknüpfte Datensatzgruppe entfernt und die Routine CreateOrdersRecordset aufgerufen. Diese Routine legt die mit dem Formular fsubOrders verknüpfte Datensatzgruppe an. Wenn die Registerkarte ORDER DETAILS aktiviert wurde, wird zuerst die Routine CreateOrdersRecordset und dann die Routine CreateOrderDetailsRecordset aufgerufen. Die Routine CreateOrderDetailsRecordset ist für das Anlegen der mit dem Unterformular fsubOrderDetails verknüpften Datensatzgruppe zuständig. Beide Routinen werden weiter hinten in diesem Kapitel behandelt.
805
Eine Client-Server-Anwendung mit Hilfe eines Access-Datenprojekts erstellen
Das Unterformular fsubOrders erstellen Das Unterformular fsubOrders dient zur Anzeige der mit den ausgewählten Kunden verknüpften Bestellungen. Unternehmen Sie Folgendes, um das Unterformular zu erstellen und es in die Seite ORDERS des Registersteuerelements einzufügen: 1. Aktivieren Sie in der Entwurfsansicht das Formular frmCustomer. 2. Markieren Sie mit einem Klick die Seite ORDERS des Registersteuerelements. 3. Vergewissern Sie sich, dass das Werkzeug STEUERELEMENT-ASSISTENTEN aktiv ist. 4. Wählen Sie das Steuerelement UNTERFORMULAR/UNTERBERICHT. 5. Klicken Sie auf die Stelle auf der Registerkarte ORDERS, an der das Steuerelement eingefügt werden soll. Dadurch gelangen Sie in den Unterformular-Assistenten. 6. Markieren Sie BEREITS VORHANDENE TABELLEN und klicken Sie auf WEITER.
UND
ABFRAGEN
VERWENDEN
7. Wählen sie im Listenfeld TABELLEN/ABFRAGEN den Eintrag tblOrders. 8. Fügen Sie alle Felder der Abfrage in die Liste AUSGEWÄHLTE FELDER ein. 9. Klicken Sie auf WEITER. 10. Geben Sie fsubOrders als Namen des Unterformulars ein und klicken Sie auf FERTIG STELLEN. 11. Passen Sie ggf. die Größe des Unterformularsteuerelements an. 12. Öffnen Sie das Formular fsubOrders und löschen Sie seine Datenherkunft. Die Datenherkunft des Formulars wird dann vom Programm gesteuert. Das Unterformular fsubOrderDetails erstellen Das Unterformular fsubOrderDetails wird verwendet, um die mit der ausgewählten Bestellung verknüpften Bestelldetails anzuzeigen. Unternehmen Sie Folgendes, um das Unterformular zu erstellen und es in die Seite ORDER DETAILS des Registersteuerelements einzufügen: 1. Aktivieren Sie das Formular frmCustomer in der Entwurfsansicht. 2. Markieren Sie mit einem Klick die Seite ORDER DETAILS des Registersteuerelements. 3. Vergewissern Sie sich, dass das Werkzeug STEUERELEMENT-ASSISTENTEN aktiv ist. 4. Wählen Sie das Steuerelement UNTERFORMULAR/UNTERBERICHT. 5. Klicken Sie auf die Stelle der Registerkarte ORDER DETAILS, an der das Steuerelement eingefügt werden soll. Der Assistent für Unterformulare erscheint.
806
Kapitel 21: Eine Client-Server-Anwendung in Aktion
6. Markieren Sie BEREITS VORHANDENE TABELLEN und klicken Sie auf WEITER.
UND
ABFRAGEN
VERWENDEN
7. Wählen Sie in der Liste TABELLEN/ABFRAGEN den Eintrag qryOrderDetails. 8. Fügen Sie alle Felder der Abfrage in die Liste AUSGEWÄHLTE FELDER ein. 9. Klicken Sie auf WEITER. 10. Geben Sie fsubOrderDetails als Namen des Unterformulars ein und klicken Sie auf FERTIG STELLEN. 11. Ändern Sie ggf. die Größe des Unterformularsteuerelements. 12. Öffnen Sie das Formular fsubOrderDetails und entfernen Sie seine Datenherkunft. Die Datenherkunft des Formulars wird dann vom Programm gesteuert. Die Unterformulare mit Daten füllen Da die Eigenschaft RecordSource der Formulare fsubOrders und fsubOrderDetails leer ist, müssen beide Formulare per Programm ausgefüllt werden. Der Code in Listing 21.6, den Sie im Formular frmCustomers finden, ist dafür zuständig, das Formular fsubOrders mit Daten zu füllen. Listing 21.6:
Die Routine CreateOrdersRecordset erstellt die Datensatzgruppe, die zum Füllen des Unterformulars fsubOrders mit Daten verwendet wird
Sub CreateOrdersRecordset() Set mrstOrders = New ADODB.Recordset With mrstOrders .ActiveConnection = CurrentProject.Connection .CursorLocation = adUseClient .CursorType = adOpenDynamic .LockType = adLockOptimistic .Source = "Select * from Orders Where CustomerID = '" & _ Me.cboSelectCompany & "'" .Open End With Set Me.fsubOrders.Form.Recordset = mrstOrders End Sub
Zunächst wird eine Datensatzgruppenvariable auf Modulebene instanziiert, dann werden ihre Eigenschaften festgelegt. Beachten Sie, dass die Eigenschaft CursorType auf adOpenDynamic und die Eigenschaft LockType auf adLockOptimistic gesetzt wird. Die Kombination dieser beiden Eigenschaften macht die entstehende Datensatzgruppe aktualisierbar. Die Eigenschaft Source der Datensatzgruppe basiert auf einer SQL-Anweisung, die alle Datensätze der Tabelle Orders auswählt, bei denen das Feld CustomerID mit der Kundennummer des im Kombinationsfeld cboSelectCompany aus-
Eine Client-Server-Anwendung mit Hilfe eines Access-Datenprojekts erstellen
807
gewählten Kunden übereinstimmt. Dann wird die Datensatzgruppe geöffnet und zum Ausfüllen der mit dem Unterformular fsubOrders verknüpften Datensatzgruppe verwendet. Der Code in Listing 21.7, der sich ebenfalls im Formular frmCustomers befindet, ist für das Füllen des Formulars fsubOrderDetails mit Daten zuständig.
Listing 21.7:
Die Routine CreateOrderDetailsRecordset erstellt die Datensatzgruppe, die zum Füllen des Unterformulars fsubOrderDetails mit Daten verwendet wird
Sub CreateOrderDetailsRecordset() Set mrstOrderDetails = New ADODB.Recordset With mrstOrderDetails .ActiveConnection = CurrentProject.Connection .CursorLocation = adUseClient .CursorType = adOpenDynamic .LockType = adLockOptimistic .Source = "Select * from [Order Details] Where OrderID = " & _ Me.fsubOrders!OrderID .Open End With Set Me.fsubOrderDetails.Form.Recordset = mrstOrderDetails End Sub
Diese Routine ist mit der Routine CreateOrdersRecordset bis auf die Eigenschaft Source identisch. Die Eigenschaft Source wählt alle Datensätze der Tabelle OrderDetails aus, bei denen das Feld OrderID mit der Bestellnummer des im Unterformular fsubOrders markierten Datensatzes übereinstimmt. Die daraus resultierende Datensatzgruppe wird dann zum Ausfüllen des Unterformulars fsubOrderDetails verwendet. Auf das Anklicken der verschiedenen Formularseiten reagieren Den Schlussstein des Puzzles bildet der Code, der darauf reagiert, dass der Benutzer verschiedene Formularseiten per Mausklick auswählt. Sie sehen ihn in Listing 21.8. Listing 21.8:
Die Behandlungsroutine für das Ereignis Change des Steuerelements tabDataEntry reagiert darauf, dass der Benutzer per Mausklick verschiedene Formularseiten auswählt
Private Sub tabDataEntry_Change() Select Case Me.tabDataEntry.Pages. _ Item(Me.tabDataEntry.Value).Name Case "pagCustomers" Me.fsubOrders.SourceObject = "" Me.fsubOrderDetails.SourceObject = ""
808
Kapitel 21: Eine Client-Server-Anwendung in Aktion
Case "pagOrders" Me.fsubOrders.SourceObject = "fsubOrders" Call CreateOrdersRecordset Me.fsubOrderDetails.SourceObject = ""
Case "pagOrderDetails" Me.fsubOrderDetails.SourceObject = "fsubOrderDetails" Call CreateOrderDetailsRecordset End Select End Sub
Der Code beginnt mit dem Auswerten der ausgewählten Seite. Wenn es sich um die Seite CUSTOMERS handelt, wird die Eigenschaft SourceObject der Unterformularsteuerelemente fsubOrders und fsubOrderDetails auf "" gesetzt. Wenn es sich um die Seite ORDERS handelt, wird die Eigenschaft SourceObject des Unterformularsteuerelements fsubOrders auf "fsubOrders" gesetzt und anschließend die Routine CreateOrdersRecordset aufgerufen, um das Formular fsubOrders mit den passenden Daten zu füllen. Die Eigenschaft SourceObject des Unterformularsteuerelements fsubOrderDetails wird auf "" gesetzt. Wenn es sich um die Seite ORDER DETAILS handelt, wird die Eigenschaft SourceObject des Unterformularsteuerelements fsubOrderDetails auf "fsubOrderDetails" gesetzt. Dann wird die Routine CreateOrderDetailsRecordset aufgerufen, um das Unterformular fsubOrderDetails mit den passenden Daten zu füllen.
Transaktionsverarbeitung
Kapitel
Hier lesen Sie:
Von Atomarität bis Konsistenz Die Vorteile Das Standardverhalten verändern Explizite Transaktionsverarbeitung implementieren Einige Bemerkungen zur Transaktionsverarbeitung Transaktionsverarbeitung in einer Mehrbenutzerumgebung Transaktionsverarbeitung in einer Client-Server-Umgebung
22.1
Von Atomarität bis Konsistenz
Mit »Transaktionsverarbeitung« ist die Zusammenfassung mehrerer Änderungen zu einem Batch gemeint. Der gesamte Änderungs-Batch wird als Gruppe durchgeführt oder verworfen. Zu den häufigsten Implementierungen der Transaktionsverarbeitung zählen Transaktionen bei Geldautomaten. Stellen Sie sich vor, dass Sie zum Geldautomaten gehen, um Ihr Gehalt einzuzahlen. Mitten in der Verarbeitung kommt es zu einem Stromausfall. Unglücklicherweise hat die Bank den eingehenden Betrag vor dem Stromausfall vermerkt, aber er war Ihrem Konto noch nicht gutgeschrieben worden, als der Stromausfall kam. Transaktionsverarbeitung hätte dies verhindert. Bei Transaktionsverarbeitung wäre der gesamte Prozess als Einheit erfolgreich oder nicht erfolgreich. Eine Gruppe von Operationen gilt als Transaktion, wenn sie folgende Kriterien erfüllt:
Atomarität – Die Gruppe von Operationen sollte entweder als Einheit oder überhaupt nicht ausgeführt werden.
810
Kapitel 22: Transaktionsverarbeitung
Konsistenz – Wenn die Gruppe von Operationen als Einheit ausgeführt wird, bleibt die Konsistenz der Anwendung erhalten.
Isolation – Die Gruppe von Operationen ist von anderen Vorgängen im System unabhängig.
Dauerhaftigkeit – Nachdem die Gruppe von Operationen übernommen wurde, bleiben die Änderungen bestehen, selbst wenn das System zusammenbricht. Wenn Ihre Anwendung eine Gruppe von Operationen enthält, die atomar und isoliert ist und wenn alle Änderungen weiterbestehen müssen, um die Konsistenz der Anwendung zu erhalten, auch wenn das System zusammenbricht, sollten Sie diese Gruppe von Operationen in eine Transaktionsschleife einbinden. Bei Access 2000 liegt der wesentliche Vorteil der Transaktionsverarbeitung in der Datenintegrität. Wie Sie im nächsten Abschnitt sehen werden, brachte die Transaktionsverarbeitung auch schon in älteren Versionen als Access 95 Leistungsvorteile.
22.2
Die Vorteile
In Access 2.0 ergab die zusätzliche Transaktionsverarbeitung viele geringfügige Vorteile, weil Access 2.0 selbst keine implizite Transaktionsverarbeitung durchführte. Listing 22.1 zeigt Code, der beim Betrieb unter Access 2.0 jedesmal Daten auf die Platte schreibt, wenn die Schleife die Methode Update erreicht. Diese Schreibvorgänge waren in Hinblick auf die Leistung kostspielig, insbesondere wenn sich die Tabellen nicht auf einem lokalen Rechner befanden. Listing 22.1:
Transaktionsverarbeitung mit Hilfe von Access Basic wie in Access 2.0
Sub IncreaseQuantity() On Error GoTo IncreaseQuantity_Err Dim db As DAO.DATABASE Dim rst As DAO.Recordset Set db = CurrentDb Set rst = db.OpenRecordset("Select OrderId, Quantity From tblOrderDetails", _ dbOpenDynaset) 'Datensatzgruppe durchlaufen und das Mengenfeld um 1 erhöhen Do Until rst.EOF rst.Edit rst!Quantity = rst!Quantity + 1 rst.UPDATE rst.MoveNext Loop IncreaseQuantity_Exit:
Die Vorteile
811
Set db = Nothing Set rst = Nothing Exit Sub IncreaseQuantity_Err: MsgBox "Error # " & Err.Number & ": " & Error.Description Resume IncreaseQuantity_Exit End Sub
Dieser und der gesamte Code des Kapitels befindet sich im Modul basTrans der Datenbank CHAP22EX.MDB auf der CD-ROM mit dem Beispiel-Code.
Derselbe Code wie in Listing 22.1 verhält sich bei der Ausführung in Access 2000 wesentlich anders. Neben der expliziten Transaktionsverarbeitung, die Sie möglicherweise aus Gründen der Datenintegrität implementieren, führt Access 2000 hinter den Kulissen eine eigene Transaktionsverarbeitung durch. Diese implizite Transaktionsverarbeitung geschieht allein zur Verbesserung der Leistung Ihrer Anwendung. Während die Verarbeitungsschleife in der Routine IncreaseQuantity ausgeführt wird, schreibt Access die Daten in einen Pufferspeicher und dann in bestimmten Abständen auf die Festplatte. In einer Mehrbenutzerumgebung führt Jet (implizit) standardmäßig alle 50 Millisekunden eine Übernahme aus. Diese Zeitspanne ist auf Parallelität optimiert, nicht auf Leistung. Wenn Sie es für nötig erachten, Parallelität zugunsten von Leistung zu opfern, können Sie einige Einstellungen in der Windows-Registry ändern, um die gewünschten Ergebnisse zu erzielen. Diese Einstellungen werden im nächsten Abschnitt behandelt. Obwohl implizite Transaktionsverarbeitung zusammen mit den veränderbaren Einstellungen der Windows-Registry im Allgemeinen höhere Leistung liefert als explizite Transaktionsverarbeitung, ist diese Situation nicht festgeschrieben. Die Leistungsvorteile durch implizite und explizite Transaktionsverarbeitung werden von zahlreichen Faktoren beeinflusst:
von der Menge freien Speichers von der Anzahl der zu aktualisierenden Spalten und Zeilen von der Länge der zu aktualisierenden Zeilen vom Netzwerkverkehr Falls Sie vorhaben, Transaktionsverarbeitung nur zum Zweck der Leistungssteigerung zu implementieren, sollten Sie darauf achten, dass Sie die Leistung sowohl bei impliziter als auch bei expliziter Transaktionsverarbeitung messen. Es kommt darauf an, dass Ihre Testumgebung der Produktionsumgebung, in der die Anwendung laufen soll, so ähnlich wie möglich ist.
812
22.3
Kapitel 22: Transaktionsverarbeitung
Das Standardverhalten verändern
Bevor Sie erfahren, wie Transaktionsverarbeitung implementiert wird, sollten Sie einen Blick darauf werfen, was Sie tun können, um das Standardverhalten der in Access 2000 integrierten Transaktionsverarbeitung zu verändern. Implizite Transaktionen werden in Access 2000 von drei Registry-Einstellungen beeinflusst: ImplicitCommitSync, ExclusiveAsyncDelay und SharedAsyncDelay. Diese Schlüssel befinden sich im Registry-Ordner \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0\Engines\Jet 4.0. Sie können mit dem Dienstprogramm RegEdit auf die Windows-Registry zugreifen. Dazu wählen Sie im Startmenü die Option AUSFÜHREN und geben dann RegEdit ein. Die Einstellung ImplicitCommitSync bestimmt, ob das System wartet, bis eine Übernahme durchgeführt ist, bevor es die Ausführung der Anwendung fortsetzt. Die Standardeinstellung ist No, d.h., das System fährt fort, ohne auf das Ende der Übernahme zu warten. Im Allgemeinen werden Sie diese Einstellung nicht ändern wollen, weil dadurch die Leistung enorm erhöht wird. Die Gefahr beim Bestätigen dieses Wertes liegt in der längeren Zeitspanne, in der die Daten verletzbar sind. Bevor die Daten auf die Platte geschrieben sind, könnte der Benutzer den Rechner abschalten und die Integrität der Daten beeinträchtigen. Die Einstellung ExclusiveAsyncDelay gibt die maximale Anzahl Millisekunden an, die vergehen, bevor Jet eine implizite Transaktion übernimmt, wenn eine Datenbank für exklusive Nutzung geöffnet wurde. Die Standardeinstellung beträgt 2 000 Millisekunden. Dieser Wert hat keinen Einfluss auf Datenbanken, die für gemeinsame Nutzung geöffnet wurden. Die Einstellung SharedAsyncDelay ähnelt der Einstellung ExclusiveAsyncDelay. Sie gibt die maximale Anzahl Millisekunden an, die vergehen, bevor Jet eine implizite Transaktion übernimmt, wenn eine Datenbank für gemeinsame Nutzung geöffnet wurde. Die Standardeinstellung beträgt 50 Millisekunden. Je höher dieser Wert liegt, desto größer sind die Leistungsvorteile durch implizite Transaktionen, aber auch das Risiko von Parallelitätsproblemen. Parallelitätsprobleme werden im Abschnitt »Transaktionsverarbeitung in einer Mehrbenutzerumgebung« weiter hinten in diesem Kapitel ausführlich behandelt. Neben den Einstellungen, die die implizite Transaktionsverarbeitung in Access 2000 beeinflussen, gibt es noch eine Registry-Einstellung für die explizite Transaktionsverarbeitung mit dem Namen UserCommitSync, die steuert, ob explizite Transaktionen synchron oder asynchron durchgeführt werden. Bei der Standardeinstellung Yes gibt eine CommitTrans-Anweisung die Kontrolle erst zurück, wenn die Transaktionen tatsächlich auf die Platte geschrieben wurden, d.h., es handelt sich um synchrone
Explizite Transaktionsverarbeitung implementieren
813
Transaktionen. Wenn der Wert auf No geändert wird, bilden mehrere Änderungen eine Warteschlange und die Steuerung wird zurückgegeben, bevor die Änderungen abgeschlossen sind. Sie können die Werte dieser Registry-Einstellungen und anderer Jet-Einstellungen für Windows 95/98 mit Hilfe des Registry-Editors (Regedit.exe) bzw. für Windows NT mit RegEdt32.exe verändern. Änderungen in diesem Abschnitt der Registry betreffen alle Anwendungen, welche die Jet 4.0-Engine benutzen. Wenn nur Ihre Anwendung betroffen sein soll, können Sie den Microsoft Jet betreffenden Teil des Registry-Verzeichnisbaums in den Registry-Verzeichnisbaum Ihrer Anwendung importieren. Dann können Sie die Registry-Einstellungen an Ihre Anwendung anpassen. Um in Ihrer Anwendung das Laden des richtigen Registry-Verzeichnisbaums zu erzwingen, müssen Sie die Eigenschaft INIPath des Objekts DBEngine entsprechend angeben. Ein wesentlich einfacherer Ansatz besteht darin, die Eigenschaften des ADOObjekts Connection festzulegen: Sie können zur Laufzeit neue Einstellungen für alle zuvor erwähnten Registry-Einstellungen sowie zusätzliche Einträge angeben. Ein weiterer Vorteil dieses Ansatzes liegt darin, dass die Registry-Einträge für alle Rechner (temporär) geändert werden, auf denen Ihre Anwendung läuft. Alle Werte, die Sie zur Laufzeit temporär ändern, überschreiben die festgelegten Registry-Werte und ermöglichen die einfache Steuerung und Pflege bestimmter Einstellungen für jede Anwendung. Der folgende Code veranschaulicht, wie die Einstellungen ExclusiveAsyncDelay und SharedAsyncDelay mit Hilfe der Eigenschaften eines ConnectionObjekts verändert werden: Sub ChangeOptions() Dim cnn As ADODB.Connection Set cnn = CurrentProject.Connection cnn.Properties("Jet OLEDB:Exclusive Async Delay") = 1000 cnn.Properties("Jet OLEDB:Shared Async Delay") = 50 End Sub
22.4
Explizite Transaktionsverarbeitung implementieren
Nachdem Sie jetzt die Einstellungen kennen, welche die Transaktionsverarbeitung beeinflussen, können Sie lernen, wie Transaktionsverarbeitung implementiert wird. Die Transaktionsverarbeitung wird von drei Methoden des Objekts Connection (siehe Kapitel 12) gesteuert:
BeginTrans CommitTrans RollbackTrans
814
Kapitel 22: Transaktionsverarbeitung
Die Methode BeginTrans des Objekts Connection eröffnet die Transaktionsschleife. Sobald Access auf BeginTrans trifft, werden alle Änderungen in eine Protokolldatei im Arbeitsspeicher geschrieben. Solange die Methode CommitTrans für das Objekt Connection nicht ausgeführt wird, werden sie nicht in die Datenbankdatei aufgenommen. Nach dem Aufrufen der Methode CommitTrans werden die Änderungen dann dauerhaft in das Datenbankobjekt geschrieben. Wenn die Methode RollbackTrans für das Objekt Connection in Aktion tritt, wird das Protokoll im Arbeitsspeicher gelöscht. Listing 22.2 zeigt ein Beispiel für die Funktionsweise der Transaktionsverarbeitung in Access 2000. Vergleichen Sie es mit Listing 22.1! Listing 22.2:
Transaktionsverarbeitung in Access 2000 mit Hilfe von BeginTrans, Protokollierung, CommitTrans und RollbackTrans
Sub IncreaseQuantityTrans() On Error GoTo IncreaseQuantityTrans_Err Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim boolInTrans As Boolean boolInTrans = False Set rst = New ADODB.Recordset Set cnn = CurrentProject.Connection rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.LockType = adLockOptimistic rst.Open "Select OrderId, Quantity From tblOrderDetails"
'Anfang der Transaktionsschleife cnn.BeginTrans boolInTrans = True 'Schleife durch die Datensatzgruppe, Mengenfeld um 1 erhöhen Do Until rst.EOF rst!Quantity = rst!Quantity + 1 rst.UPDATE rst.MoveNext Loop 'Transaktion übernehmen; alles ist planmäßig verlaufen cnn.CommitTrans boolInTrans = False IncreaseQuantityTrans_Exit: Set cnn = Nothing Set rst = Nothing Exit Sub IncreaseQuantityTrans_Err:
Einige Bemerkungen zur Transaktionsverarbeitung
815
MsgBox "Error # " & Err.Number & ": " & Err.Description 'Transaktion zurücksetzen; ein Fehler ist aufgetreten If boolInTrans Then cnn.RollbackTrans End If Resume IncreaseQuantityTrans_Exit End Sub
Dieser Code verwendet eine Transaktionsschleife, um sicherzustellen, dass alles wie geplant beendet oder überhaupt nicht ausgeführt wird. Beachten Sie, dass die Schleife, die sich durch die Datensatzgruppe bewegt und das Mengenfeld der einzelnen Datensätze um 1 erhöht, in einer Transaktionsschleife platziert wurde. Wenn die gesamte Verarbeitung innerhalb der Schleife erfolgreich abgeschlossen ist, wird die Methode CommitTrans ausgeführt. Im Falle eines Fehlers wird die Methode RollbackTrans ausgelöst, die sicherstellt, dass keine der Änderungen auf die Platte geschrieben wird. Mit Hilfe der Variablen boolInTrans wird ermittelt, ob sich der Code in der Transaktionsschleife befindet. Damit wird gewährleistet, dass die Fehlerbehandlungsroutine nur dann ein Zurücksetzen ausführt, wenn ein Fehler innerhalb der Transaktionsschleife auftritt. Wenn die Methode CommitTrans oder RollbackTrans gestartet wird, ohne dass eine offene Transaktion vorliegt, zieht dies einen Fehler nach sich.
22.5
Einige Bemerkungen zur Transaktionsverarbeitung
Bevor Sie beschließen, dass Transaktionsverarbeitung die beste Erfindung seit fertig geschnittenem Brot ist, sollten Sie einige Aspekte der Transaktionsverarbeitung bedenken, die in diesem Abschnitt umrissen werden.
22.5.1
Transaktionen finden in einem Arbeitsbereich statt
Transaktionen existieren im Kontext eines Connection-Objekts. Die Methoden BeginTrans, CommitTrans und RollbackTrans beeinflussen alle Operationen an der betreffenden Verbindung. Wenn Sie wollen, dass gleichzeitige unverbundene Transaktionen wirksam werden, müssen Sie einzelne Connection-Objekte anlegen, in denen die Transaktionen ablaufen. Während DAO Transaktionen unterstützte, die über mehrere Datenbanken liefen, sind ADO-Transaktionen auf eine konkrete Datenquelle beschränkt, weil sie im Kontext einer Verbindung bestehen.
22.5.2
Sicherstellen, dass die Datenquelle Transaktionen unterstützt
Nicht alle Datenquellen unterstützen Transaktionsverarbeitung, wie beispielsweise Excel- und dBase-Dateien und auch einige Back-End-ODBC-Datenbank-Server. Im Zweifelsfall können Sie mit Hilfe der Eigenschaft Transaction DDL des Objekts Con-
816
Kapitel 22: Transaktionsverarbeitung
nection ermitteln, ob die Datenquelle Transaktionsverarbeitung unterstützt. Wenn die Eigenschaft vorhanden und nicht mit einem Nullwert versehen ist, trifft dies zu. Um festzustellen, ob die Eigenschaft vorhanden ist, fragen Sie ihren Wert ab. Wenn sie nicht vorhanden ist, wird ein Fehler ausgelöst. Listing 22.3 zeigt ein Beispiel dafür, wie man ermittelt, ob ein Objekt Transaktionsverarbeitung unterstützt. Listing 22.3:
Bestimmen, ob eine Verbindung Transaktionsverarbeitung unterstützt
Sub SupportsTransCurrentDB() On Error GoTo SupportsTrans_Err Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim boolSupportsTrans As Boolean Dim vntValue As Variant boolSupportsTrans = False Set cnn = CurrentProject.Connection Set rst = New ADODB.Recordset rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.LockType = adLockOptimistic rst.Open "tblOrderDetails" 'Transaktionsschleife nur beginnen, wenn 'Datensatzgruppe Transaktionen unterstützt On Error Resume Next vntValue = cnn.Properties.Item("Transaction DDL") If Not Err.Number And _ cnn.Properties.Item("Transaction DDL").Value <> 0 Then boolSupportsTrans = True cnn.BeginTrans End If On Error GoTo SupportsTrans_Err 'Schleife durch Datensatzgruppe, Mengenfeld um 1 erhöhen Do Until rst.EOF rst!Quantity = rst!Quantity + 1 rst.UPDATE rst.MoveNext Loop 'CommitTrans starten, wenn alles nach Plan verlaufen ist 'und Datensatzgruppe Transaktionen unterstützt If boolSupportsTrans Then cnn.CommitTrans End If
Einige Bemerkungen zur Transaktionsverarbeitung
817
SupportsTrans_Exit: Set cnn = Nothing Set rst = Nothing Exit Sub SupportsTrans_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description 'Transaktion zurücksetzen, wenn Fehler aufgetreten ist 'und Datensatzgruppe Transaktionen unterstützt If boolSupportsTrans Then cnn.RollbackTrans End If Resume SupportsTrans_Exit End Sub
Der Code verwendet eine Boolesche Variable mit dem Namen boolSupportsTrans, um zu verfolgen, ob die Verbindung Transaktionen unterstützt. Beachten Sie die Anweisung On Error Resume Next. Die Eigenschaft Transaction DDL des Objekts Connection wird ausgewertet. Wenn sie nicht vorhanden ist, wird ein Fehler ausgelöst. Die nächste Anweisung prüft auf eine Fehlernummer und einen Eigenschaftswert ungleich 0. Nur wenn die Eigenschaft Transaction DDL für das Objekt Connection vorhanden und ungleich 0 ist, wird die Methode BeginTrans aufgerufen und die Variable boolSupportsTrans auf True gesetzt. Die Variable wird im weiteren Verlauf der Routine zweimal ausgewertet. Die Methode CommitTrans wird nur ausgelöst, wenn boolSupportsTrans mit True belegt ist. Bei der Fehlerbehandlung wird die Methode RollbackTrans ebenfalls nur ausgeführt, wenn boolSupportsTrans gleich True ist. Listing 22.4 zeigt ein Beispiel, in dem die Datenquelle, ein Excel-Arbeitsblatt, keine Transaktionen unterstützt. Beachten Sie, dass eine Datenquelle verwendet wird, die auf das Excel-Arbeitsblatt verweist. Mit Hilfe des Connection-Objekts wird eine Datensatzgruppe geöffnet. Der übrige Code entspricht dem in Listing 22.3. gezeigten. Listing 22.4:
Bestimmen, ob eine auf einer anderen Datenquelle als Access basierende Verbindung Transaktionsverarbeitung unterstützt
Sub SupportsTransOtherDB() On Error GoTo SupportsTrans_Err Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim boolSupportsTrans As Boolean Dim vntValue As Variant boolSupportsTrans = False
818
Kapitel 22: Transaktionsverarbeitung
Set cnn = New ADODB.Connection cnn.Open "DSN=TestXLS;UID=;PWD=;" Set rst = New ADODB.Recordset With rst .ActiveConnection = cnn .CursorType = adOpenKeyset .LockType = adLockOptimistic .Open "tblCustomers" End With 'Transaktionsschleife nur beginnen, wenn 'Datensatzgruppe Transaktionen unterstützt On Error Resume Next vntValue = cnn.Properties.Item("Transaction DDL") If Not Err.Number And _ cnn.Properties.Item("Transaction DDL").Value <> 0 Then boolSupportsTrans = True cnn.BeginTrans End If On Error GoTo SupportsTrans_Err
'Schleife durch Datensatzgruppe, Mengenfeld um 1 erhöhen Do Until rst.EOF rst!City = "Thousand Oaks" rst.UPDATE rst.MoveNext Loop 'CommitTrans starten, wenn alles nach Plan verlaufen ist 'und Datensatzgruppe Transaktionen unterstützt If boolSupportsTrans Then cnn.CommitTrans End If SupportsTrans_Exit: Set cnn = Nothing Set rst = Nothing Exit Sub SupportsTrans_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description
Einige Bemerkungen zur Transaktionsverarbeitung
819
'Transaktion zurücksetzen, wenn Fehler aufgetreten ist 'und Datensatzgruppe Transaktionen unterstützt If boolSupportsTrans Then cnn.Rollback End If Resume SupportsTrans_Exit End Sub
Wenn es bei einer Anwendung um eine Verknüpfung mit einer Datenquelle geht, die keine Transaktionen unterstützt, wird die Eigenschaft Transaction DDL nicht korrekt ausgewertet. Weil beim Umgang mit verknüpften Tabellen die Verbindung der Access-Datenbank verwendet wird, scheint es, als ob die Eigenschaft Transaction DDL Transaktionen unterstütze. Dasselbe Verhalten zeigt sich, wenn für die Verbindung der Datenquelle der Jet Provider eingesetzt wird. In beiden Fällen wird beim Aufrufen der Methoden BeginTrans, CommitTrans und RollbackTrans kein Fehler ausgelöst, sondern der Vorgang scheint erfolgreich abgeschlossen zu werden. Wenn die Methode RollbackTrans aufgerufen wird, findet keine Rücknahme statt und alle Änderungen bleiben erhalten.
22.5.3
Transaktionen verschachteln
Ein weiterer Punkt, den Sie in Bezug auf Transaktionen kennen sollten, ist die Möglichkeit, Transaktionen zu verschachteln. Die Hierarchie richtet sich nach dem FIFO-Prinzip. Die inneren Transaktionen müssen immer vor den äußeren übernommen oder zurückgesetzt werden. Nachdem für eine Transaktion ein CommitTrans ausgeführt wurde, können Sie Änderungen an dieser nur vornehmen, wenn sie in eine andere Transaktion verschachtelt ist, die ihrerseits zurückgesetzt wurde. Die Methode BeginTrans gibt einen Wert zurück, der die Verschachtelungsebene angibt. Mit 1 wird eine Transaktion auf höchster Ebene, mit 2 eine Transaktion auf der nächst niedrigen Ebene bezeichnet usw.
22.5.4
Die explizite Übernahme von Transaktionen vergessen
Wenn sich eine Transaktionsschleife in der Ausführung befindet, werden alle Änderungen in eine Protokolldatei im Arbeitsspeicher geschrieben. Wenn es niemals zu einem CommitTrans kommt, werden die Änderungen praktisch zurückgesetzt. Anders gesagt: es gibt ein implizites Zurücksetzen, wenn die Änderungen nicht mit der Methode CommitTrans explizit auf die Platte geschrieben werden. Das geschieht im Allgemeinen zu Ihrem Vorteil. Wenn die Stromzufuhr unterbrochen wird oder der Rechner sich aufhängt, bevor der CommitTrans ausgeführt wird, werden alle Änderungen zurückgenommen. Dieses Verhalten kann Sie jedoch in Schwierigkeiten stürzen, wenn Sie die Methode CommitTrans vergessen. Wenn die Verbindung geschlossen wird, ohne dass die Methode CommitTrans ausgeführt wurde, wird das Protokoll im Speicher gelöscht und die Transaktion implizit zurückgesetzt.
820
22.5.5
Kapitel 22: Transaktionsverarbeitung
Den verfügbaren Arbeitsspeicher prüfen
Ein weiteres Problem bei Transaktionen tritt auf, wenn das Transaktionsprotokoll den physischen Arbeitsspeicher des Rechners verbraucht hat. Access 2000 versucht zunächst, virtuellen Speicher zu nutzen. Das Transaktionsprotokoll wird in das Verzeichnis geschrieben, das in der Umgebungsvariablen TEMP des Rechners genannt ist. Diese Methode verlangsamt den Transaktionsprozess erheblich. Wenn das Transaktionsprotokoll den gesamten Arbeitsspeicher und den virtuellen Speicher auf der Festplatte aufgebraucht hat, wird ein Fehler mit der Nummer 2004 gemeldet. An dieser Stelle müssen Sie ein Zurücksetzen einleiten, da Sie sonst in Gefahr geraten, die Integrität der Datenbank zu verletzen. Wenn Ihr Code versucht, die Transaktion zu übernehmen, nachdem ein Fehler mit der Nummer 2004 aufgetreten ist, übernimmt die Jet-Engine so viele Änderungen wie möglich und lässt die Datenbank in einem inkonsistenten Zustand zurück. Der Fehler 2004 lässt sich mit Hilfe der Eigenschaft SQLSTATE der Auflistung Errors des Objekts Connection feststellen.
22.5.6
Formulare und Transaktionen
Bei gebundenen Formularen setzt Access seine eigene Transaktionsverarbeitung ein, über die Sie keinerlei Kontrolle besitzen. Wenn Sie selbst im Zusammenhang mit Formularen Transaktionsverarbeitung betreiben wollen, müssen Sie ungebundene Formulare erstellen oder Code ohne Formularschnittstelle ausführen.
22.6
Transaktionsverarbeitung in einer Mehrbenutzerumgebung
In einer Mehrbenutzerumgebung hat Transaktionsverarbeitung Konsequenzen, die über den Schutz von Daten hinausgehen. Indem Sie einen Prozess in eine Transaktionsschleife einbetten, stellen Sie sicher, dass Sie die Kontrolle über alle Datensätze besitzen, die von dem Prozess betroffen sind. Der Preis für diese zusätzliche Kontrolle besteht in geringerer Parallelität für die übrigen Benutzer der Anwendung. Listing 22.5 veranschaulicht dieses Szenario. Listing 22.5:
Ein sicherer Weg, in einer Mehrbenutzerumgebung Transaktionen durchzuführen, der jedoch zu Parallelitätseinbußen führt
Sub MultiPessimistic() On Error GoTo MultiPessimistic_Err Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim intCounter As Integer
Transaktionsverarbeitung in einer Mehrbenutzerumgebung
821
Dim intChoice As Integer Dim intTry As Integer Dim boolInTrans As Boolean boolInTrans = False Set rst = New ADODB.Recordset Set cnn = CurrentProject.Connection rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.CursorLocation = adUseServer rst.LockType = adLockPessimistic rst.Open "Select OrderId, ProductID, UnitPrice " & _ "From tblOrderDetails Where ProductID > 50" 'Transaktionsschleife beginnen cnn.BeginTrans boolInTrans = True 'Schleife durch die Datensatzgruppe, dabei UnitPrice erhöhen Do Until rst.EOF 'Hier Sperre für jeden Datensatz innerhalb der Schleife rst!UnitPrice = rst!UnitPrice * 1.1 rst.UPDATE rst.MoveNext Loop 'Transaktion übernehmen; alles ist nach Plan verlaufen 'Alle Sperren für alle am Prozess beteiligten Datensätze werden aufgehoben cnn.CommitTrans boolInTrans = False Set cnn = Nothing Set rst = Nothing Exit Sub MultiPessimistic_Err: Select Case cnn.Errors(0).SQLState Case 3260 intCounter = intCounter + 1 If intCounter > 2 Then intChoice = MsgBox(Err.Description, vbRetryCancel + vbCritical) Select Case intChoice Case vbRetry intCounter = 1 Case vbCancel 'Benutzer hat Abbruch gewählt, zurücksetzen Resume TransUnsuccessful End Select End If
822
Kapitel 22: Transaktionsverarbeitung
DoEvents For intTry = 1 To 100: Next intTry Resume Case Else MsgBox "Error # " & Err.Number & ": " & Err.Description End Select TransUnsuccessful: If boolInTrans Then cnn.RollbackTrans End If MsgBox "Warning: Entire Process Rolled Back" Set cnn = Nothing Set rst = Nothing Exit Sub End Sub
Die Routine MultiPessimistic wendet pessimistisches Sperren an, d.h., dass der betroffene Datensatz bei jeder Bearbeitung der Daten gesperrt wird. Wenn alles klappt und kein Fehler auftritt, wird die Sperre aufgehoben, wenn die Methode CommitTrans erreicht ist. Ein Fehler mit der Nummer 3260, welcher besagt, dass der Datensatz von einem anderen Benutzer gesperrt wurde, wird von der Fehlerbehandlungsroutine abgefangen. Derjenige, der die Transaktionsverarbeitung ausführt, kann zwischen erneutem Versuch und Abbruch wählen. Wenn er sich für einen neuen Versuch entscheidet, versucht der Code noch einmal, Daten im betreffenden Datensatz zu bearbeiten. Wenn er sich für den Abbruch entscheidet, wird die Transaktion zurückgesetzt. Damit werden die Änderungen an allen am Prozess beteiligten Datensätzen zurückgenommen. Zwei wichtige Bemerkungen zur Routine MultiPessimistic: Erstens wird bei der Ausführung dieser Routine jeder am Prozess beteiligte Datensatz gesperrt. Das kann bedeuten, dass alle anderen Benutzer einen großen Teil oder sogar alle Datensätze erst bearbeiten können, wenn der Transaktionsprozess abgeschlossen ist. Das ist unter dem Aspekt der Datenintegrität wundervoll, aber es könnte in einer Umgebung, in der Daten häufig aktualisiert werden müssen, undurchführbar sein. Deshalb ist es günstig, Transaktionsschleifen zeitlich möglichst kurz zu halten. Zweitens muss die gesamte Transaktion abgebrochen werden, wenn ein einziger Sperrversuch misslingt. Dies könnte wiederum unter dem Aspekt der Datenintegrität Ihren Wünschen entsprechen, aber möglicherweise erfordern, dass alle Benutzer auf Datenbearbeitung verzichten, während ein wichtiger Prozess abläuft. Im optimistischen Sperrmodus findet der Sperrversuch nicht beim Beginn der Datenbearbeitung, sondern beim Aufruf der Methode Update statt. Das macht allerdings keinen großen Unterschied; alle an der Transaktion beteiligten Datensätze bleiben gesperrt, bis CommitTrans oder RollbackTrans ausgeführt sind. Der Hauptun-
Transaktionsverarbeitung in einer Mehrbenutzerumgebung
823
terschied liegt in den Fehlern, die Sie abfangen müssen. Listing 22.6 zeigt den Code für optimistisches Sperren in einer Mehrbenutzerumgebung. Listing 22.6:
Optimistisches Sperren in einer Mehrbenutzerumgebung
Sub MultiOptimistic() On Error GoTo MultiOptimistic_Err Dim cnn As ADODB.Connection Dim rst As ADODB.Recordset Dim intCounter As Integer Dim intChoice As Integer Dim intTry As Integer Dim boolInTrans As Boolean boolInTrans = False Set rst = New ADODB.Recordset Set cnn = CurrentProject.Connection rst.ActiveConnection = cnn rst.CursorType = adOpenKeyset rst.CursorLocation = adUseServer rst.LockType = adLockOptimistic rst.Open "Select OrderId, ProductID, UnitPrice " & _ "From tblOrderDetails Where ProductID > 50" 'Transaktionsschleife beginnen cnn.BeginTrans boolInTrans = True 'Schleife durch die Datensatzgruppe, dabei UnitPrice erhöhen Do Until rst.EOF rst!UnitPrice = rst!UnitPrice * 1.1 'Hier Sperre für jeden Datensatz innerhalb der Schleife rst.UPDATE rst.MoveNext Loop 'Transaktion übernehmen; alles ist nach Plan verlaufen 'Alle Sperren für alle am Prozess beteiligten Datensätze werden aufgehoben cnn.CommitTrans boolInTrans = False Set cnn = Nothing Set rst = Nothing Exit Sub MultiOptimistic_Err: Select Case Err.Number Case 3197 'Data Has Changed-Fehler If rst.EditMode = adEditInProgress Then intChoice = MsgBox("Overwrite Other User's Changes?", _
824
Kapitel 22: Transaktionsverarbeitung
vbYesNoCancel + vbQuestion) Select Case intChoice Case vbCancel, vbNo MsgBox "Update Canceled" Resume TransNotSuccessful Case vbYes rst.UPDATE Resume End Select End If Case 3186, 3260 'Gesperrt oder Läßt sich nicht sichern intCounter = intCounter + 1 If intCounter > 2 Then intChoice = MsgBox(Err.Description, vbRetryCancel + vbCritical) Select Case intChoice Case vbRetry intCounter = 1 Case vbCancel 'Benutzer hat Abbruch gewählt, zurücksetzen Resume TransNotSuccessful End Select End If DoEvents For intTry = 1 To 100: Next intTry Resume Case Else MsgBox "Error # " & Err.Number & ": " & Err.Description End Select TransNotSuccessful: If boolInTrans Then cnn.RollbackTrans End If MsgBox "Warning: Entire Process Rolled Back" Set cnn = Nothing Set rst = Nothing Exit Sub End Sub
Beachten Sie, dass die Sperre in der Routine MultiOptimistic bei jedem Aufruf der Methode Update verhängt wird. Alle Sperren werden aufgehoben, wenn die Methode CommitTrans ausgeführt wird. Außerdem prüft die Fehlerbehandlung auf einen Fehler mit der Nummer 3197 (Datenänderung), der auftritt, wenn die Daten von einem anderen Benutzer zwischen dem Start der Methode Edit und unmittelbar vor dem Start der Methode Update geändert werden.
Transaktionsverarbeitung in einer Client-Server-Umgebung
22.7
825
Transaktionsverarbeitung in einer Client-Server-Umgebung
Wenn es um Transaktionen in einer Client-Server-Umgebung geht, müssen Sie einige weitere Punkte beachten: wann und wie die Transaktionen stattfinden, welche Transaktionstypen unterstützt werden und welcher Art die potentiellen Probleme sind.
22.7.1
Implizite Transaktionen
Wenn keine expliziten Transaktionen verwendet werden, hängt die Art der Übernahme von Transaktionen auf dem Datenbank-Server davon ab, welche Art Befehle ausgeführt werden. Im Allgemeinen ist jede Code-Zeile von einer impliziten Transaktion umschlossen, d.h., es gibt keine Möglichkeit, eine Aktion zurückzusetzen, weil sie unmittelbar auf dem Datenbank-Server übernommen wird. Ausnahmen von dieser Regel bilden SQL-Anweisungen, die Daten verändern. Diese (UPDATE, INSERT und APPEND) werden im Batch ausgeführt; implizit wird eine Transaktionsschleife um die gesamte Anweisung gelegt. Wenn sich nur ein an der SQL-Anweisung beteiligter Datensatz nicht erfolgreich aktualisieren lässt, wird die gesamte UPDATE-, INSERT- oder APPEND-Aktion zurückgesetzt.
22.7.2
Explizite Transaktionen
Bei expliziten Transaktionen übersetzt ODBC die Methoden BeginTrans, CommitTrans und RollbackTrans in die passende Syntax des Back-End-Servers und die Transaktion wird erwartungsgemäß ausgeführt. Die wesentliche Ausnahme von dieser Regel liegt vor, wenn das von Ihnen benutzte Back-End keine Transaktionen unterstützt. Listing 22.7 zeigt ein Beispiel für Transaktionsverarbeitung mit einem SQL ServerBack-End. Listing 22.7:
Transaktionsverarbeitung mit einem SQL Server-Back-End
Sub TransSQLServer() Dim cnn As ADODB.Connection Dim cmd As ADODB.Command Dim boolInTrans As Boolean boolInTrans = False Set cnn = New ADODB.Connection Set cmd = New ADODB.Command cnn.ConnectionString = "Provider=SQLOLEDB; Data Source=Alexis; Initial _ Catalog=Pubs; User ID=SA; Password=" cnn.Open
826
Kapitel 22: Transaktionsverarbeitung
cnn.BeginTrans boolInTrans = True cmd.ActiveConnection = cnn cmd.CommandText = "UPDATE sales Set qty = qty + 1 " & _ "Where Stor_ID = '7067';" cmd.CommandType = adCmdText cmd.Execute cmd.CommandText = "Update titles Set price = price + 1 " & _ "Where Type = 'Business'" cmd.CommandType = adCmdText cmd.Execute cnn.CommitTrans boolInTrans = False TransSQLServer_Exit: Set cnn = Nothing Set cmd = Nothing Exit Sub TransSQLServer_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description If boolInTrans Then cnn.RollbackTrans End If Resume TransSQLServer_Exit End Sub
Die Routine TransSQLServer beginnt mit dem Anlegen der beiden Objektvariablen der Typen Connection und Command. Als nächstes wird die Methode BeginTrans für die Verbindung ausgeführt. Sie erstellt eine temporäre Abfragedefinition. Die Eigenschaft ConnectionString des Connection-Objekts wird mit einem Zeiger auf eine SQL Server-Datenbank mit dem Namen Pubs versehen. Mit der Methode Open des Connection-Objekts wird die Verbindung geöffnet und mit der Methode BeginTrans desselben Objekts beginnt die Transaktionsschleife. Für das Command-Objekt werden u.a. die Eigenschaften ActiveConnection, CommandText und CommandType festgelegt. Danach wird die temporäre Abfrage ausgeführt. Die Eigenschaft CommandText der Abfragedefinition wird verändert und die Abfrage noch einmal ausgeführt. Wenn beide ExecuteMethoden erfolgreich verlaufen, wird die Methode CommitTrans des ConnectionObjekts gestartet. Falls während der Verarbeitung ein Fehler auftritt, wird die Methode RollbackTrans aufgerufen. Listing 22.7 bietet ein Beispiel für die Verwendung von Transaktionen bei der Verarbeitung von Daten, die in Microsoft SQL Server gespeichert wurden. Die Verwendung von ADO-Datensatzgruppen zur Aktualisierung von Client-ServerDaten ist sehr ineffizient. Wie in Kapitel 19 erläutert, ist die Aktualisierung von Client-Server-Daten mit Hilfe gespeicherter Prozeduren meistens vorzuziehen.
Transaktionsverarbeitung in einer Client-Server-Umgebung
22.7.3
827
Sperrbeschränkungen
Ein potentielles Problem im Zusammenhang mit Client-Server-Datenbanken betrifft Sperrbeschränkungen. Viele Datenbank-Server stellen strenge Grenzen dafür auf, wie viele Datensätze gleichzeitig gesperrt werden dürfen. Wie Sie in den Listings 22.2 und 22.3 gesehen haben, kann eine Transaktionsschleife u.U. eine erhebliche Zahl von Datensätzen sperren. Wenn Sie in Ihrem VBA-Code Transaktionsschleifen verwenden, müssen Sie unbedingt an die maximale Anzahl der Sperren denken, die Ihr Back-End unterstützt. Das Problem entfällt, wenn Sie zur Aktualisierung von ClientServer-Daten gespeicherte Prozeduren verwenden.
22.7.4
Negative Interaktionen mit Server-spezifischen Transaktionsbefehlen
Beim Erstellen von Pass-Through-Abfragen sollten Sie keinesfalls die Server-spezifischen Transaktionsbefehle verwenden. Diese können mit den Methoden BeginTrans, CommitTrans und RollbackTrans in Konflikt geraten und Verwirrung und sogar Schäden an Daten verursachen.
22.7.5
Für die Praxis
Die Integrität des Zeit- und Abrechnungssystems mit Hilfe der Transaktionsverarbeitung steigern Bei der Weiterentwicklung des Zeit- und Abrechnungssystems halten Sie es möglicherweise für notwendig, bestimmte Aufgaben mit Hilfe von VBA-Code zu erledigen. Diese Aufgaben erfordern vielleicht, dass mehrere Prozesse entweder erfolgreich oder überhaupt nicht abgeschlossen werden. Wenn solche Situationen entstehen, sollten Sie erwägen, sie in eine Transaktionsschleife einzubetten. Ein Beispiel für eine derartige Situation stellt das Formular frmArchivePayments dar, das Sie in Abbildung 22.1 sehen. Dieses Formular ermöglicht dem Benutzer, einen Datumsbereich anzugeben, der als Kriterium dafür verwendet wird, welche Daten an die Tabelle tblPaymentsArchive gesendet und aus der Tabelle tblPayments gelöscht werden. Wenn dieser Prozess ausgeführt wird, soll sichergestellt werden, dass er entweder in seiner Gesamtheit oder überhaupt nicht stattfindet. Listing 22.8 zeigt den Code der für die Beispielanwendung passenden Transaktionsschleife.
Abbildung 22.1: Im Formular frmArchivePayments kann der Benutzer einen Datumsbereich für zu archivierende Zahlungen angeben
828
Kapitel 22: Transaktionsverarbeitung
Listing 22.8:
Eine für die Beispielanwendung geeignete Transaktionsschleife
Sub cmdArchivePayments_Click() On Error GoTo Err_cmdArchivePayments_Click Dim cnn As ADODB.Connection Dim strSQL As String Dim boolInTrans As Boolean boolInTrans = False If MsgBox("Archives Payments in Selected Date Range, Proceed?", _ vbYesNo, "Please Respond") = vbYes Then Set cnn = CurrentProject.Connection cnn.BeginTrans boolInTrans = True strSQL = "INSERT INTO tblPaymentsArchive" & _ " SELECT DISTINCTROW tblPayments.* " & _ " FROM tblPayments " & _ " WHERE tblPayments.PaymentDate Between #" & _ Me!txtStartDate & _ "# And #" & _ Me!txtEndDate & "#;" cnn.Execute strSQL strSQL = "DELETE DISTINCTROW tblPayments.PaymentDate " & _ "FROM tblPayments " & _ " WHERE tblPayments.PaymentDate Between #" & _ Me!txtStartDate & _ "# And #" & _ Me!txtEndDate & "#;" cnn.Execute strSQL cnn.CommitTrans boolInTrans = False End If MsgBox "Process Completed Successfully!", vbInformation Exit_cmdArchivePayments_Click: Exit Sub Err_cmdArchivePayments_Click: MsgBox Err.Description If boolInTrans Then cnn.RollbackTrans End If Resume Exit_cmdArchivePayments_Click End Sub
Transaktionsverarbeitung in einer Client-Server-Umgebung
829
Diese Routine startet mit Hilfe der Methode BeginTrans des Connection-Objekts eine Transaktionsschleife. Es wird eine SQL-Anweisung erstellt, welche die Werte der Steuerelemente txtStartDate und txtEndDate im Formular als Kriterien verwendet und alle Datensätze im angegebenen Datumsbereich in die Tabelle tblPaymentsArchive einfügt. Die Methode Execute wird auf das Connection-Objekt angewandt und verwendet die SQL-Zeichenfolge als Argument. Die Zeichenfolge wird dann verändert, um eine Anweisung zu bilden, die alle Datensätze im angegebenen Datumsbereich aus der Tabelle tblPayments löscht. Wenn beide SQL-Anweisungen erfolgreich verlaufen, wird die Methode CommitTrans ausgeführt, die beide Transaktionen übernimmt. Im Fehlerfall wird die gesamte Transaktion zurückgesetzt.
Replikation leicht gemacht
Kapitel
Hier lesen Sie:
Datenänderungen weiterreichen Einsatzmöglichkeiten für Replikation Replikation implementieren Die Architektur der Replikation Replikationstopologien Eine Datenbank replikationsfähig machen Zusätzliche Replikate erstellen Replikate synchronisieren Replikationskonflikte lösen Der Replikations-Manager Replikation per Programm
23.1
Datenänderungen weiterreichen
Access 95 war die erste Einzelplatzdatenbank, die integrierte Replikationsfähigkeiten besaß. Die Replikation ist mit der Einführung von Access 2000 ausgereifter geworden. Sie ist eine leistungsfähige Funktion, die in der heutigen Welt der mobilen und verteilten Informationsverarbeitung immer wichtiger wird. Dieses Kapitel stellt Ihnen die Replikation und ihre Implementierung mit Hilfe der Benutzerschnittstelle und mittels Code vor.
832
23.2
Kapitel 23: Replikation leicht gemacht
Einsatzmöglichkeiten der Replikation
Als »Datenreplikation« wird die Fähigkeit eines Systems bezeichnet, automatisch Kopien seiner Daten und Anwendungsobjekte an entfernten Standorten anzulegen. Alle Änderungen am Original oder Datenänderungen an den Kopien werden an alle anderen Kopien weitergegeben. Datenreplikation ermöglicht die Offline-Veränderung von Daten an entfernten Standorten. Änderungen am Original oder an den entfernten Daten werden mit anderen Instanzen der Datenbank synchronisiert. Die Ausgangsdatenbank wird als »Hauptentwurf (Designmaster)« bezeichnet. Änderungen an Definitionen von Tabellen oder anderen Datenbankobjekten können nur im Designmaster vorgenommen werden. Dieser wird zur Anfertigung spezieller Kopien mit der Bezeichnung »Replikate« verwendet. Es gibt zwar nur einen Designmaster, aber Replikate können auch von anderen Replikaten angelegt werden. Der Vorgang der Weitergabe von Änderungen vom Designmaster an die Replikate wird als »Synchronisierung« bezeichnet. Der Designmaster und die Replikate, die am Synchronisierungsvorgang beteiligt sind, werden als »Replikatgruppe« zusammengefasst. Stellen Sie sich, um ein Beispiel für Datenreplikation in Funktion zu sehen, ein Verkaufsteam vor, das den ganzen Tag unterwegs ist. Am Ende des Arbeitstages meldet sich jeder Verkäufer über DUN (Dial-Up Networking) oder RAS (Remote Access Services) bei einem der Windows NT-Server der Firma an. Die Transaktionen aller Verkäufer werden an den Server gesendet. Falls nötig, werden Änderungen an den Server-Daten zum Verkäufer gesendet. Wenn sich die Benutzer beim System anmelden, werden außer den zu replizierenden Daten auch die Änderungen an den Komponenten der Anwendung aktualisiert, wenn die Entwickler der Organisation fleißig Formulare, Berichte und Module in das Master-Exemplar der Datenbank einfügen. Dieses Beispiel veranschaulicht nur eine der vielen sinnvollen Einsatzmöglichkeiten der Replikation. Kurz gesagt: Datenreplikation dient zur Verbesserung der Verfügbarkeit und Integrität der Daten innerhalb einer Organisation oder eines Unternehmens. Die praktischen Einsatzmöglichkeiten der Datenreplikation sind zahlreich. Sie lassen sich in fünf allgemeine Bereiche gliedern, die in den folgenden Abschnitten erläutert werden.
23.2.1
Gemeinsame Nutzung von Daten in mehreren Büros
In der globalen Wirtschaft von heute ist es für Firmen normal, mehrere überall im Land oder sogar weltweit verteilte Büros zu besitzen. Vor Access 95 war es schwierig, eine Access-Anwendung zu implementieren, welche die gemeinsame Nutzung von Daten in mehreren Büros unterstützte. Mit Replikation kann jedoch jedes Büro über ein Replikat der Datenbank verfügen. Im Lauf des Tages kann jedes Büro seine Änderungen in gewissen Abständen mit dem Hauptsitz der Firma synchronisieren. Wie oft synchronisiert wird, hängt davon ab, wie häufig die Daten an den einzelnen Standorten aktualisiert werden müssen, um sie aktuell zu halten.
Einsatzmöglichkeiten der Replikation
23.2.2
833
Gemeinsame Nutzung von Daten durch Einzelpersonen an unterschiedlichen Standorten
Die gemeinsame Nutzung von Daten durch Einzelpersonen an unterschiedlichen Standorten wird durch das bereits genannte Beispiel des Verkaufsteams veranschaulicht. Diese Implementierung von Replikation betrifft meistens mobile Benutzer, die nach der Änderung von Daten unterwegs Verbindung zum Netzwerk aufnehmen. Da nur inkrementelle Änderungen vom Designmaster (dem Original) zu den Replikaten (den Kopien) und von den Replikaten zum Designmaster übertragen werden, ist diese Form der Replikation ökonomisch praktikabel.
23.2.3
Die Netzwerkbelastung reduzieren
Replikation kann bei der Reduzierung der Netzwerkbelastung sehr effizient sein. Der Designmaster kann auf einen oder mehrere zusätzliche Server repliziert werden. Dann können verteilte Benutzer Änderungen auf einem der zusätzlichen Server vornehmen und die Leistung im Netzwerk wird durch die Verteilung der Arbeitslast deutlich gesteigert. Datenänderungen auf den zusätzlichen Servern lassen sich in gewissen Abständen während des Tages mit dem Haupt-Server synchronisieren. Wie häufig synchronisiert wird, hängt davon ab, wie wichtig die ständige Aktualität der Daten ist.
23.2.4
Anwendungsaktualisierungen verteilen
Replikation stellt ein hervorragendes Transportmittel für die Verteilung von Aktualisierungen der Anwendung dar. Entwurfsänderungen können nur am Designmaster vorgenommen werden. Deshalb werden alle strukturellen Änderungen an der Anwendung zu den Benutzer gesendet, wenn sie sich organisationsweit zur Synchronisierung mit dem Designmaster anmelden. Dies ist wesentlich effizienter und wirkungsvoller, als jedem Benutzer ein völlig neues Exemplar der Anwendungsdatenbank zu übermitteln, sobald eine kleine Änderung am Schema vorgenommen wird.
23.2.5
Die Daten in der Anwendung durch Kopien sichern
Viele Leute halten Replikation nicht für ein Mittel zur Sicherung von Anwendungsdaten, aber sie eignet sich für diese Aufgabe hervorragend. Normalerweise müssen sich alle Benutzer beim System abmelden, damit eine Sicherungskopie einer AccessDatenbank erstellt werden kann, aber mit Replikation ist das nicht nötig. Der Synchronisierungsprozess kann in gewissen Abständen während des Tages stattfinden, obwohl die Benutzer beim System angemeldet sind, und alle Änderungen werden repliziert. Das ist nicht nur effizienter, als die gesamte Datenbank zu sichern, sondern gewährleistet auch, dass der Betrieb auf einem Sicherungs-Server reibungslos weitergeführt werden kann, wenn auf einem Server Probleme auftreten.
834
23.3
Kapitel 23: Replikation leicht gemacht
Wann ist Replikation nicht geeignet?
Trotz der vielen positiven Aspekte der Replikation ist sie in einigen Situationen ungeeignet, wie z.B. wenn die Datenkonsistenz von wesentlicher Bedeutung ist. Wenn eine Anwendung verlangt, dass die Daten jederzeit aktuell sind, ist sie kein guter Kandidat für Replikation. Replikation ist auch nicht wirkungsvoll, wenn bestehende Datensätze in großer Menge im Lauf des Tages von vielen verschiedenen Benutzern geändert werden. In einer solchen Situation wäre die Lösung von Konflikten, die auftreten, wenn mehrere Benutzer denselben Datensatz modifizieren, nicht praktikabel. Außerdem können Sie Replikation nicht nutzen, wenn Sie den Entwicklungsprozess mit Visual SourceSafe verwalten. Schließlich lassen sich Designmaster weder umbenennen noch verschieben und ein beschädigter Designmaster ist schwierig wiederherzustellen.
23.4
Replikation implementieren
Der Replikationsprozess setzt sich aus folgenden Schritten zusammen: 1. Replizierbarkeit der Datenbank herstellen 2. Replikate anlegen und verteilen 3. Replikate mit dem Designmaster synchronisieren 4. Konflikte lösen Diese Schritte lassen sich folgendermaßen erledigen:
mit Hilfe der Access-Benutzerschnittstelle, mit Hilfe des Windows-Aktenkoffers, mit Hilfe des Replikations-Managers, mittels ADO-Code. Die für den Replikationsprozess erforderlichen Schritte und die Alternativen für deren Ausführung werden in diesem Kapitel behandelt. Einen Überblick über die Alternativen finden Sie in den folgenden Abschnitten.
23.4.1
Die Access-Benutzerschnittstelle
Die Access-Benutzerschnittstelle stellt einige Menüpunkte bereit, mit deren Hilfe Sie die einzelnen Schritte des Replikationsprozesses ausführen können. Das Menü EXTRAS|REPLIKATION umfasst folgende Optionen: JETZT SYNCHRONISIEREN, DATENBANK IN REPLIKAT KONVERTIEREN, TEILREPLIKATIONS-ASSISTENT, DESIGNMASTER WIEDERHERSTELLEN und KONFLIKTE LÖSEN. Diese werden im Verlauf des Kapitels erläutert.
Replikation implementieren
23.4.2
835
Aktenkoffer-Replikation
Der Windows-Aktenkoffer liefert die Grundlage, die Access für den Replikationsprozess benötigt. Die Benutzer können eine Datenbankdatei einfach in den Aktenkoffer ziehen, um sie zu replizieren bzw. um unterwegs Änderungen an der Datei vorzunehmen und um das Replikat mit dem Designmaster zu synchronisieren, wenn sie erneut Verbindung zum Netzwerk aufnehmen. Das funktioniert, weil Access 2000 bei der Installation eine spezielle Klassen-ID beim Windows-Aktenkoffer registrieren lässt. Wenn eine Datenbank in den Aktenkoffer gezogen wird, wird der Synchronisierungs-Code des Aktenkoffers aufgerufen. Sobald der Benutzer im Aktenkoffermenü AUSWAHL AKTUALISIEREN oder ALLES AKTUALISIEREN wählt, wird eine Aktualisierungsroutine aufgerufen. Aktenkoffer-Replikation ist als Installationsoption für Windows 95, seine Nachfolger und Windows NT 4.0 verfügbar.
23.4.3
Der Replikations-Manager
Der Replikations-Manager ist ein ausgefeiltes Werkzeug, das zu Microsoft Office 2000 Developer gehört. Im Replikationsprozess ist er ein Pflichtbestandteil, wenn Sie viele Replikate verwalten. Er stellt nicht nur die Grundfunktionalität bereit, sondern mit Hilfe des Replikations-Managers können Sie alle Aspekte des Replikationsprozesses verwalten und feinfühlig steuern. Er wird im Abschnitt »Den ReplikationsManager verwenden« ausführlicher behandelt.
23.4.4
ADO-Code
Die meisten Teile des Replikationsprozesses lassen sich auch mittels ADO-Code erledigen, der eingesetzt werden kann, um eine Datenbank replikationsfähig zu machen, um Replikate zu erstellen und zu synchronisieren und um Eigenschaften einer replizierbaren Datenbank abzufragen und festzulegen. ADO lässt sich mühelos in die übrigen Replikationsmethoden integrieren. ADO-Code verlangt von Ihnen zwar am meisten Zeitaufwand und Anstrengung, aber die Replikation lässt sich auf Ereignisse anstelle von Zeitangaben aufbauen und Sie können den Benutzern eine individuelle Schnittstelle für den Replikationsprozess zur Verfügung stellen.
23.4.5
Programme, die Replikation mittels Datenzugriffsobjekten unterstützen
Visual Basic ab Version 4.0, Excel ab der Version für Windows 95 und Visual C++ unterstützen die Replikation mit Hilfe von Datenzugriffsobjekten (ADO). Mit diesen Produkten können Sie Replikation jedoch nicht mit Hilfe des Aktenkoffers oder von Microsoft Office Developer durchführen und deshalb ist es einfacher, die Replikation auf einem Rechner zu erledigen, auf dem Access installiert ist.
836
23.5
Kapitel 23: Replikation leicht gemacht
Die Architektur der Replikation: Was setzt die Replikation in Bewegung?
Nachdem Sie jetzt wissen, was Replikation ist und welche Alternativen Sie für die Implementierung haben, sind Sie bereit, etwas darüber zu erfahren, was die Replikation in Bewegung setzt. Für den Replikationsprozess sind sechs Komponenten zuständig:
die Verfolgungsschicht der Microsoft Replikations-Manager der Synchronizer der Dateisystemtransport die Aktenkoffer-Synchronisierung Registry-Einträge
23.5.1
Die Verfolgungsschicht
Mit der Verfolgungsschicht ist derjenige Teil der Jet-Engine gemeint, der alle Änderungen am Designmaster und an einzelnen Replikaten verfolgen und aufzeichnen kann. Die Verfolgungsschicht ist dafür zuständig, dass die Änderungen mit Sicherheit für die Übermittlung an andere Replikate verfügbar sind.
23.5.2
Der Microsoft Replikations-Manager
Der Microsoft Replikations-Manager stellt Ihnen die Werkzeuge zur Verfügung, die zur Unterstützung des Replikationsprozesses benötigt werden. Außerdem lässt er sich zum Erstellen von Berichten über Synchronisierungsaktivitäten einsetzen.
23.5.3
Der Synchronizer
Wenn Sie den Aktenkoffer oder die Access-Benutzerschnittstelle zum Verwalten des Replikationsprozesses einsetzen, erledigt Jet den Austausch von Informationen zwischen den Replikaten. Wenn Sie den Replikationsprozess mit Hilfe des ReplikationsManagers durchführen, ist der Synchronizer für die Überwachung der Änderungen und die Erledigung des Datenaustausches zwischen den Replikaten zuständig. Wenn Sie den Replikations-Manager einsetzen, wird jedem Replikat ein Synchronizer zugewiesen, der entweder direkte oder indirekte Synchronisierung zwischen den Mitgliedern einer Replikatgruppe durchführt. Beim Start der Synchronisierung versucht er, eine direkte Verbindung zum Zielmitglied der Replikatgruppe herzustellen. Wenn er beide Mitglieder der Replikatgruppe gleichzeitig öffnen kann, findet direkte
Die Architektur der Replikation: Was setzt die Replikation in Bewegung?
837
Synchronisierung statt, d.h., Änderungen durch ein Mitglied der Replikatgruppe werden direkt an das andere übermittelt. Wenn der Synchronizer feststellt, dass das Zielmitglied der Replikatgruppe nicht verfügbar ist, kommt es zu indirekter Replikation. Es gibt viele Gründe für eine Nichterreichbarkeit. Im Folgenden mögliche Gründe, warum keine direkte Verbindung hergestellt werden kann:
Der Netzwerk-Server, auf dem das Replikat liegt, ist ausgefallen. Der Rechner mit dem anderen Replikat ist nicht beim Netzwerk angemeldet. Das andere Mitglied nimmt gerade an einer anderen Replikation teil. Das andere Mitglied befindet sich nicht in einem gemeinsam genutzten Ordner. Unabhängig vom Grund für eine indirekte Synchronisierung hinterlässt der Synchronizer für das erste Mitglied des Replikats eine Nachricht für den Synchronizer des Mitgliedes der unerreichbaren Replikatgruppe. Diese wird in einem gemeinsam genutzten Ordner in dem Netzwerk abgelegt, der als Ablagestelle für das Zielmitglied dient. Alle während der Unerreichbarkeit eines Mitgliedes einer Replikatgruppe gesendeten Nachrichten werden an dieser Ablagestelle gespeichert. Wenn Sie feststellen müssen, dass eine direkte oder eine indirekte Synchronisierung stattgefunden hat, können Sie die Systemtabelle MSysExchangeLog durchsehen. Diese nur in replizierten Datenbanken vorkommende Tabelle wird im Abschnitt »Zur Datenbank hinzugefügte Systemtabellen« dieses Kapitels behandelt. Der Synchronizer wird über die Benutzerschnittstelle des Replikations-Managers konfiguriert und im Abschnitt »Den Replikations-Manager verwenden« ausführlicher besprochen.
23.5.4
Der Dateisystemtransport
Der Dateisystemtransport ist für die Bereitstellung von Messaging-Diensten für den Synchronizer zuständig.
23.5.5
Die Aktenkoffer-Synchronisierung
Eine weitere wesentliche Komponente der Replikationsarchitektur ist die Aktenkoffer-Synchronisierung. Wie bereits erwähnt, stellt sie sicher, dass eine Datenbank replizierbar ist und verwaltet das Zusammenführen von Änderungen zwischen dem Aktenkoffer- und dem Desktop-Replikat.
838
23.5.6
Kapitel 23: Replikation leicht gemacht
Die Registry-Einträge
Beim Replikationsprozess helfen mehrere Windows-Redistry-Einträge, von denen Sie einige in Abbildung 23.1 sehen. Beachten Sie den Teilschlüssel Transporter unter dem Schlüssel \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Jet\4.0, der wichtige Pfadinformationen enthält, welche der Replikations-Manager und der Synchronizer nutzen. Die Aktenkoffer-Synchronisierung verwendet Einträge unter \HKEY_CLASSES_ROOT\CLSID. Beachten Sie, dass der Registry-Schlüssel weiterhin Transporter heißt, obwohl der Name in Synchronizer geändert wurde.
Abbildung 23.1: Replikation und die WindowsRegistry
23.6
Replikationstopologien
Die Topologie der Datensynchronisierung bestimmt, welche Replikate mit welchen anderen Replikaten synchronisiert werden. Die »Topologie« ist eigentlich ein Plan dafür, wie die Änderungen zwischen den Mitgliedern der Replikatgruppe zusammengeführt werden. Für unterschiedliche Situationen setzt man unterschiedliche Topologien ein und welche Topologie Sie wählen, hängt von den Erfordernissen Ihres Geschäfts und vom Aufbau Ihrer Organisation ab. Es gibt folgende Synchronisierungstopologien: Stern, Ring, Vollverbindung, Linear und Hybrid.
23.6.1
Die Sterntopologie
Bei der Sterntopologie wird ein einziger Verteiler in gewissen Abständen mit den übrigen Replikaten synchronisiert. Der größte Vorteil dieser Topologie ist ihre Ein-
Replikationstopologien
839
fachheit und leichte Programmierbarkeit. Ein weiterer Vorteil liegt in der Kürze der Wege, welche die Daten zurücklegen müssen. Jedes Replikat wird mit nur einer anderen Datenbank, dem Verteiler, synchronisiert. Das ist jedoch nicht besonders zuverlässig. Wenn das steuernde Replikat beschädigt oder unerreichbar ist, kann keine Synchronisierung stattfinden. Ein weiterer Nachteil der Sterntopologie liegt darin, dass das Replikat, welches als erstes mit dem Verteiler synchronisiert wird, keine, das letzte jedoch alle Daten von den anderen Replikaten bekommt. Mit zwei Replikationsrunden lässt sich dieses Problem beseitigen. Schließlich lässt sich die Sterntopologie nicht bei einer großen Anzahl von Replikaten einsetzen, weil die Gesamtbelastung auf dem Verteiler liegt.
Stern
Ring
Linear
Vollständig verbunden
Hybrid
Abbildung 23.2: Beispiele für Replikationstopologien
Der Designmaster darf niemals Verteiler sein. Wenn Sie ihn als Verteiler bestimmen, kann es vorkommen, dass Teiländerungen am Entwurf versehentlich mit den übrigen Replikaten synchronisiert werden. Verlegen Sie den Designmaster lieber auf einen der äußeren Rechner und synchronisieren Sie Entwurfsänderungen mit dem steuernden Replikat, sobald sie abgeschlossen und vollständig getestet sind.
23.6.2
Ringtopologie
Bei einer Ringtopologie wird jeder Rechner mit dem nächsten Rechner in der Replikationskette synchronisiert. Es gibt in diesem Szenario keinen Synchronisierungsmittelpunkt. Der wesentliche Vorteil der Ringtopologie liegt darin, dass die Belastung auf die Umgebungsrechner verteilt wird. Der wichtigste Nachteil besteht darin,
840
Kapitel 23: Replikation leicht gemacht
dass es möglicherweise lange dauert, bis Änderungen an alle Teilnehmer weitergegeben sind, weil es keinen Mittelpunkt gibt. Außerdem wird die Synchronisierung gestoppt, wenn eines der Replikate in der Kette beschädigt oder unerreichbar ist, aber das lässt sich mit Hilfe von Code abfangen, der das Problem bemerkt und den nicht erreichbaren Rechner umgeht.
23.6.3
Die vollständig verbundene Topologie
Wenn die Topologie der Vollverbindung eingesetzt wird, wird jedes Replikat mit jedem anderen Replikat synchronisiert. Dies bietet mehrere Vorteile. Der stärkste Punkt ist die Garantie, dass die Daten in einem gegebenen Augenblick so aktuell wie möglich sind, weil sie von jedem Replikat direkt an alle anderen Replikate der Replikatgruppe gesendet werden. Deshalb ist diese Lösung die beste, wenn größtmögliche Aktualität nötig ist. Ein weiterer Vorteil der vollständig verbundenen Topologie ist der hohe Redundanzgrad, d.h., dass an mehreren Stellen dieselben Daten vorhanden sind. Wegen des niedrigen »Latenz grades« (d.h. der Wahrscheinlichkeit, dass die Daten in einem gegebenen Augenblick nicht aktuell sind) sind außerdem die Folgen bei einem Ausfall eines Replikats minimal. Auch die vollständig verbundene Topologie hat jedoch Nachteile. Sie erfordert von allen Topologien wegen des Netzwerkverkehrs, der erzeugt wird, wenn jedes Replikat mit allen anderen der Gruppe synchronisiert wird, den höchsten Aufwand. Außerdem müssen die Zeitpläne für die Replikation gestaffelt werden, da sonst mit großer Wahrscheinlichkeit Kollisionen auftreten, wenn mehr als ein Replikat versucht, sich mit ein und demselben Replikat zu synchronisieren.
23.6.4
Die lineare Topologie
Die lineare Topologie entspricht bis auf den Umstand, dass die Kette nicht geschlossen wird, der Ringtopologie. Deshalb besitzt sie den höchsten Latenzgrad. Der größte Vorteil der linearen Topologie ist das geringe Maß an Netzwerkverkehr; sie ist jedoch für die meisten Anwendungen nicht einsetzbar, weil es länger dauert, bis Änderungen alle Replikate der Gruppe erreicht haben.
23.6.5
Die Hybridtopologie
Eine Hybridtopologie besteht aus einer beliebigen Kombination der anderen Topologien. In einer komplexen Anwendung ist es normalerweise nicht sinnvoll, nur eine einzige Topologie einzusetzen. Durch Kombination von Topologien können Sie genau die Ergebnisse erzielen, die Sie benötigen. Abbildung 23.2 stellt nur ein Beispiel für eine Hybridtopologie vor – einen Ring, der mit einem Stern verbunden ist. Sie sollten mit verschiedenen Konfigurationen experimentieren, um herauszufinden, welche Topologie Prozessorbelastung, Netzwerkverkehr und Latenz der Daten am besten ausbalanciert.
Änderungen an Ihrer Datenbank durch Replikation
23.7
841
Änderungen an Ihrer Datenbank durch Replikation
Die Replikation führt zu einigen Änderungen an Ihrer Datenbank, aber diese sind notwendig, um die Erfordernisse des Replikationsprozesses zu erfüllen. Es handelt sich um Folgendes:
In jede replizierte Tabelle werden Felder eingefügt. In die Datenbank werden mehrere Systemtabellen eingefügt. In die Datenbankdokumentobjekte werden Eigenschaften eingefügt. Sequentielle Felder des Typs AutoWert werden in zufällige Felder des Typs AutoWert umgewandelt.
Die Datenbankgröße nimmt zu.
23.7.1
Felder, die in jede replizierte Tabelle eingefügt werden
Während der Replikation ermittelt die Jet-Engine, ob jede Tabelle ein Feld des Typs AutoWert und der Feldgröße ReplicationID besitzt. Wenn sie kein Feld findet, das diese Kriterien erfüllt, fügt sie ein Feld mit dem Namen s_Guid in die Tabelle ein, welches jeden Datensatz eindeutig kennzeichnet. Dieses ist für alle Replikate identisch. Außerdem fügt die Jet-Engine drei weitere Felder in jede Tabelle der Datenbank ein: s_Lineage, s_ColLineage und s_Generation. Im Feld s_Lineage werden die IDs von
Replikaten, die einen Datensatz aktualisiert haben, und die letzte von diesen Replikaten angelegte Version gespeichert, im Feld s_Generation Informationen über mehrere Änderungen. Diese Felder sind nur sichtbar, wenn Sie die Anzeige von Systemobjekten aktiviert haben (mit EXTRAS|OPTIONEN).
23.7.2
Systemtabellen, die in die Datenbank eingefügt werden
Außerdem fügt die Jet-Engine einige Systemtabellen in Ihre Datenbank ein, die Konflikte, Fehler und Austauschaktionen zwischen den Replikatdatenbanken aufzeichnen. MSysSideTables und MSysExchangeLog sind die wichtigsten; Sie können sie ansehen, wenn Sie die Anzeige von Systemobjekten aktiviert haben (mit EXTRAS|OPTIONEN). Die Tabelle MSysSideTables verfolgt Tabellen, bei denen während der Synchronisierung ein Konflikt aufgetreten ist. Sie hält den Namen der Nebentabelle fest, in der die konfliktverursachenden Datensätze stehen. Die Tabelle MSysErrors verfolgt alle nicht behobenen Synchronisierungsfehler. Sie ist leer, wenn alle Fehler abgearbeitet sind. Sie finden diese Tabelle in allen Replikaten.
842
Kapitel 23: Replikation leicht gemacht
Die Tabelle MSysSchemaProb stellt Fehler fest, die beim Synchronisieren des Entwurfs eines Replikats aufgetreten sind. Sie ist nur sichtbar, wenn zwischen dem Replikat des Benutzers und einem anderen Replikat in der Gruppe ein Entwurfskonflikt aufgetreten ist. Die Tabelle MSysExchangeLog ist eine lokale Tabelle, die Informationen über Synchronisierungen aufnimmt, welche zwischen dem lokalen Replikat und anderen Mitgliedern der Replikatgruppe ausgeführt wurden.
23.7.3
Eigenschaften, die den Datenbankobjekten hinzugefügt werden
Einer replikationsfähigen Datenbank werden mehrere Eigenschaften hinzugefügt, von denen einige nur im VBA-Code zur Verfügung stehen. Die Eigenschaft Replicable der Datenbank wird auf True gesetzt und kann danach nicht mehr verändert werden. Die Eigenschaft ReplicaID ist eine eindeutige ID, welche jedem Replikat zugewiesen wird. Die Eigenschaft DesignMaster kann den Status Designmaster an eine andere Datenbank übertragen. Das geschieht im Allgemeinen, wenn der ursprüngliche Designmaster irreparabel beschädigt ist. Außer den Eigenschaften, die für die Datenbank gelten, können noch zwei Eigenschaften auf die Tabellen, Abfragen, Formulare, Berichte, Makros und Module in der Datenbank angewandt werden: KeepLocal und Replicable. Die Eigenschaft KeepLocal, die einem Objekt vor dem Replizieren der Datenbank zugewiesen wird, verhindert das Kopieren des Objekts in die übrigen Replikate der Gruppe. Die Eigenschaft Replicable, die nach dem Replizieren einer Datenbank angewandt wird, besagt, dass das Objekt repliziert werden soll.
23.7.4
Änderungen an sequentiellen Feldern des Typs AutoWert
Eine weitere wichtige Änderung an Ihren Tabellen beim Replizieren der Datenbank ist die Umwandlung aller Felder des Typs AutoWert von sequentieller in zufällige Nummerierung. Bestehende Datensätze sind davon nicht betroffen, aber neue Schlüssel werden nach dem Zufallsprinzip erzeugt, weil dadurch Konflikte beim Synchronisieren der Datenbank verringert werden. Wenn alle Kopien sequentielle Schlüssel erzeugen, können Sie vorhersehen, dass es zu Konflikten kommen wird, wenn Sie versuchen, die Änderungen zusammenzuführen. Durch die Erzeugung zufälliger Primärschlüssel sinkt die Wahrscheinlichkeit solcher Konflikte.
23.7.5
Änderung der Datenbankgröße
Wenn eine Datenbank repliziert wird, wird sie wegen der hinzugefügten Felder und Tabellen größer. Dies stellt im Allgemeinen kein Problem dar. Wenn Platz auf der Festplatte sehr gefragt ist, sollten Sie diesen Aspekt der Replikation jedoch bedenken, bevor Sie Replikation in Ihre Anwendungen integrieren.
843
Eine Datenbank replikationsfähig machen
23.8
Eine Datenbank replikationsfähig machen
Eine replikationsfähige Datenbank ist nichts weiter als eine Datenbank, deren Eigenschaft Replicable auf True gesetzt wurde. Wenn eine Datenbank nicht als replizierbar markiert ist, kann sie nicht repliziert werden. Wenn eine Datenbank jedoch als replizierbar gekennzeichnet wird, nimmt die Jet-Engine einige Veränderungen an ihr vor, um sie replizierbar zu machen. Bevor diese vollzogen sind, wird die Datenbank nicht als Teil einer Replikationsgruppe erkannt und lässt sich nicht mit anderen Datenbanken synchronisieren. Wenn Sie eine Datenbank replizieren wollen, sollten Sie Folgendes unternehmen: 1. Kennzeichnen Sie alle Objekte in der Datenbank, die nicht repliziert werden sollen, als lokal, indem Sie die Eigenschaft KeepLocal der Objekte auf True setzen. 2. Legen Sie einen Designmaster für die Replikation an, indem Sie die Eigenschaft Replicable der Datenbank auf True setzen. 3. Legen Sie Kopien (Replikate) des Designmasters an. Sie können eine Datenbank mit Hilfe der Access-Benutzerschnittstelle, des Windows-Aktenkoffers, des Replikations-Managers oder mittels Code replizierbar machen. Die beiden folgenden Abschnitte behandeln die Access-Benutzerschnittstelle und den Windows-Aktenkoffer. Die Verwendung des Replikations-Managers wird im Abschnitt »Den Replikations-Manager verwenden«, die Verwendung von Code im Abschnitt »Replikation mittels Code implementieren« besprochen.
23.8.1
Eine Datenbank mit Hilfe der Access-Benutzerschnittstelle replizierbar machen
Wählen Sie EXTRAS|REPLIKATION|DATENBANK IN REPLIKAT KONVERTIEREN. Microsoft Access übermittelt Ihnen eine Warnmeldung, dass die Datenbank vor der Verarbeitung geschlossen wird (siehe Abbildung 23.3). Abbildung 23.3: Dieses Dialogfeld warnt Sie davor, dass Access die Datenbank schließen muss, bevor sie zum Designmaster erklärt werden kann
844
Kapitel 23: Replikation leicht gemacht
Nachdem Sie JA gewählt haben, sehen Sie ein weiteres Dialogfeld, in dem Sie gefragt werden, ob Access eine Sicherungskopie der Datenbank anlegen soll, bevor es fortfährt (siehe Abbildung 23.4). Vor der Replikation eine Sicherungskopie anzulegen, ist immer günstig, weil sich eine Datenbank nach der Markierung als replizierbar nicht in den nicht replizierbaren Zustand zurückversetzen lässt.
Abbildung 23.4: Dieses Dialogfeld fordert Sie auf, Access vor der Replikation der Datenbank eine Sicherungskopie anlegen zu lassen
Als nächstes werden Sie im Dialogfeld SPEICHERORT DES NEUEN REPLIKATS nach Namen und Speicherort des neuen Replikats gefragt (siehe Abbildung 23.5). Nachdem Sie auf OK geklickt haben, wird das neue Replikat angelegt und der Vorgang ist abgeschlossen. Ihre Ursprungsdatenbank wird in einen Designmaster umgewandelt; das Replikat bekommt den im Dialogfeld SPEICHERORT DES NEUEN REPLIKATS angegebenen Namen und Speicherort. Wenn der Replikationsvorgang erfolgreich beendet wurde, erscheint das in Abbildung 23.6 gezeigte Dialogfeld. Beachten Sie, dass nur der Designmaster Änderungen an der Datenbankstruktur (dem Schema) entgegennehmen kann.
Abbildung 23.5: Im Dialogfeld Speicherort des neuen Replikats können Sie Speicherort und Namen für das Replikat angeben
845
Verhindern, dass Objekte repliziert werden
Abbildung 23.6: Dieses Dialogfeld erscheint nach der erfolgreichen Replikation einer Datenbank
23.8.2
Eine Datenbank mit Hilfe des Windows-Aktenkoffers replizierbar machen
Anstelle der Access-Benutzerschnittstelle können Sie zur Replikation einer Datenbank auch den Windows-Aktenkoffer verwenden. Sie brauchen die Datenbankdatei lediglich vom Windows-Explorer auf das Aktenkoffersymbol in Ihrem Arbeitsplatz zu ziehen, um in das in Abbildung 23.7 gezeigte Dialogfeld zu gelangen.
Abbildung 23.7: Dieses Dialogfeld erscheint, nachdem Sie eine Datenbank zum Zweck der Replikation in den Aktenkoffer gezogen haben
Bis auf die letzte Meldung sehen Sie dieselbe Folge von Meldungen, die sie erhalten, wenn Sie im Menü EXTRAS in der Access-Benutzerschnittstelle REPLIKATION wählen. Nur eine Datenbank kann für Änderungen am Entwurf, z.B. für die Modifikation von Tabellenstrukturen, verwendet werden. Das in Abbildung 23.8 gezeigte Aktenkoffer-Dialogfeld fragt, welche Datenbank Sie gern als Designmaster hätten. Im Allgemeinen wählen Sie das Original, nicht die Aktenkofferkopie, weil letztere normalerweise nur unterwegs als Mittel zum Hinzufügen, Bearbeiten und Löschen von Daten verwendet wird.
23.9
Verhindern, dass Objekte repliziert werden
Möglicherweise möchten Sie verhindern, dass bestimmte Objekte einer replikationsfähigen Datenbank repliziert werden, falls beispielsweise bestimmte Daten vertraulich sind oder die meisten Benutzer bestimmte Daten nicht zu sehen brauchen. Möglicherweise wird im Designmaster zum Beispiel eine Gehaltstabelle der Mitarbeiter unterhalten und verwendet, die aber für keines der Replikate erforderlich ist. Je weniger Objekte repliziert werden, desto wirkungsvoller ist der Replikationsvorgang.
846
Kapitel 23: Replikation leicht gemacht
Abbildung 23.8: Die letzte Dialogfeld, das Sie bei der Aktenkoffer-Replikation sehen, lässt Ihnen die Wahl, welches Exemplar als Designmaster verwendet werden soll
In der Access-Benutzerschnittstelle können Sie beim Erstellen eines neuen Objekts das Kontrollkästchen DIESES OBJEKT REPLIZIEREN aktivieren, wie in Abbildung 23.9 gezeigt (ohne Aktivierung bleibt das neue Objekt lokal), oder die Eigenschaft Replizierbar eines vorhandenen Objekts auf dessen Eigenschaftenseite ändern (siehe Abbildung 23.10). Replizierte Objekte sind in der Objektliste des Access-Datenbankfensters durch ein Globussymbol mit rotierenden Pfeilen gekennzeichnet.
Abbildung 23.9: Ein neues Objekt im Dialogfeld Speichern unter replizierbar machen
Abbildung 23.10: Die Eigenschaft Replizierbar eines Objekts auf dessen Eigenschaftenseite ändern
Zusätzliche Replikate erstellen
847
Außerdem können Sie die Eigenschaft Replizierbar mittels VBA-Code oder mit Hilfe des Replikations-Managers ändern. Dazu setzen Sie die Eigenschaft KeepLocal des Objekts auf True. Wenn Sie versuchen, dies mittels VBA-Code zu erreichen, bekommen Sie eine Fehlermeldung, falls Sie die Eigenschaft noch nicht an das Objekt angefügt haben. Deshalb müssen Sie in Ihren Code eine entsprechende Fehlerbehandlung einbauen. Die Verwendung des Replikations-Managers, um ein Objekt nicht replizierbar zu machen, wird im Abschnitt »Eine Datenbank mit Hilfe des Replikations-Managers replizieren« behandelt. Den erforderlichen Code, um ein Objekt mit der Eigenschaft KeepLocal zu versehen und den Wert der Eigenschaft auf True zu setzen, finden Sie in Abschnitt »Replikation mittels Code implementieren«.
23.10 Zusätzliche Replikate erstellen Nachdem Sie ein Replikat angelegt haben, wollen Sie vermutlich noch weitere erstellen. Diese zusätzlichen Replikate sind Kopien, welche in der gesamten Organisation verteilt werden können. Sie lassen sich mit Hilfe der Access-Benutzerschnittstelle, des Windows-Aktenkoffers, des Replikations-Managers oder mittels VBA-Code erstellen. Eine Verkaufsorganisation zum Beispiel braucht vielleicht mehrere Replikate für Verkaufsmitarbeiter, die Kopien der Datenbank auf ihren Notebooks mitnehmen. Jede davon muss ein durch Replikation erzeugtes Replikat sein, keine vom Betriebssystem angelegte Kopie, sonst lässt sich die Arbeit der Verkaufsmitarbeiter nicht mit der der anderen Mitarbeiter synchronisieren. Replikate lassen sich mit allen vier genannten Methoden anlegen, aber zusätzliche Replikate können auch von jedem Mitglied der Replikatgruppe angefertigt werden. Jede Replikatgruppe ist von den anderen Replikatgruppen unabhängig. Replikate aus unterschiedlichen Replikatgruppen lassen sich nicht miteinander synchronisieren.
23.10.1 Zusätzliche Replikate mit Hilfe der Benutzerschnittstelle anlegen Um mit Hilfe der Benutzerschnittstelle zusätzliche Replikate anzulegen, unternehmen Sie Folgendes: 1. Öffnen Sie die Datenbank, die Sie replizieren wollen. 2. Wählen Sie EXTRAS|REPLIKATION|DATENBANK IN REPLIKAT KONVERTIEREN. 3. Geben Sie, wenn Sie dazu aufgefordert werden, einen Namen für das neue Replikat ein.
848
Kapitel 23: Replikation leicht gemacht
23.10.2 Zusätzliche Replikate mit Hilfe des Windows-Aktenkoffers anlegen Außerdem können Sie weitere Replikate anlegen, indem Sie den Designmaster – oder eines der Replikate – in den Aktenkoffer ziehen und dort ablegen. Wenn Sie den Designmaster wählen, werden Sie von einem Dialogfeld gefragt, ob der Designmaster oder das Replikat im Aktenkoffer abgelegt werden soll.
23.11
Replikate synchronisieren
Replikate zu »synchronisieren« bedeutet, alle Änderungen miteinander in Einklang zu bringen. Modifizierte Datensätze werden in allen Kopien geändert, gelöschte Datensätze werden aus allen Replikaten entfernt und hinzugefügte Datensätze werden an alle Replikate angehängt. Die Synchronisationsfähigkeit ist das, was die Replikation von Daten nützlich macht. Ergänzungen, Modifikationen und Löschungen werden an alle Replikate einer Gruppe weitergegeben und die Benutzer bekommen zu sehen, was andere Benutzer geändert haben. Wie beim Erstellen eines Replikats stellt Access Ihnen zum Synchronisieren der Replikate vier Methoden zur Verfügung: die Access-Benutzerschnittstelle, den Windows-Aktenkoffer, den Replikations-Manager und VBA-Code.
23.11.1 Datenbanken mit Hilfe der Access-Benutzerschnittstelle synchronisieren Um die Synchronisierung mit Hilfe der Access-Benutzerschnittstelle durchzuführen, unternehmen Sie Folgendes: 1. Wählen Sie EXTRAS|REPLIKATION|JETZT SYNCHRONISIEREN. 2. Das Dialogfeld DATENBANK SYNCHRONISIEREN wird eingeblendet (siehe Abbildung 23.11). Markieren Sie die zu synchronisierende Datenbank und klicken Sie auf OK. 3. Sie werden aufgefordert, Access die Datenbank vor der Synchronisierung schließen zu lassen (siehe Abbildung 23.12). Wenn Sie JA wählen, schließt Access die Datenbank und öffnet sie dann erneut.
23.11.2 Datenbanken mit Hilfe des Windows-Aktenkoffers synchronisieren Die zweite Möglichkeit, Replikate zu synchronisieren, bietet der Windows-Aktenkoffer. Öffnen Sie einfach das Aktenkofferfenster und wählen Sie die Datenbankdatei aus. Klicken Sie im Aktenkoffermenü auf AUSWAHL AKTUALISIEREN. Wenn Sie alle
Replikate synchronisieren
849
Abbildung 23.11: Im Dialogfeld Datenbank synchronisieren können Sie die zu synchronisierende Datenbank auswählen Abbildung 23.12: Dieses Dialogfeld bestätigt, dass Sie Access erlauben, die Datenbank vor der Synchronisierung zu schließen
im Aktenkoffer befindlichen Replikate synchronisieren wollen, klicken Sie auf ALLES AKTUALISIEREN, um das Dialogfeld AKTENKOFFER AKTUALISIEREN zu öffnen (siehe Abbildung 23.13). Klicken Sie auf AKTUALISIEREN und die Synchronisierung wird abgeschlossen.
Abbildung 23.13: Das Dialogfeld Aktenkoffer aktualisieren erscheint, wenn Sie die Synchronisierung vom Aktenkoffer aus vornehmen
850
23.12
Kapitel 23: Replikation leicht gemacht
Replikationskonflikte beheben
Wenn die Jet-Engine versucht, zwei Datenbanken zu synchronisieren, stellt sie möglicherweise fest, dass dieselbe Zeile in beiden Datenbanken geändert wurde, so dass sich ein Konflikt ergibt, der bearbeitet werden muss. In der Regel gewinnt meistens die Datenbank, in der die Zeile am häufigsten geändert wurde. Wenn sich beide Zeilen genauso oft geändert haben, entscheidet der Zufall. Das klingt möglicherweise erschreckend, ist aber nicht so schlimm, wie es scheint, weil Sie dem Benutzer mitteilen können, welche Änderungen nicht berücksichtigt wurden. Sie müssen erfahren, ob zwei Mitglieder der Replikatgruppe widersprüchliche Informationen enthalten. Möglicherweise haben zwei Benutzer im Außendienst unterschiedliche Informationen über einen Verkauf oder einen Kunden eingegeben. Deshalb ist es wichtig, dass das Programm diese Inkonsistenzen erkennt und eine Methode für die Behandlung solcher Fälle besitzt. Wenn es Konflikte gibt, werden Sie darüber informiert, wenn Sie versuchen, die Datenbank, welche die Konflikte enthält, zu öffnen (siehe Abbildung 23.14). Sie haben dann die Möglichkeit, die Konflikte zu lösen (oder auch nicht). Abbildung 23.14: Dieses Dialogfeld warnt vor Synchronisierungskonflikten
Wenn der Benutzer JA wählt, versucht die Jet-Engine, die Konflikte zu identifizieren. Danach wird das Dialogfeld MICROSOFT-REPLIKATIONSKONFLIKT-VIEWER eingeblendet (siehe Abbildung 23.15). Beachten Sie, dass die Jet-Engine in diesem Fall einen Konflikt in der Tabelle tblClients festgestellt hat. Der Benutzer kann diesen entweder beheben oder die Konfliktlösung aufschieben. Wenn der Benutzer auf ANZEIGEN klickt, erscheint ein weiteres Dialogfeld MICRO(siehe Abbildung 23.16), welches jeden Datensatz mit einem Konflikt anzeigt und die Möglichkeit bietet, vorhandene oder korrigierte Daten beizubehalten bzw. mit Konfliktdaten oder mit korrigierten Daten zu überschreiben.
SOFT-REPLIKATIONSKONFLIKT-VIEWER
Der Benutzer kann die Details des Konflikts zum späteren Nachlesen aufzeichnen und die Lösung der einzelnen Konflikte sofort vornehmen oder aufschieben. Nachdem alle Konflikte abgearbeitet sind, kehrt er zum Dialogfeld MICROSOFT-REPLIKATIONSKONFLIKT-VIEWER zurück.
Replikationskonflikte beheben
851
Abbildung 23.15: Verwenden Sie das Dialogfeld MicrosoftReplikationskonflikt-Viewer zur Lösung von Konflikten zwischen Tabellen
Abbildung 23.16: In diesem Dialogfeld Microsoft-ReplikationskonfliktViewer sehen Sie sich bestimmte Konflikte an und beheben sie
852
Kapitel 23: Replikation leicht gemacht
Wenn Ihre Benutzer kein so hohes Maß an Kontrolle über die Lösung von Konflikten bekommen sollen, können Sie Code schreiben, der Konflikte auf jede von Ihnen gewünschte Weise behebt. Dies wird im Abschnitt »Eine Datenbank mit Hilfe von Code synchronisieren« behandelt.
23.13
Den Replikations-Manager verwenden
Der Replikations-Manager ist ein leistungsfähiges Werkzeug, mit dessen Hilfe Sie die Vorteile der Replikation in Access 2000 vollständig ausnutzen können. Er wird nur zusammen mit Microsoft Office 2000 Developer als Entwicklungswerkzeug geliefert und bietet im Wesentlichen folgende Vorteile:
Datenbanken lassen sich mühelos replizieren. Zusätzliche Replikate sind einfach zu erstellen. Er gibt Ihnen die Möglichkeit, alle Replikate der Gruppe zu synchronisieren. Er ermöglicht automatisches Synchronisieren nach Zeitplan. Der Replikationsverlauf eines Objekts kann eingesehen werden. Replikationseigenschaften sind einfach zu verwalten. Er ermöglicht das Synchronisieren mit Replikaten an entfernten Standorten. Er erlaubt das Synchronisieren über ein lokales Netzwerk, ein Intranet oder das Internet.
23.13.1 Den Replikations-Manager zum ersten Mal ausführen Der Replikations-Manager lässt sich über eine Desktop-Verknüpfung oder über das Windows-Startmenü (Programmgruppe MICROSOFT OFFICE 2000 DEVELOPER) öffnen. Wenn Sie den Replikations-Manager zum ersten Mal ausführen, erscheint der Configure Replication Manager Wizard. (siehe Abbildung 23.17). 1. Klicken Sie auf NEXT, um den Konfigurationsprozess und den Configure Replication Manager Wizard zu starten. 2. Dieser Schritt des Configure Replication Manager Wizard fragt, ob Sie indirekte Synchronisierung unterstützen wollen (siehe Abbildung 23.18). Dabei öffnet jeweils ein Synchronizer für jedes der beiden Replikate sein Replikat lokal. Ein stationärer Rechner hinterlässt Änderungen in einem Ablagefeld im Netzwerk. Wenn das Notebook Verbindung zum Netzwerk aufnimmt, findet sein Synchronizer die Änderungen in seinem Ablageordner vor und wendet sie auf das Replikat an. Es hinterlässt seine Änderungen seinerseits in einem Ablageordner des Synchronizers für den stationären Rechner, welcher die Änderungen vorfindet
Den Replikations-Manager verwenden
853
Abbildung 23.17: Der Configure Replication Manager Wizard
und anwendet. Dies ist die bevorzugte Synchronisierungsmethode für entfernte Benutzer, die nicht ständig beim Netzwerk angemeldet sind. Treffen Sie Ihre Wahl und klicken Sie auf NEXT.
Abbildung 23.18: Auswahl einer Synchronisierungsmethode
3. Wenn Sie sich für indirekte Synchronisierung entscheiden, informiert Sie der nächste Schritt des Assistenten über Synchronisierungsarten. Klicken Sie nach dem Lesen auf NEXT. Dann fragt der Assistent nach einem Speicherort für den Ablageordner (siehe Abbildung 23.19). Wählen Sie einen Ordner aus und klicken Sie auf NEXT.
854
Kapitel 23: Replikation leicht gemacht
Abbildung 23.19: Auswahl eines Speicherortes, an dem der Synchronizer Änderungen ablegen kann
4. Dann werden Sie gefragt, ob der Rechner, auf dem der Assistent läuft, ein Internetserver ist. Treffen Sie Ihre Wahl und klicken Sie auf NEXT. 5. Wenn Sie diese Frage bejahen, werden Sie gefragt, ob Sie ihn zur Synchronisierung replizierter Datenbanken einsetzen wollen. Wenn Sie mit YES antworten und auf NEXT klicken, werden Sie nach seinem Namen gefragt. Geben Sie den Namen ein und klicken Sie auf NEXT (siehe Abbildung 23.20). Im nächsten Schritt sollen Sie einen gemeinsam genutzten Ordner und einen Freigabenamen angeben, der bei der Synchronisierung über das Internet verwendet wird. Klicken Sie auf NEXT. Sie werden nach einem FTP-Aliasnamen gefragt. Wählen Sie einen und klicken Sie auf NEXT.
Abbildung 23.20: Wenn Ihr Rechner ein Internetserver ist, können Sie dem Assistenten hier seinen TeilURL nennen
Den Replikations-Manager verwenden
855
6. Der nächste Schritt des Assistenten für die Konfiguration des ReplikationsManagers fordert Sie auf, den Ordner zu nennen, in dem die Synchronisierungsversuche stattfinden sollen. Das Beispiel in Abbildung 23.21 zeigt, dass indirekte Synchronisierung versucht werden soll. Wenn dies nicht gelingt, wird direkte Synchronisierung versucht und dann als letzte Möglichkeit Synchronisierung über das Internet. 7. Wählen Sie einen Speicherort für die Protokolldatei, die zum Aufzeichnen wichtiger Vorkommnisse während der Synchronisierung dient (siehe Abbildung 23.22) und klicken Sie auf NEXT.
Abbildung 23.21: Wählen Sie die Reihenfolge, in der die Synchronisierungsmethoden versucht werden sollen
8. Im nächsten Schritt fragt der Assistent nach einem Namen für den Synchronizer, der für ein Symbol und als aussagekräftige Bezeichnung für diesen verwendet werden soll. Außerdem wird gefragt, ob der Synchronizer automatisch beim Start von Windows gestartet werden soll (siehe Abbildung 23.23). Der Synchronizer muss in Betrieb sein, damit Synchronisierung nach Zeitplan stattfinden kann; möglicherweise wollen Sie also diese Option aktivieren. Geben Sie einen Namen für den Synchronizer und Ihre Wahl in bezug auf den automatischen Start ein und klicken Sie auf NEXT. 9. Klicken Sie auf FINISH, um den Vorgang abzuschließen. Nachdem Sie mit dem Assistenten für die Konfiguration des Replikations-Managers fertig sind, können Sie entweder eine Datenbank in einen Designmaster umwandeln oder ein neues Replikat anlegen (siehe Abbildung 23.24). Diese Aufgaben können Sie jederzeit durchführen. Deshalb sollten Sie auf CLOSE klicken.
856
Kapitel 23: Replikation leicht gemacht
Abbildung 23.22: Auswahl eines Namens und eines Speicherortes für die Protokolldatei
Abbildung 23.23: Auswahl eines Namens für den Synchronizer
Wenn Sie sich dafür entschieden haben, den Synchronizer bei jedem WindowsStart zu laden, jedoch ohne ihn automatisch auszuführen, müssen Sie das Synchronizer-Symbol aus dem Windows-Startordner entfernen.
23.13.2 Eine Datenbank mit Hilfe des Replikations-Managers replizieren Außer mit Hilfe der Access-Benutzerschnittstelle oder des Windows-Aktenkoffers können Sie eine Datenbank auch mit Hilfe des Replikations-Managers replizierbar
Den Replikations-Manager verwenden
857
Abbildung 23.24: Der Microsoft ReplikationsManager wird zum ersten Mal gestartet.
machen. Dieser bietet zusätzliche Optionen wie z.B. die Kennzeichnung eines Objekts als lokal. Folgende Schritte sind erforderlich: 1. Klicken Sie im Replikations-Manager auf die Schaltfläche CONVERT DATABASE TO THE DESIGN MASTER in der Symbolleiste oder wählen Sie DATEI|CONVERT DATABASE TO DESIGN MASTER. Das Dialogfeld DATABASE TO CONVERT TO THE DESIGN MASTER wird eingeblendet (siehe Abbildung 23.25).
Abbildung 23.25: Wählen Sie die Datenbank aus, die Designmaster werden soll
2. Wählen Sie eine zu konvertierende Datei und klicken Sie auf OK. 3. Sie gelangen in den Convert Database to Design Master Wizard. Klicken Sie auf NEXT, nachdem Sie die einführenden Informationen gelesen haben. 4. Geben Sie an, ob Sie eine Sicherungskopie der Datenbank anlegen wollen, bevor Sie sie zum Designmaster konvertieren. Klicken Sie auf NEXT. Es ist immer günstig, eine Kopie der noch nicht replizierten Datenbank aufzubewahren.
858
Kapitel 23: Replikation leicht gemacht
5. Geben Sie eine Beschreibung der neuen Replikatgruppe ein und klicken Sie auf NEXT. Alle von diesem Designmaster angefertigten Replikate sind Mitglieder der Replikatgruppe, die Sie anlegen (siehe Abbildung 23.26).
Abbildung 23.26: Eingabe einer Beschreibung für die Replikatgruppe
6. Dann werden Sie gefragt, ob Sie alle Objekte für die Replikatgruppe verfügbar machen oder einige als lokal kennzeichnen wollen (siehe Abbildung 23.27). Wenn Sie auf MAKE ALL OBJECTS AVAILABLE TO THE ENTIRE REPLICA SET und danach auf die Schaltfläche CHOOSE OBJECTS klicken, wird das Dialogfeld SELECT REPLICATED OBJECTS eingeblendet, damit Sie die ausgewählten Objekte als lokal kennzeichnen können (siehe Abbildung 23.28). Um ein Objekt als lokal zu kennzeichnen, entfernen Sie die Markierung aus dem Kontrollkästchen. Klicken Sie auf OK, wenn Sie fertig sind. 7. Als nächstes geben Sie an, ob die Replikate schreibgeschützt sein sollen (Abbildung 23.29). Der Designmaster ist die einzige Stelle, an der Sie Schemaänderungen vornehmen können. Wenn Sie auch Datenänderungen auf den Designmaster beschränken wollen, aktivieren Sie die Option, die alle Replikate mit Schreibschutz versieht. Im Allgemeinen sollten Sie die Standardoption I WANT TO BE ABLE TO CREATE READ/WRITE REPLICAS beibehalten. Klicken Sie nach der Auswahl auf NEXT. 8. Im nächsten Schritt des Assistenten werden Sie gefragt, ob Sie die Synchronisierung des Designmasters mit dem auf dem aktuellen Rechner vorliegenden Synchronizer verwalten wollen. Wenn Sie mit NO antworten, muss die Synchronisierung von einem anderen verwalteten Mitglied der Replikatgruppe ausgehen. Treffen Sie Ihre Wahl und klicken Sie auf NEXT.
Den Replikations-Manager verwenden
859
Abbildung 23.27: Sollen alle oder nur einige Objekte repliziert werden?
Abbildung 23.28: Objekte als lokal oder repliziert kennzeichnen
9. Klicken Sie auf FINISH, um den Assistenten zu beenden. Anschließend werden Sie über den Erfolg bzw. etwaige Probleme während der Konvertierung informiert.
860
Kapitel 23: Replikation leicht gemacht
Abbildung 23.29: Sollen Replikate mit Leseund Schreibzugriff erstellt werden können?
Eine Tabelle kann nicht als lokal gekennzeichnet werden, wenn sie in Beziehung zu einer replizierten Tabelle steht.
Wenn Sie mehr als eine Replikatgruppe besitzen, müssen Sie das Symbol MANAGED REPLICAS in der Symbolleiste REPLICATION MANAGER verwenden, um eine andere Replikatgruppe anzuzeigen. Es kann jeweils nur eine Replikatgruppe angezeigt werden.
23.13.3 Replikate mit Hilfe des Replikations-Managers erstellen Genauso, wie Sie Replikate mit Hilfe der Access-Benutzerschnittstelle oder des Windows-Aktenkoffers erstellen können, können Sie dazu auch den Replikations-Manager verwenden. Dazu unternehmen Sie Folgendes: 1. Klicken Sie in der Symbolleiste auf NEW REPLICA und dann auf NEXT. 2. Wählen Sie eine Quelle und ein Ziel für das Replikat aus. Die Quelle ist der Name der zu replizierenden Datenbank, das Ziel der Name des Replikats. Klicken Sie auf NEXT. 3. Geben Sie an, ob es möglich sein soll, im Replikat Daten zu ändern. Klicken Sie auf NEXT. 4. Geben Sie an, ob das Replikat vom Synchronizer auf dem aktuellen Rechner verwaltet werden soll. Klicken Sie auf NEXT. 5. Klicken Sie auf FINISH.
Den Replikations-Manager verwenden
861
Wenn Sie ein Replikat einer Datenbank anlegen, die von einem anderen Synchronizer verwaltet wird, müssen Sie diesen Synchronizer mit dem ReplikationsManager auf dem anderen Rechner konfigurieren.
23.13.4 Replikate mit Hilfe des Replikations-Managers synchronisieren Genauso, wie Sie Replikate mit Hilfe der Access-Benutzerschnittstelle oder des Windows-Aktenkoffers synchronisieren können, können Sie dazu auch den Replikations-Manager verwenden, wenn Sie Folgendes unternehmen: 1. Klicken Sie in der Symbolleiste des Replikations-Managers auf SYNCHRONIZE NOW. 2. Das Dialogfeld SYNCHRONIZE NOW wird eingeblendet (siehe Abbildung 23.30). Dort können Sie Einzelheiten der Synchronisierung festlegen. Wenn Sie fertig sind, klicken Sie auf OK, um den Synchronisierungsvorgang abzuschließen.
Abbildung 23.30: Im Dialogfeld Jetzt synchronisieren können Sie Einzelheiten der Synchronisierung festlegen
Entfernte Synchronisierung Möglicherweise sind Sie überrascht, dass das Topologiefenster des ReplikationsManagers nur einen Rechner anzeigt, obwohl Sie viele Replikate besitzen. Für jeden Synchronizer der Replikatgruppe erscheint ein Symbol. Abbildung 23.31 zeigt zwei an der Replizierung beteiligte Synchronizer: ALEXIS und DELL. Der zweite Standort wurde durch Installation des Replikations-Managers auf dem zweiten Rechner eingerichtet. Dann kann jedes Replikat vom lokalen Standort an den entfernten Standort verschoben werden, indem man eine Verbindung zu diesem errichtet und FILE|MOVE REPLICA wählt. Sie können den verwalteten Ordner am entfernten Standort suchen und das Replikat in diesen verschieben. Wenn beide Standorte im Topologiefenster der Replikation erscheinen, können Sie die Synchronisierung mit Hilfe der Verknüpfungslinie erledigen, die sie verbindet.
862
Kapitel 23: Replikation leicht gemacht
Abbildung 23.31: Das Topologiefenster des Replikations-Managers zeigt zwei Synchronizer
Sie können auf die Linie doppelklicken und SYNCHRONIZE NOW wählen oder mit EDIT SCHEDULE einen Zeitplan für die Synchronisierung einrichten. Synchronisierung nach Zeitplan wird im nächsten Abschnitt behandelt. Synchronisierung nach Zeitplan Synchronisierung zwischen Replikaten, die vom selben Synchronizer oder von zwei unterschiedlichen Synchronizern verwaltet werden, lässt sich nach Zeitplan durchführen. Um Synchronisierung zwischen Replikaten mit demselben Synchronizer zeitlich geplant zu erledigen, klicken Sie mit der rechten Maustaste auf das Symbol für den lokalen Synchronizer und wählen EDIT LOCALLY MANAGED REPLICA SCHEDULE (siehe Abbildung 23.32). Dort können Sie Tag und Uhrzeit für die Synchronisierung wählen. Um die Synchronisierung zwischen zwei verschiedenen Synchronizern nach Zeitplan durchzuführen, klicken Sie mit der rechten Maustaste auf die Verbindungslinie und wählen EDIT SCHEDULE, um das gleichnamige Dialogfeld zu öffnen. Dort können Sie die Einzelheiten der Synchronisierung zwischen den beiden Standorten zeitlich festlegen. Die Schattierung der beiden Felder zeigt an, welcher Synchronizer den Austausch anstößt. Wenn beim Start des Austausches keine Verbindung hergestellt werden kann, speichert der Ablageordner ein temporäres Protokoll der Änderungen. Alle 15 Minuten wird ein neuer Versuch unternommen, bis die Verbindung steht.
Den Replikations-Manager verwenden
863
Abbildung 23.32: Im Dialogfeld Edit Schedule können Sie Tag und Uhrzeit für die Synchronisierung der Replikate auswählen
23.13.5 Den Synchronisierungsverlauf untersuchen Der Synchronisierungsverlauf kann sehr hilfreich sein. Er liefert Ihnen nicht nur eine Spur für die Prüfung, sondern trägt auch zur Analyse der Wirksamkeit der Topologie und des Synchronisierungszeitplans bei, die Sie gewählt haben. Der Replikations-Manager unterhält drei Arten von Protokollen:
Den lokalen Synchronisierungsverlauf Den entfernten Synchronisierungsverlauf Das Synchronizer-Protokoll Um den lokalen Synchronisierungsverlauf zu sehen, klicken Sie mit der rechten Maustaste auf das Symbol des lokalen Rechners und wählen View Local Synchronization History. Damit wird das Dialogfeld Synchronization History angezeigt (siehe Abbildung 23.33), das Ihnen Einzelheiten über den Informationsaustausch zwischen den lokalen Replikaten aufzeigt. Um den entfernten Synchronisierungsverlauf anzuzeigen, markieren Sie die Verbindungslinie, die zwei Synchronizer verbindet und wählen VIEW|SYNCHRONIZATION HISTORY, um das Dialogfeld SYNCHRONIZATION HISTORY zu öffnen. Wenn Sie mehr Informationen über einen der Protokolleinträge wünschen, klicken Sie auf DETAILS, um das Dialogfeld SYNCHRONIZATION DETAILS einzublenden (siehe Abbildung 23.34).
23.13.6 Mit Synchronisierungseigenschaften arbeiten Sie können sich auch Eigenschaften des gewählten Synchronizers ansehen. Dazu doppelklicken Sie auf den Synchronizer und das Fenster REPLICA PROPERTIES wird eingeblendet. Dieses mit Registerkarten versehene Dialogfeld übermittelt interessante Informationen über den gewählten Synchronizer.
864
Kapitel 23: Replikation leicht gemacht
Abbildung 23.33: Der lokale Synchronisierungsverlauf
Abbildung 23.34: Das Dialogfeld Synchronization Details zeigt Einzelheiten eines Synchronisierungsverlaufs
Partielle Replikation
865
Jet 4.0 und Access 2000 unterstützen Synchronisierung über das Internet oder ein Intranet. Sie legen ein Replikat auf einem Server ab und synchronisieren mit Hilfe des Replikations-Managers über eine übliche HTTP-Verbindung. Dieser Vorgang wird in Kapitel 31 behandelt.
23.14 Partielle Replikation Jet 3.5 und Access 97 haben die »partielle Replikation« eingeführt, d.h., dass nur eine Teilmenge der Daten repliziert wird. Das ist sinnvoll, wenn beispielsweise mehrere Verkäufer vorhanden sind und jeder nur seine eigenen Daten haben soll. Alle Verkäufer sollen jedoch ihre Änderungen mit anderen Datenbanken im Netzwerk synchronisieren können. Partielle Replikate lassen sich mit Hilfe des Assistenten für partielle Replikation erstellen, der über die Access-Benutzerschnittstelle oder VBACode zu erreichen ist. Die Prozedur der Erstellung eines Teilreplikats mittels VBACode wird im Abschnitt »Ein partielles Replikat mittels Code erstellen« dargestellt, der Assistent für partielle Replikation in diesem Abschnitt. Um ein Teilreplikat zu erstellen, unternehmen Sie Folgendes: 1. Wählen Sie in Microsoft Access, während die zu replizierende Datenbank geöffnet ist, EXTRAS|REPLIKATION|TEILREPLIKATIONS-ASSISTENT. Dies startet den Teilreplikations-Assistenten. 2. Legen Sie fest, ob ein neues Teilreplikat angelegt oder ein bestehendes modifiziert werden soll (siehe Abbildung 23.35). Klicken Sie auf WEITER.
Abbildung 23.35: Legen Sie fest, ob ein neues Teilreplikat angelegt oder ein bestehendes modifiziert werden soll
866
Kapitel 23: Replikation leicht gemacht
3. Geben Sie Namen und Speicherort für das Teilreplikat an. Klicken Sie auf WEITER. 4. Erstellen Sie einen Filterausdruck, der die im Teilreplikat enthaltenen Daten einschränkt. Dazu markieren Sie die Tabelle, deren Daten gefiltert werden sollen, das Feld, das Sie als Kriterium verwenden wollen und den Operator für den Ausdruck. Klicken Sie auf EINFÜGEN. Um den Ausdruck zu vervollständigen, geben Sie den Wert ein, den Sie zur Einschränkung der im Teilreplikat enthaltenen Daten verwenden wollen. Sie können die Auswahl mit AND und OR nach Bedarf erweitern oder verfeinern. Abbildung 23.36 zeigt einen Filterausdruck, der ein Teilreplikat mit Daten nur für Kunden im Staat Kalifornien erstellt. Klicken Sie auf WEITER.
Abbildung 23.36: Legen Sie den Filterausdruck für die Einschränkung der im Teilreplikat enthaltenen Daten fest
5. Der nächste Schritt des Assistenten für Teilreplikate ist sehr wichtig. Er ermöglicht die Angabe weiterer Tabellen, die in das Teilreplikat aufgenommen werden sollen. Tabellen in fetter Schrift besitzen eine Beziehung zu der Tabelle, deren Kriterien Sie für die Erstellung des Teilreplikats verwenden. Sie müssen die Markierung dieser Tabellen aufheben, damit nur Datensätze mit einer Beziehung zu den Datensätzen in Ihrem Filter in das Teilreplikat aufgenommen werden. Tabellen, die nicht in fetter Schrift dargestellt werden, besitzen keine Beziehung zu der gefilterten Tabelle und es wird keine referentielle Integrität erzwungen. Es ist Ihre Sache, ob die Daten in diesen Tabellen ohne Beziehung in das Replikat aufgenommen werden sollen. In Abbildung 23.37 wurden die Markierungen bei allen verknüpften Tabellen entfernt, nicht aber für die nicht verknüpfte Tabelle, d.h., dass verknüpfte Daten für alle Tabellen aufgenommen werden, für die refe-
Replikation mittels Code implementieren
867
rentielle Integrität eingerichtet wurde, während die Tabelle tblCompanyInfo als ganze aufgenommen wird. 6. Zuletzt können Sie noch festlegen, ob Access einen Bericht mit allen Eigenschaftseinstellungen anfertigen soll, die für das Teilreplikat gelten. Treffen Sie Ihre Wahl und klicken Sie auf FERTIG STELLEN.
Abbildung 23.37: Legen Sie fest, welche weiteren Daten in das Teilreplikat aufgenommen werden
23.15
Replikation mittels Code implementieren
Die meisten Replikationsfunktionen lassen sich auch mittels Code implementieren, aber dies ist nicht die einfachste Möglichkeit, Replikation durchzuführen. Vielleicht wollen Sie aber gelegentlich bestimmte Aspekte des Replikationsvorgangs mittels Code implementieren, damit Sie den Vorgang und die Schnittstelle besser aus der Anwendung heraus steuern können. Alle folgenden Beispiele setzen die Objektbibliothek Jet Replication Objects (JRO) voraus. Um auf diese zuzugreifen, müssen Sie die Microsoft Jet and Replication Objects 2.1 Library über EXTRAS|VERWEISE im VBE auswählen. Die Datenbank, welche die JRO-Bibliothek benötigt, muss geöffnet sein.
868
Kapitel 23: Replikation leicht gemacht
23.15.1 Eine Datenbank mittels Code replizierbar machen Die in Listing 23.1 gezeigte Routine, welche sich in der Datenbank Chap23Ex befindet, macht eine Datenbank mittels Code replizierbar.
Listing 23.1:
Eine Datenbank replizierbar machen
Sub MakeReplicable(strMaster As String) Dim rep As JRO.Replica Set rep = New JRO.Replica rep.MakeReplicable strMaster, True Set rep = Nothing End Sub
Diese Routine übernimmt den Pfad zu einer beliebigen Datenbank als Parameter. Zuerst legt sie ein JRO-Objekt Replica an. Mit Hilfe der Methode MakeReplicable des Objekts Replica wird die Datenbank in einen Designmaster konvertiert. Die Methode übernimmt den Namen der Datenbank, die konvertiert werden soll und einen optionalen Parameter, mit dessen Hilfe Sie angeben können, ob der Master Verfolgung auf Spaltenebene anwenden soll (siehe Hinweis). Vor Access 2000 entstanden Konflikte auf Datensatzebene, d.h., dass ein Konflikt entstand, wenn zwei Benutzer unterschiedliche Felder desselben Datensatzes änderten. Access 2000 führt Verfolgung auf Spaltenebene ein, d.h., dass kein Konflikt entsteht, wenn zwei Benutzer unterschiedliche Felder desselben Datensatzes ändern. Konflikte treten nur auf, wenn zwei Benutzer dasselbe Feld eines Datensatzes ändern. Verfolgung auf Spaltenebene ist ein optionales Merkmal, das standardmäßig aktiv ist und nur bei replikationsfähigen Datenbanken zur Verfügung steht.
23.15.2 Ein Objekt als lokal kennzeichnen Normalerweise werden alle Objekte einer Datenbank in den Replikationsvorgang eingeschlossen. Der Code in Listing 23.2 veranschaulicht, wie man ein Datenbankobjekt als lokal kennzeichnet und zwar in diesem Fall die Tabelle tblEmployee. Listing 23.2:
Ein Objekt als lokal kennzeichnen
Sub MakeLocal(strDatabase As String, _ strName As String, _ strObjType As String)
Replikation mittels Code implementieren
869
Dim rep As New JRO.Replica rep.ActiveConnection = strDatabase rep.SetObjectReplicability strName, strObjType, False Set rep = Nothing End Sub
Zuerst wird ein JRO-Replica-Objekt deklariert. Die Eigenschaft ActiveConnection dieses Objekts wird mit einem Zeiger auf die Datenbank versehen, deren Objekt als lokal gekennzeichnet werden soll. Mit der Methode SetObjectReplicability des Replica-Objekts wird ein Datenbankobjekt als lokal gekennzeichnet. Sie übernimmt den Namen und den Typ des betreffenden Objekts. Da der Code die Replizierbarkeit auf False setzt, ist das Objekt als lokal gekennzeichnet.
23.15.3 Ein Replikat mittels Code erstellen Ein neues Replikat lässt sich mit Hilfe der Methode CreateReplica des Objekts Replica erstellen. Sie sehen den Code dafür in Listing 23.3. Listing 23.3:
Ein Replikat anlegen
Sub MakeReplica(strMaster As String, strReplica As String) Dim rep As JRO.Replica Set rep = New JRO.Replica rep.ActiveConnection = strMaster rep.CreateReplica strReplica, "Replica of " & strMaster End Sub
Er übernimmt zwei Parameter. Der erste enthält Pfad und Dateinamen für den Designmaster, der zweite Pfad und Dateinamen für das Replikat. Dann wird die Methode CreateReplica für das Objekt Replica ausgeführt. Der erste Parameter für diese Methode ist der Name des zu erstellenden Replikats, der zweite der Name des Designmasters. Weitere optionale Parameter betreffen den Typ, die Sichtbarkeit, die Priorität und die Aktualisierbarkeit des zu erstellenden Replikats. Replikattypen Beim Erstellen eines Replikats dient der Parameter ReplicaType dazu, den Typ des zu erstellenden Replikats festzulegen. Ein Replikat kann als Designmaster, vollständiges Replikat, Teilreplikat oder nicht replizierbares Replikat angelegt werden. Sichtbarkeit von Replikaten Access 2000 und JRO führen eine neue Eigenschaft ein, die dazu dient, die Sichtbarkeit des Replikats anzugeben. Die Sichtbarkeit bestimmt, welche Replikate mit einem bestimmten Replikat synchronisiert werden können. Sie lässt sich nur bei der Erstellung des Replikats festlegen. Ein Replikat kann global, lokal oder anonym sein. Ein
870
Kapitel 23: Replikation leicht gemacht
globales Replikat kann mit allen Replikaten der Replikatgruppe synchronisiert werden. Standardmäßig sind alle Replikate global. Ein lokales Replikat kann nur mit seinem übergeordneten Replikat synchronisiert werden und ein übergeordnetes Replikat kann die Synchronisierung mit einem lokalen Replikat nach Zeitplan vornehmen. Es erledigt Replikationskonflikte und Fehler im Auftrag des lokalen Replikats. Ein lokales Replikat kann nur weitere lokale Replikate erstellen. Diese haben das übergeordnete Replikat mit dem lokalen Replikat gemeinsam. Alle anderen Replikate kennen das lokale Replikat nicht. Ein anonymes Replikat kann nur mit seinem übergeordneten Replikat synchronisiert werden. Anonyme Replikate sind angebracht, wenn ein Replikat selten an der Synchronisierung teilnimmt. Das anonyme Replikat gibt seine Identität für Aktualisierungen dem veröffentlichenden Replikat bekannt. Anonyme Replikate können nur weitere anonyme Replikate erstellen. Diese haben das übergeordnete Replikat mit dem anonymen Replikat gemeinsam. Priorität für Replikate Eine weitere neue Eigenschaft von Replikaten gibt die Priorität während der Synchronisierung an. Wenn während der Synchronisierung Konflikte auftreten, siegt das Replikat mit der höchsten Priorität. Aktualisierbarkeit von Replikaten Die Aktualisierbarkeit eines Replikats bestimmt, ob die in ihm enthaltenen Daten aktualisierbar sind. Das ist standardmäßig der Fall. Wenn die Eigenschaft auf den konstanten Wert jrRepUpdReadOnly gesetzt ist, ist nur Lesezugriff auf die Daten möglich.
23.15.4 Ein partielles Replikat mittels Code erstellen Auch ein Teilreplikat lässt sich mittels VBA-Code erstellen, wie Sie in Listing 23.4 sehen. Listing 23.4:
Ein Teilreplikat anlegen
Sub CreatePartialReplica() Dim repFull As New JRO.Replica Dim repPartial As New JRO.Replica repFull.ActiveConnection = "c:\My Documents\MyMaster.mdb" repFull.CreateReplica "c:\My Documents\CA Clients.mdb", _ "Partial Replica of MyMaster", _ jrRepTypePartial Set repFull = Nothing repPartial.ActiveConnection = "c:\My Documents\CA Clients.mdb"
Replikation mittels Code implementieren
871
repPartial.Filters.Append "tblClients", jrFilterTypeTable, _ "State = 'CA'" repPartial.Filters.Append "tblProjects", jrFilterTypeRelationship, _ "ClientProjects" repPartial.PopulatePartial "c:\My Documents\MyMaster.mdb" Set repPartial = Nothing End Sub
Zuerst stellt der Code eine Verbindung zum Master her. Mit Hilfe der Methode CreateReplica des Replica-Objekts wird ein Teilreplikat erstellt. Dann wird eine Verbindung zum Replikat eingerichtet. An das Replica-Objekt werden zwei Filter angehängt. Der erste füllt die Tabelle tblClients im Replikat mit allen Kunden, die im Staat Kalifornien wohnen, der zweite die Tabelle tblProjects mit allen Projekten, die mit Kunden im Staat Kalifornien verknüpft sind. Mit Hilfe der Methode PopulatePartial wird das Replikat mit den in den Filtern ermittelten Daten gefüllt.
23.15.5 Eine Datenbank mittels Code synchronisieren Gelegentlich wollen Sie die Synchronisierung vielleicht mittels VBA-Code durchführen. Die in Listing 23.5 gezeigte Routine synchronisiert die beiden als Parameter genannten Datenbanken. Die Konstante jrSyncTypeImpExp gibt an, dass Sie eine Synchronisierung in zwei Richtungen vornehmen wollen. Die Konstante jrSyncModeDirect legt fest, dass indirekte Synchronisierung stattfinden soll. Listing 23.5:
Zwei Datenbanken synchronisieren
Sub Synchronize(strDB1 As String, strDB2 As String) Dim rep As JRO.Replica rep.ActiveConnection = strDB1 rep.Synchronize strDB2, jrSyncTypeImpExp, jrSyncModeDirect Set rep = Nothing End Sub
23.15.6 Konflikte mittels Code beheben Mittels Code lassen sich auch Konflikte beheben (siehe Listing 23.6). Was Sie tun, wenn ein Konflikt festgestellt wird, richtet sich nach den geschäftlichen Bedürfnissen der Benutzer. Listing 23.6:
Konflikte mittels Code feststellen
Sub IdentifyConflicts(strConflictDB) Dim rep As New JRO.Replica Dim rst As ADODB.Recordset rep.ActiveConnection = strConflictDB Set rst = rep.ConflictTables
872
Kapitel 23: Replikation leicht gemacht
If rst.BOF And rst.EOF Then MsgBox "No Conflicts!!!" Else Do Until rst.EOF Debug.Print rst.Fields(0) rst.MoveNext Loop End If
End Sub
Diese Routine geht alle Tabellen durch und ermittelt, ob in der Tabelleneigenschaft ConflictTable etwas festgehalten ist. Wenn ja, wird von dort aus eine Datensatzgruppe geöffnet. Die Routine geht alle Datensätze der Konflikttabelle durch und zeigt den Wert des ersten Feldes im Testfenster an.
23.15.7 Für die Praxis Das Zeit- und Abrechnungssystem mit Replikation verwalten Sie müssen entscheiden, ob es erforderlich ist, Replikation in das Zeit- und Abrechnungssystem zu integrieren. Das könnte sehr sinnvoll sein, wenn Sie beispielsweise viele Berater haben, die im Außendienst tätig sind und unterwegs Informationen über Kunden, Projekte, Rechnungen und Ausgaben eingeben müssen. Mit dem, was Sie in diesem Kapitel gelernt haben, können Sie sicherstellen, dass alle Änderungen an den Datenbankexemplaren der einzelnen Berater jedesmal, wenn sich diese ins Büro einwählen, an die Datenbank auf dem Haupt-Server übermittelt werden. Replikation kann auch eingesetzt werden, um die von der Anwendung verwalteten Daten im Lauf des Tages zu aktualisieren, was das Risiko von Datenverlust und Ausfallzeiten minimiert. Schließlich wollen Sie vielleicht Replikation in die Anwendung integrieren, um die Arbeitsbelastung in Ihrer Organisation auf mehrere Server zu verteilen. Die möglichen Vorteile des Einsatzes von Replikation innerhalb der Beispielanwendung sind zahlreich. Mit dem, was Sie in diesem Kapitel gelernt haben, müssen Sie entscheiden, ob Replikation für Ihre Anwendung das Richtige ist und wie sie sich in Ihrer Organisation am besten einsetzen lässt.
Fortgeschrittene Programmierung
Teil IV
24 Fortgeschrittene VBA-Techniken 25 ActiveX-Steuerelemente 26 Automatisierung: Mit anderen Anwendungen kommunizieren 27 Die Leistungsfähigkeit des Windows-API ausschöpfen 28 Die Leistungsfähigkeit von Klassenmodulen nutzen 29 Eigene Bibliotheken erstellen 30 Generatoren, Assistenten und Menü-Add-Ins verwenden 31 Access und das Internet 32 Datenzugriffsseiten
Fortgeschrittene VBA-Techniken
Kapitel
Hier lesen Sie:
Für erfahrene Programmierer Was sind benutzerdefinierte Typen und wozu können sie verwendet werden? Mit Konstanten arbeiten Mit Datenfeldern arbeiten Fortgeschrittene Methoden der Verwendung von Funktionen Mit Empty und Null arbeiten Benutzerdefinierte Auflistungen erstellen und verwenden Kompilieroptionen verstehen und effektiv nutzen Code-Module im- und exportieren Mit Projekteigenschaften arbeiten
24.1
Für erfahrenere Programmierer
Die Programmiersprache Visual Basic for Applications (VBA) ist äußerst umfassend und leistungsfähig. In diesem Buch wird überall mit VBA gearbeitet, da die Sprache diverse Anwendungsmöglichkeiten bietet, doch dieses Kapitel konzentriert sich auf einige fortgeschrittene Techniken der Anwendungsentwicklung. Zu den behandelten Themen gehören Typen, Datenfelder, fortgeschrittene Techniken des Erstellens von Funktionen und Optionen für das Kompilieren von VBA-Programmen. Das Beherrschen dieser Themen hilft Ihnen dabei, erfolgreich als VBA-Programmierer zu arbeiten.
876
24.2
Kapitel 24: Fortgeschrittene VBA-Techniken
Was sind benutzerdefinierte Typen und wozu können sie verwendet werden?
Auf benutzerdefinierte Typen wurde bereits in Kapitel 14 kurz eingegangen. In Kapitel 14 wurde ein benutzerdefinierter Typ verwendet, um Informationen über aufgetretene Fehler zu speichern. Ein benutzerdefinierter Typ, der auch als struct oder record bezeichnet wird, ermöglicht Ihnen das Erstellen von Variablen für jeweils mehrere Informationen. Benutzerdefinierte Typen werden häufig verwendet, um die Informationen eines oder mehrerer Datensätze im Hauptspeicher abzulegen. Außerdem werden sie eingesetzt, um zusammengehörige Informationen zu speichern, die ansonsten in mehreren unabhängigen Variablen gespeichert werden würden. Da jedem Element eines benutzerdefinierten Typs ein eigener Datentyp zugewiesen werden kann, können die Datentypen solcher Elemente beispielsweise mit den Datentypen spezieller Felder einer Tabelle übereinstimmen. Ein benutzerdefinierter Typ könnte beispielsweise folgendermaßen strukturiert sein: Die nachfolgenden Code-Fragmente entstammen dem Modul basDataHandling. Public Type TimeCardInfo TimeCardDetailID As Long TimeCardID As Long DateWorked As Date ProjectID As Long WorkDescription As String * 255 BillableHours As Double BillingRate As Currency WorkCodeID As Long End Type
Beachten Sie, dass der jeweilige Datentyp der einzelnen Elemente explizit deklariert ist. Das Element, welches die Zeichenkette WorkDescription enthält, wurde mit einer Länge von 255 angegeben. Benutzerdefinierte Typen erhöhen die Übersichtlichkeit der Programmstruktur, da zusammengehörige Daten als Einheit gespeichert werden können. Sie existieren ausschließlich im Hauptspeicher und sind somit rein temporär. Besonders für Informationen, die vorübergehend zur Laufzeit verarbeitet werden sollen, sind benutzerdefinierte Typen deshalb hervorragend geeignet. Da sie sich bereits im Hauptspeicher befinden, können ihre Werte äußerst effizient ausgelesen und verändert werden.
Was sind benutzerdefinierte Typen und wozu können sie verwendet werden?
24.2.1
877
Deklarieren benutzerdefinierter Typen
Ein benutzerdefinierter Typ wird mit Hilfe einer Type-Anweisung deklariert, die im Deklarationsteil des entsprechenden Moduls anzugeben ist. In Standardmodulen können Typen als öffentlich oder privat deklariert werden, während dies in Formular- bzw. Berichtsmodulen nicht möglich ist. Dort lassen sich benutzerdefinierte Typen lediglich verwenden.
24.2.2
Erstellen einer Typvariablen
Eine Typvariable ist eine Instanz eines Typs im Hauptspeicher. Vor seiner Verwendung muss ein Typ deklariert werden. Um eine Typvariable zu deklarieren, erstellen Sie basierend auf dem Typ eine Local-, Private-, Module-Level- oder Public-Variable. Der Gültigkeitsbereich einer Typvariablen ergibt sich aus der Stelle, an der Sie die Deklaration vornehmen, und aus der Art der Deklaration (Dim, Private oder Public). Ansonsten gelten für Typvariablen die gleichen Regeln wie für alle sonstigen Arten von Variablen. Mit Hilfe der Dim-Anweisung wird im nachfolgend dargestellten Code eine Variable mtypTimeCardData erzeugt. Wenn Sie diese Dim-Anweisung im Allgemeinen Abschnitt des Moduls einfügen, steht die Variable für sämtliche Routinen dieses Moduls zur Verfügung. (Beachten Sie das m, welches darauf hinweist, dass die Deklaration auf Modulebene erfolgte.) Wenn Sie die Anweisung in eine Unterroutine oder Funktion einfügen, bleibt ihr Gültigkeitsbereich auf diese spezielle Routine beschränkt: Dim mtypTimeCardData As TimeCardInfo
24.2.3
Informationen eines Datensatzes in einem Formular in einer Variablen speichern
Nachdem eine Typvariable deklariert wurde, können Sie in jedem ihrer Elemente Daten ablegen. Der folgende Code des Formulars frmTimeCardHours speichert Informationen des Formulars in einer Typvariablen mtypTimeCardData. Diese Typvariable wurde im Abschnitt für allgemeine Deklarationen des Formulars als privat deklariert. Die Type-Struktur finden Sie im Modul basDataHandling. Private Sub cmdWriteToType_Click() mtypTimeCardData.TimeCardDetailID = Me.txtTimeCardDetailID mtypTimeCardData.TimeCardID = Me.txtTimeCardID mtypTimeCardData.DateWorked = Me.txtDateWorked mtypTimeCardData.ProjectID = Me.cboProjectID mtypTimeCardData.WorkDescription = Me.txtWorkDescription mtypTimeCardData.BillableHours = Me.txtBillableHours mtypTimeCardData.BillingRate = Me.txtBillingRate mtypTimeCardData.WorkCodeID = Me.cboWorkCodeID End Sub
878
Kapitel 24: Fortgeschrittene VBA-Techniken
Den in diesem Kapitel dargestellten Code finden Sie auf der diesem Buch beiliegenden CD-ROM in der Datenbank CHAP24EX.MDB. Der Vorteil dieses Codes besteht darin, dass für diese acht Elemente zusammengehöriger Informationen nicht acht Variablen erstellt werden, sondern lediglich eine, in der alle acht Elemente gespeichert werden können. Auf diese Weise bleibt alles klar und übersichtlich.
24.2.4
Informationen aus den Elementen einer Typvariablen abrufen
Um die in Ihrer Typvariablen enthaltenen Informationen abzurufen, verwenden Sie einfach den Variablennamen, gefolgt von einem Punkt und dem Namen des jeweiligen Elements. Der folgende Code stellt eine Meldung dar, welche sämtliche auf einer Stempelkarte enthaltenen Informationen umfasst: Private Sub cmdDisplayFromType_Click() MsgBox "Timecard Detail ID Is " & _ mtypTimeCardData.TimeCardDetailID & Chr(13) & _ "Timecard ID Is " & mtypTimeCardData.TimeCardID & Chr(13) & _ "Date Worked Is " & mtypTimeCardData.DateWorked & Chr(13) & _ "Project ID Is " & mtypTimeCardData.ProjectID & Chr(13) & _ "Work Description Is " & _ Trim(mtypTimeCardData.WorkDescription) & Chr(13) & _ "Billable Hours Is " & mtypTimeCardData.BillableHours & Chr(13) & _ "Billing Rate Is " & mtypTimeCardData.BillingRate & Chr(13) & _ "Workcode ID Is " & mtypTimeCardData.WorkCodeID End Sub
24.3
Mit Konstanten arbeiten
Eine »Konstante« ist ein sinnvoller Name, mit dem eine wenig aussagekräftige Zahl oder eine Zeichenkette versehen wurde. Konstanten können ausschließlich für Werte verwendet werden, die zur Laufzeit unverändert bleiben. Dabei könnte es sich im Rahmen unserer Beispielanwendung beispielsweise um einen Steuersatz oder um einen Rabatt handeln. In Access gibt es drei Arten von Konstanten:
symbolische integrierte systemdefinierte Symbolische Konstanten werden unter Verwendung des Schlüsselworts Const erstellt, um den Code lesbarer und besser handhabbar zu gestalten. Statt beispielsweise immer die Zahl .0875 anzugeben, wenn Sie den Steuersatz meinen, benutzen Sie die Konstante MTAXRATE. Sobald sich der Steuersatz ändert und Ihr Code deshalb geändert werden muss, brauchen Sie die Änderung nur noch an einer einzigen Stelle vorzunehmen. Außerdem ist die Bezeichnung MTAXRATE erheblich aussagekräftiger als die Zahl .0875.
Mit Konstanten arbeiten
879
Integrierte Konstanten sind feste Bestandteile von Microsoft Access und gehören unmittelbar zur Sprache selbst. Als Access-Programmierer können Sie die zu Microsoft Access, Visual Basic und die zu den ActiveX-Datenobjekten (ADO) gehörigen Konstanten verwenden. Außerdem haben Sie die Möglichkeit, Konstanten beliebiger im Rahmen Ihrer Anwendung genutzter Objektbibliotheken zu benutzen. Es sind lediglich drei systemdefinierte Konstanten für sämtliche Anwendungen auf Ihrem Computer verfügbar: True, False und Null.
24.3.1
Eigene Konstanten definieren
Es wurde bereits erwähnt, dass symbolische Konstanten mit Hilfe des Schlüsselworts Const deklariert werden. Die Konstantendeklaration kann innerhalb einer Unterroutine oder Funktion oder auch im Allgemeinen Abschnitt eines Formular-, Berichtsoder Klassenmoduls erfolgen. Im Gegensatz zu früheren Versionen von Access können Konstanten in Access 97 und Access 2000 sogar strikt typisiert werden. Für Konstanten gibt es einige Namenskonventionen. Beispielsweise sollte der erste Buchstabe des Namens einer Konstanten auf deren Gültigkeitsbereich hinweisen und der nachfolgende Buchstabe c signalisiert, dass es sich nicht um eine Variable handelt. Danach folgt die eigentliche Bezeichnung des Datentyps. Eine private Konstante könnte folgendermaßen deklariert und verwendet werden: Private Const mccurTaxRate As Currency = .0875
Ich bevorzuge eine Namenskonvention, bei welcher der Name einer Konstanten mit einem Präfix für den Gültigkeitsbereich beginnt und vollständig in Großbuchstaben geschrieben wird. Das soeben angegebene Beispiel sieht dann so aus: Private Const MTAXRATE as Currency = .0875
Wenn dieser Code im Deklarationsteil eines Moduls eingefügt wird, sorgt er dafür, dass eine private Konstante mit dem Namen MTAXRATE und dem Wert .0875 erstellt wird. Innerhalb des Codes wird die Konstante wie folgt verwendet: Function TotalAmount(curSaleAmount As Currency) TotalAmount = curSaleAmount * MTAXRATE End Function
Diese Routine multipliziert die als Parameter übernommene Variable curSaleAmount mit der Konstanten MTAXRATE. Das Ergebnis der Multiplikation dieser beiden Werte wird dem Namen der Funktion zugewiesen und dient somit als Rückgabewert. In diesem Beispiel besteht der Vorteil der Verwendung einer Konstanten in der besseren Lesbarkeit. Der Ausdruck TotalAmount = curSaleAmount * .0875 ist sicherlich weniger aussagekräftig.
880
Kapitel 24: Fortgeschrittene VBA-Techniken
Den Gültigkeitsbereich symbolischer Konstanten festlegen Analog zu herkömmlichen Variablen verfügen auch benutzerdefinierte Konstanten über einen Gültigkeitsbereich. Im vorherigen Beispiel haben Sie eine private Konstante erstellt. Wird der folgende Ausdruck im Deklarationsteil eines Moduls eingefügt, zieht dies das Erstellen einer öffentlichen Konstanten nach sich: Public Const GTAXRATE As Currency = 0.0875
Da diese Konstante als öffentlich deklariert wurde, kann sie von jeder Unterroutine bzw. Funktion (einschließlich der Ereignisroutinen) innerhalb Ihrer Anwendung benutzt werden. Um die Vorteile einer öffentlichen Konstanten besser zu verstehen, stellen Sie sich bitte vor, dass Sie mit zahlreichen Funktionen und Unterroutinen arbeiten, welche alle die Konstante GTAXRATE verwenden. Was wäre zu tun, wenn der Steuersatz geändert werden müsste? Wenn Sie keine Konstante benutzt hätten, müssten Sie Ihre gesamte Anwendung durchsuchen, um überall den alten Steuersatz durch den neuen zu ersetzen. Da Sie jedoch eine öffentliche Konstante verwendet haben, brauchen Sie lediglich die eine Code-Zeile zu ändern, in der die Konstante deklariert wurde. Der Wert einer Konstanten darf zur Laufzeit grundsätzlich nicht verändert werden. Falls Sie es trotzdem versuchen, verursachen Sie den folgenden VBA-Kompilierfehler: Fehler beim Kompilieren: Zuweisung zu einer Konstanten nicht zulässig.
Die entsprechende Meldung ist in Abbildung 24.1 dargestellt. Der Kompilierfehler wurde durch den Versuch ausgelöst, den Wert der Konstanten GTAXRATE zu verändern. Falls ein Verändern des Werts zur Laufzeit erforderlich ist, sollten Sie erwägen, den Wert in einer Tabelle zu speichern, statt ihn als Konstante zu deklarieren. Dann können Sie den Wert in eine Variable einlesen, sobald die Anwendung gestartet wird, und ihn bei Bedarf ändern. Außerdem haben Sie die Möglichkeit, den neuen Wert in der Tabelle abzulegen.
Abbildung 24.1: Diese Fehlermeldung ergibt sich aus dem Versuch, den Wert einer Konstanten zu verändern
Mit Konstanten arbeiten
24.3.2
881
Mit integrierten Konstanten arbeiten
Microsoft Access deklariert einige integrierte Konstanten, die in Code-, Formularund Berichtsmodulen verwendet werden können. Da diese Konstanten für Microsoft Access reserviert sind, haben Sie weder die Möglichkeit, deren Wert zu ändern, noch ihre Namen anderweitig zu benutzen. Konstanten dieser Art können jedoch jederzeit verwendet werden, ohne zuvor deklariert worden zu sein. In Ihrem Code sollten Sie so oft wie möglich von integrierten Konstanten Gebrauch machen. Auf diese Weise sorgen Sie nicht nur für eine bessere Lesbarkeit des Codes, sondern erreichen zusätzlich eine bessere Portierbarkeit Ihres Codes auf künftige Versionen von Access. Microsoft könnte zwar den mit einer Konstanten assoziierten Wert modifizieren, doch der Name der Konstanten wird wohl kaum verändert. Sämtliche integrierte Konstanten werden im Objektkatalog aufgeführt. Um eine von ihnen zu aktivieren, brauchen Sie lediglich innerhalb des VBE auf das Werkzeug OBJEKTKATALOG in der Visual-Basic-Symbolleiste zu klicken. Die zur Programmiersprache VBA gehörenden Konstanten können Sie betrachten, indem Sie im aufklappbaren Listenfeld PROJEKT/BIBLIOTHEK des Objektkatalogs den Eintrag VBA auswählen. Sobald Sie im Listenfeld KLASSEN auf einzelne Konstanten klicken, erscheint eine Liste jener Konstanten im Listenfeld ELEMENTE VON 'CONSTANTS' (siehe Abbildung 24.2).
Abbildung 24.2: Betrachten integrierter Konstanten mit Hilfe des Objektkatalogs
Innerhalb des in Abbildung 24.2 dargestellten Listenfelds beginnen sämtliche Namen von Konstanten mit Vb. VBA-Konstanten sind grundsätzlich mit dem Präfix Vb versehen, für ActiveX-Datenobjekte wird als Präfix Ad verwendet, Datenzugriffsobjekte (DAO – Data Access Objects) beginnen stets mit Db und zu Access
882
Kapitel 24: Fortgeschrittene VBA-Techniken
gehörende Konstanten sind am Präfix Ac erkennbar. Um die speziellen Konstanten von Access zu betrachten, wählen Sie zunächst im aufklappbaren Listenfeld PROJEKT/BIBLIOTHEK den Eintrag ACCESS und anschließend im Listenfeld KLASSEN die Option CONSTANTS. Wenn Sie andererseits ADO-Konstanten aufgelistet bekommen möchten (ADO – ActiveX Data Object), wählen Sie ADODB aus dem aufklappbaren Listenfeld PROJEKT/BIBLIOTHEK aus. Die Konstanten sind auch hier gemäß ihrer jeweiligen Funktion unterschiedlichen Klassen zugeordnet (z.B. LockTypeEnum oder ExecuteOptionEnum). Sobald Sie im Listenfeld KLASSEN eine dieser Klassen auswählen, erscheinen deren Elemente im Listenfeld ELEMENTE VON ... Während des Umgangs mit Parametern innerhalb des Code-Fensters bietet sich Ihnen eine weitere Möglichkeit des Betrachtens von Konstanten. Klicken Sie hinter dem Parameternamen auf die rechte Maustaste und wählen Sie im daraufhin erscheinenden Kontextmenü die Option KONSTANTEN ANZEIGEN aus. In Kapitel 7 wurde diese Funktion bereits ausführlich erörtert.
24.4
Mit Datenfeldern arbeiten
Ein »Datenfeld« ist eine Folge von Variablen, die über den gleichen Namen angesprochen wird. Die einzelnen Elemente des Datenfelds werden durch eindeutige Indexnummern unterschieden, der Datentyp der einzelnen Elemente muss jedoch einheitlich sein. Datenfelder ermöglichen eine effizientere Gestaltung von Programmen. Es ist sehr einfach, sämtliche Elemente eines Datenfelds zu durchlaufen und jeweils auf bestimmte Weise zu bearbeiten. Datenfelder verfügen über eine Untergrenze, welche standardmäßig Null beträgt, und über eine Obergrenze. Die Nummern der Elemente eines Datenfelds müssen aufeinanderfolgend sein. Der Gültigkeitsbereich eines Datenfelds kann Private, Public oder Module sein. Wie bei anderen Variablen auch, hängt dies davon ab, wo das Datenfeld mit welchem Schlüsselwert deklariert wird.
24.4.1
Feste Datenfelder deklarieren und verwenden
Beim Deklarieren eines »festen Datenfelds« teilen Sie VBA die Obergrenze und den zu benutzenden Datentyp mit. Der folgende Code erstellt ein Datenfeld mit sechs String-Variablen: Dim astrNames(5) As String
»Fest« bedeutet, dass die Größe des Datenfelds zur Laufzeit nicht verändert werden kann. Der folgende Code zeigt, wie Sie das Datenfeld durchlaufen können: Sub FixedArray() Dim astrNames(5) As String Dim intCounter As Integer astrNames(0) = "Dan"
Mit Datenfeldern arbeiten
883
astrNames(1) = "Reggie" astrNames(2) = "Chelsea" astrNames(3) = "Joshua" For intCounter = 0 To UBound(astrNames) Debug.Print astrNames(intCounter) Next intCounter End Sub
Dieser Code weist zunächst den ersten vier Elementen eines sechselementigen Datenfelds bestimmte Werte zu. Anschließend wird jedes Element des Datenfelds durchlaufen und der jeweilige Inhalt ausgegeben. Beachten Sie, dass die For...NextSchleife mit Null beginnt und bei der Obergrenze des Datenfelds (5) endet. Da das Datenfeld aus Zeichenketten besteht, enthalten seine letzten beiden Elemente leere Zeichenketten. Wäre es aus Integer-Werten zusammengesetzt, würden die beiden letzten Elemente Nullen enthalten. Eine weitere Möglichkeit, wie Sie das Datenfeld durchlaufen können, besteht in der Verwendung des Konstrukts For Each...Next. Ihr Code würde dann folgendermaßen aussehen: Sub ArrayWith() Dim astrNames(5) As String Dim intCounter As Integer Dim vntAny As Variant astrNames(0) = "Dan" astrNames(1) = "Reggie" astrNames(2) = "Chelsea" astrNames(3) = "Joshua" For Each vntAny In astrNames Debug.Print vntAny Next vntAny End Sub
Dieser Code deklariert eine Variable des Typs Variant mit der Bezeichnung vntAny. Statt eine Schleife mit Ubound als oberer Grenze zu verwenden, wird in diesem Fall das Konstrukt For Each...Next benutzt. Häufig wird es als lästig empfunden, dass die Elemente eines Datenfelds standardmäßig mit der Nummer Null beginnen. Glücklicherweise ermöglicht VBA Ihnen, sowohl die untere als auch die obere Grenze von Datenfeldern selbst festzulegen. Die entsprechende Syntax sieht folgendermaßen aus: Dir astrNames(1 to 6)
884
24.4.2
Kapitel 24: Fortgeschrittene VBA-Techniken
Dynamische Datenfelder deklarieren und verwenden
Oftmals wissen Sie nicht im Voraus, wie viele Elemente Ihr Datenfeld umfassen soll. In einem solchen Fall sollten Sie das Deklarieren eines dynamischen Datenfelds in Betracht ziehen. Die Größe dynamischer Datenfelder kann zur Laufzeit verändert werden. Das Verwenden von Datenfeldern dieser Art kann die Effizienz Ihres Codes steigern, da VBA für sämtliche Elemente fester Datenfelder bereits im Voraus Speicher reserviert, auch wenn einige dieser Elemente gar nicht benötigt werden. Falls Sie sich nicht sicher sind, wie viele Elemente Ihr Datenfeld enthalten wird, kann es äußerst ineffizient sein, prophylaktisch größere Mengen an Speicher zu reservieren. Um ein dynamisches Datenfeld zu erstellen, deklarieren Sie es ohne Angabe der oberen Grenze. Dazu lassen Sie beim Deklarieren einfach die Zahl zwischen den Klammern weg. Das folgende Beispiel veranschaulicht dies: Sub DynamicArray() Dim astrNames() As String Dim intCounter As Integer Dim vntAny As Variant ReDim astrNames(1) astrNames(0) = "Dan" astrNames(1) = "Reggie" For Each vntAny In astrNames Debug.Print vntAny Next vntAny End Sub
Das Verändern der Datenfeldgröße kann jedoch zu Problemen führen: Sub ResizeDynamic() Dim astrNames() As String Dim intCounter As Integer Dim vntAny As Variant ReDim astrNames(1) astrNames(0) = "Dan" astrNames(1) = "Reggie" ReDim astrNames(3) astrNames(2) = "Chelsea" astrNames(3) = "Joshua" For Each vntAny In astrNames Debug.Print vntAny Next vntAny End Sub
Möglicherweise gehen Sie davon aus, dass alle vier Elemente Daten enthalten. Dies ist jedoch nicht der Fall. Stattdessen initialisiert die Anweisung ReDim die Elemente neu und nur das zweite und dritte Element enthalten Werte. Mit Hilfe des Schlüsselworts Preserve kann dieses Problem vermieden werden. Der folgende Code funktioniert etwas anders:
Mit Datenfeldern arbeiten
885
Sub ResizePreserve() Dim astrNames() As String Dim intCounter As Integer Dim vntAny As Variant ReDim astrNames(1) astrNames(0) = "Dan" astrNames(1) = "Reggie" ReDim Preserve astrNames(3) astrNames(2) = "Chelsea" astrNames(3) = "Joshua" For Each vntAny In astrNames Debug.Print vntAny Next vntAny End Sub
In diesem Beispiel sind sämtliche im Datenfeld gespeicherten Werte bereits vordefiniert. Auch das Schlüsselwort Preserve wirft einige Probleme auf. Während des ReDim-Vorgangs kann es zeitweilig sehr viel Hauptspeicher beanspruchen, da VBA eine Kopie des ursprünglichen Datenfelds erzeugt. Letzteres wird erst gelöscht, nachdem all seine Werte in ein neues Datenfeld kopiert wurden. Wenn Sie mit sehr großen Datenfeldern arbeiten und nur über verhältnismäßig wenig Hauptspeicher verfügen, kann es bei der Verwendung des Schlüsselworts Preserve zu Schwierigkeiten kommen. Die unterschiedlichen Arten von Datenfeldern weisen jeweils eigene Vor- und Nachteile auf. Als VBA-Entwickler haben Sie die Möglichkeit, sich die für die jeweilige Situation am besten geeignete Art von Datenfeld auszusuchen. Feste Datenfelder sollten verwendet werden, wenn die Anzahl der benötigten Elemente kaum variiert, während bei stark variierender Anzahl dynamische Datenfelder besser geeignet sind, falls ausreichend Speicherplatz zur Verfügung steht, um auch die Größe der größtmöglichen Datenfelder noch verändern zu können.
24.4.3
Datenfelder als Parameter übergeben
Vielen Entwicklern ist nicht bekannt, dass auch Datenfelder als Parameter an Funktionen oder Unterroutinen übergeben werden können. Der folgende Code veranschaulicht diese Vorgehensweise: Sub PassArray() Dim astrNames(5) As String Dim intCounter As Integer Call FillNames(astrNames) For intCounter = 0 To UBound(astrNames) Debug.Print astrNames(intCounter) Next intCounter
886
Kapitel 24: Fortgeschrittene VBA-Techniken
End Sub Sub FillNames(varNameList As Variant) varNameList(0) = "Alison" varNameList(1) = "Dan" varNameList(2) = "Alexis" varNameList(3) = "Joshua" varNameList(4) = "Amanda" varNameList(5) = "Brianna" End Sub
Am Anfang dieses Codes wird zunächst ein festes Datenfeld astrNames deklariert. Anschließend wird die Routine FillNames aufgerufen und dabei ein Datenfeld als Parameter übergeben, dessen Elementen Werte zugewiesen werden sollen. Zum Schluss wird der Inhalt sämtlicher Elemente im Rahmen einer Schleife ausgegeben.
24.5
Fortgeschrittene Methoden der Verwendung von Funktionen
Die in diesem Abschnitt erläuterten fortgeschrittenen Methoden der Funktionsprogrammierung erlauben Ihnen das Erstellen effizienter Prozeduren. Als erstes lernen sie den Unterschied zwischen Funktionsaufrufen mit Adress- und Wertübergabe kennen und erfahren, dass die standardmäßige Methode der Parameterübergabe nicht immer die vernünftigste ist. Der zweite Teil dieses Abschnitts zeigt, wie Sie mit optionalen Parametern umgehen, die Ihren Funktionen zusätzliche Flexibilität verleihen. Diese Möglichkeit erlaubt Ihnen das Auslassen von Parametern, während benannte Parameter im Wesentlichen die Lesbarkeit Ihres Codes verbessern. Bei der Benutzung benannter Parameter brauchen Sie sich außerdem nicht mehr darum zu kümmern, in welcher Reihenfolge die Parameter erscheinen. Nach dem Lesen dieses Abschnitts werden Sie in der Lage sein, stabilere und einfacher zu benutzende Funktionen zu schreiben.
24.5.1
Adressübergabe im Vergleich zur Wertübergabe
In Access werden Parameter standardmäßig als Adresse übergeben. Dies bedeutet, dass die aufgerufene Funktion nicht den Wert, sondern die Adresse der Variablen im Speicher erhält. Dieser Vorgang kann am besten durch ein entsprechendes Beispiel veranschaulicht werden: Sub PassByRef() Dim strFirstName As String Dim strLastName As String strFirstName = "Alison" strLastName = "Balter"
Fortgeschrittene Methoden der Verwendung von Funktionen
887
Call FuncByRef(strFirstName, strLastName) Debug.Print strFirstName Debug.Print strLastName End Sub
Möglicherweise hätten Sie nicht erwartet, dass die Debug.Print-Anweisungen in der Unterroutine PassByRef das Ausgeben der Zeichenketten "Bill" und "Gates" bewirken. Dies liegt daran, dass strFirstParm tatsächlich ein Verweis auf strFirstName und strSecondParm eine Referenz auf strSecondParm ist. Dies widerspricht allerdings dem Konzept der in sich geschlossenen Verarbeitung, welches besagt, dass eine Variable nicht außerhalb jener Routine verändert werden kann, in der sie deklariert wurde. Durch den folgenden Code wird dieses Problem beseitigt: Sub PassByVal() Dim strFirstName As String Dim strLastName As String strFirstName = "Alison" strLastName = "Balter" Call FuncByVal(strFirstName, strLastName) Debug.Print strFirstName Debug.Print strLastName End Sub
Diese Unterroutine FuncByVal übernimmt die Parameter als Wert, was bedeutet, dass FuncByVal lediglich die Werte in StrFirstName und strLastName übergeben werden. auf diese Weise wird das Verändern dieser Variablen in FuncByVal möglich gemacht. Die Anweisung Debug.Print gibt also »Alison« und »Balter« aus. Das folgende Beispiel veranschaulicht, weshalb es sinnvoll sein kann, Parameter als Adresse zu übergeben: Sub GoodPassByRef() Dim blnSuccess As Boolean Dim strName As String strName = "Microsoft" blnSuccess = GoodFunc(strName) Debug.Print blnSuccess End Sub Function GoodFunc(strName As String) If Len(strName) Then strName = UCase$(strName) GoodFunc = True Else GoodFunc = False End If End Function
888
Kapitel 24: Fortgeschrittene VBA-Techniken
Im Grunde soll die Funktion GoodFunc zwei Werte zurückgeben. Sie soll nicht nur die an sie übergebene Zeichenkette in Großbuchstaben liefern, sondern zusätzlich eine Bestätigung der erfolgreichen Verarbeitung. Da eine Funktion nur einen Wert zurückgeben kann, müssen Sie in der Lage sein, den Wert von strName innerhalb der Funktion zu verändern. Solange Ihnen bewusst ist, was Sie tun, treten bei der Adressübergabe von Parametern keine Probleme auf. Ich bediene mich einer speziellen Methode, um Lesern meines Codes zu verdeutlichen, ob ich Parameter als Adresse oder als Wert übergebe. Bei der Adressübergabe verwende ich für den Parameter den gleichen Namen, mit dem auch die Variable der ursprünglichen Routine bezeichnet ist. Wenn ich hingegen Parameter als Wert übergebe, benutze ich in der aufgerufenen Prozedur für die Variable einen anderen Namen als in der aufrufenden Routine. Nachdem Sie diesen Abschnitt gelesen haben, fragen Sie sich möglicherweise, ob Parameter als Adresse oder eher als Wert übergeben werden sollten. Gemäß des Prinzips der geschlossenen Verarbeitung ist es besser, Parameter als Wert zu übergeben, doch Code, der von der Adressübergabe Gebrauch macht, kann schneller ausgeführt werden. Solange Sie und die Programmierer, mit denen Sie zusammenarbeiten, sich der Probleme bewusst sind, die sich aus der Adressübergabe ergeben können, bin ich der Meinung, dass Parameter als Adresse übergeben werden sollten.
24.5.2
Optionale Parameter: Funktionen flexibel gestalten
Access 97 und Access 2000 erlauben Ihnen das Verwenden optionaler Parameter. Sie brauchen also nicht immer genau zu wissen, wie viele Parameter übergeben werden. Der zweite und dritte Parameter der Funktion ReturnInit im folgenden Code sind optional. Die Funktion ermittelt, welche Parameter tatsächlich angegeben wurden und reagiert entsprechend: Function ReturnInit(ByVal strFName As String, _ Optional ByVal strMI, Optional ByVal strLName) If IsMissing(strMI) Then strMI = InputBox("Enter Middle Initial") End If If IsMissing(strLName) Then strLName = InputBox("Enter Last Name") End If ReturnInit = strLName & "," & strFName & " " & strMI End Function
Diese Funktion könnte folgendermaßen aufgerufen werden: strName = ReturnInit("Bill",,"Gates")
Fortgeschrittene Methoden der Verwendung von Funktionen
889
Wie Sie sehen, wurde hier der zweite Parameter weggelassen. Obgleich in älteren Versionen von Access ein Compiler-Fehler ausgelöst worden wäre, kann dieser Code problemlos kompiliert und ausgeführt werden. Die in Access integrierte Funktion IsMissing ermittelt, ob ein Parameter übergeben wurde oder nicht. Sobald das Fehlen eines Parameters festgestellt wird, wird auf die von Ihnen vorzugebende Weise reagiert. Im folgenden Beispiel fordert die Funktion den Benutzer auf, die fehlende Information einzugeben, doch es gibt noch weitere Möglichkeiten:
Fehlende Parameter können durch Standardwerte ersetzt werden. Sie können Ihren Code in angemessener Weise auf fehlende Parameter reagieren lassen. Listing 24.1 und Listing 24.2 veranschaulichen die Durchführung dieser beiden Alternativen. Listing 24.1:
Einfügen von Standardwerten bei fehlenden Parametern
Function ReturnInit2(ByVal strFName As String, _ Optional ByVal strMI, Optional ByVal strLName) If IsMissing(strMI) Then strMI = "B" End If If IsMissing(strLName) Then strLName = "Jones" End If ReturnInit2 = strLName & "," & strFName & " " & strMI End Function
In diesem Beispiel wird ein »B« als Standardwert für die mittlere Initiale verwendet und der Nachname lautet standardmäßig Jones. Schauen Sie sich nun Listing 24.2 an, welches eine weitere Möglichkeit des Umgangs mit fehlenden Parametern illustriert. Listing 24.2:
Berücksichtigen fehlender Parameter
Function ReturnInit3(ByVal strFName As String, _ Optional ByVal strMI, Optional ByVal strLName) Dim strResult As String If IsMissing(strMI) And IsMissing(strLName) Then ReturnInit3 = strFName ElseIf IsMissing(strMI) Then ReturnInit3 = strLName & ", " & strFName ElseIf IsMissing(strLName) Then ReturnInit3 = strFName & " " & strMI Else ReturnInit3 = strLName & "," & strFName & " " & strMI
890
Kapitel 24: Fortgeschrittene VBA-Techniken
End If End Function
In diesem Beispiel wird der Rückgabewert in Abhängigkeit von den jeweils übergebenen Parametern verändert. Falls keiner der optionalen Parameter angegeben wurde, wird lediglich der Vorname angezeigt. Werden der Vorname und die mittlere Initiale übergeben, so umfasst der Rückgabewert den Vornamen, gefolgt von der mittleren Initiale. Wenn ausschließlich Vor- und Nachname angegeben werden, enthält der Rückgabewert den Nachnamen, ein Komma und den Vornamen. Bei Übergabe aller drei Parameter liefert die Funktion den Nachnamen, ein Komma, ein Leerzeichen, den Vornamen, noch ein Leerzeichen sowie zuletzt die mittlere Initiale.
24.5.3
Benannte Parameter: Beseitigen des Erfordernisses, Kommas zu zählen
In allen bislang dargestellten Beispielen wurden die Parameter positionsgebunden an Prozeduren übergeben. Benannte Parameter ermöglichen Ihnen das Angeben von Parametern in beliebiger Reihenfolge. Besonders für Prozeduren, an die optionale Parameter übergeben werden können, ist dies sehr nützlich. Schauen Sie sich das folgende Beispiel an: strName = ReturnInit3("Bill",,"Gates")
Da der zweite Parameter nicht angegeben wird und die Parameter positionsgebunden übergeben werden, muss als Platzhalter für den optionalen zweiten Parameter ein Komma angegeben werden. Dieses Vorgehen ist recht umständlich, sobald Sie mit mehreren optionalen Parametern arbeiten. Im folgenden Beispiel erfolgt die Übergabe der Parameter auf eine wesentlich einfachere Weise, die außerdem erheblich aussagekräftiger ist: strName = ReturnInit3(strFName:= "Bill",strLName:= "Gates")
Wie Sie dem folgenden Beispiel entnehmen können, spielt die Reihenfolge, in der die Parameter angegeben werden, bei der Übergabe durch den Namen keine Rolle: strName = ReturnInit3(strLName:= "Gates",strFName:="Bill")
Dieser Aufruf der Funktion ReturnInit3 bewirkt dasselbe Resultat wie der Aufruf der gleichen Funktion im vorhergehenden Beispiel. Bei der Verwendung benannter Parameter müssen die Parameternamen jeweils exakt mit dem in der aufgerufenen Funktion angegebenen Namen übereinstimmen. Sie müssen die aufzurufende Funktion also genau kennen. Das Benutzen benannter Parameter birgt einen weiteren wichtigen Nachteil: Sobald der Autor der aufzurufenden Funktion den Namen eines Parameters ändert, werden sämtliche Aufrufe dieser Funktion fehlschlagen, die unter Verwendung benannter Parameter erfolgen.
Mit Empty und Null arbeiten
24.6
891
Mit Empty und Null arbeiten
Empty und Null sind Werte, die ausschließlich Variablen des Typs Variant zugewiesen
werden können. Sie unterscheiden sich voneinander und entsprechen weder dem Wert Null noch einer leeren Zeichenkette. Nur bei Variablen des Typs Variant kann unterschieden werden, ob sie den Wert Null, eine leere Zeichenkette, Empty oder Null enthalten.
24.6.1
Mit Empty arbeiten
Variant-Variablen werden mit dem Wert Empty initialisiert. Sie werden häufiger wissen wollen, ob in einer Variant-Variablen bereits ein Wert abgelegt wurde. Wenn einer solchen Variablen bislang kein Wert zugewiesen wurde, weist sie den Wert Empty auf. Wie bereits erwähnt, ist der Wert Empty von den Werten Null, Null und einer leeren Zeichenkette zu unterscheiden.
Innerhalb einer Laufzeitumgebung ist es sehr wichtig, feststellen zu können, ob eine Variable den Wert Empty enthält. Dies können Sie mit der Funktion IsEmpty bewerkstelligen. Im folgenden Beispiel wird ermittelt, ob eine bestimmte String-Variable den Wert Empty aufweist: Sub StringVar() Dim strName As String Debug.Print IsEmpty(strName) 'Gibt False aus Debug.Print strName = "" 'Gibt True aus End Sub
Die Anweisung Debug.Print gibt den Wert False aus. Diese Variable enthält eine leere Zeichenkette, da sie als String-Variable initialisiert wurde. Variablen des Typs String werden grundsätzlich mit einer leeren Zeichenkette initialisiert. Im folgenden Beispiel wird überprüft, ob eine Variant-Variable den Wert Empty enthält: Sub EmptyVar() Dim vntName As Variant Debug.Print IsEmpty(vntName) vntName = "" Debug.Print IsEmpty(vntName) vntName = Empty Debug.Print IsEmpty(vntName) End Sub
Sobald einer Variant-Variablen irgendein Wert zugewiesen wird (dies kann auch eine Null, Null oder eine leere Zeichenkette sein), enthält sie nicht mehr den Wert Empty. Nur wenn dieser Variablen explizit das Schlüsselwort Empty zugewiesen wird, weist sie wieder diesen Wert auf.
892
24.6.2
Kapitel 24: Fortgeschrittene VBA-Techniken
Mit Null arbeiten
Null ist ein spezieller Wert, der auf unbekannte oder fehlende Daten hinweist. Null stimmt weder mit Empty noch mit einem anderen Wert überein. Nur Variablen des Typs Variant können den speziellen Wert Null annehmen.
Häufig werden Sie wissen wollen, ob bestimmte Felder oder Steuerelemente bislang noch nicht initialisiert wurden. Nicht initialisierte Felder und Steuerelemente enthalten den Wert Null. Indem Sie Felder oder Steuerelemente auf Null überprüfen, können Sie feststellen, ob diese Werte enthalten. Wenn Sie ermitteln möchten, ob sämtliche Felder und Steuerelemente Ihrer Anwendung Daten enthalten, müssen Sie diese jeweils auf Null überprüfen. Dies kann mit der Funktion IsNull bewerkstelligt werden: Sub NullVar() Dim vntName As Variant Debug.Print IsEmpty(vntName) Debug.Print IsNull(vntName) vntName = Null Debug.Print IsNull(vntName) End Sub
Beachten Sie, dass vntName nur dann den Wert Null aufweist, wenn der Variablen dieser Wert explizit zugewiesen wurde. Der Wert Null ist nicht nur im Zusammenhang mit Variablen von Interesse, sondern auch für Felder in Datenbanken. Wenn ein Feld keinen Standardwert hat und bislang keine Daten in das Feld eingegeben wurden, enthält es den Wert Null. In Abfragen können Sie das Kriterium "Is Null" verwenden, um alle Datensätze zu finden, die Felder enthalten, welche den Wert Null aufweisen. Auch beim Umgang mit Datensatzgruppen (diese wurden bereits in Kapitel 12 erörtert) können Sie die Funktion IsNull verwenden, um festzustellen, ob ein Feld den Wert Null enthält. Es folgt ein Beispiel: Sub LoopProjects() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.Open "tblProjects", CurrentProject.Connection Do Until rst.EOF Debug.Print rst!ProjectID, rst!ProjectName If IsNull(rst!ProjectBeginDate) Then Debug.Print "Project Begin Date Contains No Value!!" End If rst.MoveNext Loop End Sub
Mit Empty und Null arbeiten
893
Sie können auch die etwas kürzere Funktion Nz verwenden, um Null-Werte aufzufinden und entsprechende Meldungen auszugeben: Sub LoopProjects2() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.Open "tblProjects", CurrentProject.Connection Do Until rst.EOF Debug.Print rst!ProjectID, rst!ProjectName Debug.Print Nz(rst!ProjectBeginDate, _ "Project Begin Date Contains No Value!!") rst.MoveNext Loop End Sub
Sämtliche Konzepte des Umgangs mit Datensatzgruppen wurden bereits in Kapitel 12 erörtert. An dieser Stelle ist lediglich entscheidend, dass der Code sämtliche Datensätze von tblProjects durchläuft. Die Funktion IsNull wird benutzt, um festzustellen, ob das Feld ProjectBeginDate den Wert Null enthält. Wenn dies tatsächlich der Fall ist, erscheint im gegenwärtig aktiven Fenster eine Warnung. Es folgt ein weiteres Beispiel: Private Sub Form_Current() Dim ctl As Control For Each ctl In Controls If TypeOf ctl Is TextBox Then If IsNull(ctl.Value) Then ctl.BackColor = vbCyan Else ctl.BackColor = vbWhite End If End If Next ctl End Sub
Der Code dieses Beispiels, der im Formular frmProjects in der Datenbank CHAP24.MDB zu finden ist, durchläuft jedes Steuerelement des aktuellen Formulars. Wenn es sich bei dem Steuerelement um ein Textfeld handelt, überprüft die Routine, ob es den Wert Null aufweist. Gegebenenfalls wird die Eigenschaft BackColor des Textfelds auf vbCyan gesetzt. Ansonsten wird eine weiße Hintergrundfarbe zugewiesen. Die folgenden drei Eigenarten von Null sollten Ihnen bekannt sein:
Ausdrücke, die den Wert Null enthalten, ergeben stets Null (siehe nächstes Beispiel).
Eine Funktion, an die der Wert Null übergeben wird, gibt den Wert Null auch wieder zurück.
894
Kapitel 24: Fortgeschrittene VBA-Techniken
Null-Werte verbreiten sich durch integrierte Funktionen, die Variant-Variablen zurückgeben. Das folgende Beispiel zeigt, wie sich Null-Werte verbreiten: Sub PropNulls() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.Open "tblProjects", CurrentProject.Connection Do Until rst.EOF Debug.Print rst!ProjectID, rst!ProjectBeginDate + 1 rst.MoveNext Loop End Sub
Abbildung 24.3 veranschaulicht die Auswirkungen dieser Routine auf eine Tabelle, in welcher der erste und dritte Datensatz jeweils den Wert Null enthält. Beachten Sie, dass diese Berechnung für jene Datensätze den Wert Null ergibt, weil sie ihn bereits enthalten.
Abbildung 24.3: Das Ergebnis der Routine PropNulls
Beachten Sie, in welcher Weise sich das Ergebnis ändert, wenn der Wert des Felds gleich Empty ist: Sub EmptyVersusNull() Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.Open "tblProjects", CurrentProject.Connection Do Until rst.EOF Debug.Print rst!ProjectID, rst!PurchaseOrderNumber + "Hello" rst.MoveNext Loop End Sub
In diesem Beispiel enthält die Tabelle tblProjects vier Datensätze. Das Feld PurchaseOrderNumber enthält im ersten Datensatz den Wert Null und im dritten den Wert Empty. Beachten Sie die unterschiedlichen Auswirkungen dieser beiden Werte (siehe Abbildung 24.4).
Mit Empty und Null arbeiten
895
Abbildung 24.4: Das Ergebnis des Ausführens der Routine EmptyVersusNull
Beim Betrachten von Abbildung 24.4 sehen Sie, dass für den ersten Datensatz der Wert Null und für den dritten die Zeichenkette Hello ausgegeben wird. In der Routine EmptyVersusNull wird ein numerischer Operator verwendet (+). Wie bereits erwähnt, ist das Ergebnis einer Berechnung, an der ein Null-Wert beteiligt ist, stets Null. Bei Zeichenketten können Sie statt eines Pluszeichens ein kaufmännisches Und (&) verwenden, um dieses Problem zu umgehen. In Abbildung 24.5 sehen Sie das Ergebnis des gleichen Codes, bei dem die Zeichenketten jedoch statt mit + durch & miteinander verknüpft wurden. Offensichtlich ergeben sich aus derartigen Verknüpfungen von Zeichenketten keine Null-Werte. Abbildung 24.5: Das Ergebnis des Änderns des Pluszeichens (+) in der Routine EmptyVersusNull in ein kaufmännisches Und (&)
Häufig werden allgemeine Routinen erstellt, die beliebige Werte entgegennehmen, um zu überprüfen, ob es sich bei dem übergebenen Wert um Null handelt. Als Rückgabewert werden ausschließlich von Null abweichende Werte verwendet. Die nachfolgend dargestellte Funktion CvNulls ist ein Beispiel für eine solche Routine: Function CvNulls(vntVar1 As Variant, vntVar2 As Variant) _ As Variant CvNulls = IIf(IsNull(vntVar1), vntVar2, vntVar1) End Function
Diese Routine würde folgendermaßen aufgerufen werden: Sub TestForNull(vntSalary As Variant, vntCommission As Variant) Dim curTotal As Currency curTotal = CvNulls(vntSalary, 0) + CvNulls(vntCommission, 0) MsgBox curTotal End Sub
896
Kapitel 24: Fortgeschrittene VBA-Techniken
An die Routine TestForNull sind zwei Parameter zu übergeben: salary und commission. Beide Werte werden addiert, um die Summe der Verkäufe zuzüglich der Provisionen zu ermitteln. Wenn einer der beiden Parameter den Wert Null aufweist, ergibt auch der Ausdruck den Wert Null. Dieses Problem wird durch die Funktion CvNulls beseitigt, an die ebenfalls zwei Parameter zu übergeben sind. Der erste Parameter ist die auf Null zu überprüfende Variable und als zweiter Parameter dient jener Wert, den die Funktion zurückgeben soll, falls der erste Parameter den Wert Null aufweist. Die Routine kombiniert die Funktionen Immediate If(IIf) und IsNull, welche der Auswertung des ersten Parameters und der Rückgabe des entsprechenden Werts dienen. Wenn Sie den Wert Null einer Variablen einfach durch einen anderen ersetzen wollen, können Sie dies statt mit einer benutzerdefinierten auch mit der íntegrierten Funktion NZ bewerkstelligen. Wenn Sie weiter reichende Möglichkeiten brauchen, eignet sich eine benutzerdefinierte Funktion jedoch besser.
24.7
Benutzerdefinierte Auflistungen erstellen und verwenden
In diesem Kapitel habe ich bereits einige Schwierigkeiten erörtert, die im Zusammenhang mit Datenfeldern auftreten können. Falls Sie nicht genau wissen, wie viele Elemente ein Datenfeld enthalten wird, dann könnten feste Datenfelder unnötig viel Speicherplatz einnehmen. Andererseits ist auch das Verändern der Größe dynamischer Datenfelder recht aufwendig. Schließlich müssen sämtliche Elemente eines Datenfelds aufeinander folgend sein und der willkürliche Bezeichner für Datenfeldelemente ist bedeutungslos. Benutzerdefinierte Auflistungen schaffen hier Abhilfe. Solche Auflistungen können sowohl Werte als auch Objekte enthalten und es können auf einfache Weise Elemente hinzugefügt oder entfernt werden. Jedes Element einer Auflistung erhält einen eindeutigen und aussagekräftigen Namen. Benutzerdefinierte Auflistungen sind Datenfeldern somit sehr ähnlich, weisen jedoch einige zusätzliche Vorteile auf:
Speicherbereiche für Auflistungen werden dynamisch reserviert. Sie beanspruchen stets nur den jeweils erforderlichen Speicherplatz. Die Größe von Datenfeldern muss hingegen im Voraus bestimmt oder zur Laufzeit neu festgelegt werden. Wenn die Größe eines Datenfelds verändert wird, legt Access dafür zunächst eine Kopie des Datenfelds an und nimmt somit umfangreiche Ressourcen in Anspruch. Indem Sie benutzerdefinierte Auflistungen verwenden, können Sie diese Beanspruchung zusätzlicher Ressourcen vermeiden.
Einer Auflistung ist die Anzahl der in ihr enthaltenen Elemente stets bekannt und Elemente können auf einfache Weise hinzugefügt oder entfernt werden.
Benutzerdefinierte Auflistungen erstellen und verwenden
897
Die Datentypen der Elemente einer Auflistung können unterschiedlich sein. Einzelne Elemente können beliebigen Elementen einer Auflistung hinzugefügt werden. Die Listings der in diesem Kapitel dargestellten Beispiele finden Sie im Modul basCollection der Datenbank Chap24Ex.
24.7.1
Eine Auflistung erstellen
Eine Auflistung wird mit Hilfe eines Collection-Objekts erstellt. Sobald ein Auflistungsobjekt deklariert wurde, können ihm Elemente hinzugefügt werden. Der für das Erstellen einer benutzerdefinierten Auflistung erforderliche Code sieht folgendermaßen aus: Dim colNames as Collection
24.7.2
Einer Auflistung Elemente hinzufügen
Die Methode Add des Auflistungsobjekts wird verwendet, um einer benutzerdefinierten Auflistung Elemente hinzuzufügen. Sie übernimmt als ersten Parameter eine Referenz auf einen Wert oder ein Objekt und als zweiten einen innerhalb der Auflistung eindeutigen Schlüssel für das Element. Die Methode Add wird folgendermaßen verwendet: colNames.Add "Alexis", "Alexis"
Der oben angegebene Code fügt einer Auflistung colNames ein Element mit der Bezeichnung Alexis hinzu. Im folgenden Code-Beispiel wird die Auflistung colNames zunächst deklariert und dann erstellt. Anschließend werden ihr einige Namen hinzugefügt. Sub AddToCollection() Dim colNames As Collection Set colNames = New Collection colNames.Add "Alison", "Alison" colNames.Add "Dan", "Dan" colNames.Add "Alexis", "Alexis" colNames.Add "Joshua", "Joshua" colNames.Add "Amanda", "Amanda" colNames.Add "Brianna", "Brianna" End Sub
898
Kapitel 24: Fortgeschrittene VBA-Techniken
Im Gegensatz zu fast allen anderen Datenfeldern oder Auflistungen in VBA werden Elemente benutzerdefinierter Auflistungen mit Eins anstatt mit Null beginnend nummeriert. Dies bedeutet eine erhebliche Umstellung, falls Sie bislang davon ausgegangen sind, dass Datenfelder und Auflistungen gleichermaßen mit dem nullten Element beginnen.
24.7.3
Auf ein Element einer Auflistung zugreifen
Nachdem einer Auflistung Elemente hinzugefügt wurden, wird die Methode Item verwendet, um entweder über den zugeordneten Schlüssel oder über die jeweilige Nummer auf die Elemente zuzugreifen. Folgendermaßen kann mit Hilfe der Nummer auf ein Element einer Auflistung zugegriffen werden: Debug.Print colNames.Item(1)
Da Item die Standardmethode des Auflistungsobjekts ist, kann dieser Code auch kürzer formuliert werden: Debug.Print colNames(1)
Ich spreche Elemente von Auflistungen bevorzugt über deren eindeutigen Schlüssel an. Der entsprechende Code sieht dann wie folgt aus: Debug.Print colNames("Alexis")
24.7.4
Elemente aus einer Auflistung entfernen
Die Methode Remove des Collection-Objekts wird verwendet, um Elemente aus der Auflistung zu entfernen. Die entsprechende Syntax sieht folgendermaßen aus: colNames.Remove 2
Die oben dargestellte Zeile würde das Entfernen des zweiten Elements der Auflistung bewirken. Unter Verwendung des Schlüssels sähe der Code so aus: colNames.Remove "Brianna"
Ihnen stehen zwei einfache Möglichkeiten zur Verfügung, sämtliche Elemente einer Auflistung auf einmal zu entfernen: Set colNames = New Collection
oder Set colNames = Nothing
Kompilieroptionen verstehen und effektiv nutzen
24.7.5
899
Die Elemente einer Auflistung durchlaufen
Für das Durchlaufen aller Elemente einer Auflistung wird die For...Each-Schleife verwendet. Der entsprechende Code sieht dann so aus: Sub IterateCollection() Dim colNames As Collection Dim varItem As Variant Set colNames = New Collection colNames.Add colNames.Add colNames.Add colNames.Add colNames.Add colNames.Add
"Alison", "Alison" "Dan", "Dan" "Alexis", "Alexis" "Joshua", "Joshua" "Amanda", "Amanda" "Brianna", "Brianna"
For Each varItem In colNames Debug.Print colNames(varItem) Next varItem End Sub
Beachten Sie, dass zusätzlich zur Auflistungsvariablen eine Variable vom Typ Variant als Zähler für die For...Each-Schleife deklariert wird, welche dem Durchlaufen der Elemente der Auflistung dient. Beachten Sie außerdem, dass die Variant-Variable innerhalb der For...Each-Schleife als Index für Zugriffe auf einzelne Elemente der Auflistung verwendet wird.
24.8
Kompilieroptionen verstehen und effektiv nutzen
Microsoft Access bietet Ihnen für das Kompilieren verschiedene Möglichkeiten. Wenn Sie diese Alternativen kennen, können Sie festlegen, ob die Geschwindigkeit des Kompilierens oder das Auffinden von Kompilierfehlern wichtiger ist.
24.8.1
Bei Bedarf kompilieren
Standardmäßig kompiliert VBA Ihren Code nur, wenn Änderungen an dem jeweiligen Modul vorgenommen wurden oder eine Prozedur eines Moduls von einem anderen Modul aus aufgerufen wird. Diese Einstellung kann den Kompiliervorgang zwar erheblich beschleunigen, birgt jedoch das Risiko unentdeckter Zeitbomben, die sich irgendwo innerhalb Ihrer Anwendung verbergen können. Beispielsweise kann es vorkommen, dass Sie ein bestimmtes Formular öffnen, einige einfache Modifikationen daran vornehmen, die Änderungen speichern und das For-
900
Kapitel 24: Fortgeschrittene VBA-Techniken
mular schließen. Mit einigen anderen Formularen verfahren Sie genauso. Außerdem öffnen Sie einige Module, um ebenfalls einige einfache Änderungen an ihnen durchzuführen. Bei der Fehlersuche vergessen Sie, ein oder mehrere Formulare bzw. Module zu testen. Falls die Option KOMPILIEREN BEI BEDARF auf True gesetzt ist (dies ist der Standardwert), können Fehler unbemerkt bleiben, bis der fehlerhafte Code tatsächlich verwendet wird. Um die Option KOMPILIEREN BEI BEDARF zu deaktivieren, wählen Sie zunächst innerhalb des VBE im Menü EXTRAS den Eintrag OPTIONEN aus. Anschließend wechseln Sie zur Registerkarte ALLGEMEIN und deaktivieren darauf das Kontrollkästchen BEI BEDARF im Abschnitt KOMPILIEREN. Möglicherweise werden Sie danach feststellen, dass das Kompilieren Ihres Codes etwas länger dauert, doch es lohnt sich, diesen zusätzlichen Zeitaufwand in Kauf zu nehmen.
24.9
Code-Module im- und exportieren
Der VBE von Access 2000 ermöglicht es Ihnen, Code- und Formularmodule in eine Datenbank zu importieren oder aus ihr zu exportieren. Code- und Formularmodule können Sie folgendermaßen exportieren: 1. Aktivieren Sie den VBE. 2. Klicken Sie innerhalb des Projekt-Explorers mit der rechten Maustaste auf das zu exportierende Objekt. 3. Wählen Sie DATEI EXPORTIEREN.
EXPORTIEREN.
Anschließend erscheint das Dialogfeld DATEI
4. Geben Sie für die zu exportierende Datei einen Ort und einen Namen an und klicken Sie auf SPEICHERN. Module werden stets als ASCII-Dateien exportiert. Solche Textdateien können Sie in andere Microsoft Access-Datenbanken, in sonstige Microsoft Office-Produkte (z.B. Microsoft Excel) oder in ein Visual Basic-Projekt importieren. Beim Exportieren eines Formularmoduls wird lediglich das dem Formular zu Grunde liegende Klassenmodul exportiert. Die visuellen Aspekte des Formulars bleiben beim Exportieren unberücksichtigt. So wie Sie eine Textdatei exportieren können, haben Sie auch die Möglichkeit, eine Textdatei zu importieren. Auf diese Weise können Sie einem Projekt ein bereits existierendes Modul oder Formular hinzufügen. Die Datei wird dazu kopiert und in die Datenbank importiert. Die ursprüngliche Datei bleibt dabei unverändert. Gehen Sie folgendermaßen vor, um eine Datei in Ihre Access-Datenbank zu importieren:
Mit Projekteigenschaften arbeiten
901
1. Aktivieren Sie den VBE. 2. Klicken Sie innerhalb des Projekt-Explorers mit der rechten Maustaste und wählen Sie DATEI IMPORTIEREN. Daraufhin erscheint das Dialogfeld DATEI IMPORTIEREN. 3. Suchen Sie nach der zu importierenden Datei und klicken Sie anschließend auf ÖFFNEN.
24.10 Mit Projekteigenschaften arbeiten Jedes Datenbankprojekt verfügt über Eigenschaften, die vom Benutzer zu definieren sind. Dazu gehören die folgenden:
der Projektname eine Beschreibung des Projekts der Name der zum Projekt gehörigen Hilfedatei die Kontext-ID des Projekts Argumente für bedingte Kompilierung ein dem Projekt zugeordnetes Kennwort Gehen Sie folgendermaßen vor, um Projekteigenschaften zu betrachten oder zu verändern: 1. Aktivieren Sie den VBE. 2. Wählen Sie im Menü EXTRAS die Option EIGENSCHAFTEN VON aus. Daraufhin erscheint das in Abbildung 24.6 dargestellte Dialogfeld PROJEKTEIGENSCHAFTEN. 3. Wechseln Sie zur Registerkarte ALLGEMEIN, um die allgemeinen Projekteigenschaften festzulegen oder zu verändern. 4. Auf der Registerkarte SCHUTZ können Sie für das VBA-Projekt ein Kennwort angeben. 5. Klicken Sie auf die Schaltfläche OK, damit die von Ihnen angegebenen Optionen angewendet werden. Sicherheitsoptionen werden erst nach dem Schließen und erneuten Öffnen der Datenbank wirksam. Die Schutzoptionen verdienen besondere Beachtung. Wenn Sie die Option PROJEKT ANZEIGE SPERREN auswählen, kann das VBA-Projekt nur noch von Personen betrachtet oder bearbeitet werden, denen das entsprechende Kennwort bekannt ist. Falls Sie diese Option nicht auswählen, kann das VBA-Projekt zwar von jedem betrachtet werden, doch das Verändern der Projekteigenschaften bleibt jenen vorbehalten, die das entsprechende Kennwort kennen.
FÜR DIE
902
Kapitel 24: Fortgeschrittene VBA-Techniken
Abbildung 24.6: Das Dialogfeld Projekteigenschaften
24.10.1 Für die Praxis Integrieren fortgeschrittener Techniken in die Zeit- und Abrechnungsanwendung In der Anwendung für das Zeit- und Abrechnungssystem werden alle Techniken, die Sie in diesem Kapitel gelernt haben, in die Praxis umgesetzt. Das folgende Beispiel veranschaulicht die Verwendung des Werts Null, integrierter Konstanten und Typstrukturen.
24.10.2 Beispiele für Null, das DoCmd-Objekt und integrierte Konstanten Die folgende Ereignisroutine dient der Betrachtung sämtlicher Projekte, die mit dem jeweils ausgewählten Kunden in Beziehung stehen. An ihr ist die Wichtigkeit der Fähigkeit des Umgangs mit Null-Werten und integrierten Konstanten erkennbar. Private Sub cmdProjects_Click() On Error GoTo Err_Projects_Click If IsNull(Me.txtClientID) Then MsgBox "Enter client information before viewing projects form." Else DoCmd.RunCommand Command:=acCmdSaveRecord DoCmd.OpenForm "frmProjects", , , "ClientID=" & Me.txtClientID End If Exit_Projects_Click: Exit Sub
Mit Projekteigenschaften arbeiten
903
Err_Projects_Click: MsgBox Err.Description Resume Exit_Projects_Click End Sub
Als erstes ruft die Routine eine Prozedur für die Fehlerbehandlung auf. (Weitere Einzelheiten zu diesem Thema finden Sie in Kapitel 14.) Anschließend wird mit Hilfe der IsNull-Funktion überprüft, ob eine Kundennummer eingegeben wurde. Wenn das Steuerelement txtClientID den Wert Null aufweist, gibt die Funktion IsNull den Wert True zurück. In diesem Fall wird eine Fehlermeldung angezeigt. Sollte das Steuerelement txtClientID einen von Null abweichenden Wert enthalten, so werden zwei Methoden auf das DoCmd-Objekt angewendet. Bei der ersten auf das DoCmd-Objekt angewendeten Methode handelt es sich um RunCommand. An diese Methode wird die Konstante übergeben, welche mit dem Namen jenes Menübefehls versehen ist, der ausgeführt werden soll. Durch die Verwendung integrierter Konstanten wird die Lesbarkeit dieses Codes erhöht und die Methode RunCommand vereinfacht das Aufrufen von Menübefehlen aus dem Code heraus erheblich. Als zweites wird die Methode OpenForm auf das DoCmd-Objekt angewendet, damit das Formular frmProjects geöffnet wird. Die beiden optionalen Parameter View und FilterName werden nicht angegeben und dem vierten Parameter mit dem Namen WhereCondition wird die Kundennummer zugewiesen, welche auch auf dem Kundenformular angezeigt wird.
24.10.3 Ein Beispiel für das Verwenden einer Typstruktur Innerhalb der Zeit- und Abrechnungsanwendung wird vielfach vorausgesetzt, dass die Unternehmensinformationen bereits in der Tabelle tblCompanyInfo erfasst sind. Es wäre ineffizient, die Daten jedesmal aus der Tabelle auszulesen, wenn sie von der Anwendung benötigt werden. Wesentlich effektiver wäre es, wenn diese Informationen nach dem Starten der Anwendung einmal gelesen und in einer Typstruktur gespeichert werden würden. Da sich die Daten dann stets im Hauptspeicher befinden, können Sie bei Bedarf jeweils rasch über sie verfügen. Sowohl das Definieren der Typstruktur als auch das Deklarieren einer auf der Typstruktur basierenden öffentlichen Variablen erfolgt im Deklarationsabschnitt eines Moduls. Dies sieht dann folgendermaßen aus: Type CompanyInfo SetUpID As Long CompanyName As String * 50 Address As String * 255 City As String * 50 StateProvince As String * 20 PostalCode As String * 20
904
Kapitel 24: Fortgeschrittene VBA-Techniken
Country As String * 50 PhoneNumber As String * 30 FaxNumber As String * 30 DefaultPaymentTerms As String * 255 DefaultInvoiceDescription As String End Type Public typCompanyInfo As CompanyInfo
Sobald das Kundenformular (Ihr Anfangsformular) zum ersten Mal geladen wird, erfolgt ein Aufruf einer Unterroutine. Diese Routine weist sämtlichen Elementen der Typstruktur Werte zu und ist folgendermaßen aufgebaut: Sub GetCompanyInfo() Dim rs As ADODB.Recordset Set db = CurrentDb Set rs = New ADODB.Recordset rs.Open "tblCompanyInfo, CurrentProject.Connection" typCompanyInfo.SetUpID = rs!SetUpID typCompanyInfo.CompanyName = rs!CompanyName typCompanyInfo.Address = rs!Address typCompanyInfo.City = rs!City typCompanyInfo.StateProvince = rs!StateProvince typCompanyInfo.PostalCode = rs!PostalCode typCompanyInfo.Country = rs!Country typCompanyInfo.PhoneNumber = rs!PhoneNumber typCompanyInfo.FaxNumber = rs!PhoneNumber rs.Close db.Close End Sub
Lassen Sie sich nicht von der Verarbeitung der Datensatzgruppe innerhalb dieses Beispiels verwirren, sondern beachten Sie, dass die Werte aller Felder des ersten (und einzigen) Datensatzes der Tabelle tblCompanyInfo den Elementen der globalen Typvariablen zugewiesen werden. Es folgt ein Beispiel für die Verwendung der Typvariablen: Sub PopulateControls() txtCompanyName.Value = Trim(typCompanyInfo.CompanyName) txtAddress.Value = Trim(typCompanyInfo.Address) txtCityStateZip.Value = Trim(typCompanyInfo.City) & ", " & _ Trim(typCompanyInfo.StateProvince) & _ " " & Format(Trim(typCompanyInfo.PostalCode), "!&&&&&-&&&&") txtPhoneFax.Value = "PHONE: " & _ Format(Trim(typCompanyInfo.PhoneNumber), "(&&&)&&&-&&&&") & _ " FAX: " & _ Format(Trim(typCompanyInfo.FaxNumber), "(&&&)&&&-&&&&") End Sub
Mit Projekteigenschaften arbeiten
905
Diese Routine wird vom Activate-Ereignis rptInvoice aufgerufen. Sie weist vier Steuerelementen des Formulars Unternehmensinformationen zu, die es aus der globalen Typvariablen bezieht.
ActiveX-Steuerelemente verwenden
Kapitel
Hier lesen Sie:
Wozu dienen ActiveX-Steuerelemente? ActiveX-Steuerelemente im Rahmen von Access 2000 verwenden Eigenschaften eines ActiveX-Steuerelements während des Entwurfs festlegen Behandlungsroutinen für die Ereignisse eines ActiveX-Steuerelements Das Kalender-Steuerelement verwenden Das Steuerelement UpDown verwenden Das Steuerelement StatusBar verwenden Das Common Dialog-Steuerelement Das RichText-Steuerelement verwenden Das TabStrip-Steuerelement verwenden Das Image List-Steuerelement verwenden Aspekte der Weitergabe und Lizenzierung
25.1
Wozu dienen ActiveX-Steuerelemente?
Ein besonderer Vorteil von Access 2000 ist dessen Erweiterbarkeit. Zusätzlich zu den im Rahmen von Access bereits standardmäßig verfügbaren Steuerelementen können Sie für Ihre Formulare auch ActiveX-Steuerelemente verwenden. Sie sind somit nicht auf die bereits vorhandenen Steuerelemente angewiesen, sondern können beispielsweise auch ActiveX-Steuerelemente von Drittanbietern benutzen.
908
Kapitel 25: ActiveX-Steuerelemente verwenden
Die zuvor als OLE-Steuerelemente bekannten Objekte wurden von Microsoft in ActiveX-Steuerelemente umbenannt. Sie können diese beiden Bezeichnungen als gleichwertig betrachten. ActiveX-Steuerelemente unterstützen die OLE 2.0-Architektur für benutzerdefinierte Steuerelemente und können die Leistungsfähigkeit von 32-Bit-Betriebssystemen ausschöpfen. Sie verfügen über eigenen Code sowie eigene Eigenschaften, Methoden und Ereignisse. Die Funktionalität eines ActiveX-Steuerelements wird in einer Datei mit der Erweiterung .OCX abgespeichert. Ein OCX-Steuerelement für Kalender wird bereits mit Microsoft Access ausgeliefert und zu den Werkzeugen der Microsoft Office 2000 Developer Edition (ODE) gehören weitere OCX-Steuerelemente. Zusätzliche OCX-Steuerelemente können über Drittanbieter wie FMS, Database Creations, Crescent, Sheridan, Far Point und viele andere bezogen werden. Es gibt zwei Arten von ActiveX-Steuerelementen. Die erste Art ist sowohl zur Entwurfs- als auch zur Laufzeit sichtbar. Nachdem einem Formular ein solches Steuerelement hinzugefügt wurde, stellt es eine Benutzerschnittstelle zur Verfügung, über die der Benutzer das Objekt direkt beeinflussen kann. Dies gilt beispielsweise für das Kalender-Steuerelement von Access 2000. Die zweite Art von ActiveX-Steuerelementen ist zwar zur Entwurfs-, nicht jedoch zur Laufzeit sichtbar. Ein solches Steuerelement ermöglicht Ihnen beispielsweise den Zugriff auf sämtliche Standarddialogfelder von Windows, wie etwa ÖFFNEN, DRUCKEN usw. Das Steuerelement selbst ist für den Benutzer zur Laufzeit nicht sichtbar, doch seine Funktionalität ist verfügbar. Ein weiteres Beispiel ist ein Zeitgeber-Steuerelement. Es wird im Rahmen der Anwendung verarbeitet, um das Ausführen von Ereignisbehandlungsroutinen zu veranlassen, bleibt für den Benutzer jedoch unsichtbar. Mit Hilfe von ActiveX-Steuerelementen können Sie Ihre Anwendungen auf einfache Weise um zusätzliche Funktionen erweitern. Wenn auf Ihrem Formular beispielsweise ein Kalender erscheinen soll, brauchen Sie diesen nicht selbst zu erstellen. Stattdessen können Sie ihm einfach ein benutzerdefiniertes Kalender-Steuerelement hinzufügen und dessen Verhalten durch das Ändern seiner Eigenschaften sowie durch das Ausführen seiner Methoden steuern.
25.2
ActiveX-Steuerelemente im Rahmen von Access 2000 verwenden
Bevor Sie Ihrer Anwendung ein ActiveX-Steuerelement hinzufügen können, müssen Sie die folgenden Schritte durchführen: 1. Installieren Sie das ActiveX-Steuerelement. 2. Registrieren Sie das Steuerelement. 3. Fügen Sie Ihrem Formular das Steuerelement hinzu.
ActiveX-Steuerelemente im Rahmen von Access 2000 verwenden
25.2.1
909
ActiveX-Steuerelemente installieren
Wenn Sie ein ActiveX-Steuerelement kaufen, verfügt dieses im Allgemeinen über ein Installationsprogramm, das die OCX-Datei in Ihr Windows-Systemverzeichnis kopiert. Der Name dieses Verzeichnisses kann davon abhängen, ob Sie mit Windows 95, Windows 98 oder mit Windows NT arbeiten und welches Verzeichnis Sie während der Installation des Betriebssystems angegeben haben.
25.2.2
ActiveX-Steuerelemente registrieren
Nachdem Sie das Steuerelement installiert haben, können Sie es innerhalb von Access registrieren. Häufig werden Steuerelemente bereits während der Installation automatisch registriert. Dies gilt beispielsweise für das in Access enthaltene Kalender-Steuerelement und auch für sämtliche mit den Microsoft ODE-Werkzeugen ausgelieferten OCX-Steuerelemente. In der Windows-Registrierung werden OCXSteuerelemente unter dem Schlüssel HKEY_LOCAL_MACHINE\SOFTWARE registriert (siehe Abbildung 25.1). In der Abbildung ist das als ImagelistCtrl registrierte Steuerelement für Abbildungslisten ausgewählt.
Abbildung 25.1: OCX-Steuerelemente in der Windows-Registrierung
Falls ein ActiveX-Steuerelement noch nicht registriert wurde, können Sie dies im Dialogfeld ACTIVEX-STEUERELEMENTE erledigen (siehe Abbildung 25.2).
910
Kapitel 25: ActiveX-Steuerelemente verwenden
Abbildung 25.2: ActiveX-Steuerelemente können Sie im Dialogfeld ActiveXSteuerelemente registrieren
Im Dialogfeld ACTIVEX-STEUERELEMENTE sind alle gegenwärtig innerhalb von Access registrierten ActiveX-Steuerelemente aufgeführt. Klicken Sie auf die Schaltfläche REGISTRIEREN, um der Liste ein ActiveX-Steuerelement hinzuzufügen. Daraufhin erscheint das Dialogfeld ACTIVEX-STEUERELEMENT HINZUFÜGEN (siehe Abbildung 25.3).
Abbildung 25.3: Im Dialogfeld ActiveX-Steuerelement hinzufügen können Sie nach dem zu registrierenden ActiveX-Steuerelement suchen
Geben Sie zunächst das Verzeichnis an, in dem das zu registrierende OCX-Steuerelement enthalten ist, welches zuvor installiert worden sein muss. Falls es noch nicht installiert wurde, werden Sie es in der Liste nicht vorfinden. Wählen Sie das zu registrierende OCX-Steuerelement aus und klicken Sie auf OK. Anschließend gelangen Sie wieder in das Dialogfeld ACTIVEX-STEUERELEMENTE. Dort wird das soeben ausgewählte Steuerelement nun in der Liste der registrierten Steuerelemente angezeigt. Jetzt können Sie das Steuerelement einem Formular hinzufügen. Falls Sie ein ActiveX-Steuerelement nicht mehr verwenden wollen, sollten Sie es im Dialogfeld ACTIVEX-STEUERELEMENTE auswählen und auf die Schaltfläche REGIS-
ActiveX-Steuerelemente im Rahmen von Access 2000 verwenden
911
klicken. Auf diese Weise können die Registrierungseinträge nicht mehr benötigter Steuerelemente entfernt werden.
TRIERUNG AUFHEBEN
25.2.3
Formularen ActiveX-Steuerelemente hinzufügen
Nachdem Sie ein ActiveX-Steuerelement registriert haben, können Sie es Ihren Formularen hinzufügen. Sie können dies auf zweierlei Weise bewerkstelligen:
Wählen Sie das ActiveX-Steuerelement in der Toolbox aus, indem Sie auf die Schaltfläche WEITERE STEUERELEMENTE klicken.
Wählen Sie ACTIVEX-STEUERELEMENT im Menü EINFÜGEN aus, während Sie sich in der Formular- oder Berichtsansicht befinden. Mit Hilfe des Werkzeugs WEITERE STEUERELEMENTE können Sie sich sämtliche in Ihrem System angemeldeten ActiveX-Steuerelemente anzeigen lassen. Dies betrifft sowohl die zu Excel und Visual Basic als auch die zu anderen Anwendungen gehörenden ActiveX-Steuerelemente. Einige dieser Steuerelemente können unter Access nicht problemlos verwendet werden. Um festzustellen, welche Steuerelemente Sie ohne Schwierigkeiten in Ihre Anwendung einbinden können, brauchen Sie sich nur die Access-Liesmich-Datei durchzulesen oder beim Anbieter des ActiveX-Steuerelements nachzufragen. In Abbildung 25.4 ist das Menü WEITERE STEUERELEMENTE dargestellt.
Abbildung 25.4: Im Menü Weitere Steuerelemente sind sämtliche auf Ihrem System registrierten ActiveX-Steuerelemente aufgeführt
Im Menü WEITERE STEUERELEMENTE werden sämtliche auf dem System installierten ActiveX-Steuerelemente angezeigt. Außerdem haben Sie die Möglichkeit, über das
912
Kapitel 25: ActiveX-Steuerelemente verwenden
Menü EINFÜGEN in das Dialogfeld ACTIVEX-STEUERELEMENT EINFÜGEN zu gelangen, um darin ein ActiveX-Steuerelement auszuwählen (siehe Abbildung 25.5). Nachdem Sie im Listenfeld ACTIVEX-STEUERELEMENT AUSWÄHLEN ein Steuerelement ausgewählt haben, erscheint dieses auf dem Formular. Auf diesen können Sie das Steuerelement in der gewünschten Weise positionieren und seine Form und Größe nach Bedarf ändern.
Abbildung 25.5: Verwenden Sie das Dialogfeld ActiveX-Steuerelement einfügen, um einem Formular ein ActiveX-Steuerelement hinzuzufügen
Nachdem Sie einem Formular ein ActiveX-Steuerelement hinzugefügt haben, kann das Steuerelement in seinem Standardformat verarbeitet werden. Wenn Sie einem Formular das Kalender-OCX-Steuerelement hinzufügen, sieht es so aus, wie es in Abbildung 25.6 dargestellt ist.
Abbildung 25.6: Ein Kalender-OCX ohne explizit festgelegte Eigenschaften in der Formularansicht
ActiveX-Steuerelemente im Rahmen von Access 2000 verwenden
913
Das Kalender-Steuerelement kann alle Monate des Jahres sowie die zu den Monaten gehörenden Tage darstellen. Bislang haben Sie weder irgendwelche Eigenschaften des Kalenders geändert noch Code geschrieben, der nach dem Auftreten der Ereignisse des Kalenders jeweils ausgeführt werden soll. Das Festlegen der Eigenschaften eines ActiveX-Steuerelements, das Ausführen seiner Methoden und das Reagieren auf seine Ereignisse wird in den nachfolgenden Abschnitten erörtert.
25.2.4
Die Referenz auf ein Steuerelement innerhalb Ihrer AccessAnwendung verstehen und benutzen
Sobald Sie einem Formular ein ActiveX-Steuerelement hinzufügen, erstellt Access automatisch eine Referenz auf die Typenbibliothek des Steuerelements, die im Dialogfeld VERWEISE aufgeführt wird (siehe Abbildung 25.7). Das Dialogfeld VERWEISE können Sie aufrufen, indem Sie innerhalb des Visual Basic Editors im Menü EXTRAS die Option VERWEISE auswählen. Beachten Sie, dass in diesem Dialogfeld der vollständige Pfad des Steuerelements angegeben ist. Der Abbildung 25.7 können Sie beispielsweise entnehmen, dass die OCX-Datei des Kalender-Steuerelements unter C:\Programme\Microsoft Office\Office vorzufinden ist. Wenn ein Steuerelement verschoben wird, ist VBA möglicherweise nicht in der Lage, die Referenz entsprechend anzupassen. In diesem Fall müssen Sie das Dialogfeld VERWEISE öffnen, die Kennzeichnung des Fehlens der Referenz von Hand deaktivieren und die korrekte Position des ActiveX-Steuerelements angeben.
Abbildung 25.7: Verwenden Sie das Dialogfeld Verweise, um Verweise an Bibliotheken hinzuzufügen und zu entfernen
Wenn Sie eine Anwendung mit ActiveX-Steuerelementen versehen, können dabei unter Umständen Schwierigkeiten auftreten. Access ist stets bestrebt, möglichst mit korrekten Verweisen auf ActiveX-Steuerelemente zu arbeiten. Falls sich die Steuer-
914
Kapitel 25: ActiveX-Steuerelemente verwenden
elemente im Verzeichnis Windows\System oder in jenem Verzeichnis befinden, in das Access installiert wurde, kann Access die Referenzen automatisch feststellen, auch wenn die Anwendung auf dem Rechner des Benutzers in einem anderen Verzeichnis installiert wurde, als dies auf Ihrem Computer der Fall war. Denken Sie daran, dass ActiveX-Steuerelemente nicht nur eine korrekte Referenz erfordern, sie müssen auch in der Windows-Registrierung registriert worden sein. Wenn Sie den zu den Microsoft ODE-Werkzeugen gehörenden Packages and Deployment Wizard verwenden, um ihre Anwendung weiterzugeben, werden die Steuerelemente automatisch registriert, sobald der Benutzer Ihre Anwendung installiert. Falls Sie diesen Assistenten hingegen nicht benutzen, müssen Sie ein spezielles Programm schreiben, welches die ActiveX-Steuerelemente registriert. Ansonsten haben Sie selbstverständlich noch die Möglichkeit, die Steuerelemente von Hand zu registrieren.
25.3
Eigenschaften eines ActiveX-Steuerelements während des Entwurfs festlegen
Die zu einem ActiveX-Steuerelement gehörenden Methoden, Ereignisse und Eigenschaften sind jeweils unterschiedlich. Sie sind auf das jeweilige Steuerelement abgestimmt und werden vom Entwickler des Steuerelements festgelegt. Die Methoden, Ereignisse und Eigenschaften werden verwendet, um die Erscheinungsform und das Verhalten eines Steuerelements zu regulieren. Sie werden für jedes Steuerelement in einer speziellen .OCX-Datei abgespeichert. Wenn Sie die Eigenschaften eines Steuerelements unverändert lassen, wird es den Vorgabewerten für sein Aussehen und Verhalten entsprechend ausgeführt. Ein Großteil der Leistungsfähigkeit der Steuerelemente von Drittanbietern ergibt sich aus der Möglichkeit, die Eigenschaften dieser Steuerelemente sowohl zur Entwicklungs- als auch zur Laufzeit zu beeinflussen. Einige Steuerelemente unterstützen »Datenbindungen«. Das ermöglicht Ihnen das Darstellen der Daten, die in einem Feld einer zu Grunde liegenden Tabelle enthalten sind, auf einem Formular. Außerdem haben Sie die Möglichkeit, auf die Ereignisse eines ActiveX-Steuerelements und somit auf das Einwirken des Benutzers auf das Steuerelement angemessen zu reagieren. Auch durch das Ausführen der Methoden eines Steuerelements können Sie dessen Verhalten in der gewünschten Weise beeinflussen. In Abbildung 25.8 sehen Sie einige der vielen Eigenschaften des Kalender-Steuerelements. Wie bei jedem anderen Steuerelement können seine Eigenschaften zur Entwurfszeit festgelegt und zur Laufzeit geändert oder ausgelesen werden. Auch auf grafische Weise können Sie die Eigenschaften eines Steuerelements verändern, indem Sie im Eigenschaftenfenster des Steuerelements die Eigenschaft Benutzerdefiniert auswählen und auf die Schaltfläche ERSTELLEN klicken. Beispielsweise können Sie die Eigenschaft Benutzerdefiniert im Eigenschaftenfenster des Kalen-
915
Behandlungsroutinen programmieren
Abbildung 25.8: Das Eigenschaftenfenster des Steuerelements Kalender
der-Steuerelements auswählen und anschließend auf die Schaltfläche ERSTELLEN klicken. Daraufhin erscheint das Dialogfeld EIGENSCHAFTEN VON KALENDER-STEUERELEMENT (siehe Abbildung 25.9). Darin können Sie einen Großteil der Attribute des Kalenders verändern, etwa den ersten Tag der Woche, ob die Wochentage dargestellt werden sollen oder auch die Farben und Schriftarten. Die in diesem Dialogfeld angezeigten Eigenschaften sind je nach Steuerelement unterschiedlich. Zum Dialogfeld EIGENSCHAFTEN VON STEUERELEMENT können Sie gelangen, wenn Sie in der Entwurfsansicht eines Formulars auf das jeweilige ActiveX-Steuerelement doppelklicken.
25.4
Behandlungsroutinen für die Ereignisse eines ActiveX-Steuerelements programmieren
Analog zu den Eigenschaften können auch Ereignisse zur Laufzeit festgelegt oder ausgewertet werden. Eine Liste sämtlicher zu einem ActiveX-Steuerelement gehörenden Ereignisse finden Sie im Prozedurenfeld im Fenster für das Modul. Sorgen Sie dafür, dass der Name Ihres ActiveX-Steuerelements im Objektfeld erscheint. In Abbildung 25.10 sind alle Ereignisse des Kalender-Steuerelements aufgeführt.
916
Kapitel 25: ActiveX-Steuerelemente verwenden
Abbildung 25.9: Im Dialogfeld Eigenschaften von Kalender-Steuerelement können Sie einige Anfangseigenschaften für dieses Steuerelement festlegen
Abbildung 25.10: Betrachten der Ereignisse des Steuerelements Kalender
Das AfterUpdate-Ereignis des Kalender-Steuerelements wird ausgelöst, sobald der Benutzer im Kalender ein Datum auswählt. Der nachfolgend dargestellte Code verändert den Inhalt des Textfelds txtDateSelected in die Value-Eigenschaft des Steuerelements calPickADay. Dieser Code wird der AfterUpdate-Eigenschaft des KalenderSteuerelements zugeordnet, damit er ausgeführt wird, sobald der Benutzer im Kalender ein Datum auswählt. Private Sub calPickADay_AfterUpdate() txtDateSelected.Value = calPickADay.Value End Sub
Das Kalender-Steuerelement verwenden
917
Diesen Code – und einen Großteil des sonstigen in diesem Kapitel dargestellten Codes – finden Sie auf der diesem Buch beiliegenden CD-ROM im Verzeichnis CHAP25EX.MDB. Dieses Beispiel wurde dem Formular frmPickADay entnommen.
25.5
Das Kalender-Steuerelement verwenden
Das Kalender-Steuerelement ist ein besonders leistungsfähiges ActiveX-Steuerelement. Wenn Sie seine Eigenschaften und Methoden kennen, wird Ihnen der Umgang mit ihm wesentlich leichter fallen. Mit Hilfe der nachfolgenden Abschnitte können Sie sich die entsprechenden Kenntnisse aneignen. Die meisten der im Folgenden verwendeten Beispiele wurden dem Formular frmCalPropsAndMethods entnommen.
25.5.1
Eigenschaften eines Kalender-Steuerelements
Die Eigenschaften Day, Month und Year bestimmen den auf dem Kalender darzustellenden Tag, den Monat und das Jahr. Diese Eigenschaften werden zur Laufzeit automatisch geändert, sobald der Benutzer auf dem Kalender ein anderes Datum auswählt. Mit Hilfe von Makros oder Visual Basic können Sie den ausgewählten Tag, den Monat und das Jahr auch von Ihrem Programm ändern lassen. Die Value-Eigenschaft ist eine der wichtigsten Eigenschaften des Kalender-Steuerelements. Sie ermittelt das im Kalender ausgewählte Datum oder verändert den jeweils hervorzuhebenden Tag. Der folgende Code verwendet die Eigenschaft Value, um den ausgewählten Tag in einem Meldungsfeld auszugeben: Private Sub cmdDisplayDate_Click() MsgBox calSelectADay.Value End Sub
Mit Hilfe der Eigenschaft ValueIsNull können Sie angeben, dass auf dem Kalender kein Datum als ausgewählt dargestellt werden soll. Diese Eigenschaft wird verwendet, um sicherzustellen, dass der Benutzer explizit ein Datum auswählt. Die Eigenschaften DayFont und DayFontColor bestimmen die für das Darstellen der Bezeichnungen der Tage zu verwendende Schriftart und -farbe. Die DayFont-Eigenschaft besteht ihrerseits aus den untergeordneten Eigenschaften Name, Size, Bold, Italic, Underline und Strikethrough. Eine einzelne Eigenschaft kann folgendermaßen verändert werden: calSelectADay.DayFont.Italic = True
Um mehrere Eigenschaften auf einmal zu verändern, können Sie das Konstrukt With...End With verwenden:
918
Kapitel 25: ActiveX-Steuerelemente verwenden
With calSelectADay.DayFont .Bold = True .Italic = True .Name = "Arial" End With
Mit Hilfe der Eigenschaft DayFontColor kann auf einfache Weise die Farbe der Bezeichnungen der Tage verändert werden: calSelectADayFontColor = 16711680
Die Eigenschaften GridFont und GridFontColor ähneln den Eigenschaften DayFont und DayFontColor. GridFont bestimmt die Schriftart und die Größe des Textes des Kalenders und GridFontColor legt die Farbe des Texts im Kalender fest. Die folgende Routine verändert beispielsweise die untergeordneten Eigenschaften Bold, Italic und Name der Eigenschaft GridFont. Außerdem wird die Farbe für die Angabe der Tage innerhalb des Kalenders geändert: Private Sub cmdChangeGridFont_Click()
With calSelectADay.GridFont .Bold = True .Italic = True .Name = "Arial" End With calSelectADay.GridFontColor = 8388736 End Sub
Die Eigenschaften DayLength und MonthLength bestimmen die Art der Darstellung der Bezeichnungen für die Tage und Monate. Für DayLength kann zwischen den Werten kurz (0), mittel (1) und lang (2) ausgewählt werden. Bei der kurzen Darstellung erscheint der Tag als ein Buchstabe, bei mittlerer Länge werden die Tage jeweils als zwei Buchstaben und bei der langen Darstellungsweise wird der gesamte Name des Tages angezeigt (beispielsweise Montag). Für die Eigenschaft MonthLength stehen die Werte kurz (0) und lang (2) zur Auswahl. Bei der kurzen Darstellung erscheinen die Monate jeweils als drei Buchstaben und bei der langen Form wird der vollständige Name des Monats angezeigt. Im folgenden Code wird sowohl für DayLength als auch für MonthLength die kurze Darstellungsweise festgelegt: Private Sub cmdChangeLength_Click() calSelectADay.DayLength = 0 calSelectADay.MonthLength = 0 End Sub
Die Eigenschaft ShowDateSelectors bestimmt, ob oben im Kalender Kombinationsfelder angezeigt werden, die dem Benutzer das Auswählen eines Monats und eines Jahres ermöglichen. Dieser Eigenschaft kann der Wert True oder False zugewiesen werden.
Das Kalender-Steuerelement verwenden
919
Die Eigenschaft ShowTitle gibt an, ob der Monat und das Jahr im oberen Teil des Kalenders dargestellt werden. Mit Hilfe der Eigenschaften GridLinesFormat und GridLinesColor kann festgelegt werden, ob die Rasterlinien erhöht, vertieft oder flach erscheinen und in welcher Farbe sie dargestellt werden sollen.
25.5.2
Methoden eines Kalender-Steuerelements
Außerdem verfügt das Kalender-Steuerelement über mehrere Methoden bzw. Aktionen, die Sie auf das Kalender-Objekt anwenden können. Die Methoden NextDay, PreviousDay, NextWeek, PreviousWeek, NextMonth, PreviousMonth, NextYear und PreviousYear dienen alle dem Erhöhen bzw. Verringern der Eigenschaft Value um eine bestimmte Zeitspanne. Zusätzlich stellt Ihnen das Kalender-Steuerelement die folgenden Methoden zur Verfügung:
Die Methode Refresh sorgt für eine erneute Darstellung des Kalender-Steuerelements.
Die Methode Today weist der Eigenschaft Value das aktuelle Datum als Wert zu. Mit Hilfe der Methode AboutBox kann das zum Kalender gehörende Info-Dialogfeld aufgerufen werden. Die nachfolgenden Beispiele erfordern Steuerelemente, die in der Microsoft Office 2000 Developer Edition enthalten sind. Sie benötigen demnach die entsprechende ODE, um die Beispiele ausführen zu können. Falls Sie diese ODE haben, können Sie die erstellten Werkzeuge anderen Benutzern zur Verfügung stellen, ohne Registrierungsgebühren zu entrichten. Falls einige der folgenden Beispiele nicht ausgeführt werden können, obgleich die benötigte ODE installiert wurde, sollten Sie im Dialogfeld VERWEISE nachschauen, ob in korrekter Weise auf die Steuerelemente verwiesen wird. In Abbildung 25.11 sehen Sie, wie das Kalender-Steuerelement funktioniert. Das Formular frmCalendar ermöglicht dem Benutzer deutlich erkennbar das Wechseln zwischen einzelnen Tagen, Monaten und Jahren. Außerdem kann der Benutzer zum aktuellen Datum umschalten oder ein beliebiges anderes Datum auswählen und anschließend auf die Schaltfläche DISPLAY ORDERS FOR SELECTED DATE klicken, damit alle Bestellungen angezeigt werden, die mit dem angegebenen Datum verknüpft sind. Der Code für die Schaltfläche TODAY veranschaulicht die Verwendung der Methode Today.
920
Kapitel 25: ActiveX-Steuerelemente verwenden
Abbildung 25.11: Ein Beispiel für die Verwendung des Steuerelements Kalender Private Sub cmdToday_Click() calPickADay.Today End Sub
Sobald die Schaltfläche TODAY des Kalender-Steuerelements angeklickt wird, erscheint das gegenwärtige Datum als ausgewähltes Datum. Der Code für die Schaltfläche DISPLAY ORDERS FOR SELECTED DATE sieht folgendermaßen aus: Private Sub cmdOrders_Click() frmOrdersByDate.Form.RecordSource = _ "Select * from qryOrdersByDate Where OrderDate = #" _ & calPickADay.Value & "#" End Sub
In diesem Code wird die Eigenschaft RecordSource des Unterformulars so verändert, dass nur noch jene Aufträge angezeigt werden, deren Datum mit dem ausgewählten Datum übereinstimmen. Der übrige Code des Formulars frmCalendar wird im nächsten Abschnitt erörtert.
25.6
Das Steuerelement UpDown verwenden
Das Steuerelement UpDown ist ein für das Erhöhen und Verringern von Werten hervorragend geeignetes Werkzeug. In Verbindung mit anderen Steuerelementen kann es verwendet werden, um deren Werte auf einfache Weise zu erhöhen oder zu verringern. Beim Formular frmCalendar dienen UpDown-Objekte beispielsweise dem Erhöhen bzw. Verringern des ausgewählten Tags, Monats und Jahres. Analog zum Kalender-Steuerelement verfügt das UpDown-Objekt über seine eigenen integrierten Eigenschaften und Methoden. Seine Eigenschaften können zwar auf der Registerkarte WEITERE des Eigenschaftenfensters verändert werden, doch im Dialogfeld
Das Steuerelement UpDown verwenden
921
EIGENSCHAFTEN VON UPDOWN kann dies wesentlich einfacher bewerkstelligt werden (siehe Abbildung 25.12). Um es zu öffnen, doppelklicken Sie auf das jeweilige UpDown-Objekt, dessen Eigenschaften Sie ändern möchten.
Abbildung 25.12: Das Dialogfeld Eigenschaften von UpDown
Die Eigenschaft Orientation gehört zu den wichtigsten des UpDown-Objekts. Sie bestimmt, ob das UpDown-Objekt waagerecht oder senkrecht dargestellt wird. Die beiden am häufigsten verwendeten Ereignisse von UpDown-Objekten sind UpClick und DownClick. Sie legen fest, was geschieht, wenn der Benutzer auf eine der entsprechenden Schaltflächen auf dem Steuerelement klickt. Der folgende Code stammt aus der Routine zum Ereignis DownClick von frmCalendar. Beachten Sie, dass der Code die Methode PreviousDay des Steuerelements calPickADay aufruft, damit im KalenderSteuerelement der jeweils vorhergehende Tag ausgewählt wird: Private Sub updnDay_DownClick() calPickADay,PreviousDay End Sub
In dem Code für das Ereignis UpClick des Steuerelements updnDay wird die Methode NextDay des Steuerelements calPickADay aufgerufen, damit der jeweils nachfolgende Tag ausgewählt wird: Private Sub updnDay_UpClick() calPickADay,NextDay End Sub
922
Kapitel 25: ActiveX-Steuerelemente verwenden
In dem Code für das Ereignis DownClick des Steuerelements updnMonth wird die Methode PreviousMonth des Kalender-Steuerelements aufgerufen, damit der jeweils vorherige Monat ausgewählt wird: Private Sub updnMonth_DownClick() calPickADay.PreviousMonth End Sub
In dem Code für das Ereignis UpClick des Steuerelements updnMonth wird die Methode NextMonth des Kalender-Steuerelements aufgerufen, damit der gleiche Tag des nachfolgenden Monats ausgewählt wird: Private Sub updnMonth_UpClick() calPickADay.NextMonth End Sub
In dem Code für die Ereignisse DownClick und UpClick des Steuerelements updnYear werden die Methoden PreviousYear und NextYear des Kalender-Steuerelements verwendet, um im Kalender das jeweils vorherige bzw. nächste Jahr auszuwählen: Private Sub updnYear_DownClick() calPickADay.PreviousYear End Sub Private Sub updnYear_UpClick() calPickADay.NextYear End Sub
Wie Sie sehen, können Sie durch das Kombinieren unterschiedlicher ActiveX-Steuerelemente sehr benutzerfreundliche und nützliche Anwendungen erstellen.
25.7
Das Steuerelement StatusBar verwenden
Das Steuerelement StatusBar können Sie verwenden, um professionell aussehende Statusleisten schnell und einfach in Ihre Formulare einzufügen. In Abbildung 25.11 sehen Sie ein Beispiel für das Formular frmCalendar. Die Statusleiste in der Abbildung besteht aus sechs Panel-Feldern. In den ersten beiden werden das gegenwärtige Datum und die Uhrzeit angezeigt und in den letzten drei Panels werden die Zustände der Feststelltaste sowie der Tasten [Num] und [Einfg] dargestellt. Die Eigenschaften des StatusBar-Steuerelements können als Ganzes oder für einzelne Panels festgelegt werden (siehe Abbildung 25.13). Die Eigenschaft Style bestimmt, ob die Statusleiste aus einem oder aus mehreren Panels bestehen soll. Die Eigenschaft SimpleText wird ausschließlich für Statusleisten verwendet, die lediglich aus einem Panel bestehen. Sie gibt den Text an, der in dem Panel angezeigt werden
Das Steuerelement StatusBar verwenden
923
soll. Mit Hilfe der Eigenschaft MousePointer können Sie schließlich noch die Art des Mauszeigers angeben, welche verwendet wird, sobald sich der Mauszeiger über dem StatusBar-Steuerelement befindet.
Abbildung 25.13: Die allgemeinen Eigenschaften des Steuerelements StatusBar
Jedes Panel des StatusBar-Steuerelements verfügt über Eigenschaften, welche sein Aussehen und Verhalten bedingen. Die Eigenschaft Index eines Panels wird benutzt, um sich auf die einzelnen Panels zu beziehen. Die Eigenschaften von Panel-Feldern sind in Abbildung 25.14 dargestellt. Besonders wichtig ist die Eigenschaft Style. Sie bestimmt, welche Informationen in einem Panel angezeigt werden. Sie kann die Werte Text, Caps, Num Lock, Ins, Scroll, Time, Date oder Kana Lock annehmen. Sobald dieser Eigenschaft einer dieser Werte zugewiesen wurde, kann das Steuerelement automatisch ermitteln, ob die Feststelltaste oder eine der anderen Tasten gedrückt wurde. Die Eigenschaft Text gibt den Text an, der in einem Bereich angezeigt werden soll, falls dessen Style-Eigenschaft den Wert Text aufweist. Der Wert dieser Eigenschaft wird häufig zur Laufzeit verändert, damit spezielle Nachrichten für den Benutzer angezeigt werden. Die Eigenschaft Alignment legt fest, ob die Information im Panel linksbündig, rechtsbündig oder zentriert ausgegeben wird, und die Eigenschaft Bevel kann auf None, Insert oder Raised gesetzt werden. Sobald Sie Panels hinzufügen oder entfernen, wird jedem ein Index zugewiesen. Um sich zur Laufzeit auf ein bestimmtes Panel zu beziehen, wird wie im folgenden Beispiel die Eigenschaft Index verwendet: Private Sub calPickADay_AfterUpdate()
If calPickADay.Value = Date Then sbrStatus.Panels(3).Text = "TODAY!!!"
924
Kapitel 25: ActiveX-Steuerelemente verwenden
Abbildung 25.14: Die PanelFlächen-Eigenschaften von StatusBar Else sbrStatus.Panels(3).Text = "" End If End Sub
In diesem Code wird zunächst ermittelt, ob der Wert von calPickADay mit dem gegenwärtigen Datum übereinstimmt. Gegebenenfalls wird dem dritten Panel der Text TODAY!!! zugewiesen, während die Eigenschaft Text des dritten Panels sonst auf eine leere Zeichenkette gesetzt wird. In Access beginnen Nummerierungen nahezu grundsätzlich mit der Null. Selbstverständlich gibt es aber für jede Regel Ausnahmen. Das StatusBar-Steuerelement ist eine von ihnen – bei ihm wird von Eins an gezählt. Im Code des vorherigen Beispiels wird tatsächlich der Text des dritten Panels verändert.
25.8
Das Steuerelement Common Dialog
Das Steuerelement Common Dialog kann man sich im Grunde wie mehrere Steuerelemente in einem vorstellen. Es wird verwendet, um die unter Windows üblichen Dialogfelder ÖFFNEN, SPEICHERN UNTER, SCHRIFTART, FARBE und DRUCKEN darzustellen. Bei Common Dialog handelt es sich um ein ausgeblendetes Steuerelement, das zur Laufzeit nicht angezeigt wird, dessen Eigenschaften und Methoden jedoch mit Hilfe von VBA-Code verändert werden können. Das in Abbildung 25.15 gezeigte
Das Steuerelement Common Dialog
925
Formular frmCommonAndRich veranschaulicht die Verwendung mehrerer Standdarddialogfelder und auch des im nächsten Abschnitt beschriebenen RichText-Steuerelements.
Abbildung 25.15: Dieses Formular dient der Veranschaulichung von Standarddialogfeldern und RTF-Steuerelementen
An den Befehlsschaltflächen SCREEN COLOR und BUTTON FRONT können Sie erkennen, wie das Steuerelement Common Dialog verwendet wird. Diese Schaltflächen bewirken, dass die Dialogfelder FARBE bzw. SCHRIFTART aufgerufen werden. Der Code für das Ereignis Click der Befehlsschaltfläche cmdColor sieht folgendermaßen aus: Private Sub cmdColor_Click() dlgCommon.Flags = cdlCCFullOpen dlgCommon.ShowColor Me.Detail.BackColor = dlg Common.Color End Sub
Am Anfang des Codes wird zunächst die Eigenschaft Flags des Common DialogSteuerelements gesetzt, welche die Attribute des Standarddialogfelds bestimmt. Der Wert cdlCCFullOpen bestimmt beim Standarddialogfeld FARBE beispielsweise, dass das gesamte Dialogfeld dargestellt wird, einschließlich der Möglichkeit des Erstellens benutzerdefinierter Farben. Durch das Aufrufen der Methode ShowColor des Standarddialogfelds wird dafür gesorgt, dass das Standarddialogfeld FARBE erscheint (siehe Abbildung 25.16). Die vom Benutzer ausgewählte Farbe kann aus der Eigenschaft Color des Common Dialog-Steuerelements ausgelesen werden. Diese Farbe wird benutzt, um die Eigenschaft BackColor des Detailbereichs des Formulars zu verändern.
926
Kapitel 25: ActiveX-Steuerelemente verwenden
Abbildung 25.16: Dieses Dialogfeld zur Farbauswahl ist ein Bestandteil des Standarddialogfelds
Im folgenden Code wird eine With...End-Schleife verwendet, um einige Eigenschaften des Standarddialogfelds zu ändern: Private Sub cmdFont_Click()
Dim ctl As Control dlgCommon.Flags = cdlCFScreenFonts dlgCommon.ShowFont For Each ctl In Controls If TypeOf ctl Is CommandButton Then With ctl .FontName = dlgCommon.FontName .FontBold = dlgCommon.FontBold .FontItalic = dlgCommon.FontItalic .FontSize = dlgCommon.FontSize End With End If Next ctl End Sub
Das Ereignis Click von cmdFont weist zunächst der Eigenschaft Flags des Common Dialog-Steuerelements den Wert cdlCFScreenFonts zu. Dies bewirkt, dass in dem Dialogfeld lediglich die vom System des Benutzers unterstützten Bildschirmschriftarten aufgeführt werden. Die Methode ShowFont wird benutzt, um das gegenwärtige Dialogfeld aufzurufen (siehe Abbildung 25.17). Im Rahmen eines With...End WithKonstrukts werden im Code sämtliche Eigenschaften des Standarddialogfelds festgelegt. Außerdem wird in dieser Schleife die zum Formular gehörende Auflistung von Steuerelementen durchlaufen, um die Attribute der für die einzelnen Befehlsschaltflächen verwendeten Schriftarten zu verändern.
Das RichText-Steuerelement verwenden
927
Die Standarddialogfelder ÖFFNEN, SPEICHERN und DRUCKEN werden im nächsten Abschnitt behandelt.
Abbildung 25.17: Das Standarddialogfeld Schriftart ermöglicht Ihnen das Festlegen mehrerer Eigenschaften der Schriftart auf einmal
25.9
Das RichText-Steuerelement verwenden
Mit Hilfe des RichText-Steuerelements können Sie ein Textfeld für das Schreiben von Code erstellen, welches sich auf den ausgewählten Text auswirkt. Für den ausgewählten Text können Eigenschaften wie beispielsweise Font, Font Size, Bold und Italic festgelegt werden und Sie können den ausgewählten Text sogar mit Aufzählungszeichen versehen. Außerdem haben Sie die Möglichkeit, Inhalte des RichTextSteuerelements im RTF-Format abzuspeichern und später wieder in das Steuerelement einzufügen. Der folgende Code veranschaulicht die Verwendung einiger Eigenschaften des RichText-Steuerelements: Private Sub cmdTextColor_Click() dlgCommonShowColor rtfDocument.SelColor = dlgCommon.Color End Sub
In diesem Code wird das Standarddialogfeld FARBE verwendet, um die Eigenschaft SelColor des RichText-Steuerelements festzulegen. Der ausgewählte Text erscheint jeweils in jener Farbe, die sich der Benutzer in dem Standarddialogfeld ausgesucht hat. Die Behandlungsroutine für das Ereignis Click der Befehlsschaltfläche cmdTextFont bewirkt, dass den Eigenschaften SelFontName, SelBold, SelItalic und SelFontSize des
928
Kapitel 25: ActiveX-Steuerelemente verwenden
RichText-Steuerelements die im Standarddialogfeld SCHRIFTART ausgewählte Schriftart, der angegebene Schriftschnitt und die Größe zugewiesen werden: Private Sub cmdTextFont_Click()
dlgCommon.Flags = cdlCFScreenFonts dlgCommon.ShowFont With rtfDocument .SelFontName = dlgCommon.FontName .SelBold = dlgCommon.FontBold .SelItalic = dlgCommon.FontItalic .SelFontSize = dlgCommon.FontSize End With End Sub
Die angegebenen Attribute werden ausschließlich auf den ausgewählten Text angewendet. Das RichText-Steuerelement verfügt über eine Methode mit der Bezeichnung SaveFile, welche Ihnen das Speichern seiner Inhalte in einer RTF-Datei ermöglicht. Der Code sieht folgendermaßen aus: Private Sub cmdSave_Click()
dlgCommon.Filter = "RTF Files (*.rtf)|*.rtf" dlgCommon.ShowSave If dlgCommon.FileName = "" Then MsgBox "You Must Specify a File Name", vbExclamation, "File NOT Saved!" Else rtfDocument.SaveFile dlgCommon.FileName End If End Sub
In dem Code wird zunächst die Eigenschaft Filter des Common Dialog-Steuerelements festgelegt. Auf diese Weise wird veranlasst, dass die im Standarddialogfeld SPEICHERN angegebenen Dateinamen gefiltert werden. Die Methode ShowSave sorgt dafür, dass das Standarddialogfeld SPEICHERN UNTER erscheint (siehe Abbildung 25.18). Nachdem der Benutzer einen Dateinamen eingegeben oder ausgewählt hat, wird der Eigenschaft FileName des Common Dialog-Steuerelements genau dieser Dateiname zugewiesen. Falls der Benutzer auf die Schaltfläche ABBRECHEN klickt, enthält die Eigenschaft FileName anschließend eine leere Zeichenkette und dem Benutzer wird gemeldet, dass die Datei nicht gespeichert wurde. Es wurde bereits erwähnt, dass Sie die Möglichkeit haben, den Inhalt einer RTFDatei in Ihr Steuerelement einzufügen. Der entsprechende Code sieht folgendermaßen aus: Private Sub cmdOpen_Click()
dlgCommon.FileName = "" dlgCommon.Filter = "RTF Files (*.rtf)|*.rtf" dlgCommon.InitDir = CurDir
Das RichText-Steuerelement verwenden
929
Abbildung 25.18: Das Standarddialogfeld Speichern unter ermöglicht Ihnen das Eingeben eines Namens, einer Position und einer Erweiterung für Ihre Datei dlgCommon.ShowOpen If dlgCommon.FileName = "" Then MsgBox "You Must Specify a File Name", vbExclamation, "File Cannot Be _ Opened!" Else rtfDocument.LoadFile dlgCommon.FileName End If End Sub
Die Behandlungsroutine für das Ereignis Click der Befehlsschaltfläche cmdOpen verwendet die Methode ShowOpen, damit das Standarddialogfeld ÖFFNEN dargestellt wird (siehe Abbildung 25.19). Nachdem sich der Benutzer eine Datei ausgesucht hat, verwendet die Methode LoadFile des RichText-Steuerelements die Eigenschaft FileName des Common Dialog-Steuerelements als Name der zu öffnenden Datei.
Abbildung 25.19: Im Standarddialogfeld Öffnen können Sie lediglich die zu öffnende Datei angeben. Dafür haben Sie jedoch die Möglichkeit, diese Datei auf Ihrem Computer oder innerhalb des Netzwerks zu suchen
930
Kapitel 25: ActiveX-Steuerelemente verwenden
Sie können den Inhalt eines RichText-Steuerelements nicht nur speichern und laden, sondern auch drucken. Die Behandlungsroutine für das Ereignis Click der Befehlsschaltfläche cmdPrint weist der Eigenschaft Flags des Common Dialog-Steuerelements den Wert cdlPDAllPages zu: Private Sub cmdPrint_Click() dlgCommon.Flags = cdlPDAllPages dlgCommon.ShowPrinter rtfDocument.SelPrint dlgCommon.hDC End Sub
Auf diese Weise wird das Optionsfeld ALLES des Dialogfelds DRUCKEN ausgewählt. (Die Optionsfelder SEITEN und AUSWAHL sind somit anschließend nicht mehr ausgewählt.) Die Methode ShowPrinter sorgt dafür, dass das Standarddialogfeld DRUCKEN dargestellt wird (siehe Abbildung 25.20). Anschließend wird die Methode SelPrint des RichText-Steuerelements benutzt, um den ausgewählten Text mit dem im Standarddialogfeld DRUCKEN angegebenen Drucker auszudrucken.
Abbildung 25.20: Im Standarddialogfeld Drucken können Sie mehrere Optionen für den Druckvorgang festlegen
25.10
Das TabStrip-Steuerelement verwenden
Das TabStrip-Steuerelement können Sie verwenden, um die Daten eines Formulars auf mehreren »Seiten« darzustellen, damit der sonstige Bildschirminhalt erhalten bleibt. Das in der ODE enthaltene TabStrip-Steuerelement stimmt mit dem Registerkarten-Steuerelement überein, das Ihnen bereits aus Anwendungen wie Microsoft Word und Microsoft Excel bekannt ist. Sie können es auf einfache Weise für Ihre eigenen Formulare benutzen. In Abbildung 25.21 sehen Sie ein Formular mit der Bezeichnung frmTabbed, welches das TabStrip-Steuerelement verwendet.
Das TabStrip-Steuerelement verwenden
931
Abbildung 25.21: Für dieses Formular wurde das TabStripSteuerelement verwendet
Sobald der Benutzer auf die einzelnen Registerkarten klickt, erscheinen jeweils die ihnen entsprechenden Informationen. Wenn der Benutzer beispielsweise auf der Registerkarte CUSTOMERS einen Kunden auswählt und anschließend die Registerkarte ORDERS anklickt, werden alle Bestellungen des jeweiligen Kunden angezeigt. Falls er auf der Registerkarte ORDERS Bestellungen auswählt und danach zur Registerkarte ORDER DETAILS wechselt, erscheinen die Bestelldetails. Der entsprechende Code sieht folgendermaßen aus: Private Sub tabSelect_Click()
Select Case Me!tabSelect.SelectedItem.INDEX Case 1 Me!fsubCustomers.Visible = True Me!fsubOrders.Visible = False Me!fsubOrderDetails.Visible = False Case 2 Me!fsubOrders.Form.RecordSource = _ "Select * from tblOrders Where CustomerID = '" _ & Me!fsubCustomers.Form!CustomerID & "';" Me!fsubCustomers.Visible = False Me!fsubOrders.Visible = True Me!fsubOrderDetails.Visible = False Case 3 Me!fsubOrders.Form.RecordSource = _ "Select * from tblOrderDetails Where OrderID = " _ & Me!fsubOrders.Form!OrderID & ";" Me!fsubCustomers.Visible = False Me!fsubOrders.Visible = False Me!fsubOrderDetails.Visible = True End Select End Sub
932
Kapitel 25: ActiveX-Steuerelemente verwenden
Der Code funktioniert so: Nachdem dem Formular ein TabStrip-Steuerelement hinzugefügt wurde, können Sie es doppelklicken, um seine Eigenschaften zu betrachten (siehe Abbildung 25.22). Im Dialogfeld EIGENSCHAFTEN VON TABSTRIP können Sie die Eigenschaften des TabStrip-Steuerelements im Allgemeinen sowie die Eigenschaften für die einzelnen Registerkarten festlegen. Sobald die Registerkarten hinzugefügt wurden, können Sie das Ereignis Click des TabStrip-Steuerelements programmieren, um zu bestimmen, was geschehen soll, wenn der Benutzer auf die einzelnen Registerkarten klickt.
Abbildung 25.22: Auf der Eigenschaftenseite des TabStrip-Steuerelements können dem TabStrip-Steuerelement Anfangswerte zugewiesen werden
Sie finden ein Register-Steuerelement standardmäßig auch in der Access-Toolbox, so dass es nicht erforderlich ist, das ActiveX-Steuerelement in Ihren Anwendungen einzusetzen. Drittanbieter stellen außerdem Register-Steuerelemente bereit, welche die von Microsoft in Sachen Funktionalität übertreffen. Doch sind alle diese Steuerelemente echte ActiveX-Steuerelemente. Wie beim Steuerelement StatusBar beginnt die Nummerierung der einzelnen Registerkarten des TabStrip-Steuerelements mit der Eins. Mit Hilfe einer Case-Anweisung wird ermittelt, welche Registerkarte ausgewählt wurde. Das Formular frmTabbed verfügt über drei Unterformulare: fsubCustomers, fsubOrders und fsubOrderDetails. Wenn das Formular frmTabbed erstmals dargestellt wird, ist zunächst lediglich das Unterformular-Steuerelement fsubCustomers sichtbar. Sobald der Benutzer auf die einzelnen Registerkarten des TabStrip-Steuerelements klickt, erscheint jeweils das entsprechende Unterformular und die beiden anderen Unterformulare sind ausgeblendet. Die Eigenschaft RecordSource von fsubOrders wird zur Laufzeit verändert, damit stets nur die Bestellungen des auf dem Unterformular fsubCustomers ausgewählten Kunden angezeigt werden. Auch die Eigenschaft RecordSource von fsubOr-
933
Das ImageList-Steuerelement verwenden
derDetails wird zur Laufzeit geändert, da ausschließlich die Einzelheiten der auf der Registerkarte fsubOrders ausgewählten Bestellung dargestellt werden sollen.
25.11
Das ImageList-Steuerelement verwenden
Das TabStrip-Steuerelement kann mit Hilfe des ImageList-Steuerelements erweitert werden, in dem Abbildungen gespeichert werden können, die auf dem Formular dargestellt werden sollen. Die Abbildungen werden zur Entwurfszeit auf dem Formular angeordnet. Zur Laufzeit bleibt das ImageList-Steuerelement verborgen, doch die in ihm gespeicherten Abbildungen können Sie für Ihr Formular verwenden. Das in Abbildung 25.23 gezeigte Formular frmImageList ähnelt dem Formular frmTabbed, auf seinen Registerkarten werden jedoch zusätzlich die im ImageListSteuerelement imgPictures gespeicherten Abbildungen angezeigt. Die Eigenschaften des ImageList-Steuerelements sind in Abbildung 25.24 aufgeführt. Beachten Sie, dass drei Abbildungen eingefügt wurden. Die Größe der Abbildungen wurde auf der Registerkarte ALLGEMEIN mit 16x16 festgelegt und dem Steuerelement tabSelect wurde auf seiner Registerkarte ALLGEMEIN das Steuerelement imgPictures als Abbildungsliste hinzugefügt. Die Indizes der einzelnen Abbildungen, die im ImageList-Steuerelement imgPictures gespeichert sind, wurden jeweils den Image-Eigenschaften der einzelnen Registerkarten des TabStrip-Steuerelements hinzugefügt. Die Eigenschaft Image legt fest, welche der im entsprechenden ImageList-Steuerelement gespeicherten Abbildungen auf der jeweiligen Registerkarte dargestellt werden soll.
Abbildung 25.23: Das Formular frmImageList mit Abbildungen für die Registerkarten
934
Kapitel 25: ActiveX-Steuerelemente verwenden
Abbildung 25.24: Die Eigenschaftenseite des ImageList-Steuerelements
25.12
Aspekte der Weitergabe und Lizenzierung
Einige OCX-Steuerelemente können ohne Weiteres weitergegeben werden, für andere gelten hingegen unterschiedliche Beschränkungen. Die Lizenzierungsrichtlinien für ein bestimmtes OCX-Steuerelement werden vom jeweiligen Anbieter festgelegt. Die Lizenzierungsrichtlinen für OCX-werden teilweise durch bestimmte gesetzliche Rahmenbedingungen festgelegt. Die nicht autorisierte Weitergabe von Steuerelementen kann somit durchaus eine Straftat sein. Das Weitergeben von OCX-Steuerelementen ohne die dafür erforderlichen Lizenzen ist genauso verboten, wie das illegale Kopieren sonstiger Software. Wenden Sie sich an den Anbieter eines Steuerelements, falls Sie nicht wissen, ob es eine Lizenzierung erfordert. Möglicherweise muss eine einmalige Gebühr entrichtet werden, um das Steuerelement frei weitergeben zu können. Gelegentlich muss auch für jede weiterzugebende Kopie eines Steuerelements eine Lizenzgebühr bezahlt werden. Falls Sie nicht sicher sind, ob Sie ein Steuerelement eines Drittanbieters tatsächlich kaufen wollen, könnte es sich lohnen, sich mit dem Anbieter in Verbindung zu setzen. Viele Anbieter gestatten potentiellen Kunden für eine begrenzte Zeitspanne das kostenlose Ausprobieren ihrer Produkte. Viele Testversionen sind auch online verfügbar.
25.12.1 Für die Praxis ActiveX-Steuerelemente implementieren Innerhalb der Anwendung für das Zeit- und Abrechnungssystem können Steuerelemente vielerorts verwendet werden. Denken Sie darüber nach, wie Sie Ihre Anwendung mit Hilfe von Steuerelementen nützlicher gestalten können. Die folgenden Bei-
Aspekte der Weitergabe und Lizenzierung
935
spiele veranschaulichen einige der Möglichkeiten, die sich aus der Verwendung von ActiveX-Steuerelementen ergeben.
25.12.2 Dem Dialogfeld für Berichtskriterien einen Kalender hinzufügen Ein Beispiel für ein ActiveX-Steuerelement ist das in Abbildung 25.25 gezeigte Dialogfeld frmReportDateRange. Die Textfelder BEGINNING DATE und ENDING DATE können mit Hilfe des Kalender-Steuerelements festgelegt werden.
Abbildung 25.25: Einfügen des Kalender-Steuerelements in das Formular für Berichtskritierien
Der Code zum Hinzufügen des Kalender-Steuerelements sieht folgendermaßen aus: Private Sub cmdSetDates_Click()
On Error GoTo cmdSetDates_Error If cmdSetDates.Caption = "Set Beginning Date" Then Me.txtBeginDate = calSetDates.Value cmdSetDates.Caption = "Set Ending Date" Else Me.txtEndDate = calSetDates.Value cmdSetDates.Caption = "Set Beginning Date" End If Exit Sub cmdSetDates_Error: MsgBox "Error # " & Err.Number & ": " & Err.Description Exit Sub End Sub
936
Kapitel 25: ActiveX-Steuerelemente verwenden
Da zum Ausfüllen der Textfelder BEGINNING DATE und ENDING DATE der gleiche Kalender benutzt wird, verfügt das Formular über eine Befehlsschaltfläche mit variabler Beschriftung. Der Benutzer kann ein Datum auswählen und anschließend auf die Schaltfläche SET BEGINNING DATE klicken. Das Textfeld BeginDate wird daraufhin ausgefüllt und auf der Befehlsschaltfläche erscheint die neue Beschriftung SET ENDING DATE. Sobald der Benutzer danach auf diese Schaltfläche klickt, wird das gegenwärtig im Kalender ausgewählte Datum in das Textfeld ENDING DATE eingefügt und auf der Schaltfläche erscheint wieder die Beschriftung SET BEGINNING DATE.
Automatisierung: Mit anderen Anwendungen kommunizieren
Kapitel
Hier lesen Sie:
Eine Objektvariable als Verweis auf Ihre Anwendung deklarieren Ein Automatisierungsobjekt erstellen Ein Automatisierungsobjekt anpassen Excel mit Access steuern Ein Excel-Automatisierungsobjekt schließen Mit Hilfe von Access ein Diagramm erstellen Word von Access aus steuern PowerPoint von Access aus steuern Access von anderen Anwendungen aus steuern
26.1
Von außen mit Access arbeiten
Benutzer von Windows erwarten mittlerweile die nahtlose Zusammenarbeit von Anwendungen. Sie interessieren sich nicht für das Produkt, mit dem sie eine Anwendung erstellen, sondern wollen lediglich ihre Aufgaben ausführen können. Häufig ist Microsoft Word, Microsoft Excel oder ein anderes Produkt für die Bewältigung bestimmter Teilaufgaben innerhalb Ihrer Anwendungen am besten geeignet. Es liegt in Ihrer Verantwortung, für einzelne Aufgaben das jeweils beste Werkzeug auszuwählen. Sie müssen also wissen, wie Sie von Ihrer Anwendung aus mit diesem Programm direkt kommunizieren können. Dies bedeutet, dass es nicht mehr ausreicht, wenn Sie sich lediglich mit Ihrem Produkt und der als Entwicklungswerkzeug verwendeten Programmiersprache beschäftigen. Zusätzlich müssen Ihnen all die anderen verfügbaren Anwendungen bekannt sein. Außerdem müssen Sie wissen, wie Sie mit diesen Anwendungen kommunizieren können – dies ist zweifellos eine echte Herausforderung.
938
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
»ActiveX-Automatisierung« ist die Fähigkeit einer Anwendung, Objekte anderer Anwendungen zu steuern. Dies bedeutet, dass Ihre Access-Anwendung beispielsweise Excel starten sowie eine Tabelle verändern und auch ausdrucken kann, ohne ein direktes Vorgehen des Benutzers in Excel zu erfordern. Automatisierung wird vielfach mit dem Vorgang des Verknüpfens und Einbettens verwechselt. OLE 1.0 ermöglichte Ihnen das Erstellen zusammengesetzter Dokumente. Beispielsweise konnten Sie eine Excel-Tabelle in ein Word-Dokument einbetten oder von einem Word-Dokument aus auf eine Excel-Tabelle verweisen. Diese Möglichkeit war einst sehr aufregend und ist auch heute noch in vielen Zusammenhängen nützlich, doch OLE 2.0 bietet Ihnen (zusätzlich zu den Funktionen von OLE 1.0) die Möglichkeit, von einer Anwendung aus Objekte anderer Anwendungen zu steuern. Mit der Einführung von Office 97 änderte Microsoft die Art der Nutzung von OLE. Die neuen Funktionen werden als »Automatisierung« bezeichnet und stellen einen Industriestandard dar, der auch im »Component Object Model« (COM) Berücksichtigung fand. Genauso wie Sie andere Anwendungen mit Hilfe von Automatisierung steuern können, kann auch Ihre Access-Anwendung von anderen Anwendungen kontrolliert werden, wie beispielsweise von einer Excel- oder einer Visual Basic-Anwendung. Sie können sich also von Ihrer Visual Basic-Anwendung aus die vorzügliche Berichtsfunktion von Access zunutze machen. Sie haben sogar die Möglichkeit, sämtliche Access-Berichte aufzulisten, damit der Benutzer sich einen aussuchen kann, der anschließend ausgeführt wird – und all dies im Rahmen eines Visual Basic-Formulars.
26.2
Begriffe zur Automatisierung
Bevor Sie sich mit der Funktionsweise der Automatisierung auseinandersetzen, sollten Ihnen einige wenige diesbezügliche Begriffe bekannt sein. Automatisierung erfordert einen Automatisierungs-Client und einen Automatisierungs-Server. Die als »Automatisierungs-Client« fungierende Anwendung übernimmt die Kommunikation und steuert die Server-Anwendung. Da dieses Buch Access zum Thema hat, übernimmt in den meisten hier angeführten Beispielen Access die Rolle des Automatisierungs-Clients, wobei Access die jeweils andere Anwendung (etwa Excel oder Word) steuert. Die gesteuerte Anwendung wird als »Automatisierungs-Server« bezeichnet und umfasst die zu verwendenden Objekte. Excel fungiert als Automatisierungs-Server, wenn von Access aus Excel gestartet und sichtbar gemacht, eine neue Tabelle erstellt, die Ergebnisse einer Abfrage in die Tabelle übertragen und die in ihr enthaltenen Daten grafisch dargestellt werden. In diesem Fall werden Objekte von Excel gesteuert, Eigenschaften von Excel verändert und Methoden von Excel ausgeführt. Ein weiterer wichtiger Bestandteil des Automatisierungsvorgangs ist die Typbibliothek. Dabei handelt es sich um eine Datenbank, in der die von einem Automatisierungs-Server zur Verfügung gestellten Objekte, Eigenschaften, Methoden und Ereignisse aufgeführt sind. Die Typbibliotheken ermöglichen dem Access-Compiler
Einen Objektvariablenverweis auf Ihre Anwendung deklarieren
939
das Überprüfen der Syntax der Objekte, Eigenschaften und Methoden einer ServerAnwendung. Außerdem können Sie eine Typbibliothek verwenden, um für die Objekte, Eigenschaften und Methoden einer anderen Anwendung von Access aus Hilfetexte aufzurufen. Ein »Objektmodell« eines Automatisierungs-Servers umfasst jene Gruppe von Objekten, die Automatisierungs-Clients zur Verfügung gestellt werden. Die Objekte im Objektmodell werden als »Objekttypen« bezeichnet. Beim Schreiben von Automatisierungscode erstellen Sie Instanzen eines Objekttyps und nehmen Veränderungen an ihnen vor. Solche Instanzen heißen »Objekte«. Berücksichtigen Sie stets die Anforderungen an die Hardware, welche sich aus der Automatisierung ergeben. Einem Entwickler, der für seine Arbeit einen Pentium II mit 128 MB RAM einsetzt, kann es leicht passieren, dass er eine ausgefeilte Anwendung erstellt, die jedoch leider auf den von den Benutzern verwendeten 486er-PCs mit 12 MB nicht funktioniert. Automatisierung »frisst« Hauptspeicher. Je mehr davon vorhanden ist, desto besser! Für Anwendungen, die mit Automatisierung arbeiten, empfehle ich mindestens 48 MB RAM. Außerdem ist zu bedenken, dass Automatisierung auch auf den flottesten Rechnern relativ langsam abläuft.
26.3
Einen Objektvariablenverweis auf Ihre Anwendung deklarieren
Automatisierung erfordert das Erstellen von Objektvariablen, die sich auf die Anwendungsobjekte beziehen. Nachdem Sie eine Objektvariable erstellt haben, können Sie die Eigenschaften des entsprechenden Objekts durchsuchen und seine Methoden ausführen. Mit Hilfe der Objektbibliotheken eines Objekts können Sie sich über seine Eigenschaften und Methoden informieren. Eine »Objektbibliothek« enthält eine Auflistung aller von einem Objekt angebotenen Eigenschaften und Methoden. Um von Access aus mit fremden Objekten arbeiten zu können, müssen Sie zunächst einen Verweis auf die entsprechende Anwendung erstellen. Anschließend können Sie sich die Eigenschaften und Methoden sowie sämtliche verfügbaren Module und Klassen des Objekts mit Hilfe des Objektkatalogs anschauen. Um ein Objekt registrieren zu können, muss der Visual Basic Editor (VBE) aktiv sein. Wählen Sie im Menü EXTRAS des Code-Fensters die Option VERWEISE aus. Das daraufhin erscheinende Dialogfeld VERWEISE sehen Sie in Abbildung 26.1. Jedesmal, wenn Sie ein Programm installieren, wird die Windows-Registrierung aktualisiert. Im Dialogfeld VERWEISE sind sämtliche Objekte aufgeführt, die unter Windows registriert sind (siehe Abbildung 26.2). Eine Verknüpfung mit einem der innerhalb von Access verfügbaren Objekte können Sie erstellen, indem Sie das ent-
940
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
Abbildung 26.1: Das Dialogfeld Verweise
sprechende Kontrollkästchen neben dem Namen des Objekts aktivieren und auf die Schaltfläche OK klicken. Im Objektkatalog können Sie sich anschließend die Eigenschaften und Methoden jenes Objekts anschauen (siehe Abbildung 26.3). In Kapitel 8 wurde bereits erwähnt, dass Sie den Objektkatalog aufrufen können, indem Sie im Menü ANSICHT die Option OBJEKTKATALOG auswählen, [F2] drücken oder im Fenster MODULE auf das Werkzeug OBJEKTKATALOG klicken. Beachten Sie in Abbildung 26.3, dass im Objektkatalog sämtliche Klassen der Excel 9.0-Objektbibliothek dargestellt werden. Die Klasse Range wurde bereits ausgewählt. Im Listenfeld auf der rechten Seite sehen Sie die Elemente der Klasse Range. In diesem Fall ist die Methode AutoFill ausgewählt. Im unteren Teil des Objektkatalogs sind sämtliche Parameter der Methode AutoFill der Klasse Range aufgeführt.
26.4
Ein Automatisierungsobjekt erstellen
Bevor Sie mit einer Anwendung kommunizieren können, müssen Ihnen die in ihr enthaltenen Objekte bekannt sein. Anschließend können Sie mit Hilfe der Anweisungen Dim, Private bzw. Public unterschiedliche Objekte der Anwendung ansprechen und steuern. Jedes Produkt wird mit einer Dokumentation ausgeliefert, in der auf die von ihm unterstützten Objekte verwiesen wird. Außerdem können Sie sich die von einem Produkt unterstützten Objekte mit dem Objektkatalog anschauen. Nachdem Sie eine Objektvariable erstellt haben, können Sie das jeweilige Objekt ohne weiteres Einwirken des Benutzers verwenden.
941
Ein Automatisierungsobjekt erstellen
Abbildung 26.2: Registrierte Automatisierungs-ServerObjekte
Abbildung 26.3: Der Objektkatalog
942
26.4.1
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
Eine Objektvariable deklarieren
Um eine Instanz eines Objekts zu erstellen, müssen Sie zunächst eine Objektvariable erstellen, welche auf das Objekt verweist. Dies können Sie mit Hilfe der Dim-Anweisung bewerkstelligen: Dim objExcel As New Excel.Application
Dieser Code erstellt eine Objektvariable, welche auf das Application-Objekt von Excel verweist. Eine neue Instanz von Excel wird automatisch gestartet. Dieses Excel-Objekt ist ein Bestandteil der Anwendung Excel. Es kann von VBA aus mit Hilfe der Objektvariablen gesteuert werden. Falls nichts anderes angegeben wurde, bleibt die Instanz von Excel verborgen. Durch die folgende Anweisung können Sie sie sichtbar machen: objExcel.Visible = True
Sie können ein Objekt auch mittels der beiden folgenden Anweisungen deklarieren und die Instanz bilden: Dim objExcel as Excel.Application Set objExcel = New Excel.Application
Durch die Dim-Anweisung wird eine Objektvariable deklariert, die unmittelbar mit einer laufenden Instanz von Excel verknüpft werden kann. Die Set-Anweisung startet Excel und lässt die Objektvariable auf die laufende Instanz von Excel verweisen. Der Vorteil dieser Methode besteht darin, dass Sie besser regulieren können, wann die Instanz von Excel tatsächlich erstellt wird. Falls die Deklaration beispielsweise im Abschnitt ALLGEMEINE DEKLARATIONEN eines Formulars angegeben wird, besteht die Möglichkeit, die Set-Anweisung einer Befehlsschaltfläche zuzuordnen, welche verwendet wird, um Excel zu starten.
26.5
Ein Automatisierungsobjekt anpassen
Nachdem Sie eine Instanz eines Objekts erstellt haben, können Sie dessen Eigenschaften festlegen und seine Methoden ausführen. Mit Hilfe der von Ihnen erstellten Objektvariablen können Sie mit dem Objekt kommunizieren, Eigenschaften ermitteln und festlegen sowie Methoden ausführen.
26.5.1
Eigenschaften festlegen und abrufen
Sämtliche Objekte, die Sie per Automatisierung ansprechen, verfügen über Eigenschaften. »Eigenschaften« sind Attribute des Objekts – die Adjektive, welche Sie für das Beschreiben der Objekte verwenden. Mit Hilfe von VBA können Sie die Werte der Eigenschaften von Objekten ermitteln und festlegen. Dies sind einige Beispiele:
Excel mit Access steuern
943
objExcel.Visible = True objExcel.Caption = "Hello World" objExcel.Cells(1, 1).Value = "Here I Am"
Jedes dieser Beispiele legt Eigenschaften des Excel-Anwendungsobjekts fest. Das erste Beispiel weist der Eigenschaft Visible des Objekts den Wert True zu, das zweite Beispiel bestimmt die Beschriftung des Objekts und das letzte Beispiel legt die Eigenschaft Value des im Excel-Objekt enthaltenen Objekts Cells als "Here I Am" fest.
26.5.2
Methoden ausführen
Eigenschaften beziehen sich auf die Attribute eines Objekts und »Methoden« entsprechen den Aktionen, die Sie auf das Objekt anwenden können. Methoden sind die zu einem bestimmten Objekttyp gehörenden Verben. Es folgt ein Beispiel: objExcel.Workbooks.Add
Dieser Code fügt dem Excel-Objekt mit Hilfe der Methode Add eine Arbeitsmappe hinzu.
26.6
Excel mit Access steuern
Bevor Sie versuchen, mit Excel zu kommunizieren, müssen Sie das Objektmodell der Anwendung kennen. Excel bietet Ihnen einen hervorragenden Überblick über das Objektmodell von Excel. Sie können dieses Modell auffinden, indem Sie in der Excel-Hilfe nach dem Begriff »Objektmodell« suchen. Für jedes Objekt des Modells finden Sie dort Hyperlinks, anhand derer Sie weitere Einzelheiten über das Objekt, seine Eigenschaften und seine Methoden erfahren können. Wenn Sie Excel starten, wird es standardmäßig als verborgenes Fenster aktiviert, dessen Eigenschaft Visible den Wert False aufweist. Das Beseitigen der Objektvariablen von Excel bewirkt jedoch nicht das Beenden der Anwendung. Um die Dinge noch komplizierter zu machen, wird jedesmal, wenn Sie das Schlüsselwort New im Rahmen einer Dim- oder Set-Anweisung verwenden, eine neue Instanz von Excel gestartet. Sie können demnach mit zahlreichen verborgenen Instanzen von Excel gleichzeitig arbeiten, was jedoch erhebliche Ressourcen beanspruchen kann. Falls Sie mit einer bereits aktiven Instanz von Excel arbeiten, können Sie das Schlüsselwort New vermeiden. Doch auch diese Vorgehensweise hat Nachteile. Gehen wir beispielsweise einmal davon aus, dass der Benutzer Ihrer Anwendung eine umfangreiche Tabelle erstellt hat, die bislang nicht gespeichert wurde. Ihre Anwendung verwendet eine vorhandene Instanz von Excel, erstellt eine neue Arbeitsmappe, druckt diese und verlässt Excel ohne vorheriges Speichern. Dies könnte dazu führen, dass der Benutzer über den Verlust seiner Arbeit äußerst ungehalten reagiert. Ich halte es aus diesem Grund für besser, eine eigene Instanz von Excel zu erstellen und den dafür erforderlichen Aufwand hinzunehmen. Wenn Sie Excel verborgen gestartet und ihre
944
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
Arbeit getan haben, sollten Sie darauf achten, Excel vor der Beendigung Ihres Codes zu beenden. Bevor Sie Code starten, für dessen Ausführung eine Kopie von Excel erforderlich ist, müssen Sie sicherstellen, dass Excel einwandfrei gestartet wurde. In dem in Listing 26.1 dargestellten Code wird zunächst versucht, Excel zu starten. Wenn dieser Vorgang erfolgreich verläuft, liefert die Funktion den Wert True. Ansonsten gibt sie den Wert False zurück. Listing 26.1:
Die Unterroutine CreateExcelObj
Function CreateExcelObj() As Boolean On Error GoTo CreateExcelObj_Err CreateExcelObj = False 'Versuch, Excel zu starten Set gobjExcel = New Excel.Application Create ExcelObj = True CreateExcelObj_Exit Exit Function CreateExcelObj_Err MsgBox "Couldn't Launch Excel!!", vbCritical, "Warning!!" CreateExcelObj = False Resume CreateExcelObj_Exit End Function
Die Routine beginnt mit der Ausführung einer Fehlerbehandlung. Der Rückgabewert der Funktion wird mit False initialisiert. Anschließend wird versucht, Excel zu starten. Falls dies gelingt, verweist die öffentliche Variable gobjExcel auf die laufende Instanz von Excel und die Funktion gibt den Wert True zurück. Wenn ein Fehler auftritt, wird der Code der Fehlerbehandlungsroutine ausgeführt, eine entsprechende Meldung ausgegeben und der Rückgabewert der Funktion auf False gesetzt. Diesen und den Code der meisten anderen Beispiele dieses Kapitels finden Sie in der Datenbank CHAP26EX.MDB auf der diesem Buch beiliegenden CD-ROM. Diese Routine befindet sich im Modul basUtils.
Damit die gesamte Bandbreite der durch Automatisierung gebotenen Möglichkeiten verfügbar ist, müssen sämtliche Automatisierungs-Server-Anwendungen auf dem Rechner des Benutzers installiert sein und der Benutzer muss über eine vollwertige Lizenz für die Server-Anwendungen verfügen. Die in der Beispieldatenbank für dieses Kapitel enthaltenen Beispiele können tatsächlich nicht gestartet werden, falls die ServerAnwendungen nicht zuvor auf Ihrem Entwicklungsrechner installiert wurden.
Excel mit Access steuern
945
Die Funktion CreatExcelObj wird über das Ereignis Click der Befehlsschaltfläche cmdFillExcel des Formulars frmSimpleExcel aufgerufen. Die Anwendung versucht nur dann mit dem Excel-Objekt zu kommunizieren, wenn der Rückgabewert der Funktion den Wert True aufweist und somit bestätigt, dass Excel erfolgreich gestartet werden konnte. Private Sub cmdFillExcel_Click() If CreateExcelObj() Then Call FillCells End If End Sub
Falls Excel erfolgreich gestartet werden kann, wird die in Listing 26.2 dargestellte Unterroutine FillCells ausgeführt. Listing 26.2:
Die Unterroutine FillCells
Sub FillCells() Dim objWS As Excel.Worksheet With gobjExcel .Workbooks.Add Set objWS = gobjExcel.ActiveSheet With objWS .Cells(1, 1).Value = "Schedule" .Cells(2, 1).Value = "Day" .Cells(2, 2).Value = "Tasks" .Cells(3, 1).Value = 1 .Cells(4, 1).Value = 2 End With .Range("A3:A4").Select .Selection.AutoFill gobjExcel.Range("A3:A33") .Range("A1").Select .Visible = True End With End Sub
Diese relativ einfache Routine gehört zum Formular frmSimpleExcel, einem Bestandteil der Datenbankdatei CHAP26EX.MDB (siehe Abbildung 26.4). Zunächst wird auf die Arbeitsmappenauflistung des Excel-Objekts die Methode Add angewendet, um der Instanz von Excel eine neue Arbeitsmappe hinzuzufügen. Anschließend wird durch die Anweisung Set objWS = gobjExcel.ActiveSheet eine Verknüpfung zum Kommunizieren mit der neuen Excel-Arbeitsmappe erstellt. Mit Hilfe der Objektreferenz objWS werden die Werte diverser Zellen verändert. Die Methode AutoFill wird benutzt, um rasch einen Bereich von Zellen mit Daten zu füllen. Nach dem Festlegen der Einfügemarkenposition im Feld A1 wird das Excel-Objekt sichtbar gemacht. Möglicherweise ist Ihnen der Zweck der Methode AutoFill nicht bekannt. Diese Methode automatisiert den Vorgang des Ausfüllens
946
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
eines Bereichs von Zellen mit einem bestimmten Muster von Daten. Das Ergebnis sehen Sie in Abbildung 26.5. Ich erwähne dies nicht nur, damit Sie diese Funktion verstehen, sondern auch, um eine wichtige Tatsache zu verdeutlichen: Das zu automatisierende Produkt und die von ihm gebotenen Möglichkeiten müssen Ihnen bekannt sein. Falls Sie sich mit dem Produkt noch nicht als Benutzer auseinandergesetzt haben, wird es Ihnen außerordentlich schwer fallen, entsprechende Instanzen zu automatisieren.
Abbildung 26.4: Dieses Formular wird verwendet, um Excel zu starten, mit der Anwendung zu kommunizieren und sie zu schließen
Abbildung 26.5: Ausfüllen eines Bereichs von Zellen mit Hilfe der Funktion AutoFill
Ein Excel-Automatisierungsobjekt schließen
26.7
947
Ein Excel-Automatisierungsobjekt schließen
Sobald der Benutzer die Schaltfläche Close Excel anklickt, wird die Unterroutine CloseExcel aufgerufen (siehe Abbildung 26.3). Die Routine überprüft zunächst, ob die Objektvariable gobjExcel noch immer gesetzt ist. Falls dies so ist, wird Exel weiter ausgeführt. Der Eigenschaft DisplayAlerts von Excel wird der Wert False zugewiesen und auf diese Weise dafür gesorgt, dass Excel während des Ausführens der Methode Quit keine Warnung bezüglich nicht gespeicherter Kalkulationstabellen ausgibt. Diese Vorgehensweise ist durchführbar, da sämtliche Aufgaben mit Hilfe einer neuen Instanz der Anwendung Excel ausgeführt wurden. Falls Sie möchten, dass Ihre Arbeit gespeichert wird, sollten Sie die entsprechende Methode vor dem Aufrufen der Methode Quit ausführen. Listing 26.3:
Die Routine CloseExcel
Sub CloseExcel() If Not gobjExcel Is Nothing Then gobjExcel.DisplayAlerts = False gobjExcel.Quit End If CloseExcel_Exit: Set gobjExcel = Nothing Exit Sub CloseExcel_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description Resume CloseExcel_Exit End Sub
26.8
Mit Hilfe von Access ein Diagramm erstellen
Nachdem Sie nun wissen, wie mit Excel kommuniziert werden kann, können Sie sich praktischeren Anwendungen widmen. In Abbildung 26.6 sehen Sie ein Formular namens frmCreateExcelGraph. Das Formular enthält das Ergebnis einer Abfrage, welche das Ergebnis der Multiplikation von Preis und Anzahl eines verkauften Gutes für jedes Land zusammenfasst. Die Befehlsschaltfläche CREATE EXCEL GRAPH sendet das Ergebnis der Abfrage an Excel und generiert das in Abbildung 26.7 dargestellte Diagramm. (Listing 26.4 enthält den dafür zuständigen Code.)
948
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
Abbildung 26.6: Das zum Erstellen eines Excel-Diagramms verwendete Formular
Abbildung 26.7: Das als Diagramm dargestellte Ergebnis einer Abfrage Listing 26.4:
Erstellen eines Diagramms von Access aus
Private Sub cmdCreateGraph_Click() On Error GoTo cmdCreateGraph_Err Dim rstData As ADODB.Recordset Dim rstCount As ADODB.Recordset Dim fld As ADODB.Field
Mit Hilfe von Access ein Diagramm erstellen
Dim Dim Dim Dim
949
rng As Excel.Range objWS As Excel.Worksheet intRowCount As Integer intColCount As Integer
'Sanduhr anzeigen DoCmd.Hourglass True Set rstData = New ADODB.Recordset rstData.ActiveConnection = CurrentProject.Connection Set rstCount = New ADODB.Recordset rstCount.ActiveConnection = CurrentProject.Connection 'Versuch, Datensatzgruppe zu erstellen und Excel zu starten If CreateRecordset(rstData, rstCount, "qrySalesByCountry") Then If CreateExcelObj() Then gobjExcel.Workbooks.Add Set objWS = gobjExcel.ActiveSheet intRowCount = 1 intColCount = 1 ' Durchlaufen der Auflistung der Felder mit ' den Feldnamen als Spaltenüberschriften For Each fld In rstData.Fields If fld.Type <> adLongVarBinary Then objWS.Cells(1, intColCount).Value = fld.Name intColCount = intColCount + 1 End If Next fld ' Senden einer Datensatzgruppe an Excel objWS.Range("A1").CopyFromRecordset rstData, 500
'Daten formatieren With gobjExcel .Columns("A:B").Select .Columns("A:B").EntireColumn.AutoFit .Range("A1").Select .ActiveCell.CurrentRegion.Select Set rng = .Selection .Selection.NumberFormat = "$#,##0.00" 'Diagrammobjekt hinzufügen .ActiveSheet.ChartObjects.Add(135.75, 14.25, 607.75, 301).Select 'Diagramm-Assistent ausführen .ActiveChart.ChartWizard Source:=Range(rng.Address), _ Gallery:=xlColumn, _ Format:=6, PlotBy:=xlColumns, CategoryLabels:=1, SeriesLabels _ :=1, HasLegend:=1, Title:="Sales By Country", CategoryTitle _ :="", ValueTitle:="", ExtraTitle:="" 'Excel sichtbar machen
950
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
.Visible = True End With Else MsgBox "Excel Not Successfully Launched" End If Else MsgBox "Too Many Records to Send to Excel" End If DoCmd.Hourglass False cmdCreateGraph_Exit: Set rstData = Nothing Set rstCount = Nothing Set fld = Nothing Set rng = Nothing Set objWS = Nothing DoCmd.Hourglass False Exit Sub cmdCreateGraph_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description Resume cmdCreateGraph_Exit End Sub
In dieser Routine werden zunächst einige Objektvariablen erstellt. Anschließend werden zwei Datensatzgruppen erzeugt und der Eigenschaft ActiveConnection der einzelnen Datensatzgruppen wird die Verknüpfung mit dem aktuellen Projekt zugewiesen. Dann wird eine benutzerdefinierte Funktion namens CreateRecordset aufgerufen, welche sich im Modul basUtils befindet. An die Funktion CreateRecordset sind drei Parameter zu übergeben: die beiden Objektvariablen der Datensatzgruppen sowie der Name einer Abfrage. In Listing 26.5 ist die Funktion CreateRecordset dargestellt. Listing 26.5:
Die Funktion CreateRecordset
Function CreateRecordset(rstData As ADODB.Recordset, _ rstCount As ADODB.Recordset, _ strTableName As String) On Error GoTo CreateRecordset_Err ' Erstellen der Datensatzgruppe, welche die Anzahl der Datensätze 'in der Abfrage enthält rstCount.Open "Select Count(*) As NumRecords from " & strTableName 'Falls sich aus der Abfrage mehr als 500 Datensätze ergeben, wird der Rückgabewert 'auf false gesetzt 'Ansonsten wird aus der Abfrage eine Datensatzgruppe erstellt If rstCount!NumRecords > 500 Then CreateRecordset = False
Mit Hilfe von Access ein Diagramm erstellen
951
Else rstData.Open strTableName CreateRecordset = True End If CreateRecordset_Exit: Set rstCount = Nothing Exit Function CreateRecordset_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description Resume CreateRecordset_Exit End Function
Diese Funktion ermittelt zunächst, wie viele Datensätze durch den übergebenen Abfragenamen zurückgegeben wurden. Falls dies mehr als 500 sind, liefert die Funktion den Wert False. Ansonsten öffnet die Funktion basierend auf dem Abfragenamen eine Datensatzgruppe und gibt den Wert True zurück. Diese Funktion gewährleistet, dass nur eine vernünftige Anzahl von Datensätzen an Excel gesendet wird und die Datensatzgruppe erfolgreich geöffnet werden kann. Falls die Funktion CreateRecordset den Wert True zurückgibt, wird der restliche Code zur Behandlung des Ereignisses Click der Befehlsschaltfläche cmdCreateGraph ausgeführt. Excel wird von der Routine mit Hilfe der Funktion CreateExcelObj gestartet. Wenn Excel erfolgreich geöffnet werden konnte, wird eine neue Arbeitsmappe erstellt. Anschließend durchläuft die Routine jedes einzelne Feld der Auflistung Fields der Datensatzgruppe (dem Ergebnis der Abfrage). Den Zellen der ersten Zeile des Tabellenblatts werden die Namen der Felder in der Datensatzgruppe zugewiesen. Als nächstes verwendet die Routine die Methode CopyFromRecordset des ExcelObjekts Range, um die Inhalte der Datensatzgruppe rstData in die Zelle A1 des aktiven Arbeitsblatts zu kopieren. Die Daten jeder einzelnen Zeile werden auf dem Arbeitsblatt jeweils unterschiedlichen Zeilen zugewiesen und auch die Daten in den einzelnen Spalten werden auf dem Arbeitsblatt in separaten Spalten erfasst. OLE-Objektfelder (adLongVarBinary) bleiben bei diesem Vorgang unberücksichtigt. Nachdem sämtliche Daten der Datensatzgruppe an Excel gesendet wurden, kann das Erstellen eines Diagramms in Angriff genommen werden. Die Routine bewegt den Cursor zur Zelle A1 und wählt anschließend den gesamten angrenzenden Bereich von Daten aus. Dann fügt sie dem Arbeitsblatt ein Diagrammobjekt hinzu und verwendet den Diagramm-Assistenten, um das Diagramm zu erstellen. Abschließend wird Excel sichtbar gemacht, damit der Benutzer die Früchte dieser Anstrengungen betrachten kann.
952
26.9
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
Word von Access aus steuern
Im vorherigen Abschnitt haben Sie bereits festgestellt, dass Excel diverse Objekte zur Verfügung stellt. Jedes dieser Objekte kann mit Hilfe seiner eigenen Methoden und Eigenschaften einzeln modifiziert werden. Vor Office 97 galt dies für Word nicht, da Word lediglich ein einziges Objekt mit der Bezeichnung Word.Basic verfügbar machte. Microsoft Word 97 und Microsoft Word 2000 unterstützen die Programmiersprache Visual Basic for Applications jedoch vollständig. Sowohl Word 97 als auch Word 2000 stellen zahlreiche Objekte zur Verfügung, wie es auch bei Excel und anderen Microsoft-Produkten der Fall ist. Word können Sie genau wie Excel mit Hilfe der Anweisung Dim bzw. Dim as New starten. Analog zu Excel wird Word als verborgenes Objekt gestartet. Das Word-Anwendungsobjekt verfügt über eine Visible-Eigenschaft, anhand derer das Word-Objekt sichtbar gemacht werden kann. Wenn Sie ein Word-Objekt mittels Automatisierung erstellen, wird Word nicht automatisch beendet, nicht einmal, wenn die Objektvariable gelöscht wird. In Abbildung 26.8 sehen Sie das Formular frmMergeToWord, in dem die Ergebnisse einer Abfrage mit der Bezeichnung qryMailMerge erfasst sind. Sobald der Benutzer auf die Schaltfläche WORD klickt, werden alle dargestellten Datensätze zum Seriendruck an Word gesendet und ausgedruckt. In Abbildung 26.9 sehen Sie ein Beispiel für ein auf diese Weise erstelltes Dokument. Der Code, mit dem dieses Dokument erzeugt wurde, ist in Listing 26.6 dargestellt.
Abbildung 26.8: Dies sind die einem WordDokument hinzuzufügenden Daten
Word von Access aus steuern
953
Abbildung 26.9: Das Ergebnis eines Seriendrucks Listing 26.6:
Erzeugen eines Word-Serienbriefs
Private Sub cmdMergeToWord_Click() On Error GoTo cmdMergeToWord_Err DoCmd.Hourglass True If CreateWordObj() Then With gobjWord .Visible = True .Documents.Open "c:\windows\desktop\avorwort2.doc" DoEvents With gobjWord.ActiveDocument.MailMerge .Destination = wdSendToNewDocument .SuppressBlankLines = True .Execute End With .ActiveDocument.PrintPreview 'Preview .Visible = True End With End If cmdMergeToWord_Exit: DoCmd.Hourglass False Exit Sub cmdMergeToWord_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description
954
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
Set gobjWord = Nothing Resume cmdMergeToWord_Exit End Sub
Während der Verarbeitung des Codes verwandelt sich der Mauszeiger zunächst in eine Sanduhr. Dies signalisiert dem Benutzer, dass der gegenwärtige Vorgang einige Zeit in Anspruch nimmt. Anschließend wird die Routine CreateWordObj aufgerufen und damit ein Word-Objekt erstellt. Die Routine CreateWordObj ähnelt der in diesem Kapitel bereits vorgestellten Routine CreateExcel. Für die Auflistung der Dokumente des Word-Objekts wird die Methode Open angewendet. Auf diese Weise wird ein Dokument mit der Bezeichnung customerletter im Verzeichnis Eigene Dateien geöffnet. Mit Hilfe der Ergebnisse einer Abfrage namens qryMerge wurde das Dokument customerletter bereits als Seriendruck eingerichtet. Die Unterroutine legt die Eigenschaft Destination des MailMerge-Objekts als neues Dokument fest. Sie weist der Eigenschaft SuppressBlankLines den Wert True zu und führt den Seriendruck anschließend anhand der Methode Execute aus. So werden die Ergebnisse von qryMailMerge miteinander verknüpft und ein neuer Serienbrief erstellt. Die Methode PrintPreview wird auf das Objekt ActiveDocument angewendet, damit das Seriendruckdokument gedruckt wird. Abschließend wird der Eigenschaft Visible des Word-Objekts noch der Wert True zugewiesen, um das Word-Dokument sichtbar zu machen und die Sanduhr verschwindet.
26.10 PowerPoint von Access aus steuern Ob Sie es glauben oder nicht, sogar PowerPoint kann mittels Automatisierung gesteuert werden. Sie können eine Präsentation erstellen, drucken oder sogar von Access aus auf dem Bildschirm präsentieren. PowerPoint wird zunächst als verborgenes Fenster gestartet. Um PowerPoint sichtbar zu machen, müssen Sie die Eigenschaft Visible von AppWindow auf True setzen. Das Löschen der Objektvariablen von PowerPoint ist nicht hinreichend, um die PowerPoint-Anwendung zu beenden. Die Einzelheiten des PowerPoint-Objektmodells sind auf der CD-ROM des Microsoft Solutions Development Kits beschrieben. Mit diesem Objektmodell sollten Sie sich auseinandersetzen, bevor Sie versuchen, mit PowerPoint zu kommunizieren. Der in Listing 26.7 dargestellte Code wurde dem Ereignis Click der Befehlsschaltfläche cmdChangePicture des Formulars frmOLEToPowerPoint zugewiesen, welche in Abbildung 26.10 dargestellt ist. In Abbildung 26.11 sehen Sie die daraus resultierende PowerPoint-Folie.
PowerPoint von Access aus steuern
955
Abbildung 26.10: Das zum Erstellen einer PowerPoint-Folie verwendete Formular
Abbildung 26.11: Eine mittels Automatisierung erstellte PowerPoint-Folie Listing 26.7:
Auswählen eines Bildes
Private Sub cmdChangePicture_Click() dlgCommon.ShowOpen If Len(dlgCommon.Filename) Then olePicture.SourceDoc = dlgCommon.Filename olePicture.Action = acOLECreateLink End If End Sub
956
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
Im Code des Ereignisses Click der Befehlsschaltfläche cmdChangePicture wird das Dialogfeld DATEI ÖFFNEN aufgerufen, damit der Benutzer ein Bild auswählen kann, welches der Folie hinzugefügt werden soll. Die vom Dialogfeld zurückgegebene Eigenschaft FileName wird für das Automatisierungsobjekt als SourceDoc-Eigenschaft verwendet. Anschließend wird das neue Bild mit dem Automatisierungsobjekt verknüpft. In Listing 26.8 sehen Sie die Routine, welche die PowerPoint-Folie erstellt. Listing 26.8:
Erstellen der PowerPoint-Folie
Private Sub cmdMakePPTSlide_Click() Dim objPresentation As PowerPoint.Presentation Dim objSlide As PowerPoint.Slide If IsNull(Me.txtTitle) Or Me.olePicture.SourceDoc = "" Then MsgBox "A Title Must Be Entered, and a Picture Selected Before Proceeding" Else 'PowerPoint-Instanz erstellen Set mobjPPT = New PowerPoint.Application 'Instanz sichtbar machen mobjPPT.Visible = True 'Eine Präsentation hinzufügen Set objPresentation = mobjPPT.Presentations.Add 'Eine Folie hinzufügen Set objSlide = objPresentation.Slides.Add(1, ppLayoutTitleOnly) 'Den Folienhintergrund ändern objSlide.Background.Fill.ForeColor.RGB = RGB(255, 100, 100) 'Den Folientitel ändern With objSlide.Shapes.Title.TextFrame.TextRange .Text = Me.txtTitle .Font.Color.RGB = RGB(0, 0, 255) .Font.Italic = True End With 'OLE-Bilder hinzufügen objSlide.Shapes.AddOLEObject _ Left:=200, Top:=200, Width:=500, Height:=150, _ Filename:=olePicture.SourceDoc, link:=True End If cmdMakePPTSlide_Exit: Set objPresentation = Nothing Set objSlide = Nothing
Access von anderen Anwendungen aus steuern
957
Exit Sub cmdMakePPTSlide_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description Resume cmdMakePPTSlide_Exit End Sub
In der Routine wird zunächst eine Instanz von PowerPoint erstellt und sichtbar gemacht. Anschließend wird dem PowerPoint-Objekt eine Präsentation hinzugefügt, der ihrerseits eine Folie hinzugefügt wird. Der Hintergrund der Folie wird verändert und die Eigenschaften text, color und italic des Titelobjekts werden angepasst. Abschließend wird die Eigenschaft SourceDoc des Objekts olePicture verwendet, um ein Automatisierungsobjekt zu erstellen, welches der Folie hinzugefügt wird.
26.11
Access von anderen Anwendungen aus steuern
Häufig ist es zweckmäßig, Access von anderen Anwendungen aus zu steuern. Beispielsweise können Sie beabsichtigen, einen Access-Bericht von einer Visual Basicoder einer Excel-Anwendung aus zu starten. Genauso wie Sie einen Großteil der zahlreichen Funktionen anderer Produkte (etwa Excel) von Access aus benutzen können, haben Sie die Möglichkeit, über einige der Funktionen von Access von anderen Anwendungen aus zu verfügen. Glücklicherweise ist es ausgesprochen einfach, Access von anderen Anwendungen aus zu steuern. Einen Überblick über das Objektmodell von Access finden Sie in der Access-Hilfe. Wenn Sie sich mit dem Access-Objektmodell noch nicht besonders gut auskennen, sollten Sie diese grafische Veranschaulichung des Objektmodells von Access betrachten, bevor Sie versuchen, Access zu steuern. Beim Starten von Access weist dessen Visible-Eigenschaft standardmäßig den Wert False auf. Sie können die Visible-Eigenschaft des Anwendungsobjekts in True ändern, um Access sichtbar zu machen. Bei dem in Abbildung 26.12 gezeigten Formular handelt es sich um ein mit einer Excel-Tabelle verknüpftes UserForm-Formular. Diese wird als frmReportSelect bezeichnet und gehört zur Excel-Kalkulationstabelle RunAccessReports.xls, welche Sie auf der diesem Buch beiliegenden CD-ROM vorfinden. Dieses Formular erlaubt Ihnen das Auswählen einer beliebigen Access-Datenbank. Auf Ihm wird eine Liste sämtlicher Berichte der ausgewählten Datenbank angezeigt. Sie können diese Liste benutzen, um eine Vorschau eines Access-Berichts zu betrachten oder mehrere Access-Berichte auszudrucken. In Listing 26.9 sehen Sie, wie dieses Benutzerformular seine Arbeit verrichtet.
958
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
Abbildung 26.12: Dieses Benutzerformular ermöglicht Ihnen das Ausdrucken von Berichten Listing 26.9:
Erstellen eines Visual Basic-Formulars zum Ausdrucken von Berichten
Private Sub cmdSelectDatabase_Click() dlgCommon.Filter = ".mdb" dlgCommon.ShowOpen If dlgCommon.FileName = "" Then MsgBox "You Must Select a File to Continue" Else Me.txtSelectedDB = _ dlgCommon.FileName Call ListReports End If End Sub Private Sub ListReports() On Error GoTo ListReports_Err Dim vntReport As Variant If mobjAccess Is Nothing Then Set mobjAccess = New Access.Application End If mobjAccess.OpenCurrentDatabase (Me.txtSelectedDB) lstReports.Clear For Each vntReport In mobjAccess.CurrentProject.AllReports lstReports.AddItem vntReport.Name Next vntReport ListReports_Exit: Exit Sub
Access von anderen Anwendungen aus steuern
959
ListReports_Err: MsgBox "Error #" & Err.Number & _ ": " & Err.Description Resume ListReports_Exit End Sub
In der Routine für das Ereignis cmdSelectDatabase_Click wird die Eigenschaft Filter auf das Common Dialog-Steuerelement für Access-Datenbankdateien gesetzt. Die Methode ShowOpen des Standarddialogfelds wird verwendet, um das Dialogfeld ÖFFNEN für den Benutzer anzuzeigen. Sobald der Benutzer in dem Dialogfeld eine Datei auswählt, wird die Routine ListReports ausgeführt. In der Unterroutine ListReports wird zunächst eine Instanz der Access-Anwendung erstellt. Die Methode OpenCurrentDatabase des Access-Objekts wird verwendet, um die vom Benutzer im Dialogfeld ÖFFNEN ausgewählte Datei zu öffnen. Anschließend wird die Auflistung des Objekts CurrentProject durchlaufen, welches mit der ausgewählten Datenbank verknüpft ist. Die Namen der einzelnen Berichte werden dem Listenfeld hinzugefügt. Mit Hilfe der in Listing 26.10 dargestellten Routine werden die ausgewählten Berichte ausgedruckt. Listing 26.10: Erstellen einer neuen Instanz des Access-Anwendungsobjekts Private Sub cmdPrint_Click() On Error GoTo cmdPreview_Err Dim intCounter As Integer Dim intPrintOption As Integer If optPreview.Value = True Then intPrint.Option = acViewPreview ElseIf optPrint.Value = True Then intPrint.Option = acViewNormal EndIf mobjAccess.Visible = True For intCounter = 0 To _ lstReports.ListCount – 1 If lstReports.Selected(intCounter) Then mobjAccess.DoCmd.OpenReport _ ReportName:=Me.lstReports.List(intCounter), _ View:=intPrintOption EndIf Next intCounter cmdPreview_Exit Exit Sub cmdPreview_Err: MsgBox "Error #" & Err.Number & _
960
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
": " & Err.Description If Not mobjAccess Is Nothing Then mobjAccess.Quit EndIf Set mobjAccess = Nothing Resume cmdPreview_Exit End Sub
In der Routine für das Ereignis cmdPrint_Click wird zunächst ermittelt, welche der Schaltfläche DRUCKEN bzw. VORSCHAU ausgewählt wurde. Danach wird das AccessAnwendungsobjekt sichtbar gemacht. Anschließend durchläuft der Code das Listenfeld lstReports und druckt die ausgewählten Berichte aus oder zeigt eine Vorschau an. Die Methode OpenReport wird gemeinsam mit der Konstanten acViewPrewiew oder acViewNormal verwendet, um dies zu bewerkstelligen.
26.11.1 Für die Praxis Erweitern der Funktionalität der Anwendung für das Zeit- und Abrechnungssystem mit Hilfe von Automatisierung Für die Anwendung des Zeit- und Abrechnungssystems bieten sich diverse automatisierbare Anwendungen an. Eine von ihnen wird in diesem Abschnitt erörtert. Das in Abbildung 26.13 dargestellte Formular ermöglicht Benutzern das Auswählen einer Tabelle oder Abfrage, die an Excel gesendet werden soll. Das Formular wird als frmSendToExcel bezeichnet.
Abbildung 26.13: Exportieren einer an Excel zu sendenden Tabelle oder Abfrage
Das Listenfeld auf dem Formular wird mit Hilfe der in Listing 26.11 dargestellten Funktion Callback ausgefüllt. Beachten Sie, dass die Funktion die Auflistungen All-
Access von anderen Anwendungen aus steuern
961
Tables und AllQueries der aktuellen Datenbank verwendet, um die Einträge des Listenfelds zu erstellen. Die Systemtabellen bleiben hierbei unberücksichtigt. Listing 26.11: Verwenden der Callback-Funktion zum Ausfüllen eines Listenfelds Function FillWithTableList(ctl As Control, vntID As Variant, _ lngRow As Long, lngCol As Long, intCode As Integer) _ As Variant Dim intCounter As Integer Static sastrTables() As String Static sintNumTables As Integer Dim vntRetVal As Variant Dim vntData As Variant vntRetVal = Null Select Case intCode Case acLBInitialize ' Initialisieren ' Anzahl Tabellen und Abfragen bestimmen sintNumTables = CurrentData.AllTables.Count + _ CurrentData.AllQueries.Count ReDim sastrTables(sintNumTables – 2) ' Dem Listenfeld Tabellennamen hinzufügen For Each vntData In CurrentData.AllTables If Left(vntData.Name, 4) <> "MSys" Then sastrTables(intCounter) = vntData.Name intCounter = intCounter + 1 End If Next vntData ' Dem Listenfeld Abfragenamen hinzufügen For Each vntData In CurrentData.AllQueries sastrTables(intCounter) = vntData.Name intCounter = intCounter + 1 Next vntData vntRetVal = sintNumTables Case acLBOpen 'Öffnen vntRetVal = Timer 'Eindeutige Steuerelement-ID generieren Case acLBGetRowCount 'Anzahl der Zeilen bestimmen vntRetVal = sintNumTables Case acLBGetColumnCount 'Anzahl der Spalten bestimmen vntRetVal = 1 Case acLBGetColumnWidth 'Spaltenbreite bestimmen vntRetVal = -1 '-1 erzwingt Standardbreite Case acLBGetValue 'Daten empfangen vntRetVal = sastrTables(lngRow) End Select FillWithTableList = vntRetVal End Function
962
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
Die Routine für die Eigenschaft Click der Befehlsschaltfläche cmdSendToExcel sendet die ausgewählte Tabelle bzw. Abfrage an Excel. Der entsprechende Code ist in Listing 26.12 dargestellt. Listing 26.12: Senden einer Tabelle oder Abfrage an Excel Private Sub cmdSendToExcel_Click() On Error GoTo cmdSendToExcel_Err Dim objWS As Excel.Worksheet Dim rstData As ADODB.Recordset Dim rstCount As ADODB.Recordset Dim fld As ADODB.Field Dim intColCount As Integer Dim intRowCount As Integer Set rstData = New ADODB.Recordset rstData.ActiveConnection = CurrentProject.Connection Set rstCount = New ADODB.Recordset rstCount.ActiveConnection = CurrentProject.Connection 'Sanduhr DoCmd.Hourglass True 'Datensatzgruppe und Excel-Objekt erstellen If CreateRecordset(rstData, rstCount, lstTables.Value) Then If CreateExcelObj() Then 'Arbeitsmappe hinzufügen gobjExcel.Workbooks.Add 'Eine Verknüpfung erstellen Set objWS = gobjExcel.ActiveSheet intRowCount = 1 intColCount = 1 'Fields-Auflistung durchlaufen 'Feldnamen zu Spaltenköpfen in Excel machen For Each fld In rstData.Fields If fld.Type <> adLongVarBinary Then objWS.Cells(1, intColCount).Value = fld.Name intColCount = intColCount + 1 End If Next fld 'Datensatzgruppe an Excel senden objWS.Range("A2").CopyFromRecordset rstData, 500 gobjExcel.Range("A1").Select 'AutoFilter einrichten gobjExcel.Selection.AutoFilter gobjExcel.Visible = True Else MsgBox "Excel Not Successfully Launched" End If
Access von anderen Anwendungen aus steuern
963
Else MsgBox "Too Many Records to Send to Excel" End If
cmdSendToExcel_Exit: DoCmd.Hourglass False Set objWS = Nothing Set rstCount = Nothing Set rstData = Nothing Set fld = Nothing Exit Sub cmdSendToExcel_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description Resume cmdSendToExcel_Exit End Sub
In der Routine wird zunächst mit Hilfe der in Listing 24.13 dargestellten Funktion CreateRecordSet ein Datensatzgruppenobjekt erstellt. Anschließend wird versucht, Excel zu starten. Falls dies gelingt, werden die Elemente der Fields-Auflistung der Datensatzgruppe durchlaufen, welche sich aus der ausgewählten Tabelle bzw. Abfrage ergibt. Die Namen sämtlicher Felder erscheinen in Excel als Spaltenüberschriften. Als nächstes wird die Methode CopyFromRecordset des Bereichsobjekts verwendet, um alle Feldwerte in die Zeilen des Excel-Arbeitsblatts zu übertragen. Ein abschließender Aufruf der Methode AutoFilter sorgt dafür, dass die Benutzer die in Excel übertragenen Daten problemlos bearbeiten und auf die gewünschte Weise filtern können (siehe Abbildung 26.14). Die Methode CopyFromRecordset des Bereichsobjekts ist zwar äußerst einfach verwendbar, weist jedoch eine wesentliche Einschränkung auf. Falls die für das Ausfüllen der Datensatzgruppe verwendete Tabelle oder Abfrage, welche an Excel gesendet wird, ein OLE-Objektfeld enthält, schlägt die Methode fehl. Für dieses Problem gibt es zwei Lösungen. Die einfachste Lösung besteht darin, als Grundlage der Datensatzgruppe ausschließlich Abfragen an Excel zu senden. Beziehen Sie dabei in der Abfrage einfach keine OLE-Objektfelder mit ein. Eine zweite Lösung besteht in der Verwendung einer weniger eleganten Alternative zur Methode CopyFromRecordset. Durchlaufen Sie einfach nacheinander die einzelnen Datensätze der Datensatzgruppe und senden Sie sie an die entsprechenden Zeilen und Spalten. Da die erste Methode nicht nur einfacher programmierbar, sondern auch besser ist, sollten Sie diese bevorzugt verwenden.
964
Kapitel 26: Automatisierung: Mit anderen Anwendungen kommunizieren
Abbildung 26.14: Analysieren der an Excel gesendeten Daten mit Hilfe von AutoFilter Listing 26.13: Überprüfen der Größe eines Datensatzes Function CreateRecordset(rstData As ADODB.Recordset, _ rstCount As ADODB.Recordset, _ strTableName As String) On Error GoTo CreateRecordset_Err rstCount.Open "Select Count(*) As NumRecords from " & strTableName If rstCount!NumRecords > 500 Then CreateRecordset = False Else rstData.Open strTableName CreateRecordset = True End If CreateRecordset_Exit: Set rstCount = Nothing Exit Function CreateRecordset_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description Resume CreateRecordset_Exit End Function
Diese Routine entstammt dem Modul basUtils und gewährleistet, dass die Datensatzgruppe nicht zu groß ist, um an Excel gesendet werden zu können. Wenn die Größe der Datensatzgruppe annehmbar ist, wird sie erstellt und die Routine gibt den Wert True zurück.
Die Leistungsfähigkeit des Windows-API ausschöpfen
Kapitel
Hier lesen Sie:
Fundgrube Windows-Bibliotheken Eine externe Funktion für den Compiler deklarieren Mit Konstanten und Typen arbeiten DLL-Funktionen aufrufen: wichtige Aspekte Unterschiede zwischen 16- und 32-Bit-APIs API-Funktionen verwenden Informationen über die Arbeitsumgebung erlangen Laufwerkstypen und verfügbaren Platz auf Laufwerken ermitteln
27.1
Fundgrube Windows-Bibliotheken
Eine der reichhaltigsten Bibliotheken bezüglich des Programmierens von Funktionen bietet Windows selbst. Diese Funktionsbibliothek wird häufig als »Windows API« (Application Programming Interface) bezeichnet. Glücklicherweise können Sie sich die Windows-Funktionsbibliothek zunutze machen, indem Sie diese vorgefertigten Windows-Funktionen in Ihren eigenen VBA-Modulen verwenden. Außerdem könnten Sie andere »Dynamic Link Librarys« (DLLs) entdecken, welche Funktionen enthalten, die Sie für Ihre Anwendungen verwenden möchten. Auch diese DLLs können Sie benutzen, wenn Sie über die entsprechenden Lizenzen für deren Nutzung und Weitergabe verfügen. Eine DLL ist eine Bibliothek von Prozeduren, welche Anwendungen mit Hilfe entsprechender Verknüpfungen zur Laufzeit verwenden können. Die im Windows API und anderen DLLs enthaltenen Funktionen bieten Ihnen zahlreiche Möglichkeiten. Das Bewerkstelligen einer Aufgabe mit Hilfe einer externen DLL ist weitaus effektiver als das Schreiben einer eigenen VBA-Funktion zum Erledigen der gleichen Aufgabe.
966
27.2
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
Eine externe Funktion für den Compiler deklarieren
Eine DLL-Funktion können Sie folgendermaßen verwenden:
Deklarieren Sie die Funktion für den VBA-Compiler. Rufen Sie die Funktion auf. Verwenden Sie den Rückgabewert. Standardmäßig sind der Programmiersprache VBA die über externe Bibliotheken verfügbaren Funktionen nicht bekannt. Durch das Deklarieren einer DLL-Funktion werden dem VBA-Compiler der Name der Funktion, die Bibliothek, in der sie sich befindet, die erforderlichen Parameter und die erwarteten Rückgabewerte bekanntgegeben. Falls Sie dem VBA-Compiler die Bibliotheksfunktion nicht korrekt mitteilen, erhalten Sie eine Fehlermeldung, die besagt, dass die Unterroutine oder Funktion nicht definiert ist. Benutzerdefinierte Funktionen und in VBA geschriebene Unterroutinen werden mit Hilfe der Schlüsselwörter Sub bzw. Funktion definiert. Diese Schlüsselwörter geben die Prozeduren an, damit VBA die Routinen finden kann, sobald diese aufgerufen werden. Funktionen innerhalb einer DLL werden auf die gleiche Weise deklariert. Nachdem Sie dem Compiler eine DLL-Funktion bekanntgegeben haben, kennt Access deren Position und Sie können sie im Rahmen Ihrer Anwendung benutzen. Mit Hilfe der Anweisung Declare geben Sie VBA eine externe Funktion bekannt. Declare-Anweisungen können Sie im Deklarationsteil eines Standardmoduls, in einem einzelnen Klassenmodul oder in dem zu einem Formular oder einem Bericht gehörenden Klassenmodul angeben. Eine in einem Standardmodul angegebene Declare-Anweisung wirkt sich unmittelbar auf Ihre gesamte Anwendung aus. Falls die Declare-Anweisung explizit als privat deklariert wird, ist sie ausschließlich in dem Modul verfügbar, das sie enthält. Eine im Abschnitt Allgemeine Deklarationen eines einzelnen Klassenmoduls oder in einem Klassenmodul zu Formular bzw. Bericht angegebene Declare-Anweisung ist erst nach dem Laden des Formulars oder des Berichts bzw. nach dem Bilden der Klasseninstanz verfügbar. Außerdem ist der Gültigkeitsbereich einer auf diese Weise angegebenen Declare-Anweisung ausschließlich privat. Mit Hilfe einer Declare-Anweisung können Sie sowohl Unterroutinen als auch Funktionen deklarieren, wobei von der zweiten Möglichkeit Gebrauch zu machen ist, wenn Sie einen Rückgabewert brauchen. Andernfalls ist eine Deklaration als Unterroutine notwendig.
Eine externe Funktion für den Compiler deklarieren
967
Eine Declare-Anweisung ist folgendermaßen aufgebaut: Private Declare Function GetKeyboardType Lib "user32" _ (ByVal nTypeFlag As Long) As Long
Mit Hilfe dieser Declare-Anweisung wird eine Funktion mit der Bezeichnung GetKeyboardType deklariert, welche sich im Windows 9x- bzw. Windows NT-Systemordner in einer DLL-Datei namens user32 befindet. An sie wird ein long integer-Parameter als Wert übergeben und die Funktion gibt einen long integer-Wert zurück. Beachten Sie, dass diese Funktion als privat deklariert wurde. Bedenken Sie, dass bei den Namen der Funktion und der Bibliothek die Groß- und Kleinschreibung jeweils signifikant ist. Falls Sie den Pfad nicht explizit in der Declare-Anweisung angeben, wird standardmäßig im Windows- und WindowsSystemordner nach der Bibliothek gesucht. Die meisten Funktionen des Windows API befinden sich in den Bibliotheksdateien user32.exe, gdi32.exe und kernel32.exe.
27.2.1
Adressübergabe im Vergleich zur Wertübergabe
Bei der Übergabe eines Parameters als »Referenz« wird die Speicheradresse des Arguments an die Funktion übergeben. Bei der Übergabe eines Parameters als »Wert« wird hingegen der jeweilige Wert des Arguments an die Funktion übergeben. Standardmäßig übergibt VBA alle Parameter als Referenz. Viele Bibliotheksfunktionen erfordern aber eine Wertübergabe. Wenn an eine solche Funktion als Parameter eine Referenz auf einen Speicherort übergeben wird, kann sie nicht korrekt ausgeführt werden. Um einen Parameter als Wert zu übergeben, müssen Sie dem Argument in der Declare-Anweisung das Schlüsselwort ByVal voranstellen. Beim Aufrufen von Bibliotheksfunktionen müssen Sie die von einer Funktion erwarteten Datentypen der Parameter kennen und wissen, ob die Parameter als Referenz oder als Wert zu übergeben sind. Wird ein Parameter versehentlich als Referenz statt als Wert übergeben, oder weist ein Parameter nicht den von der Funktion erwarteten Datentyp auf, kann dies die Stabilität Ihres Systems beeinträchtigen oder gar eine allgemeine Schutzverletzung bzw. eine unerlaubte Operation auslösen.
27.2.2
Zeichenketten als Parameter übergeben
Das Übergeben von Zeichenketten als Parameter an DLL-Funktionen erfordert eine spezielle Vorgehensweise. Unter Windows werden Zeichenketten auf zweierlei Weise gespeichert: im BSTR- und im LPSTR-Format. Wenn Sie nicht mit einem API und mit OLE-Objekten (OLE – Object Linking and Embedding) arbeiten, werden die an Funktionen zu übergebenden Zeichenketten im LPSTR-Format gespeichert. DLL-Funktionen, an die Zeichenketten im LPSTR-Format zu übergeben sind, können die Größe übergebener Zeichenketten nicht verändern. Wenn Sie also an eine DLL-Funktion eine kurze Zeichenkette übergeben, in der ein umfangreicher Wert
968
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
gespeichert werden soll, überschreibt die Funktion einfach einen anderen Speicherbereich mit den zusätzlichen Zeichen. Daraus ergibt sich normalerweise eine allgemeine Schutzverletzung oder eine unerlaubte Operation. Der folgende Code veranschaulicht dies und fängt den erzeugten Fehler ab. Sub WinSysDir() Dim strBuffer As String Dim intLength As Integer Dim strDirectory As String strBuffer = Space$(160) intLength = abGetSystemDirectory(strBuffer, Len(strBuffer)) strDirectory = Left(strBuffer, intLength) MsgBox strDirectory End Sub
Der hier und ein Großteil des übrigen in diesem Kapitel angegebenen Codes befindet sich auf der Beispiel-CD-ROM unter CHAP27EX.MDB.
Beachten Sie, dass die Funktion Space$ verwendet wird, um 160 Leerzeichen in der Zeichenkettenvariablen strBuffer abzulegen. Anschließend hat die Funktion Space$ 160 Leerzeichen gefolgt von einem Null-Zeichen in der Variablen strBuffer gespeichert. An die Windows-API-Funktion abGetSystemDirectory sind die beiden folgenden Parameter zu übergeben:
der Puffer, in dem der Name des Windows-Systemordners abgelegt wird – in diesem Fall strBuffer
die Länge des Puffers – in diesem Fall Len(strBuffer); hier ist vordringlich darauf zu achten, dass der an die Funktion GetSystemDirectory übergebene Puffer groß genug ist, um den Namen des Windows-Systemordners aufzunehmen Die Funktion GetSystemDirectory legt den entsprechenden Wert im Puffer ab und gibt die Länge der ermittelten Zeichenkette zurück. Indem Sie sich die linke intLength-Anzahl von Zeichen in der Variablen strBuffer anschauen, können Sie die gegenwärtige Position des Windows-Systemordners feststellen. Die Declare-Anweisung für die Funktion GetSystemDirectory sieht folgendermaßen aus: Declare Function abGetSystemDirectory _ Lib "kernel32" _ (ByVal lpBuffer As String, ByVal nSize As Long) _ As Long
Eine externe Funktion für den Compiler deklarieren
969
Beachten Sie das Schlüsselwort ByVal, welches dem Parameter lpBuffer vorangestellt ist. Wegen der Verwendung dieses Schlüsselworts konvertiert Visual Basic die Zeichenkette vom BSTR- ins LPSTR-Format, indem der Zeichenkette ein abschließendes Null-Zeichen hinzugefügt wird, bevor sie an die DLL-Funktion übergeben wird. Ohne das Schlüsselwort ByVal würde Visual Basic einen Zeiger auf die Speicherposition der Zeichenkette an die Funktion übergeben. Dies könnte erhebliche Probleme nach sich ziehen. Aufrufe des Windows API bergen potentielle Risiken. Um Datenverlusten bzw. der Beschädigung von Daten vorzubeugen, sollten Sie Ihre Arbeit grundsätzlich speichern, bevor Sie eine Prozedur ausprobieren, die Aufrufe externer Funktionen enthält. Wenn die Access-Anwendung abgebrochen wird, bleibt Ihnen zumindest Ihre bisherige Arbeit erhalten. Außerdem sollten Sie stets darauf achten, dass eine Sicherungskopie Ihrer Datenbank angelegt wurde. Wenn die Access-Anwendung abgebrochen und Ihre Datenbank nicht korrekt geschlossen wird, besteht die Gefahr der Beschädigung der Datenbank. Durch das regelmäßige Anfertigen von Sicherungskopien bleibt gewährleistet, dass Sie auf die letzte unbeschädigte Version einer Sicherungskopie zurückgreifen können, falls die Datenbank während des Testens beschädigt wird.
27.2.3
Einer Funktion ein Alias zuweisen
Wenn Sie in VBA eine Funktion deklarieren, haben Sie die Möglichkeit, wie bei der vorherigen Funktion ein Alias zu verwenden. Ein »Alias« ist ein Ersatzname, den Sie benutzen können, um sich auf eine Funktion zu beziehen. Es gibt mehrere Gründe, für Windows API-Funktionen Aliasnamen zu verwenden:
Eine DLL-Prozedur hat einen Namen, der ein nicht zulässiges Zeichen umfasst. Der Name einer DLL-Prozedur stimmt mit einem VBA-Schlüsselwort überein. Sie wollen das für die ANSI-Version des API-Aufrufs erforderliche A umgehen. Sie wollen dafür sorgen, dass der Name einer Prozedur innerhalb einer AccessBibliothek oder einer Anwendung eindeutig ist.
Sie wollen mittels einer Ordnungszahl auf eine DLL-Prozedur zugreifen. Sie wollen Ihre API-Funktionen mit bestimmten Präfixen versehen, um Konflikte mit API-Deklarationen innerhalb anderer Module oder Add-Ins zu vermeiden. In den nachfolgenden Abschnitten wird auf die Gründe für die Verwendung von Aliasnamen für API-Funktionen näher eingegangen. Funktionsaufrufe und ungültige Zeichen Es ist nicht ungewöhnlich, dass der Name einer DLL-Prozedur ein Zeichen enthält, das in VBA-Code nicht erlaubt ist. Beispielsweise kann eine DLL-Prozedur mit dem Unterstrich (_) beginnen, was in VBA erlaubt ist, jedoch nicht vorkommen darf. Um
970
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
eine solche DLL-Funktion zu verwenden, müssen Sie wie im folgenden Beispiel einen Aliasnamen benutzen: Declare Funktion LOpen _ Lib "kernel32" _ Alias "_lopen" _ (ByVal lpPathName As String, Byval ReadWrite As Long) _ As Long
Beachten Sie, dass die Windows API-Funktion _lopen mit einem Unterstrich beginnt. Zur Verwendung innerhalb der Access-Anwendung wird der Funktion der Aliasname LOpen zugewiesen. DLL-Funktionen mit gleichen Namen Der Name einer DLL-Prozedur, die Sie verwenden möchten, könnte mit der Bezeichnung einer VBA-Funktion übereinstimmen. Dieses Problem können Sie lösen, indem Sie der DLL-Funktion ein Alias zuweisen. Im folgenden Code wird einer DLL-Funktion ein Alias zugewiesen: Declare Function GetObjectAPI _ Lib "gdi32" _ Alias "GetObject" _ (ByVal hObject As Long, _ ByVal nCount As Long, _ lpObject As Any) As Long
Die Funktion GetObject ist sowohl im Windows API als auch innerhalb von VBA definiert. Wenn Sie der Funktion einen Alias zuweisen, können diese beiden Funktionen problemlos und eindeutig aufgerufen werden. Das für ANSI erforderliche A entfernen Für viele Aufrufe von API-Funktionen gibt es sowohl ANSI- als auch Unicode-Versionen. Die ANSI-Versionen der Funktionen enden jeweils mit einem A. Möglicherweise wollen Sie die ANSI-Version einer Funktion aufrufen, dafür jedoch einen Namen ohne A verwenden. Wie Sie dies mit Hilfe eines Alias bewerkstelligen können, veranschaulicht der folgende Code: Declare Function FindWindow _ Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As Any, ByVal lpWindowName As String) As Long
Durch diese Declare-Anweisung wird ein Alias der Funktion FindWindow für die Funktion FindWindowA erstellt.
Eine externe Funktion für den Compiler deklarieren
971
»Unicode« ist ein von der »International Standards Organization« (ISO) entwickelter Code. Er wurde entwickelt, um die 256-Zeichen-Begrenzung des ANSIStandards zu überwinden. Beim ANSI-Standard wird für ein einzelnes Zeichen nur jeweils ein Byte verwendet. Somit bleibt die Anzahl der verwendbaren Zeichen auf 256 beschränkt. Beim Unicode-Standard werden einzelne Zeichen hingegen jeweils durch zwei Byte dargestellt, so dass 65.535 Zeichen unterschieden werden können. Access verwendet Unicode für Zeichenkettenoperationen, was bei DLL-Aufrufen zu Problemen führen kann. Um solche Probleme zu vermeiden, sollten Sie stets die ANSI-Version von API-Aufrufen benutzen (jene Version der Funktion, die mit einem A endet). Eindeutige Prozedurnamen in Access-Bibliotheken bzw. -Modulen Gelegentlich wollen Sie gewährleisten, dass der Name einer Prozedur innerhalb einer Bibliothek, die Sie erstellen, eindeutig ist, oder dass der Code, den Sie schreiben, keine Konflikte mit anderen von Ihnen verwendeten Bibliotheken verursacht. Falls Sie beim Deklarieren der einzelnen Funktionen das Schlüsselwort Private nicht verwenden, wirken sich Deklarationen externer Funktionen innerhalb des Speicherbereichs von Access grundsätzlich global aus. Dies könnte zu Konflikten führen, da Access kein mehrfaches Deklarieren bestimmter externer Routinen erlaubt. Aus diesem Grund können Sie die Verwendung eines eindeutigen Bezeichners bevorzugen. Beispielsweise haben Sie die Möglichkeit, den Namen der Funktionen bei deren Deklaration wie im folgenden Beispiel am Anfang oder am Ende jeweils Ihre Initialen hinzuzufügen: Declare Function ABGetWindowsDirectory Lib "kernel32" _ Alias "GetWindowsDirectory" _ (ByVal lpBuffer As String, ByVal nSize As Long) As Long
Mit Hilfe dieser Anweisung wird die Windows-API-Funktion GetWindowsDirectory deklariert, welche sich in der Bibliothek kernel32 befindet. Der Funktion wird das Alias ABGetWindowsDirectory zugewiesen, um sie von anderen Aufrufen der Funktion GetWindowsDirectory zu unterscheiden, welche den gleichen Gültigkeitsbereich aufweisen könnten. Aufrufen mit Ordnungszahlen versehener Verweise auf Funktionen Auf jede DLL-Prozedur kann außer über ihren Namen mit Hilfe einer Ordnungszahl verwiesen werden. In einigen DLLs werden sogar ausschließlich Ordnungszahlen verwendet, welche beim Deklarieren entsprechender Prozeduren anzugeben sind. Wenn Sie eine Funktion deklarieren, auf die über eine Ordnungszahl verwiesen wird, sollten Sie wie im folgenden Beispiel bei der Deklaration das Schlüsselwort Alias verwenden:
972
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
Declare Function GetAppSettings _ Lib "Utilities" _ Alias "#47" () As Long
In diesem Code wird eine Funktion mit der Ordnungszahl 47 deklariert, welche sich in der Bibliothek Utilities befindet. Anschließend kann die Funktion im VBA-Code über den Namen GetAppSettings aufgerufen werden.
27.3
Mit Konstanten und Typen arbeiten
Einige DLLs erfordern die Verwendung von Konstanten oder benutzerdefinierter Typen, die auch als »Strukturen« bzw. »Parameter« bezeichnet werden. Diese müssen Sie gemeinsam mit den Declare-Anweisungen im Abschnitt Allgemeine Deklarationen Ihres Moduls angeben.
27.3.1
Mit Konstanten arbeiten
Konstanten werden von vielen API-Funktionen verwendet. Diese ermöglichen Ihnen das Übergeben erforderlicher Werte an API-Funktionen in einer der Umgangssprache angenäherten Weise. Konstanten werden als Aliasnamen für bestimmte Werte verwendet. Es folgt ein Beispiel: Global Const SM_CXSCREEN = 0 Global Const SM_CYSCREEN = 1
Die Deklarationen von Konstanten und Funktionen werden im Abschnitt Allgemeine Deklarationen eines Moduls angegeben. Beim Aufrufen der Funktion GetSystemMetrics werden die Konstanten SM_CXSCREEN und SM_CYSCREEN als Parameter an die Funktion übergeben: Sub GetScreenInfo() MsgBox "Screen Resolution is: " & _ GetSystemMetrics(SM_CXSCREEN) & _ " By " & _ GetSystemMetrics(SM_CYSCREEN) End Sub
Wenn die Konstante SM_CXSCREEN an die Funktion GetSystemMetrics übergeben wird, liefert sie die horizontale Auflösung des Bildschirms. Wird hingegen die Konstante SM_CYSCREEN übergeben, gibt die Funktion die vertikale Auflösung des Bildschirms zurück.
Mit Konstanten und Typen arbeiten
27.3.2
973
Mit Typen arbeiten
Beim Umgang mit Typen müssen Sie zunächst den jeweiligen Typ im Abschnitt Allgemeine Deklarationen des Moduls deklarieren. Anschließend können Sie Elemente eines benutzerdefinierten Typs oder den gesamten Typ als einzelnen Parameter an die API-Funktion übergeben. Der folgende Code zeigt ein Beispiel für das Deklarieren eines Typs: Type OSVERSIONINFO dwOSVersionInfoSize As Long dwMajorVersion As Long dwMinorVersion As Long dwBuildNumber As Long dwPlatformId As Long strReserved As String * 128 End Type
Die Typstruktur OSVERSIONINFO wird in der in Listing 27.1 dargestellten Weise im Abschnitt Allgemeine Deklarationen des Moduls deklariert. Listing 27.1:
Deklarieren der Typstruktur OSVERSIONINFO im Allgemeinen Deklarationsteil des Moduls
Function GetOSInfo() Dim Dim Dim Dim Dim
OSInfo As OSVERSIONINFO strMajorVersion As String strMinorVersion As String strBuildNumber As String strPlatformId As String
'Festlegen der Länge der Membervariablen, bevor GetVersionExOSInfo aufgerufen wird OSInfo.dwOSVersionInfoSize = Len(OSInfo) If abGetVersionEx(OSInfo) Then strMajorVersion = OSInfo.dwMajorVersion strMinorVersion = OSInfo.dwMinorVersion strBuildNumber = OSInfo.dwBuildNumber And &HFFFF& strPlatformId = OSInfo.dwPlatformId MsgBox "The Major Version Is: " & strMajorVersion & vbCrLf & _ "The Minor Version Is: " & strMinorVersion & vbCrLf & _ "The Build Number Is: " & strBuildNumber & vbCrLf & _ "The Platform ID Is: " & IIf(strPlatformId = 1, "Win 95 or Win 98", _ "Win NT") & vbCrLf End If End Function
In diesem Listing wird durch die Anweisung Dim OSInfo As OSVERSIONINFO eine Typvariable erstellt. Die gesamte Struktur wird an die Funktion GetVersionEx übergeben. Die Funktion GetVersionEx weist den Elementen der Struktur Informationen über
974
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
das Betriebssystem zu. Diese Informationen werden ermittelt und in Variablen gespeichert, die in einer Meldung angezeigt werden können.
27.3.3
Den Windows-API-Viewer verwenden
Sicherlich können Sie sich vorstellen, dass es recht aufwendig sein kann, CodeModulen Declare-Anweisungen, Konstantendeklarationen und Typstrukturen hinzuzufügen. Glücklicherweise kann Ihnen das Anzeigemodul für das Windows API, welches in der Microsoft Office Developer Edition enthalten ist, diese Aufgaben erheblich erleichtern. Mit ihm können Sie Declare-Anweisungen, Typen und Konstanten, die für Aufrufe von Windows API-Funktionen erforderlich sind, auf einfache Weise Ihrem Code hinzufügen. Das Anzeigemodul für das Windows API können Sie wie folgt als Add-In des Access 2000-VBE starten: 1. Aktivieren Sie den VBE. 2. Wählen Sie ADD-INS|ADD-IN-MANAGER. Daraufhin erscheint der Add-InManager. 3. Wählen Sie VBA WINAPI-ANZEIGEMODUL aus. 4. Klicken Sie auf LADEN/ENTLADEN. 5. Klicken Sie auf BEIM STARTEN LADEN, falls das API-Anzeigemodul nach dem Starten von Access grundsätzlich verfügbar sein soll. 6. Klicken Sie auf OK. 7. Öffnen Sie das Menü ADD-INS. Daraufhin sollte das WinAPI-Anzeigemodul erscheinen. 8. Wählen Sie im Menü ADD-INS das WINAPI-Anzeigemodul aus. Wenn Sie das Anzeigemodul für das Windows API zum ersten Mal starten, erscheint er in der in Abbildung 27.1 dargestellten Weise. Sie können eine Textdatei oder auch eine Datenbankdatei laden, welche Deklarationen, Typen und Konstanten umfasst.
27.3.4
Eine Textdatei laden
Die Developer-Version von Micsorsoft Office umfasst eine Datei mit der Bezeichnung WIN32API.TXT. Diese können Sie laden und durchsuchen, um auf einfache Weise Declare-Anweisungen, Typstrukturen und Konstanten aufzufinden. Die Datei WIN32API.TXT können Sie folgendermaßen mit dem Anzeigemodul für das Windows API laden: 1. Wählen Sie DATEI|TEXTDATEI LADEN. Daraufhin erscheint das in Abbildung 27.2 gezeigte Dialogfeld WINAPI-ANZEIGEMODUL.
Mit Konstanten und Typen arbeiten
975
Abbildung 27.1: Der Windows API-TextViewer
2. Markieren Sie die zu ladende Textdatei und klicken Sie auf ÖFFNEN. Anschließend sieht das WinAPI-Anzeigemodul so aus, wie es in Abbildung 27.3 dargestellt ist.
Abbildung 27.2: Das Dialogfeld API-Textdatei auswählen
27.3.5
Eine Datenbankdatei laden
Nach dem Konvertieren einer Textdatei in eine Datenbank sollten Sie jedesmal, wenn Sie das Anzeigemodul für das Windows API verwenden, die Datenbank laden. Gehen Sie dazu folgendermaßen vor:
976
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
Abbildung 27.3: Der API-Viewer nach dem Laden einer Textdatei
1. Wählen Sie DATEI|DATENBANKDATEI LADEN. Daraufhin erscheint das in Abbildung 27.4 gezeigte Dialogfeld JET-DATENBANK AUSWÄHLEN. 2. Wählen Sie die zu ladende Datenbank aus und klicken Sie auf ÖFFNEN.
Abbildung 27.4: Im Dialogfeld Jet-Datenbank auswählen können Sie die im Text-Viewer zu ladende Datenbank angeben
Mit Konstanten und Typen arbeiten
27.3.6
977
API-Deklarationen, Typen und Konstanten einfügen
Unabhängig davon, ob Sie eine Text- oder eine Datenbankdatei geladen haben, erscheint das WinAPI-Anzeigemodul in der in Abbildung 27.5 dargestellten Weise. Sämtliche Deklarationen für das 32-Bit-API erscheinen daraufhin im Listenfeld VERFÜGBARE ELEMENTE. Markieren Sie die Ihrem Modul hinzuzufügende DeclareAnweisung und klicken Sie auf HINZUFÜGEN. Im aufklappbaren Listenfeld API-TYP können Sie angeben, ob Sie Deklarationen, Typen oder Konstanten betrachten wollen. In Abbildung 27.6 wurden dem Listenfeld AUSGEWÄHLTE ELEMENTE bereits die beiden Deklarationen GetVersionEx und GetWindow sowie die Konstanten SM_CXSCREEN und SM_CYSCREEN und der Typ OSVERSIONINFO hinzugefügt.
Abbildung 27.5: Der Windows API-TextViewer nach dem Laden einer Datei
Mit Hilfe der folgenden Vorgehensweise können Sie einem Modul die ausgewählten Elemente hinzufügen: 1. Klicken Sie im WinAPI-Anzeigemodul auf KOPIEREN. Die ausgewählten Deklarationen, Konstanten und Typen werden daraufhin in die Windows-Zwischenablage übertragen. 2. Platzieren Sie den Cursor an jene Stelle Ihres Moduls, an dem die ausgewählten Deklarationen, Konstanten und Typen eingefügt werden sollen. 3. Klicken Sie auf EINFÜGEN. Die ausgewählten Elemente werden daraufhin in der in Abbildung 27.7 gezeigten Weise in das Modul übertragen.
978
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
Abbildung 27.6: Der Windows API-Text-Viewer mit mehreren Elementen in der Liste ausgewählter Elemente
Abbildung 27.7: Ein Modul, nachdem ausgewählte Elemente darin eingefügt wurden
DLL-Funktionen aufrufen: Wichtige Aspekte
27.4
979
DLL-Funktionen aufrufen: Wichtige Aspekte
Nachdem eine Prozedur deklariert wurde, können Sie sie wie jede andere VBAFunktion aufrufen. Im Wesentlichen müssen Sie darauf achten, dass Sie jeweils die korrekten Werte an die DLL übergeben. Ein fehlerhafter Aufruf könnte dazu führen, dass die Ausführung Ihrer Anwendung ohne Vorwarnung endet. Aufrufe von Funktionen externer Bibliotheken sind in der Tat recht heikel. Sie sollten Ihre Arbeit deshalb grundsätzlich speichern, bevor Sie Aufrufe dieser Art ausprobieren. An die meisten DLLs sind standardmäßige C-Zeichenketten zu übergeben. Solche Zeichenketten enden stets mit einem Null-Zeichen. Zeichenketten dieser Art sind an DLLs grundsätzlich als Wert zu übergeben. Das Schlüsselwort ByVal teilt VBA mit, dass die Zeichenkette mit einem Null-Zeichen endet. Obgleich Zeichenketten als Wert zu übergeben sind, werden sie als Verweise empfangen. Das Schlüsselwort ByVal weist lediglich darauf hin, dass die Zeichenkette mit einem Null-Zeichen endet. Aus der Tatsache, dass die DLL-Prozedur den Wert der Zeichenkette ändern kann, können sich Probleme ergeben. Im Abschnitt »Zeichenketten als Parameter übergeben« dieses Kapitels wurde bereits erörtert, dass einfach Speicherbereiche überschrieben werden, die gar nicht mehr zur Zeichenkette gehören, falls für sie nicht ausreichend Platz reserviert wurde, auch wenn diese Speicherbereiche eigentlich von einer anderen Anwendung oder sogar vom Betriebssystem verwendet werden. Dieses Problem können Sie vermeiden, wenn Sie dem Zeichenkettenparameter ausreichend Platz zuweisen, damit ihm auch die längsten möglichen Werte zugewiesen werden können.
27.5
Unterschiede zwischen 16- und 32-Bit-APIs
Möglicherweise kennen Sie sich bereits mit dem 16-Bit-API früherer Versionen von Windows aus, doch müssen Sie beim Umgang mit dem 32-Bit-API einige Änderungen berücksichtigen. Wenn Sie sich dieser Änderungen nicht bewusst sind, könnte dies sehr unangenehme Konsequenzen nach sich ziehen:
Windows-Zugriffsnummern (hWnd-Eigenschaften) werden im Rahmen der 32-BitAPI im Format long integer verarbeitet. Bei dem 16-Bit-API wurden hingegen integer-Werte verwendet.
Bei den Funktionsnamen des 32-Bit-API ist im Gegensatz zum 16-Bit-API die Groß- und Kleinschreibung signifikant.
Beim Umgang mit dem 16-Bit-API sollten Sie nach dem Auftreten einer allgemeinen Schutzverletzung stets das System neu starten, da die Daten im Hauptspeicher Ihres Computers beschädigt worden sein könnten. Bei der 32-Bit-API wird hingegen jedes Programm in einem eigenen virtuellen System ausgeführt. Daher ist ein Neustart nach einer allgemeinen Schutzverletzung häufig unnötig.
980
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
Die im Rahmen des 32-Bit-API verwendeten Datentypen sind stets doppelt so lang wie die in Visual Basic anzugebenden. Dies bedeutet, dass in VBA der Datentyp long zu verwenden ist, wenn in einer Dokumentation der Programmiersprache C angegeben wird, dass ein bestimmter API-Aufruf einen Wert des Typs double erfordert.
27.6
API-Funktionen verwenden
Die durch API-Aufrufe gebotenen Möglichkeiten sind schier grenzenlos. Mit Hilfe von API-Aufrufen können Sie das Systemmenü anpassen, Systeminformationen ermitteln oder auch zwischen verschiedenen gegenwärtig laufenden Anwendungen wechseln. API-Aufrufe bieten so viele Möglichkeiten, dass diesem Thema ganze Bücher gewidmet sind. In den verbleibenden Abschnitten dieses Kapitels werden einige der häufiger verwendeten API-Aufrufe erläutert.
27.7
Informationen über die Arbeitsumgebung erlangen
Mit Hilfe von Aufrufen des Windows API haben Sie die Möglichkeit, Informationen über die Systemumgebung zu ermitteln – wie zum Beispiel die Art der Hardware, auf der die Anwendung ausgeführt wird, die Größe des vorhandenen bzw. verfügbaren Speichers sowie die Version des Betriebssystems, unter dem die Anwendung ausgeführt wird. Dies sind lediglich einige Beispiele für Informationen über die Systemumgebung, welche sie über das Windows API ermitteln können. Das Angeben von Systeminformationen im Info-Dialogfeld Ihrer Anwendung ist sowohl nützlich als auch professionell. Außerdem sind Systeminformationen bei der Handhabung von Fehlern und zur Protokollierung wichtig, da solche Informationen bei der Diagnose von Problemen helfen können. Dieses Thema wird in Kapitel 14 erörtert. In Abbildung 27.8 ist ein benutzerdefiniertes Info-Dialogfeld dargestellt, in dem auch Informationen über die Systemumgebung angegeben sind. Für dieses Formular wurden mehrere Windows-API-Aufrufe verwendet, um die auf ihm angezeigten Systeminformationen zu ermitteln. Bevor eine der für das Ermitteln dieser Funktionen erforderlichen DLL-Funktionen aufgerufen werden kann, müssen dem Compiler alle erforderlichen Funktionen bekanntgegeben werden. Dies erfolgt durch entsprechende Deklarationen im Abschnitt Allgemeine Deklarationen des Moduls basUtils. Auch die von den DLLAufrufen verwendeten Konstanten und Typstrukturen müssen im Abschnitt Allgemeine Deklarationen angegeben werden. In Listing 27.2 ist der Abschnitt Allgemeine Deklarationen des Moduls basAPICalls dargestellt.
981
Informationen über die Arbeitsumgebung erlangen
Abbildung 27.8: Ein benutzerdefiniertes InfoDialogfeld zur Veranschaulichung der Möglichkeit, mit Hilfe des Windows API Systeminformationen abzurufen Listing 27.2:
Der Abschnitt Allgemeine Deklarationen des Moduls BasUtils
Option Compare Database Option Explicit Public Const MAX_PATH = 160 Declare Function abGetVersionEx _ Lib "kernel32" _ Alias "GetVersionExA" _ (lpOSInfo As OSVERSIONINFO) As Boolean Type OSVERSIONINFO dwOSVersionInfoSize As Long dwMajorVersion As Long dwMinorVersion As Long dwBuildNumber As Long dwPlatformId As Long strReserved As String * 128 End Type 'Mit Hilfe der Funktion GetVersionEx werden Informationen über die Version des 'gegenwärtig verwendeten Betriebssystems ermittelt. Diese Informationen werden in der 'Typstruktur OSVERSIONINFO abgelegt. Const SM_CXSCREEN = 0 Const SM_CYSCREEN = 1 Const SM_MOUSEPRESENT = 19 Declare Function abGetSystemMetrics _
982
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
Lib "user32" _ Alias "GetSystemMetrics" _ (ByVal nIndex As Long) As Long 'Die Funktion GetSystemMetrics verwendet drei Konstanten, um festzustellen, ob eine 'Maus verfügbar ist und welche vertikale und horizontale Auflösung für die 'Bildschirmdarstellung eingestellt wurde. Type MEMORYSTATUS dwLength As Long dwMemoryLoad As Long dwTotalPhys As Long dwAvailPhys As Long dwTotalPageFile As Long dwAvailPageFile As Long dwTotalVirtual As Long dwAvailVirtual As Long End Type Declare Sub abGlobalMemoryStatus _ Lib "kernel32" _ Alias "GlobalMemoryStatus" _ (lpBuffer As MEMORYSTATUS) 'Die Funktion GlobalMemoryStatus dient dem Ermitteln von Informationen über den 'gegenwärtig verfügbaren Speicherplatz. Sie verweist auf eine Typstruktur namens 'SYSTEM_INFO, deren Elementen relevante Informationen über den Speicher zugewiesen 'werden. Type SYSTEM_INFO dwOemID As Long dwPageSize As Long lpMinimumApplicationAddress As Long lpMaximumApplicationAddress As Long dwActiveProcessorMask As Long dwNumberOrfProcessors As Long dwProcessorType As Long dwAllocationGranularity As Long dwReserved As Long End Type Declare Sub abGetSystemInfo Lib "kernel32" _ Alias "GetSystemInfo" _ (lpSystemInfo As SYSTEM_INFO) 'Die Funktion GetSystemInfo liefert weitere Informationen über das System. Die 'entsprechenden Informationen werden in der Typstruktur SYSTEM_INFO gespeichert.
Informationen über die Arbeitsumgebung erlangen
983
Declare Function abGetWindowsDirectory _ Lib "kernel32" _ Alias "GetWindowsDirectoryA" _ (ByVal lpBuffer As String, _ ByVal nSize As Long) As Long 'Mit Hilfe der Funktion GetWindowsDirectory wird der Name des Verzeichnisses 'ermittelt, in dem Windows ausgeführt wird Declare Function abGetSystemDirectory _ Lib "kernel32" _ Alias "GetSystemDirectoryA" _ (ByVal lpBuffer As String, _ ByVal nSize As Long) As Long 'Die Funktion GetSystemDirectory fragt den Namen des Windows-Systemverzeichnisses ab. Declare Function abGetTempPath _ Lib "kernel32" _ Alias "GetTempPathA" _ (ByVal nBufferLength As Long, _ ByVal lpBuffer As String) As Long 'Die Funktion GetTempPath bestimmt das Verzeichnis für temporäre Dateien. Declare Function abGetCommandLine _ Lib "kernel32" _ Alias "GetCommandLineA" () _ As String 'Die Funktion GetCommandLine fragt die Befehlszeile für den aktuellen Prozess ab. Declare Function abGetClassName _ Lib "user32" _ Alias "GetClassNameA" _ (ByVal hwnd As Long, _ ByVal lpClassName As String, _ ByVal nMaxCount As Long) _ As Long 'Die Funktion GetClassName gibt den Klassennamen eines Fensters zurück. Declare Function abGetParent _ Lib "user32" _ Alias "GetParent" _ (ByVal hwnd As Long) _ As Long
984
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
'Zugriffsnummer eines übergeordneten Fenster ermitteln Declare Function abGetWindowText _ Lib "user32" _ Alias "GetWindowTextA" _ (ByVal hwnd As Long, _ ByVal lpString As String, _ ByVal cch As Long) _ As Long 'Die Funktion GetWindowText bestimmt den Titel des aktuellen Fensters Declare Function abSetWindowText _ Lib "user32" _ Alias "SetWindowTextA" _ (ByVal hwnd As Long, _ ByVal lpString As String) _ As Long 'Die Funktion SetWindowText ändert den Titel des aktuellen Fensters Public Public Public Public Public Public Public
Const Const Const Const Const Const Const
DRIVE_UNKNOWN = 0 DRIVE_UNAVAILABLE = 1 DRIVE_REMOVABLE = 2 DRIVE_FIXED = 3 DRIVE_REMOTE = 4 DRIVE_CDROM = 5 DRIVE_RAMDISK = 6
Declare Function abGetDriveType _ Lib "kernel32" _ Alias "GetDriveTypeA" _ (ByVal nDrive As String) _ As Long 'Die Funktion GetDriveType bestimmt den Laufwerkstyp Declare Function abGetDiskFreeSpace _ Lib "kernel32" _ Alias "GetDiskFreeSpaceA" _ (ByVal lpRootPathName As String, _ lpSectorsPerCluster As Long, _ lpBytesPerSector As Long, _ lpNumberOfFreeClusters As Long, _ lpTotalNumberOfClusters As Long) _ As Long
Informationen über die Arbeitsumgebung erlangen
985
Wie Sie sehen, sind mehrere Typstrukturen, Konstanten und Declare-Anweisungen erforderlich, um die auf dem Formular dargestellten Informationen zu ermitteln. Nach dem Öffnen des Formulars (frmSystemInformation) werden die Funktionen des Windows API aufgerufen und die ermittelten Systeminformationen werden in die Textfelder des Formulars eingefügt. Das Ereignis Open des Formulars frmSystemInformation führt zum Aufruf einer Unterroutine mit der Bezeichnung GetSysInfo, welche in Listing 27.3 dargestellt ist. Listing 27.3:
Die Unterroutine GetSysInfo
Sub GetSysInfo(frmAny As Form) Dim intMousePresent As Integer Dim strBuffer As String Dim intLen As Integer Dim MS As MEMORYSTATUS Dim SI As SYSTEM_INFO Dim strCommandLine As String
frmAny.txtScreenResolution = abGetSystemMetrics(SM_CXSCREEN) & " By " & _ abGetSystemMetrics(SM_CYSCREEN) intMousePresent = CBool(abGetSystemMetrics(SM_MOUSEPRESENT)) frmAny.txtMousePresent = IIf(intMousePresent, "Mouse Present", "No Mouse _ Present") 'Festlegen des Werts der Membervariablen für die Länge vor dem Aufrufen von 'GlobalMemoryStatus MS.dwLength = Len(MS) abGlobalMemoryStatus MS frmAny.txtMemoryLoad = MS.dwMemoryLoad & "%" frmAny.txtTotalPhysical = Format(Fix(MS.dwTotalPhys / 1024), "###,###") & "K" frmAny.txtAvailablePhysical = Format(Fix(MS.dwAvailPhys / 1024), "###,###") & _ "K" frmAny.txtTotalVirtual = Format(Fix(MS.dwTotalVirtual / 1024), "###,###") & "K" frmAny.txtAvailableVirtual = Format(Fix(MS.dwAvailVirtual / 1024), "###,###") & _ "K" abGetSystemInfo SI frmAny.txtProcessorMask = SI.dwActiveProcessorMask frmAny.txtNumberOfProcessors = SI.dwNumberOrfProcessors frmAny.txtProcessorType = SI.dwProcessorType
strBuffer = Space(MAX_PATH) intLen = abGetWindowsDirectory(strBuffer, MAX_PATH) frmAny.txtWindowsDir = Left(strBuffer, intLen) strBuffer = Space(MAX_PATH)
986
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
intLen = abGetSystemDirectory(strBuffer, MAX_PATH) frmAny.txtSystemDir = Left(strBuffer, intLen) strBuffer = Space(MAX_PATH) intLen = abGetTempPath(MAX_PATH, strBuffer) frmAny.txtTempDir = Left(strBuffer, intLen) End Sub
Schauen Sie sich diese Unterroutine nun etwas genauer an. Zunächst ruft sie die Funktion GetSystemMetrics (über den Aliasnamen abGetSystemMetrics) insgesamt dreimal auf. Beim ersten Mal wird die Konstante SM_CXSCREEN und beim zweiten Mal die Konstante SM_CYSCREEN übergeben. Diese Aufrufe liefern die horizontale und vertikale Auflösung des Bildschirms. Durch das Übergeben der Konstanten SM_MOUSEPRESENT beim Aufrufen der Funktion GetSystemMetrics wird der logische Wert True bzw. False ermittelt, welcher angibt, ob eine Maus vorhanden ist. Der API-Aufruf GlobalMemoryStatus liefert eine Struktur mit mehreren Einzelinformationen bezüglich des Systemspeichers. Dies sind die Auslastung des Speichers, der gesamte und der verfügbare Hauptspeicher sowie der gesamte und der verfügbare virtuelle Speicher. Außerdem können Sie mit Hilfe des API-Aufrufs GetSystemInfo wertvolle Informationen über das System sammeln. Er liefert eine Struktur, in deren Elementen diverse technische Leckerbissen wie beispielsweise die aktuelle Prozessormaske, die Anzahl der laufenden Prozesse und die Art des Prozessors enthalten sind. Schließlich werden noch die Funktionen GetWindowsDirectory, GetSystemDirectory und GetTempPath aufgerufen. Diese drei Funktionen geben die Pfade des Windowsund Systemordners sowie des Ordners mit den temporären Dateien zurück. Beachten Sie, dass der Puffer vor jedem Aufruf aufgefüllt wird. Da jeder Aufruf auch die Länge des Namens des jeweiligen Pfads zurückgibt, können Sie die entsprechenden Zeichenketten, welche stets am Anfang des Puffers beginnen, präzise auslesen.
27.8
Laufwerkstypen und verfügbaren Platz auf Laufwerken ermitteln
Häufig ist das Ermitteln der Arten der verfügbaren Laufwerke sowie des jeweils verfügbaren freien Speicherplatzes erforderlich. Glücklicherweise kann dies mit Hilfe von Windows API-Funktionen bewerkstelligt werden. Auf dem Formular frmListDrives sind genau diese Daten in der in Abbildung 27.9 gezeigten Weise aufgeführt. Die für die APIs notwendigen Deklarationen sind in Listing 27.4 enthalten.
Laufwerkstypen und verfügbaren Platz auf Laufwerken ermitteln
987
Abbildung 27.9: Das Formular frmListDrives, in dem die Typen und der freie Platz aller im System installierten Laufwerke angezeigt werden Listing 27.4:
API-Deklarationen
Public Public Public Public Public Public Public
DRIVE_UNKNOWN = 0 DRIVE_UNAVAILABLE = 1 DRIVE_REMOVABLE = 2 DRIVE_FIXED = 3 DRIVE_REMOTE = 4 DRIVE_CDROM = 5 DRIVE_RAMDISK = 6
Const Const Const Const Const Const Const
Declare Function abGetDriveType _ Lib "kernel32" _ Alias "GetDriveTypeA" _ (ByVal nDrive As String) _ As Long Die GetDriveType-Funktion gibt eine ganze Zahl zurück, die den Laufwerkstyp angibt Declare Function abGetDiskFreeSpace _ Lib "kernel32" _ Alias "GetDiskFreeSpaceA" _ (ByVal lpRootPathName As String, _ lpSectorsPerCluster As Long, _ lpBytesPerSector As Long, _ lpNumberOfFreeClusters As Long, _ lpTotalNumberOfClusters As Long) _ As Long Die GetDiskFreeSpace-Funktion bestimmt die Menge des freien Speicherplatzes auf _ dem aktuellen Laufwerk
Der Code für das Ereignis Click der Befehlsschaltfläche cmdListDrives des Forumulars frmListDrives ruft eine Unterroutine mit der Bezeichnung GetDriveInfo auf und sendet die ermittelten Informationen an das Textfeld txtDrives. In Listing 27.5 ist die Prozedur GetDriveInfo dargestellt.
988
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
Listing 27.5:
Die Prozedur GetDriveInfo
Sub GetDriveInfo(ctlAny As Control) Dim intDrive As Integer Dim strDriveLetter As String Dim strDriveType As String Dim strSpaceFree As String ' Durchlaufen sämtlicher Laufwerke For intDrive = 65 To 90 'A through Z strDriveLetter = (Chr(intDrive) & ":\") ' Laufwerkstyp ermitteln strDriveType = TypeOfDrive(strDriveLetter) ' Freien Speicherplatz ermitteln strSpaceFree = NumberOfBytesFree(strDriveLetter) ctlAny.Value = _ ctlAny.Value & _ Left(strDriveLetter, 2) & _ " – " & strDriveType & _ IIf(strDriveType <> "Drive Doesn't Exist", _ strSpaceFree, "") & _ vbCrLf Next intDrive End Sub
Die Routine durchläuft alle verfügbaren Laufwerksbuchstaben. Für jeden Laufwerksbuchstaben werden die beiden benutzerdefinierten Funktionen TypeOfDrive und NumberOfBytesFree aufgerufen. In Listing 27.6 ist die Funktion TypeOfDrive dargestellt. Listing 27.6:
Die Funktion TypeOfDrive
Function TypeOfDrive(ByVal strDrive As String) As String Dim intDriveType As Integer Dim strDriveType As String intDriveType = abGetDriveType(strDrive) Select Case intDriveType Case DRIVE_UNKNOWN strDriveType = "Type Unknown" Case DRIVE_UNAVAILABLE strDriveType = "Drive Doesn't Exist" Case DRIVE_REMOVABLE strDriveType = "Removable Drive" Case DRIVE_FIXED strDriveType = "Fixed Drive" Case DRIVE_REMOTE strDriveType = "Network Drive"
Laufwerkstypen und verfügbaren Platz auf Laufwerken ermitteln
989
Case DRIVE_CDROM strDriveType = "CD-ROM" Case DRIVE_RAMDISK strDriveType = "RAM Disk" End Select TypeOfDrive = strDriveType End Function
An die Funktion TypeOfDrive wird als Parameter ein Laufwerksbuchstabe übergeben. Sie ruft die Windows API-Funktion GetDriveType auf, um die Art jenes Laufwerks zu ermitteln, dessen Buchstabe an die Funktion übergeben wurde. Die Funktion GetDriveType gibt einen numerischen Wert zurück, welcher dem Typ des angegebenen Laufwerks entspricht. Der Rückgabewert wird im Rahmen einer Case-Anweisung ausgewertet und von der Funktion wird ein Text zurückgegeben, in dem der Typ des Laufwerks angegeben ist. Mit Hilfe der Funktion NumberOfBytesFree kann in der in Listing 27.7 dargestellten Weise ermittelt werden, wie viele Bytes auf einem bestimmten Laufwerk noch verfügbar sind. Listing 27.7:
Die Funktion NumberOfBytesFree
Function NumberOfBytesFree(ByVal strDrive As String) As String Dim lngSectors As Long Dim lngBytes As Long Dim lngFreeClusters As Long Dim lngTotalClusters As Long Dim intErrNum As Integer intErrNum = abGetDiskFreeSpace(strDrive, lngSectors, _ lngBytes, lngFreeClusters, lngTotalClusters) NumberOfBytesFree = " with " & _ Format((lngBytes * lngSectors) * _ lngFreeClusters, "#,##0") & _ " Bytes Free" End Function
Als Parameter wird an diese Funktion ein Laufwerksbuchstabe übergeben. Sie ruft zunächst die Windows API-Funktion GetDiskFreeSpace mit dem Laufwerksbuchstaben und einigen long integer-Werten als Parameter auf. Diesen long integer-Werten werden sämtliche Informationen zugewiesen, die für das Ermitteln der Anzahl des freien Speicherplatzes auf dem angegebenen Laufwerk erforderlich sind. Nachdem die Art des Laufwerks und sein freier Speicherplatz festgestellt wurden, verbindet die Prozedur GetDriveInfo die ermittelten Informationen mit dem in den Textfeldern des Formulars frmListDrives enthaltenen Texten. Falls das angegebene Laufwerk gerade nicht verfügbar ist, wird die Größe seines freien Speicherplatzes nicht dargestellt.
990
27.8.1
Kapitel 27: Die Leistungsfähigkeit des Windows-API ausschöpfen
Für die Praxis
Das Gelernte bei Anwendung für das Zeit- und Abrechnungssystem einsetzen Sie können die Anwendung für das Zeit- und Abrechnungssystem ein wenig verbessern, indem Sie ihr ein benutzerdefiniertes Infoformular hinzufügen. Sie haben die Möglichkeit, das Formular bereits jetzt zu erstellen, um es der Anwendung im Rahmen von Kapitel 37 hinzuzufügen. Das Formular frmSystemInformation wurde der Anwendung und die entsprechenden Deklarationen, Konstanten und Typen dem Modul basWinAPI hinzugefügt. Außerdem wurden sowohl das Formular als auch die API-Funktionen einer Bibliothek angegliedert, damit Sie sie auch von anderen Anwendungen aus verwenden können.
Die Leistungsfähigkeit von Klassenmodulen ausnutzen
Kapitel
Hier lesen Sie:
Die Vorteile von Klassenmodulen Objektorientierung – Eine Einführung Klassenmodule erstellen und verwenden Mehrere Instanzen von Klassen erstellen Die Ereignisse Initialize und Terminate Mit benutzerdefinierten Auflistungen arbeiten
28.1
Die Vorteile von Klassenmodulen
Access 2000 stellt Ihnen zwei Arten von Modulen zur Verfügung: Standard- und Klassenmodule. In Access 95 konnten bereits Klassenmodule für Formulare und Berichte erstellt werden, doch erst seit Access 97 ist auch das Erstellen unabhängiger Klassenmodule möglich. Klassenmodule unterscheiden sich nur geringfügig von Code-Modulen. Die Unterroutinen und Funktionen des Klassenmoduls stellen die Methoden der Klasse dar und aus den Routinen Property Let und Property Get gehen die Eigenschaften der Klasse hervor. Als Name des benutzerdefinierten Objekts wird der Name des Klassenmoduls verwendet. Ein Klassenmodul ist eine hervorragende Möglichkeit, verwandte Funktionen in einem übertragbaren, eigenständigen Objekt zu kapseln. Klassenmodule können Ihnen die Durchführung folgender Aufgaben erleichtern:
Datenbanken und Datensatzgruppen verändern Windows API-Funktionen aufrufen Den grundlegenden Umgang mit Dateien bewerkstelligen Auf die Registrierung zugreifen und Veränderungen darin vornehmen
992
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
Wenn Sie regelmäßig Datenbanken und Datensatzgruppen öffnen, um auf diese mit Hilfe entsprechender Codes zuzugreifen, sind Sie möglicherweise daran interessiert, sich diese Aufgaben zu vereinfachen. Das können Sie durch das Erstellen geeigneter Klassenmodule erreichen.
28.2
Objektorientierung – Eine Einführung
Die Welt der Objektorientierung ist faszinierend, erfordert jedoch eine neue Betrachtungsweise. Access 2000 ist eher objektbasiert als objektorientiert. Wozu diese Unterscheidung? Die nachfolgenden Definitionen in diesem Zusammenhang wichtiger Begriffe werden Ihnen bei der Unterscheidung dieser beiden Konzepte dienlich sein:
Klasse – Eine Vorlage für ein Objekt Objekt – Eine Instanz einer Klasse Instanzenbildung – Der Vorgang des Erstellens eines auf einer bestimmten Klasse basierenden Objekts
Polymorphismus – Verwenden gleicher Namen für Methoden und Eigenschaften unterschiedlicher Objekte bzw. unterschiedliches Implementieren von Eigenschaften und Methoden für verschiedene Objekte
Unterklassifizierung – Basierend auf einer Klasse eine andere erstellen Vererbung – Bezieht sich auf die Tatsache, dass Unterklassen das Verhalten der ihnen übergeordneten Klassen übernehmen VBA und somit auch Access unterstützt das Erstellen benutzerdefinierter Klassen und das Bilden von Objektinstanzen, die auf diesen Klassen basieren. Polymorphismus kann auch »simuliert« werden, indem innerhalb unterschiedlicher Klassen für Methoden und Eigenschaften gleiche Namen verwendet werden. Unterklassifizierung und Vererbung wird von VBA hingegen nicht unterstützt. Es können also keine auf andere Klassen basierenden Klassen erstellt werden. Das Übernehmen des Verhaltens anderer Klassen ist demnach nicht möglich. Polymorphismus kann lediglich »simuliert« werden, da echte Polymorphie das Vererben der Eigenschaften und Methoden übergeordneter an untergeordnete Klassen erfordert. Der nachfolgende Vergleich soll sicherstellen, dass Sie die soeben erörterten Begriffe auch wirklich verstanden haben. Stellen Sie sich vor, dass Sie einige Plätzchen backen wollen. Die Plätzchenform ist in diesem Fall die Klasse, welche dem Plätzchenobjekt als Vorlage dient. Sobald Sie die Plätzchenform verwenden, um ein tatsächliches Plätzchen zu erzeugen, bilden Sie eine Instanz der Plätzchenklasse, um ein Plätzchenobjekt zu erstellen. Das Plätzchen verfügt über einige Eigenschaften, wie beispielsweise die Puderzuckereigenschaft, und über einige Methoden, etwa die Methode »zubereiten«. Eine Frikadellenklasse dient als Vorlage für ein Frikadellen-
Klassenmodule erstellen und verwenden
993
objekt. Auch sie verfügt über eine entsprechende Zubereitungsmethode, die sich jedoch von jener des Plätzchenobjekts unterscheidet. Wir haben es hier also mit einem Polymorphismus zu tun. Wäre VBA objektorientiert, würden die Plätzchenund die Frikadellenklasse von einer gemeinsamen übergeordneten Klasse abgeleitet werden. Nachdem Sie sich jetzt mit den Begriffen und Konzepten der Objektorientierung auskennen, können Sie sich als nächstes vergegenwärtigen, wie in VBA mit benutzerdefinierten Klassen umzugehen ist.
28.3
Klassenmodule erstellen und verwenden
Ein Klassenmodul können Sie auf dreierlei Weise einfügen:
Wählen Sie bei geöffnetem Datenbankfenster im Menü EINFÜGEN die Option KLASSENMODUL aus.
Wählen Sie innerhalb der interaktiven Entwicklungsumgebung im Menü EINFÜGEN
die Option KLASSENMODUL aus.
Klicken Sie innerhalb der interaktiven Entwicklungsumgebung im Projektexplorer mit der rechten Maustaste auf das jeweilige Projekt und wählen Sie im Kontextmenü die Option EINFÜGEN|KLASSENMODUL aus. Nachdem ein Klassenmodul eingefügt wurde, sieht es wie ein herkömmliches CodeModul aus (siehe Abbildung 28.1). Die Unterschiede ergeben sich aus dem Verhalten des Klassenmoduls und aus der Art und Weise, in der die Variablen und Prozeduren des Klassenmoduls angesprochen werden.
28.3.1
Eigenschaften hinzufügen
Die einfachste Möglichkeit, einem Klassenmodul eine Eigenschaft hinzuzufügen, besteht in der Verwendung einer öffentlichen Variablen. Im folgenden Code werden beispielsweise die beiden öffentlichen Variablen FirstName und LastName deklariert. Nachdem der Code einer Klasse hinzugefügt wurde, stellen die beiden Variablen Eigenschaften der entsprechenden Klasse dar. Public FirstName as String Public LastName as String
28.3.2
Methoden hinzufügen
Funktionen und Unterroutinen in Klassenmodulen fungieren als Methoden der entsprechenden Klasse. Die nachfolgend dargestellte Unterroutine Speak stellt eine Methode der Klasse PublicPerson dar. Sie greift auf die Eigenschaften FirstName und LastName der Klasse zu und stellt deren Werte im Rahmen einer Meldung dar:
994
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
Abbildung 28.1: Ein neues Klassenmodul Public Function Speak() MsgBox FirstName & " " & LastName End Function
28.3.3
Klassenobjekte erstellen und verwenden
Um den Code einer Klasse verwenden zu können, müssen Sie zunächst ein auf der Klasse basierendes Objekt erstellen. Dazu deklarieren Sie erst einmal ein auf der Klasse basierendes Objekt und bilden das Objekt anschließend mit Hilfe einer SetAnweisung. Danach können Sie auf die Eigenschaften und Methoden des Objekts zugreifen. Der Code ist folgendermaßen aufgebaut: Sub SingleInstance() Dim oPerson As Person Set oPerson = New Person oPerson.FirstName = "Alison" oPerson.LastName = "Balter" oPerson.Speak End Sub
In dem Code wird zunächst ein Person-Objekt deklariert, welches mit Hilfe einer SetAnweisung erstellt wird. Den Eigenschaften FirstName und LastName werden die Zeichenketten Alison bzw. Balter zugewiesen. Danach wird die Methode Speak aufgerufen, damit der Name der Person angezeigt wird.
Klassenmodule erstellen und verwenden
28.3.4
995
Property Let- und Property Get-Eigenschaften korrekt hinzufügen
Aus der Verwendung öffentlicher Variablen als Eigenschaften ergeben sich in erster Linie die folgenden Nachteile:
Bei der Nutzung öffentlicher Variablen können keine Eigenschaften erstellt werden, die ausschließlich gelesen bzw. geschrieben werden können.
Die Werte öffentlicher Variablen können nicht überwacht werden. Der einer öffentlichen Variablen zugewiesene Wert kann nicht mehr verändert werden.
Änderungen öffentlicher Variablen sind nicht nachvollziehbar. Aus diesen Gründen sollten eher Eigenschaftsprozeduren als öffentliche Variablen verwendet werden. Mit Eigenschaftsprozeduren können Sie eigene Laufzeiteigenschaften benutzerdefinierter Objekte erstellen. Nach dem Erstellen benutzerdefinierter Eigenschaften können Sie deren Werte mit Hilfe von Property Let und Property Get festlegen bzw. ermitteln. Benutzerdefinierte Eigenschaften bieten Ihnen beim Erstellen Ihrer Anwendungen ein größeres Ausmaß der Flexibilität. Sie haben die Möglichkeit, wiederverwendbare Objekte zu erstellen, welche anderen Objekten Eigenschaften zur Verfügung stellen. Benutzerdefinierte Eigenschaften sind standardmäßig öffentlich deklariert und werden in Modulen von Klassen, Formularen oder Berichten angegeben, damit sie auch von anderen Modulen der aktuellen Datenbank verwendet werden können. Von anderen Datenbanken aus kann nicht auf sie zugegriffen werden. Die Routine Property Let definiert eine Eigenschaftsprozedur, welche einer benutzerdefinierten Objekteigenschaft einen Wert zuweist. Das Verwenden von Property Let ähnelt der Zuweisung des Werts einer öffentlichen Variablen, eine öffentliche Variable kann jedoch innerhalb der Datenbank an beliebiger Stelle verändert werden. Der jeweilige Wert einer öffentlichen Variablen ist deshalb kaum bzw. gar nicht kontrollierbar. Eine Property Let-Routine ermöglicht Ihnen das präzise Festlegen des der Eigenschaft zugewiesenen Werts. Es folgt ein Beispiel: Public Property Let FirstName(ByVal strNewValue As String) mstrFirstName = UCase(strNewValue) End Property
Möglicherweise drängt sich Ihnen der Gedanke auf, dass sich dieser Code genau wie eine Unterroutine verhält und bis zu einem gewissen Grad stimmt dies auch. Es handelt sich um eine spezielle Art von Unterroutine, welche automatisch ausgeführt wird, sobald der Wert einer benutzerdefinierten Variablen verändert wird. Der neue Wert der Eigenschaft wird als strNewValue an den Beispielcode übergeben. Eine in Großbuchstaben umgewandelte Version des Werts wird in der privaten Variablen mstrFirstName abgelegt. Die nachfolgend angegebene Code-Zeile bewirkt, dass die Property Let-Routine ausgeführt wird:
996
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
FirstName = "Alison"
Property Let legt den Wert der benutzerdefinierten Eigenschaft fest und Property Get
leitet eine Eigenschaftsprozedur ein, welche den Wert einer benutzerdefinierten Eigenschaft ermittelt. Dieses Beispiel veranschaulicht die Verwendung von Property Get: Public Property Get FirstName() As String FirstName = mstrFirstName End Property
Die Property Get-Routine wird automatisch ausgeführt, sobald innerhalb des Codes versucht wird, den Wert der Eigenschaft zu ermitteln. Der in der privaten Variablen mstrFirstName gespeicherte Wert wird von der Prozedur Property Get zurückgegeben. Das Ausführen dieser Routine kann erwirkt werden, indem irgendwo innerhalb der Datenbank der Wert der Eigenschaft abgerufen wird. Die folgende Codezeile bewirkt die Ausführung der Property Get-Routine: MsgBox FirstName
Der nachfolgende Code beinhaltet die Deklaration der beiden privaten Variablen mstrFirstName und mstrLastName, welche von den Property Let-Routinen für FirstName und LastName verwendet werden, um Werte darin abzulegen. Die Property GetRoutinen für FirstName und LastName verwenden die in den privaten Variablen gespeicherten Werte. Private mstrFirstName As String Private mstrLastName As String Public Property Get FirstName() As String FirstName = mstrFirstName End Property Public Property Let FirstName() As String mstrFirstName = UCase(strNewValue) End Property Public Property Get LastName() As String LastName = mstrLastName End Property Public Property Let LastName() As String mstrLastName = UCase(strNewValue) End Property
Mehrere Instanzen von Klassen erstellen
28.4
997
Mehrere Instanzen von Klassen erstellen
Einer der Vorteile von Klassenmodulen besteht darin, dass mehrere Instanzen einer Klasse erstellt werden können. Jede Instanz arbeitet mit eigenen Variablen und eigenem Code. Der folgende Code veranschaulicht dies: Sub MultipleInstance() Dim oPerson1 As Person Dim oPerson2 As Person Set oPerson1 = New Person Set oPerson2 = New Person oPerson1.FirstName = "Alison" oPerson1.LastName = "Balter" oPerson1.Speak oPerson2.FirstName = "Dan" oPerson2.LastName = "Balter" oPerson2.Speak End Sub
Es werden zwei Instanzen der Klasse Person mit den Bezeichnungen oPerson1 bzw. oPerson2 erstellt. Der FirstName-Eigenschaft von oPerson1 wird der Wert Alison und der LastName-Eigenschaft dieses Objekts der Wert Balter zugewiesen. In den Eigenschaften FirstName und LastName des Objekts oPerson2 werden hingegen die Zeichenketten Dan und Balter gespeichert. Mit Hilfe der Methode Speak werden die Namen dieser beiden Personen im Rahmen einer Meldung angezeigt.
28.5
Die Ereignisse Initialize und Terminate
Bei Initialize und Terminate handelt es sich um die beiden integrierten Ereignisse, welche für ein Klassenobjekt ausgeführt werden. Das Ereignis Initialize wird während der Instanzenbildung und Terminate während des Löschens der Klasse ausgeführt.
28.5.1
Initialize
Das Ereignis Initialize wird im Allgemeinen verwendet, um beispielsweise eine Verbindung mit einer Datenbank herzustellen und Variablen zu initialisieren. Es folgt ein Beispiel für die Verwendung des Ereignisses Initialize: Private Sub Class_Initialize() FirstName = "Alison" LastName = "Balter" End Sub
998
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
In diesem Beispiel werden den Eigenschaften FirstName und LastName der Klasse die Zeichenketten Alison und Balter zugewiesen.
28.5.2
Terminate
Das Ereignis Terminate wird im Allgemeinen für Bereinigungen verwendet, welche während des Löschens einer Klasse durchzuführen sind. Beispielsweise könnte eine von der Klasse verwendete Datensatzgruppe geschlossen werden. Es folgt ein Beispiel für die Verwendung des Ereignisses Terminate: Private Sub Class_Terminate() rstCustomer.Close Set rstCustomer = Nothing End Sub
28.6
Mit benutzerdefinierten Auflistungen arbeiten
Zusätzlich zu den in Access integrierten Auflistungen und sonstigen Objektbibliotheken können Sie auch benutzerdefinierte Auflistungen erstellen. Benutzerdefinierte Auflistungen ähneln Datenfeldern, weisen jedoch mehrere Vorteile auf:
Auflistungen werden dynamisch reserviert. Ihr Speicherbedarf richtet sich stets nach dem jeweils tatsächlichen Inhalt. Die Größe von Datenfeldern hingegen muss entweder im Voraus angegeben oder zur Laufzeit neu festgelegt werden. Beim Verändern der Größe eines Datenfelds legt Access zunächst eine vollständige Kopie des Datenfelds im Speicher an, was durchaus erhebliche Ressourcen verschlingen kann. Durch das Verwenden benutzerdefinierter Auflistungen können Sie dies vermeiden.
Die Anzahl der Elemente einer Auflistung ist stets bekannt und Elemente können auf einfache Weise hinzugefügt oder entfernt werden.
Die einzelnen Elemente einer Auflistung können unterschiedliche Datentypen aufweisen.
Abzulegende Elemente können beliebigen Elementen einer Auflistung zugewiesen werden. Auflistungen sind zwar äußerst leistungsfähig und bieten zahlreiche Vorteile, doch auch über deren nachfolgend angegebene Nachteile sollten Sie sich im Klaren sein:
Jedes Element einer Auflistung wird als variant gespeichert. Die Möglichkeit, in den einzelnen Elementen einer Auflistung Daten unterschiedlichen Typs zu speichern, kann sich gelegentlich auch nachteilig auswirken. Wenn Sie versuchen, sämtliche Elemente einer Auflistung auf die gleiche Weise zu verarbeiten (beispielsweise, indem Sie auf die gleiche Eigenschaft jedes Elements der Auflistung zugreifen), können sich daraus Fehler ergeben.
Mit benutzerdefinierten Auflistungen arbeiten
999
Möglicherweise fragen Sie sich, warum Auflistungen gerade in diesem Abschnitt behandelt werden. Auflistungen werden häufig verwendet, um benutzerdefinierte Objekte darin abzulegen. Ein Beispiel für diese Vorgehensweise können Sie dem Abschnitt »Bearbeiten mehrerer Instanzen der Datei-Informationsklasse mit Hilfe einer Auflistung« dieses Kapitels entnehmen.
28.6.1
Eine Auflistung erstellen
Das Definieren einer benutzerdefinierten Auflistung (Collection) ist sehr einfach – Sie brauchen nur das Schlüsselwort Dim zu verwenden, um wie folgt ein Objekt des Typs Collection zu erstellen: Dim colSports As New Collection
Die Anweisung Dim teilt dem Compiler mit, dass Sie eine Variable deklarieren möchten und die Schlüsselwörter As New weisen darauf hin, dass Sie eine neue Instanz von Etwas erstellen. In diesem Fall wird eine neue Instanz des Typs Collection erstellt. Als nächstes wird erklärt, wie einer benutzerdefinierten Auflistung Elemente hinzugefügt und auf welche Weise Elemente aus ihr entfernt werden können.
28.6.2
Einer Auflistung Elemente hinzufügen
Mit Hilfe der Methode Add kann einer benutzerdefinierten Auflistung ein neues Element hinzugefügt werden. Dies sieht dann folgendermaßen aus: colSports.Add "Basketball"
Diese Code-Zeile fügt der Auflistung colSports den Text Basketball als Element hinzu. Für die Methode Add gibt es drei optionale Parameter: Key, Before und After. Key ist eine Bezeichnung, über die Sie auf ein Element in eindeutiger Weise zugreifen können. Die Parameter Before und After legen fest, an welcher Stelle ein neues Element in die Auflistung eingefügt werden soll. Es folgt ein Beispiel: Sub NewCollection() Dim colSports As New Collection colSports.Add "Basketball" colSports.Add "Skiing" colSports.Add "Skating", Before:=1 colSports.Add "Hockey", Before:=2 End Sub
In diesem Code wird eine neue Auflistung namens colSports erstellt, der die beiden Elemente Basketball und Skiing aufeinander folgend hinzugefügt werden. Danach wird Skating vor Basketball eingefügt. Anschließend ist Skating Element 1 und Basketball wurde zu Element 2. Schließlich wird noch Hockey hinter Element 2 eingefügt.
1000
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
Im Gegensatz zu allen anderen Datenfeldern und Auflistungen in VBA wird bei benutzerdefinierten Auflistungen statt mit Element 0 mit Element 1 begonnen. Dies stellt eine große Umstellung dar, falls Sie bislang stets davon ausgegangen sind, dass Datenfelder und Auflistungen mit Element 0 beginnen.
28.6.3
Die Elemente einer benutzerdefinierten Auflistung durchlaufen
Analog zu integrierten Auflistungen können Sie auch benutzerdefinierte Auflistungen durchlaufen. Der entsprechende Code ist folgendermaßen aufgebaut: Sub LoopThroughCollection() Dim colSports As New Collection Dim varSport As Variant colSports.Add "Basketball" colSports.Add "Skiing" colSports.Add "Skating", Before:=1 colSports.Add "Hockey", Before:=2 For Each varSport In colSports Debug.Print varSport Next varSport End Sub
In diesem Code werden die einzelnen Elemente von colSports im Rahmen einer For Each...Next-Schleife durchlaufen. Beachten Sie, dass diese Routine als Objekttyp innerhalb der Auflistung eine Variant-Variable deklariert. Das geschieht, damit die unterschiedlichen Arten von Werten in den jeweiligen Objekten der Auflistung gespeichert werden können. Access aktualisiert die Auflistung, sobald Sie eine Datenbank öffnen und auf die Auflistung zugreifen.
28.6.4
Innerhalb einer Auflistung auf Elemente verweisen
Beim Hinzufügen eines Elements zur Auflistung können Sie jeweils einen benutzerdefinierten Schlüssel angeben. Dies ermöglicht Ihnen, sich bei Bedarf jederzeit auf das Element zu beziehen. Der folgende Code veranschaulicht, wie ein benutzerdefinierter Schlüssel angegeben werden kann: Sub CustomKey() Dim colSports As New Collection colSports.Add "Basketball", "B" colSports.Add "Skiing", "S1" colSports.Add "Skating", "S2" colSports.Add "Hockey", "H" Debug.Print colSports.Item("S1") End Sub
Mit benutzerdefinierten Auflistungen arbeiten
1001
In diesem Code werden der Auflistung colSports einige Elemente hinzugefügt. Jedem neuen Element der Auflistung wird ein eindeutiger Schlüssel zugewiesen. Auf die einzelnen Elemente der Auflistung kann anschließend problemlos über die jeweiligen Schlüssel zugegriffen werden. Die Methode Item wird häufig verwendet, um einer Auflistung mehrere Instanzen eines Formulars hinzuzufügen, wie beispielsweise eines Kundenformulars. Als einheitliche Schlüssel für die einzelnen Formulare einer solchen Auflistung wird die Kundennummer verwendet. Dieser eindeutige Bezeichner ermöglicht Ihnen das präzise Zugreifen auf bestimmte Instanzen des Kundenformulars.
28.6.5
Elemente aus einer Auflistung entfernen
Das Entfernen von Objekten aus einer benutzerdefinierten Auflistung ist genauso einfach wie das Hinzufügen und kann mit Hilfe der Methode Remove folgendermaßen bewerkstelligt werden: Sub RemoveElements() Dim colSports As New Collection colSports.Add "Basketball" colSports.Add "Skiing" colSports.Add "Skating" colSports.Add "Hockey" colSports.Remove 2 End Sub
Diese Routine entfernt das Element 2 (Skiing) aus der Auflistung.
28.6.6
Für die Praxis
Klassenmodule Um die Vorteile der Verwendung von Klassenmodulen gut einschätzen zu können, ist es von Vorteil, sie in Aktion zu sehen. In diesem Kapitel werden vier Beispiele behandelt. Das erste zeigt die Verwendung einer Klasse für Datei-Informationen. Die Instanzen dieser Klasse dienen der Speicherung von Informationen über einzelne Dateien. Das zweite Beispiel veranschaulicht die Nutzung einer benutzerdefinierten Klasse für den Umgang mit Kundendaten und im dritten Beispiel wird eine Klasse für Systeminformationen dargestellt, mit deren Hilfe Informationen über das Computersystem ermittelt und verfügbar gemacht werden können. Das vierte und letzte Beispiel demonstriert die Verwendung einer benutzerdefinierten Fehlerklasse für den Umgang mit Fehlern innerhalb Ihrer Anwendung.
1002
28.6.7
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
Die Datei-Informationsklasse
Viele Anwendungen erfordern das Ermitteln des Laufwerks, Pfads oder kurzen Dateinamens für einen vollständigen Dateinamen. Diese Informationen können zwar auch mit standardmäßigen Code-Modulen und -Funktionen bewerkstelligt werden, Klassenmodule können den entsprechenden Vorgang jedoch vereinfachen. Die in der Beispieldatenbank Chap28Ex enthaltene Klasse FileInformation umfasst vier Eigenschaften: FullFileName, Drive, Path und Name. Die Eigenschaft FullFileName wird vom Benutzer der Klasse festgelegt. Sie beinhaltet den vollständigen Dateinamen und den Pfad jener Datei, deren Bestandteile der Benutzer ermitteln möchte. Die Eigenschaften Drive, Path und Name der Klasse enthalten die Angaben über das Laufwerk, den Pfad und den Namen der in der Eigenschaft FullFileName angegebenen Datei. Sowohl die Property Let- und Property GetProzeduren als auch die mit diesen Eigenschaften verknüpften privaten Variablen sind in Listing 28.1 dargestellt. Listing 28.1: Private Private Private Private
Die Deklaration der Eigenschaften der Datei-Informationsklasse
mstrFullFileName As String mstrDrive As String mstrPath As String mstrName As String
Public Property Get FullFileName() As String FullFileName = mstrFullFileName End Property Public Property Let FullFileName(ByVal strFileName As String) Call GetDrive(strFileName) Call GetPath(strFileName) Call GetName(strFileName) End Property Public Property Get Drive() As String Drive = mstrDrive End Property Public Property Get Path() As String Path = mstrPath End Property Public Property Get Name() As String Name = mstrName End Property
Beachten Sie, dass die Eigenschaften Drive, Path und Name über keine entsprechenden Property Let-Routinen verfügen. Dies liegt daran, dass diese Eigenschaften
Mit benutzerdefinierten Auflistungen arbeiten
1003
außerhalb der Klasse ausschließlich gelesen werden können. Sobald die Eigenschaft FullFileName festgelegt wird, werden die Routinen GetDrive, GetPath und GetName ausgeführt. Diese Routinen sorgen dafür, dass den entsprechenden privaten Variablen die jeweiligen Werte zugewiesen werden, welche anschließend über die Property Get-Routinen abgerufen werden können. Die Unterroutinen GetDrive, GetPath und GetName sind in Listing 28.2 dargestellt. Listing 28.2:
Mit Hilfe der Routinen GetDrive, GetPath und GetName können das Laufwerk, der Pfad und der kurze Dateiname der in der Eigenschaft FullFileName angegebenen Datei ermittelt werden
Private Sub GetDrive(ByVal strFile As String) mstrDrive = Left$(strFile, _ InStr(strFile, ":")) End Sub Private Sub GetPath(ByVal strFile As String) mstrPath = strFile Do While Right$(mstrPath, 1) <> "\" mstrPath = Left$(mstrPath, _ Len(mstrPath) – 1) Loop End Sub Private Sub GetName(strFile) mstrName = Mid$(strFile, _ Len(mstrPath) + 1) End Sub
Die Routine GetDrive verwendet alle Zeichen links neben dem Doppelpunkt sowie den Doppelpunkt selbst und ermittelt so das Laufwerk. Die Routine GetPath sucht zunächst nach dem letzten umgekehrten Schrägstrich im Dateinamen und interpretiert die Zeichen links neben ihm als Pfadnamen. Abschließend werden der Eigenschaft Name die rechts neben dem letzten umgekehrten Schrägstrich stehenden Zeichen zugewiesen. Beachten Sie, dass die Routinen GetDrive, GetPath und GetName innerhalb des Klassenmoduls als privat deklariert sind. Auf ihren Code kann deshalb von außerhalb des Klassenmoduls nicht zugegriffen werden. Der in Listing 28.3 dargestellte Code veranschaulicht die Verwendung des Codes innerhalb des Klassenmoduls. Listing 28.3:
Verwenden der Klasse FileInformation
Private Sub cmdGetFileInfo_Click() Dim oFile As FileInformation If IsNull(Me.txtFullFileName) Then MsgBox "File Name Must Be Entered" Else
1004
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
Set oFile = New FileInformation oFile.FullFileName = Me.txtFullFileName Me.txtDrive = oFile.Drive Me.txtPath = oFile.Path Me.txtName = oFile.Name End If End Sub
In diesem im Formular frmFileInformation von Chap28Ex enthaltenen Code wird eine FileInformation-Variable deklariert. Solange vom Benutzer ein Dateiname angegeben wurde, bleibt eine Instanz der Klasse FileInformation bestehen. Der Eigenschaft FullFileName wird der im Textfeld txtFullFileName enthaltene Wert zugewiesen. Dies bewirkt die Ausführung der Routinen GetDrive, GetPath und GetName, welche die Werte der privaten Variablen der Klasse enthalten. Anschließend werden die Werte der Eigenschaften Drive, Path und Name in den Textfeldern des Formulars angezeigt. Bearbeiten mehrerer Instanzen der Datei-Informationsklasse mit Hilfe einer Auflistung Das Anpassen mehrerer Instanzen einer Klasse mit Hilfe einer Auflistung, welches Ihnen möglicherweise bislang ein wenig seltsam erscheint, wird in Listing 28.4 veranschaulicht. Listing 28.4:
Anpassen mehrerer Instanzen der Datei-Informationsklasse mit Hilfe einer Auflistung
Sub FileInfoCollection(strDirName As String) Dim colFiles As Collection Dim objFileInfo As FileInformation Dim strFile As String Dim vntFile As Variant Set colFiles = New Collection strFile = Dir(strDirName) Do Until Len(strFile) = 0 Set objFileInfo = New FileInformation objFileInfo.FullFileName = strDirName & strFile colFiles.Add objFileInfo strFile = Dir() Loop For Each vntFile In colFiles Debug.Print vntFile.Drive, vntFile.Path, vntFile.Name Next vntFile End Sub
Mit benutzerdefinierten Auflistungen arbeiten
1005
An den Code wird als Parameter der Pfad eines Verzeichnisses übergeben (einschließlich des abschließenden umgekehrten Schrägstrichs). Nach dem Deklarieren und Erstellen eines Collection-Objekts wird die Funktion Dir ausgeführt, um den Namen der ersten Datei im angegebenen Verzeichnis zu ermitteln. Ist dort zumindest eine Datei vorhanden, wird der Code innerhalb der Do Until-Schleife ausgeführt. Es wird eine Instanz der Klasse FileInformation erstellt, deren FullFileNameEigenschaft der Name des zur Datei gehörigen Verzeichnisses zugewiesen wird. Anschließend wird die wichtigste Code-Zeile der Routine ausgeführt. Sie fügt die Instanz der Klasse FileInformation der Auflistung hinzu, damit sie dauerhaft verfügbar wird. Danach wird die Dir-Funktion aufgerufen, um den Namen der nächsten Datei im angegebenen Verzeichnis zu ermitteln. Dieser Vorgang wird fortgesetzt, bis keine weiteren Dateinamen mehr gefunden werden. Nachdem der Auflistung alle Instanzen der Klasse FileInformation hinzugefügt wurden, werden sämtliche Elemente der Auflistung im Rahmen einer For...EachSchleife durchlaufen. Die Eigenschaften Drive, Path und Name jedes Elements der Auflistung werden abgerufen und im Fenster DEBUG ausgegeben. Beachten Sie, dass für das Durchlaufen der Elemente des Collection-Objekts eine Variable des Typs Variant verwendet werden muss.
28.6.8 Die Klasse für den Datenzugriff Mit Hilfe von Datenzugriffsklassen kann der Umgang mit Daten erheblich vereinfacht werden. Dies gilt insbesondere, wenn auf die in einer Tabelle enthaltenen Daten von zahlreichen Formularen und Datenbanken aus zugegriffen wird. Indem Sie die für den Zugriff auf die Daten erforderlichen Anweisungen in einem Klassenmodul kapseln, können Sie effektiver dafür sorgen, dass die Daten von allen Formularen und Anwendungen auf die gleiche Weise verarbeitet werden. Jedem Feld der Tabelle wird eine Eigenschaft der Klasse zugewiesen. Die in Listing 28.5 dargestellten privaten Deklarationen sowie die Property Let- und Property Get-Routinen veranschaulichen dies. Listing 28.5: Private Private Private Private Private Private Private
Die von der Datenzugriffsklasse verwendeten privaten Variablen sowie Property Letund Property Get-Routinen
mlngClientID As Long mstrCompanyName As String mstrAddress As String mstrCity As String mconn As ADODB.Connection mrst As ADODB.Recordset mboolAddFlag As Boolean
Public Property Get ClientID() As Long ClientID = mlngClientID End Property
1006
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
Public Property Get CompanyName() As String CompanyName = mstrCompanyName End Property Public Property Let CompanyName(ByVal strCompanyName As String) mstrCompanyName = strCompanyName End Property Public Property Get Address() As String Address = mstrAddress End Property Public Property Let Address(ByVal strAddress As String) mstrAddress = strAddress End Property Public Property Get City() As String City = mstrCity End Property Public Property Let City(ByVal strCity As String) mstrCity = strCity End Property Public Property Get AddFlag() As Boolean AddFlag = mboolAddFlag End Property Public Property Let AddFlag(ByVal boolAddFlag As Boolean) mboolAddFlag = boolAddFlag End Property
Das in Listing 28.6 gezeigte Initialize-Ereignis der Klasse sorgt für das Herstellen einer Verbindung mit der Datenbank und für das auf die Tabelle tblClients basierende Öffnen einer Datensatzgruppe. Beachten Sie, dass der Eigenschaft LockType der Wert adLockOptimistic und der Eigenschaft CursorType der Wert adOpenDynamic zugewiesen wird. Das Kombinieren dieser beiden Werte für diese Eigenschaften sorgt dafür, dass die in der Datensatzgruppe enthaltenen Daten aktualisiert werden können. Listing 28.6:
Das Ereignis Initialize stellt eine Verbindung mit den Daten her und öffnet einen auf der Tabelle tblClients basierenden Datensatz
Private Sub Class_Initialize() Set mconn = New ADODB.Connection Set mrst = New ADODB.Recordset mconn.ConnectionString = CurrentProject.Connection
Mit benutzerdefinierten Auflistungen arbeiten
1007
mconn.Open mrst.LockType = adLockOptimistic mrst.CursorType = adOpenDynamic mrst.Open "tblClients", mconn, Options:=adCmdTable Call Scatter End Sub
Nach dem Öffnen der Datensatzgruppe müssen die Inhalte des ersten Datensatzes als Eigenschaften der Klasse verfügbar sein. Dies ist erforderlich, damit die Inhalte des ersten Datensatzes im Rahmen des Formulars frmClients dargestellt werden können. Mit Hilfe der in Listing 28.7 gezeigten Methode Scatter wird das bewerkstelligt. Listing 28.7:
Die Methode Scatter überträgt die Inhalte des aktuellen Datensatzes in die Variablen auf Modulebene
Public Sub Scatter() With mrst mlngClientID = !ClientID mstrCompanyName = !CompanyName mstrAddress = !Address mstrCity = !City End With End Sub
Die Methode Scatter überträgt die Inhalte der Felder einfach in den aktuellen Datensatz (in diesem Fall in den ersten Datensatz) und speichert sie in privaten Variablen, auf die innerhalb der Klasse über die Routinen Property Get und Property Let zugegriffen werden kann. Möglicherweise fragen Sie sich, wann dieser Code eigentlich ausgeführt wird. Dies wird durch das Ereignis Load des in Listing 28.8 dargestellten Formulars frmClients veranlasst. Listing 28.8:
Die Routine Form_Load des Formulars frmClients ruft die Methode Scatter auf und füllt anschließend die Textfelder des Formulars aus
Private Sub Form_Load() Set mobjClients = New Client With mobjClients .Scatter Me.txtClientID = .ClientID Me.txtCompanyName = .CompanyName Me.txtAddress = .Address Me.txtCity = .City End With End Sub
Die Routine für das Ereignis Load erstellt eine Instanz der Klasse Client, damit das Ereignis Initialize der Klasse ausgeführt wird. Daraufhin wird die Methode Scatter der Klasse ausgeführt und die Inhalte der Eigenschaften ClientID, CompanyName,
1008
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
Address und City der Klasse werden in die Textfelder des Formulars übertragen. Das mit den Daten des ersten Datensatzes der Tabelle tblClients versehene Formular frmClient sehen Sie in Abbildung 28.2.
Abbildung 28.2: Das Formular frmClients wird zum Anzeigen und Ändern der in der Tabelle tblClients enthaltenen Daten verwendet
Sobald der erste Datensatz angezeigt wird, hat der Benutzer die Möglichkeit, zum nächsten Datensatz der Datensatzgruppe zu wechseln. In Listing 28.9 ist die Routine für das Ereignis Click der Befehlsschaltfläche cmdNext des Formulars frmClients dargestellt. Listing 28.9:
Die Behandlungsroutine für das Ereignis Click der Befehlsschaltfläche cmdNext ruft die Methode MoveNext der Klasse auf und zeigt anschließend die Inhalte der Eigenschaften der Klasse an
Private Sub cmdNext_Click() With mobjClients .MoveNext Me.txtClientID = .ClientID Me.txtCompanyName = .CompanyName Me.txtAddress = .Address Me.txtCity = .City End With End Sub
Die Behandlungsroutine für das Ereignis Click ruft die Methode MoveNext der Klasse auf. Die Methode MoveNext ist für das Wechseln zwischen den Datensätzen innerhalb der Klasse zuständig. Sie verwendet das in der Routine für das Ereignis Initialize der Klasse festgelegte Datensatzgruppenobjekt auf Modulebene, welches in Listing 28.10 dargestellt ist. Listing 28.10: Die Methode MoveNext dient dem Übergang zum nächsten Datensatz der Datensatzgruppe und auch seiner Darstellung Public Sub MoveNext() With mrst
Mit benutzerdefinierten Auflistungen arbeiten
1009
If Not .EOF Then .MoveNext If .EOF Then .MoveLast End If End If Call Scatter End With End Sub
Die Methode MoveNext überprüft zunächst, ob das Ende der Datensatzgruppe bereits erreicht wurde. Wenn dies nicht der Fall ist, wird mit Hilfe der Methode MoveNext zum nächsten Datensatz der Datensatzgruppe übergegangen. Wurde das Ende der Datensatzgruppe erreicht, so geht der Code zum vorherigen Datensatz über. Die Methode Scatter wird aufgerufen, um die Werte der Variablen auf Modulebene zu aktualisieren. Die Routine für das Click-Ereignis der Schaltfläche cmdNext ermittelt diese Werte anschließend über die Property Get-Routinen, damit die auf dem Formular angezeigten Daten aktualisiert werden. Die Routine für das in Listing 28.11 dargestellte Ereignis cmdPrevious_Click ähnelt dem Ereignis cmdNext_Click. Listing 28.11: Die Routine für das Click-Ereignis der Befehlsschaltfläche cmdPrevious ruft die Methode MovePrevious der Klasse auf und zeigt anschließend die Inhalte der Eigenschaften der Klasse an Private Sub cmdPrevious_Click() With mobjClients .MovePrevious Me.txtClientID = .ClientID Me.txtCompanyName = .CompanyName Me.txtAddress = .Address Me.txtCity = .City End With End Sub
Die Routine für das Click-Ereignis der Befehlsschaltfläche cmdPrevious ruft zunächst die Methode MovePrevious der Klasse auf. Die Methode MovePrevious der Klasse ähnelt der Methode MoveNext (siehe Listing 28.12). Listing 28.12: Die Methode MovePrevious dient dem Übergang zum vorherigen Datensatz der Datensatzgruppe und auch seiner Darstellung Public Sub MovePrevious() With mrst If Not .BOF Then .MovePrevious If .BOF Then .MoveFirst
1010
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
End If End If Call Scatter End With End Sub
Die Methode MovePrevious überprüft zunächst, ob der Datensatzzeiger bereits auf die Position vor dem ersten Datensatz verweist. Wenn dies nicht der Fall ist, wird die Methode MovePrevious verwendet, um zum vorhergehenden Datensatz der Datensatzgruppe überzugehen. Falls der Zeiger bereits am Anfang der Datensatzgruppe steht, wird zum ersten Datensatz übergegangen. Die Methode Scatter wird aufgerufen, um die Werte der Variablen auf Modulebene zu aktualisieren. Diese Variablen werden anschließend in Folge des Click-Ereignisses der Befehlsschaltfläche cmdPrevious von den Property Get-Routinen ermittelt. Die Klasse Client ermöglicht dem Benutzer das Bearbeiten der im zu Grunde liegenden Datensatz enthaltenen Daten. Dazu braucht der Benutzer die Daten lediglich in die ungebundenen Textfelder des Formulars einzugeben. Nach dem Eingeben der Daten klickt der Benutzer auf die Schaltfläche SPEICHERN. Daraufhin wird die Routine für das Click-Ereignis der Befehlsschaltfläche cmdSave ausgeführt. Die Behandlungsroutine für das Click-Ereignis wird in Listing 28.13 dargestellt. Listing 28.13: Die Behandlungsroutine für das Click-Ereignis der Befehlsschaltfläche cmdSave speichert die Daten des Formulars in der zu Grunde liegenden Datensatzgruppe Private Sub cmdSave_Click() If IsNull(Me.txtCompanyName) Or _ Len(Me.txtCompanyName) = 0 Then MsgBox "Company Name Must be Filled In Before Proceeding" Else With mobjClients .CompanyName = Me.txtCompanyName .Address = Me.txtAddress .City = Me.txtCity .Save .AddFlag = False Me.txtClientID = .ClientID End With End If End Sub
Der Code zum Click-Ereignis der Befehlsschaltfläche cmdSave weist zunächst den Textfeldern die entsprechenden Werte der Eigenschaften der Klasse zu. Anschließend wird die Methode Save der Klasse ausgeführt (siehe Listing 28.15). Bevor wir uns mit der Methode Save eingehender beschäftigen, sollten wir uns mit dem Code zum Click-Ereignis der Befehlsschaltfläche cmdNew auseinandersetzen
Mit benutzerdefinierten Auflistungen arbeiten
1011
(siehe Listing 28.14). Er löscht einfach die Inhalte der Textfelder des Formulars, um diese für das Eingeben neuer Daten vorzubereiten. Anschließend wird der Eigenschaft AddFlag der Wert True zugewiesen. Listing 28.14: Die Routine für das Ereignis Click der Schaltfläche cmdNew löscht alle Textfelder und weist der Eigenschaft AddFlag den Wert True zu Private Sub cmdNew_Click() Me.txtClientID = "" Me.txtCompanyName = "" Me.txtAddress = "" Me.txtCity = "" mobjClients.AddFlag = True End Sub
Wenn ein Datensatz hinzugefügt oder bearbeitet werden soll, speichert die Methode Save der Klasse die Daten des neuen Datensatzes auf der Festplatte. Den entsprechenden Code sehen Sie in Listing 28.15. Listing 28.15: Die Methode Save dieser Klasse ruft die Routine zum Schreiben der Daten auf die Festplatte auf Public Sub Save() If mboolAddFlag Then Call AddNew Else Call Edit End If End Sub
Die Methode Save der Klasse ermittelt zunächst, ob der Benutzer Daten hinzufügen oder verändern möchte. Dies wird mit Hilfe der Eigenschaft mboolAddFlag festgestellt. mboolAddFlag weist den Wert True auf, falls die Schaltfläche ADD angeklickt wurde. Beim Bearbeiten hingegen enthält diese Variable den Wert False. Sobald der Benutzer den neuen Datensatz hinzufügt, wird die in Listing 28.16 gezeigte private Routine AddNew ausgeführt. Listing 28.16: Die Methode AddNew dieser Klasse fügt den neuen Datensatz hinzu Private Sub AddNew() With mrst .AddNew !CompanyName = mstrCompanyName !Address = mstrAddress !City = mstrCity .Update mlngClientID = !ClientID End With End Sub
1012
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
Die Methode AddNew der Klasse verwendet die Methode AddNew einer ADO-Datensatzgruppe, um einem neuen Datensatz die in den privaten Variablen enthaltenen Werte zuzuweisen. Mit Hilfe der Methode Update des Datensatzgruppenobjekts werden die neuen Daten auf die Festplatte geschrieben. Sobald die Methode Update ausgeführt wird, erhält das AutoWert-Feld seinen jeweiligen Wert. Dieser Wert wird in der Variablen mlngClientID gespeichert. Diese Variable wird im Rahmen der Behandlung des Click-Ereignisses von cmdSave ausgewertet, damit das Textfeld txtClientID den korrekten Wert enthält. Die Methode AddNew der Klasse dient dem Hinzufügen des Datensatzes zu einer Datensatzgruppe und die Methode Edit der Klasse wird für das Aktualisieren der in einem vorhandenen Datensatz enthaltenen Daten verwendet (siehe Listing 28.17). Listing 28.17: Die Edit-Methode der Klasse aktualisiert die Inhalte eines Datensatzes Private Sub Edit() With mrst !CompanyName = mstrCompanyName !Address = mstrAddress !City = mstrCity .Update End With End Sub
Die Methode Edit verwendet die Methode Update der ADO-Datensatzgruppe, um die Werte der Variablen auf Modulebene zu ermitteln und auf der Festplatte zu speichern. Schließlich hat der Benutzer des Formulars cmdClients noch die Möglichkeit, einen Datensatz aus der Datensatzgruppe zu löschen. Der Code für das Click-Ereignis der Befehlsschaltfläche cmdDelete ist in Listing 28.18 dargestellt. Listing 28.18: Die Routine für das Click-Ereignis der Befehlsschaltfläche cmdDelete ruft die DeleteMethode der Klasse auf Private Sub cmdDelete_Click() With mobjClients .Delete Me.txtClientID = .ClientID Me.txtCompanyName = .CompanyName Me.txtAddress = .Address Me.txtCity = .City End With End Sub
In diesem Code wird die in Listing 28.19 gezeigte Methode Delete der Klasse ausgeführt. Die Delete-Methode eines ADO-Datensatzes wird genutzt, um den aktuellen Datensatz aus der Datensatzgruppe zu entfernen. Nach dem Löschen zeigt der Datensatzzeiger auf den gelöschten Datensatz. Mit Hilfe der Methode MoveNext der
Mit benutzerdefinierten Auflistungen arbeiten
1013
Klasse wird der Datensatzzeiger auf den nächsten gültigen Datensatz verschoben. Anschließend sorgt die Routine für das Click-Ereignis der Befehlsschaltfläche cmdDelete dafür, dass den Textfeldern des Formulars die Werte des mit der Methode MoveNext angesteuerten Datensatzes zugewiesen werden. Listing 28.19: Die Delete-Methode der Klasse löscht einen Datensatz aus der Datensatzgruppe Public Sub Delete() With mrst .Delete Call MoveNext End With End Sub
28.6.9 Die Klasse Systeminformation Der Vorgang des Ermittelns von Systeminformationen, wie beispielsweise des verfügbaren freien Speichers auf einem Laufwerk, ist normalerweise recht umständlich. Informationen dieser Art können im Allgemeinen ausschließlich über das Windows API abgerufen werden. Das Ausführen von Windows API-Funktionen sollte am besten fortgeschritteneren Entwicklern überlassen werden. Doch wie kann nun ein weniger erfahrener Entwickler diese wichtigen Informationen abrufen? Wenn der erfahrenere Entwickler die komplexen Funktionen der Windows API-Aufrufe in einem Klassenmodul kapselt, kann der weniger erfahrene Entwickler die benötigten Systeminformationen einfach mit Hilfe der Eigenschaften der Klasse ermitteln. Die Klasse SystemInformation dient dem Ermitteln von Informationen über die Hardware, das Betriebssystem und die Ressourcen des Systems. Damit diese Informationen in Erfahrung gebracht werden können, werden die folgenden DeclareAnweisungen sowie Deklarationen von Typstrukturen und Konstanten in den Abschnitt Allgemeine Deklarationen des Klassenmoduls eingefügt (siehe Listing 29.20). Listing 28.20: Die privaten Variablen und Typstrukturen der Klasse SystemInformation Private Private Private Private Private Private Private
Declare Sub GlobalMemoryStatus Lib "Kernel32" (lpBuffer As MEMORYSTATUS) mlngTotalMemory As Long mlngAvailableMemory As Long mstrOSVersion As String msngOSBuild As Single mstrOSPlatform As String mlngProcessor As Long
Private Type MEMORYSTATUS dwLength As Long dwMemoryLoad As Long dwTotalPhys As Long dwAvailPhys As Long
1014
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
dwTotalPageFile As Long dwAvailPageFile As Long dwTotalVirtual As Long dwAvailVirtual As Long End Type Private Declare Function GetVersionEx Lib "Kernel32" Alias "GetVersionExA" _ (lpOSInfo As OSVERSIONINFO) As Boolean Private Type OSVERSIONINFO dwOSVersionInfoSize As Long dwMajorVersion As Long dwMinorVersion As Long dwBuildNumber As Long dwPlatformId As Long strReserved As String * 128 End Type Private Declare Sub GetSystemInfo Lib "Kernel32" (lpSystemInfo As SYSTEM_INFO) Private Type SYSTEM_INFO dwOemID As Long dwPageSize As Long lpMinimumApplicationAddress As Long lpMaximumApplicationAddress As Long dwActiveProcessorMask As Long dwNumberOrfProcessors As Long dwProcessorType As Long dwAllocationGranularity As Long dwReserved As Long End Type
Die Klasse SystemInformation enthält die sechs Eigenschaften TotalMemory, AvailableMemory, OSVersion, OSBuild, OSPlattform und Processor, welche jeweils ausschließlich gelesen werden können. Sie werden innerhalb der Klasse festgelegt und können von außerhalb der Klasse nicht verändert werden. Die Property Get-Funktionen dieser sechs Eigenschaften sind in Listing 28.21 dargestellt. Listing 28.21: Die für die Klasse SystemInformation erforderlichen Property Get- und Property LetRoutinen Public Property Get TotalMemory() As Long TotalMemory = mlngTotalMemory End Property Public Property Get AvailableMemory() As Long AvailableMemory = mlngAvailableMemory End Property
Mit benutzerdefinierten Auflistungen arbeiten
1015
Public Property Get OSVersion() As String OSVersion = mstrOSVersion End Property Public Property Get OSBuild() As Single OSBuild = msngOSBuild End Property Public Property Get OSPlatform() As String OSPlatform = mstrOSPlatform End Property Public Property Get Processor() As Long Processor = mlngProcessor End Property
Die eigentliche Arbeit übernimmt die Routine für das Ereignis Initialize der Klasse. Nach dem Bilden der Instanz dieser Klasse veranlasst das Initialize-Ereignis der Klasse die Ausführung der für das Ermitteln der gewünschten Systeminformationen erforderlichen Windows API-Funktionen. Listing 28.22: Die Routine für das Initialize-Ereignis der Klasse SystemInformation verwendet die für das Erlangen der Systeminformationen erforderliche Funktion des Windows API Private Sub Class_Initialize() ' Ermitteln des freien Speicherplatzes Dim MS As MEMORYSTATUS MS.dwLength = Len(MS) GlobalMemoryStatus MS mlngTotalMemory = Format(MS.dwTotalPhys, "Standard") mlngAvailableMemory = Format(MS.dwAvailPhys, "Standard") ' Ermitteln der Informationen über das Betriebssystem Dim OSInfo As OSVERSIONINFO OSInfo.dwOSVersionInfoSize = Len(OSInfo) If GetVersionEx(OSInfo) Then mstrOSVersion = OSInfo.dwMajorVersion & "." & OSInfo.dwMinorVersion msngOSBuild = OSInfo.dwBuildNumber And &HFFFF& If OSInfo.dwPlatformId = 0 Then mstrOSPlatform = "Windows 95" Else mstrOSPlatform = "Windows NT" End If End If ' Ermitteln von Systeminformationen Dim SI As SYSTEM_INFO GetSystemInfo SI
1016
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
mlngProcessor = SI.dwProcessorType End Sub
Die Windows API-Funktion GlobalMemoryStatus weist den Eigenschaften TotalMemory und AvailableMemory die entsprechenden Werte zu und die Funktion GetVersionEX wird verwendet, um die Werte der Eigenschaften OSVersion, OSBuild und OSPlatform festzulegen. Der Wert der Eigenschaft Processor wird abschließend mit Hilfe der Funktion GetSystemInfo ermittelt.
28.6.10 Die benutzerdefinierte Klasse zur Fehlerbehandlung Das Implementieren von Fehlerbehandlungsroutinen in eine Anwendung kann recht anstrengend sein. Dies gilt insbesondere, wenn Sie versuchen, einzelne von Ihnen geschriebene Routinen jeweils mit speziellen Fehlerbehandlungsroutinen auszustatten. In Kapitel 14 wurde bereits erörtert, wie allgemeine Fehlerbehandlungsroutinen zu erstellen sind. Allgemeine Fehlerbehandlungsroutinen machen die Verwendung eines Klassenmoduls zwar nicht erforderlich, eine solche Vorgehensweise kann das Implementieren der Fehlerbehandlung in Ihre Anwendungen jedoch erheblich vereinfachen (siehe Listing 28.23). Listing 28.23: Eine Access-Standardroutine Sub AnySub() Const SUBNAME As String = "AnySub" On Error GoTo AnySub_Err MsgBox "This is the rest of your code...." Err.Raise 11 MsgBox "We are Past the Error!!" Exit Sub AnySub_Err: Dim intAction As Integer Set gobjErrorHandler = New ErrorHandler With gobjErrorHandler .MODULENAME = MODULENAME .Routine = SUBNAME .ErrorMessage = Err.Description .ErrorNumber = Err.Number intAction = .ErrorProcess End With Select Case intAction Case gconERR_CONTINUE
Mit benutzerdefinierten Auflistungen arbeiten
1017
Resume Next Case gconERR_RETRY Resume Case gconERR_EXIT Exit Sub Case gconERR_QUIT Quit End Select End Sub
Sobald ein Fehler auftritt, wird eine Instanz der Klasse ErrorHandler gebildet und das Ereignis Initialize dieser Klasse ausgeführt (siehe Listing 28.24). Listing 28.24: Die Routine für das Initialize-Ereignis der Klasse ErrorHandler Private Sub Class_Initialize() mstrUserName = CurrentUser mdatDateTime = Now End Sub
Die Routine für das Initialize-Ereignis der Klasse weist den Variablen mstrUserName und mdatDateTime auf Modulebene den Wert von CurrentUser bzw. das gegenwärtige Datum und die Uhrzeit zu. Diese Variablen werden von den Eigenschaften UserName und DateTime der Klasse verwendet. Nach dem Eintreten des Initialize-Ereignisses der Klasse werden den Eigenschaften ModuleName, Routine, ErrorMessage und ErrorNumber die Werte der Konstanten MODULENAME und SUBNAME sowie der Eigenschaft Description des Objekts Err zugewiesen. Die Property Let- und Property Get-Routinen für die Eigenschaften ModuleName, Routine, ErrorMesage und ErrorNumber sind in Listing 28.25 dargestellt. Listing 28.25: Die Property Let- und Property Get-Routinen der Klasse mit den Informationen über Fehler bei Änderungen Public Property Get MODULENAME() As String MODULENAME = mstrModule End Property Public Property Let MODULENAME(ByVal strModule As String) mstrModule = strModule End Property Public Property Get Routine() As String Routine = mstrRoutine End Property Public Property Let Routine(ByVal strRoutine As String) mstrRoutine = strRoutine End Property
1018
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
Public Property Get ErrorMessage() As String ErrorMessage = mstrErrorMessage End Property Public Property Let ErrorMessage(ByVal strErrorMessage As String) mstrErrorMessage = strErrorMessage End Property Public Property Get ErrorNumber() As Integer ErrorNumber = mintErrorNumber End Property Public Property Let ErrorNumber(ByVal intErrorNumber As Integer) mintErrorNumber = intErrorNumber End Property
Wie Sie sehen, speichern die einzelnen Property Let-Routinen ihre Werte in Variablen auf Modulebene. Anschließend beziehen die Property Get-Routinen den jeweiligen Wert aus diesen Variablen. Danach wird die in Listing 28.26 dargestellte Methode ErrorProcess der Klasse ErrorHandler ausgeführt. Listing 28.26: Die ErrorProcess-Methode der Klasse ErrorHandler protokolliert den Fehler und reagiert in jeweils angemessener Weise Public Function ErrorProcess() As Integer Call LogError Dim rst As ADODB.Recordset Set rst = New ADODB.Recordset rst.ActiveConnection = CurrentProject.Connection rst.Open "Select Response from tblErrors Where ErrorNum = " & _ mintErrorNumber, Options:=adCmdText If rst.EOF Then DoCmd.OpenForm "frmError", WindowMode:=acDialog, _ OpenArgs:="ErrorHandler" ErrorHandler = ERR_QUIT Else Select Case rst!Response Case ERR_QUIT DoCmd.OpenForm "frmError", WindowMode:=acDialog, _ OpenArgs:="Critical Error: Application will Terminate" ErrorProcess = ERR_QUIT Case ERR_RETRY ErrorProcess = ERR_RETRY Case ERR_EXIT
Mit benutzerdefinierten Auflistungen arbeiten
1019
DoCmd.OpenForm "frmError", WindowMode:=acDialog, _ OpenArgs:="Severe Error: Processing Did Not Complete" ErrorProcess = ERR_EXIT Case ERR_CONTINUE ErrorProcess = ERR_CONTINUE End Select End If End Function
Die Routine ruft zunächst eine Unterroutine auf, welche den aufgetretenen Fehler protokolliert. Diese Fehlerprotokollierungsroutine wird als LogError bezeichnet und ist in Listing 28.27 dargestellt. Die Routine LogError bedient sich des ADO-Codes, um der Tabelle tblErrorLog einen Datensatz hinzuzufügen. Der hinzugefügte Datensatz enthält sämtliche Informationen über den aufgetretenen Fehler. Beachten Sie, dass die Fehlerinformationen aus den Variablen auf Modulebene bezogen werden, deren Werte durch Property Let-Routinen der Klasse ErrorHandler festgelegt wurden. Nach dem Protokollieren des Fehlers wird seine Nummer in der Tabelle tblErrors nachgeschlagen. Falls diese darin nicht verzeichnet ist, wird ein Formular mit allen wichtigen Informationen über den Fehler angezeigt. Von der Funktion ErrorHandler wird der in der Konstanten ERR_QUIT enthaltene Wert zurückgegeben. Wenn die Fehlernummer jedoch in der Tabelle tblErrors enthalten ist, wird der im Feld Response abgelegte Inhalt ausgewertet. Falls der darin enthaltene Wert mit jenem der Konstanten ERR_QUIT übereinstimmt, wird das Formular frmError angezeigt und der Wert der Konstanten ERR_QUIT von der Funktion zurückgegeben. Wenn der Wert des Felds Response mit jenem der Konstanten ERR_RETRY übereinstimmt, wird von der Funktion der Wert ERR_RETRY zurückgegeben und das Formular frmError nicht angezeigt. Falls das Feld Response einen Wert enthält, der mit der Konstanten ERR_EXIT übereinstimmt, wird das Formular frmError angezeigt und die Funktion ErrorHandler gibt den Wert ERR_EXIT zurück. Wenn schließlich der Wert des Response-Felds und der mit der Funktion ERR_CONTINUE verbundene Wert gleich sind, wird keine Fehlerinformation angezeigt und die Funktion ErrorHandler gibt den Wert ERR_CONTINUE zurück. Listing 28.27: Das Unterprogramm LogError verwendet ADO-Code, um tblErrorLog die Fehlerinformationen hinzuzufügen Private Sub LogError() Dim cnn As ADODB.Connection Dim strSQL As String strSQL = "INSERT INTO tblErrorLog ( ErrorDate, ErrorString, ModuleName, RoutineName) " strSQL = strSQL & "Select, #" & DateTime & "#, & mdatDateTime & "#, & mstrUserName & "',
ErrorTime, UserName, ErrorNum, _ #" _ '" _ " _
1020
Kapitel 28: Die Leistungsfähigkeit von Klassenmodulen ausnutzen
& & & &
mintErrorNumber & ", '" _ mstrErrorMessage & "', '" _ mstrModule & "', '" _ mstrRoutine & ","
Set cnn = New ADODB.Connection cnn.ConnectionString = CurrentProject.Connection cnn.Open cnn.Execute strSQL End Sub
Der gesamte in der Klasse ErrorHandler enthaltene Code ähnelt jenem des bereits in Kapitel 14 erörterten Moduls basErrorHandler. Der Code wurde ein wenig verändert, damit er mit den Eigenschaften und Methoden eines Class-Objekts arbeitet.
Eigene Bibliotheken erstellen
Kapitel
Hier lesen Sie:
Bibliotheksdatenbanken Vorbereiten einer Datenbank zur Verwendung als Bibliothek Einen Verweis erstellen Fehlersuche in einer Bibliotheksdatenbank
29.1
Bibliotheksdatenbanken
Nachdem Sie VBA besser kennen gelernt und Erfahrung als VBA-Programmierer gesammelt haben, wollen Sie einen Schritt weiter gehen und Funktionen und Subroutinen entwickeln, die sich auf Ihre gesamte Datenbank anwenden lassen. Ohne Bibliotheksdatenbanken ist der Code jeder Ihrer Datenbanken wie eine von der übrigen Welt abgeschnittene Insel. Wenn auch die Funktionen und Subroutinen innerhalb Ihrer Code-Module von jedem Punkt Ihrer Datenbank aus aufgerufen werden können, so ist dies nicht von einer anderen Datenbank aus möglich. Ohne eine gemeinsame Bibliothek, in der sich Code und weitere Standardobjekte befinden, sind Sie gezwungen, Routinen und andere Daten von einer Datenbank zur nächsten zu kopieren. Die Bibliotheksdatenbank kann von allen Anwendungen verwendet und an weitere Benutzer verteilt werden. Eine Bibliotheksdatenbank ist eine Datenbank wie jede andere: eine Sammlung von Abläufen und Objekten, auf die Sie von mehreren Datenbanken aus Zugriff haben wollen. Der einzige Unterschied zwischen einer Bibliotheksdatenbank und anderen Datenbanken liegt im Zugriff auf die Daten. Anstatt eine Bibliotheksdatenbank zu öffnen, um sie zu nutzen, greifen Sie von einer anderen Datenbank auf ihre Informationen zu. Access beruht in einem ganz erheblichen Maße auf dem Zugriff auf Bibliotheksdatenbanken. Tabellen-, Formular-, Berichts- und Datenbankassistent sowie Datenbankteiler, -analysierer und Dokumentierer sind Beispiele für Hilfsmittel, die in
1022
Kapitel 29: Eigene Bibliotheken erstellen
Bibliotheksdatenbanken angelegt wurden. Alle Assistenten, Generatoren und MenüAdd-Ins, die Sie benutzen, um Ihre Anwendungen zu erstellen, sind in Bibliotheksdatenbanken enthalten. Assistenten, Generatoren und Menü-Add-Ins werden in Kapitel 30 behandelt. Dieses Kapitel beschäftigt sich mit der Erstellung von Bibliotheksdatenbanken und Einbindung allgemeiner Funktionen in eine Bibliotheksdatenbank, um sie allen Ihrer Datenbanken zugänglich zu machen.
29.2
Eine Datenbank zur Verwendung als Bibliothek vorbereiten
Zwei Schritte sind notwendig, um eine Bibliotheksdatenbank zu erstellen: 1. Erstellen der als Bibliothek zu verwendenden Funktionen und Objekte 2. Laden der Datenbank als Bibliothek Zunächst erstellen Sie die Objekte, die Sie mit Ihren Anwendungen nutzen wollen. Um eine Datenbank als Bibliothek zu laden, muss sie von einer anderen Datenbank aus aufgerufen werden. Dieser Vorgang wird im nächsten Abschnitt behandelt. Eine Datenbank, die als Bibliothek genutzt werden soll, muss optimal für ihre Verwendung als Bibliothek ausgelegt sein. Auch wenn eine Bibliotheksdatenbank lediglich eine gewöhnliche Datenbank ist, stellt die Planung ihres Aufbaus den Schlüssel zu ihrem Erfolg und Nutzen dar. Unzulängliche Planung kann viele Folgen nach sich ziehen – von unverhältnismäßig hohem Speicherbedarf bis hin zur Funktionsuntüchtigkeit der Datenbank.
29.2.1
Code-Module auf optimale Leistung ausrichten
Bibliotheksdatenbanken beinhalten die gleichen Funktionen, die Sie in den meisten anderen Anwendungen auch nutzen. Aufgrund der Art und Weise, in der Access Code-Module lädt, müssen Sie Ihre Bibliotheksdatenbanken sinnvoll strukturieren, um optimale Leistung zu erhalten. Access 2.0 lud alle Code-Module bereits beim Laden der Anwendung. Dies bedeutete, dass es nicht besonders wichtig war, wie die Subroutinen und Funktionen in den verschiedenen Modulen der Datenbank strukturiert waren, wenn neue Access 2.0-Anwendungen erstellt wurden. Dies änderte sich drastisch mit den Versionen Access 95, Access 97 und Access 2000, die Code-Module nur laden, wenn sie benötigt werden. Wenn keine Vorgänge eines Moduls aufgerufen werden, wird dieses Modul in Access 2000 gar nicht erst geladen. Wird aber eine einzige Subroutine, Funktion oder Variable aufgerufen, wird das gesamte Modul geladen. Aus diesem Grund sollten Module so strukturiert werden, dass nur ein Minimum geladen werden muss.
Eine Datenbank zur Verwendung als Bibliothek vorbereiten
1023
Diese folgenden Punkte sollten Sie beachten, um Ihre Module effektiver zu strukturieren:
Trennen Sie häufig verwendete Prozeduren von solchen, die weniger häufig aufgerufen werden.
Prozeduren, die zusammen benutzt werden, sollten im selben Modul platziert werden.
Prozeduren, die nur selten aufgerufen werden, sollten in einem eigenen Modul gespeichert werden.
Wenn eine Prozedur von Routinen mehrerer Module aufgerufen wird, ist es ratsam, die betreffende Routine zu kopieren und in jedes der Module einzufügen. Hierdurch kann vermieden werden, dass ein ganzes Modul geladen wird, nur weil eine einzige Routine in ihm aufgerufen wurde.
Platzieren Sie aufeinander verweisende Prozeduren in einem Modul. Das ist wichtig, da Access potentielle Querverweise berücksichtigt, wenn ein Modul geladen wird. Wenn eine Prozedur eines Moduls von einer Prozedur eines anderen Moduls aufgerufen wird, werden beide Module geladen. Gewöhnlich streben Sie an, Ihren Arbeitsspeicher möglichst leer zu halten – mit Ausnahme von häufig verwendeten Funktionen. Durch das geschickte Anordnen von häufiger benutzten Prozeduren im selben Modul gewährleisten Sie, dass diese in den Arbeitsspeicher geladen werden und Sie bei Bedarf einen schnellen Zugriff auf sie haben, wodurch die ganze Anwendung reibungsloser arbeiten kann.
29.2.2
Funktionierenden Code für Bibliotheken schreiben
Routinen, die in einer gewöhnlichen Datenbank problemlos funktionieren, können in Bibliotheksdatenbanken plötzlich zu Problemen führen. Ein Beispiel hierfür ist die Funktion CurrentDB. Wie bereits vorher in diesem Buch beschrieben, wird die Funktion CurrentDB benutzt, um auf die gerade verwendete Datenbank zu verweisen. Man sollte annehmen, dass die Funktion CurrentDB auf die Datenbank Bezug nimmt, in welcher der jeweilige Code benutzt wird, jedoch ist dies nicht der Fall. Die Funktion CurrentDB bezieht sich nur auf die gerade in der Benutzerschnittstelle aktive Datenbank. Wenn eine Bibliotheksfunktion von CurrentDB Gebrauch macht, verweist sie nicht auf sich selbst, sondern auf die Anwendungsdatenbank, die diese Bibliotheksfunktion aufruft. Möchten Sie auf die Bibliotheksdatenbank verweisen, müssen Sie die Funktion CodeDB verwenden, da diese Funktion stets auf die Datenbank verweist, in welcher der Code benutzt wird. In Abhängigkeit von der Situation müssen Sie sich daher für CurrentDB oder CodeDB entscheiden.
1024
29.2.3
Kapitel 29: Eigene Bibliotheken erstellen
Eine Bibliothek kompilieren
Bevor eine Bibliotheksdatenbank verteilt wird, muss sie zunächst kompiliert werden. Hierdurch wird eine optimale Leistungsfähigkeit gewährleistet. Ein nicht kompilierter Bibliotheks-Code wird bei jedem Zugriff kompiliert, wodurch die Leistung Ihrer Anwendung erheblich herabgesetzt wird. Das Kompilieren und dessen Nutzen werden eingehend in Kapitel 15 besprochen. Nachdem Sie alle Änderungen an Ihrer Bibliotheksdatenbank vorgenommen haben, wählen Sie DEBUGGEN|KOMPILIEREN. Dieser Befehl muss nach jeder Änderung an der Bibliotheksdatenbank aufgerufen werden.
29.3
Einen Verweis erstellen
Ein »Verweis« dient Access zum Auffinden einer Bibliotheksdatenbank, deren Routinen verwendet werden sollen. Verweise können auf folgende vier Weisen eingerichtet werden:
Erstellen eines Bibliotheksverweises Erstellen eines Laufzeitverweises Erstellen eines expliziten Verweises Verwenden von VBA-Code Ein Großteil des nun folgenden Textes bezieht sich auf die Windows-Registrierung. Auf die Windows-Registrierung können Sie mit Hilfe des Hilfsprogramms RegEdit zugreifen. Rufen Sie RegEdit auf, indem Sie die Option AUSFÜHREN aus dem START-Menü aufrufen und dann RegEdit eingeben.
29.3.1
Einen Bibliotheksverweis erstellen
Sie können einen Bibliotheksverweis erstellen, indem Sie die Bibliothek dem Abschnitt Menu Add-Ins der Windows-Registrierung hinzufügen (siehe Abbildung 29.1). Sie finden den Abschnitt Menu Add-Ins unter dem Schlüssel HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\9.0\Access\Menu Add-Ins. So ein Verweis ist eingeschränkt, da die Funktionen der Bibliotheksdatenbank hier nur als Add-Ins aufgerufen werden. Das Erstellen eines Bibliotheksverweises wird eingehender in Kapitel 30 beschrieben.
1025
Einen Verweis erstellen
Abbildung 29.1: Betrachten des Abschnitts Menu Add-ins der Windows-Registrierung
29.3.2
Einen Laufzeitverweis erstellen
Das Erstellen eines Laufzeitverweises umfasst das Einrichten eines Verweises auf die Bibliothek zur Laufzeit. Hierfür wird die Methode Run aus dem Application-Objekt eingesetzt. Wenn ein Verweis auf diese Weise erstellt wird, wird die Bibliotheksdatenbank geöffnet und die gewünschte Funktion ausgeführt. Hierfür wird OLE verwendet. Der große Vorteil dieser Methode besteht darin, dass der Bibliotheks-Code nicht vor seiner Nutzung in den Arbeitsspeicher geladen wird. Außerdem ist es hierbei nicht notwendig, dass weitere Module geladen werden, bevor sie schließlich einzeln aufgerufen werden. Das Erstellen eines Laufzeitverweises hat allerdings auch Nachteile:
Die Bibliotheksdatenbank muss eine MDA-Erweiterung besitzen. Die Bibliotheksdatenbank muss im Add-In-Pfad der Windows-Registrierung enthalten sein. Der Add-In-Pfad befindet sich im Unterverzeichnis HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\9.0\Access\Wizards
der Windows-Registrierung (siehe Abbildung 29.2). Eine Funktion einer Bibliothek zur Laufzeit aufrufen Der Code in Listing 29.1 zeigt, wie eine Funktion in einer Bibliothek aufgerufen wird. Beachten Sie den Aufruf der Funktion IsLoaded seitens der Bibliothek. Sie finden diesen Code in der Datenbank CHAP29EX.MDB auf der CD-ROM mit den Beipielcodes.
1026
Kapitel 29: Eigene Bibliotheken erstellen
Abbildung 29.2: Der Schlüssel AddInPath in der Windows-Registrierung Listing 29.1:
Aufrufen einer Funktion einer Bibliothek
Sub AppRun () If Application.Run (Chap29Lib.IsLoaded, frmCustomers) then MsgBox Customers Form is Loaded Else MsgBox Customers Form is NOT Loaded!! End If End Sub
Dieser Code benutzt die Methode Run des Application-Objekts, um eine Funktion IsLoaded aufzurufen, die sich in der Bibliothek CHAP29LIB.MDA befindet. Auf diese Datei muss mit einem expliziten Verweis verwiesen werden (siehe »Einen expliziten Verweis erstellen« im weiteren Verlauf dieses Kapitels). Sie kann auch im Verzeichnis angesiedelt werden, auf das im Add-In-Pfad der Windows-Registrierung verwiesen wird. Beachten Sie den expliziten Verweis auf den Namen der Bibliothek, in der sich die Funktion befindet. Wenn eine Bibliothek auf diese Weise geladen wird (ohne expliziten Verweis), muss der Bibliotheksname angegeben werden. Den Schlüssel LoadOnStartup verwenden Es ist möglich, der Windows-Registrierung einen Schlüssel LoadOnStartup hinzuzufügen. Mit Hilfe dieses Schlüssels kann Access eine Typ-Bibliothek laden, während die Datenbank geladen wird. Eine Typ-Bibliothek ist kein richtiges Modul, sondern entspricht eher dem Bauplan eines Moduls. Sie zeigt die Funktionen und Konstanten eines bestimmten Moduls auf. Dies ist sehr hilfreich, da Access so Funktionen aus
Einen Verweis erstellen
1027
Modulen heraussuchen kann, ohne die Module zu laden, in denen sich diese Funktionen befinden. Dieser Schlüssel ist nicht automatisch schon vorhanden. Um den Schlüssel LoadOnStartup zu erstellen und einzugeben, gehen Sie folgendermaßen vor: 1. Wählen Sie im Windows-Menü START die Option AUSFÜHREN. 2. Geben Sie RegEdit ein und klicken Sie auf OK. Hierdurch wird der Registrierungs-Editor aufgerufen. 3. Öffnen Sie den Registrierungsbaum, bis Sie den folgenden Schlüssel sehen: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\9.0\Access\Wizards.
4. Klicken Sie auf WIZARDS. 5. Wählen Sie BEARBEITEN|NEU|SCHLÜSSEL aus. Dies fügt einen neuen Schlüssel hinzu. 6. Geben Sie dem neuen Schlüssel den Namen LoadOnStartup. 7. Lassen Sie LoadOnStartup ausgewählt und wählen Sie BEARBEITEN|NEU|ZEICHENFOLGE. 8. Geben Sie für die neue Zeichenfolge den vollständigen Namen und Pfad der Bibliothek an. 9. Wählen Sie BEARBEITEN|ÄNDERN. 10. Geben Sie den Wert rw ein. Abbildung 29.3 zeigt einen vollständigen Eintrag, der einen Verweis auf die Bibliothek im Verzeichnis C:\Eigene Dateien darstellt: CHAP29LIB.MDA. Die im Schlüssel LoadOnStartup aufgeführten Modul- und Ablauflisten der Bibliotheksdatenbank werden geladen, sobald Access aufgerufen wird. Wenn Sie die Methode RUN verwenden (siehe »Einen Bibliotheksverweis erstellen«), sucht Access in den geladenen oder durch einen Verweis bekannten Bibliotheken nach der gewünschten Prozedur. Wenn die Prozedur nicht gefunden wird, durchsucht Access jede im Schlüssel LoadOnStartup aufgeführte Datenbank. Da die unter dem Schlüssel aufgeführten Modul- und Prozedurlisten der Datenbanken beim Start von Access verfügbar werden, durchsucht Access diese Listen, bis die gewünschte Bibliothek gefunden wurde und lädt diese dann. Wie Sie feststellen werden, genießt der LoadOnStartup-Schlüssel die Vorteile von Application.Run durch die Nutzung der Typ-Bibliothek. Dies ist insofern vorteilhaft, als die Funktionen überprüft werden können, ohne das Modul zu laden.
1028
Kapitel 29: Eigene Bibliotheken erstellen
Abbildung 29.3: Mit Hilfe des RegistrierungsEditors auf eine Bibliothek verweisen
Der Schlüssel LoadOnStartup ist keine Wunderwaffe. Wird eine Typ-Bibliothek geladen, während Access läuft, wird hierdurch die Ladezeit Ihrer laufenden Anwendung verlängert. Weiterhin verbrauchen die Verweisinformationen Speicherplatz, auch wenn die Bibliotheksfunktionen gar nicht in Anspruch genommen werden. Von Fall zu Fall kann dies zu einem Problem werden.
29.3.3
Einen expliziten Verweis erstellen
Die am häufigsten benutzten Verweise sind die expliziten Verweise. Ein expliziter Verweis kann von jedem Code-Modul einer Datenbank erstellt werden, das auf die Bibliothek verweist. Gehen Sie folgendermaßen vor, um einen expliziten Verweis zu erstellen: 1. Wählen Sie ein Modul des Datenbankfensters aus. Klicken Sie nun auf die Schaltfläche ENTWURF, um die Entwurfansicht des Moduls aufzurufen. 2. Wählen Sie EXTRAS|VERWEISE aus dem VBE-Menü aus. Daraufhin erscheint das Dialogfeld VERWEISE (siehe Abbildung 29.4). 3. Klicken Sie auf DURCHSUCHEN. 4. Wählen Sie aus dem Listenfeld DATEITYP den Eintrag MICROSOFT ACCESS DATENBANKEN oder ADD-INS aus. 5. Geben Sie die Bibliotheksdatenbank an, auf die Sie verweisen möchten.
Einen Verweis erstellen
1029
Abbildung 29.4: Das Dialogfeld Verweise
6. Klicken Sie auf ÖFFNEN, um das Dialogfeld VERWEISE ßen.
HINZUFÜGEN
zu schlie-
7. Klicken Sie auf OK, um das Dialogfeld VERWEISE zu schließen. Wenn Sie dem Dialogfeld VERWEISE eine Bibliotheksdatenbank hinzufügen, lädt Access die Datenbank als Bibliothek, sobald Sie von Ihrem Code aus die Bibliothek aufrufen. Eine Bibliotheksroutine kann genau wie jede Unterroutine oder Funktion aufgerufen werden. Nun können Sie mit Hilfe von Code in der Bibliotheksdatenbank Formulare und andere in der Bibliothek gespeicherte Objekte öffnen. Access lädt die Bibliotheksdatenbank erst in den Arbeitsspeicher, wenn eine Routine der aktiven Anwendung eine Funktion oder Unterroutine der Bibliothek aufruft. Explizite Bibliotheksverweise bringen einige Beschränkungen mit sich:
Die Verweise, die Sie der Datenbank hinzufügen, sind nur dieser Datenbank zugänglich. Daher ist es notwendig, dass Sie den Bibliotheksverweis jeder Anwendung hinzufügen, die mit der Bibliothek arbeiten soll.
Der genaue Pfad des Verweises ist in der Datenbank gespeichert. Dies bringt mit sich, dass der Verweis nicht mehr korrekt ist und nicht mehr funktionieren wird, wenn die Bibliothek verschoben wird. Ausnahmen hiervon werden im weiteren Verlauf dieses Abschnitts besprochen. Wenn eine Funktion aufgerufen wird, die sich in einer nicht mehr auffindbaren Bibliothek befindet, erscheint eine Meldung wie in Abbildung 29.5. Hier wird darauf hingewiesen, dass Access nicht in der Lage ist, das Projekt oder die Bibliothek zu finden, in der sich die Prozedur befindet. Das Dialogfeld VERWEISE meldet, dass die
1030
Kapitel 29: Eigene Bibliotheken erstellen
Bibliothek nicht gefunden werden kann, wie man in der sechsten Zeile des Listenfelds VERFÜGBARE VERWEISE in Abbildung 29.6 sieht.
Abbildung 29.5: Diese Warnmeldung weist darauf hin, dass die Bibliotheksdatenbank nicht gefunden werden kann
Abbildung 29.6: Das Dialogfeld Verweise mit einer als fehlend gekennzeichneten Bibliothek
Auch wenn Access eine vorher verschobene Bibliotheksdatenbank nicht auffinden kann, wird versucht, Bibliotheksverweise wiederherzustellen. Dabei sucht Access standardmäßig an folgenden Orten:
in dem absoluten Pfad der Bibliothek in dem relativen Pfad der Bibliothek in dem Verzeichnis, in dem Access installiert ist in dem Windows-Pfad (Windows und Windows\System) in dem im RefLibPaths-Schlüssel in der Windows-Registrierung aufgeführten Pfad Auch wenn die meisten dieser Ortsbestimmungen ziemlich selbsterklärend sind, bedürfen andere einer weiteren Erläuterung. Wenn die Bibliothek nicht an der gleichen Stelle im Rechner des Benutzers eingerichtet ist wie in Ihrem Rechner, wird Access versuchen, den relativen Pfad zur nächstmöglichen Bibliothek herauszufin-
Einen Verweis erstellen
1031
den. Das bedeutet, dass die Bibliotheksdatenbank gefunden wird, wenn die Bibliothek im selben Verzeichnis wie die auf sie verweisende Datenbank oder auch nur im gleichen relativen Ort angesiedelt ist. Wenn sich Ihre Anwendung beispielsweise in C:\AccessApps\Sales und die Bibliotheksdatenbank in C:\AccessApps\Sales\Bibliotheken befindet und der Benutzer seine Anwendung unter C:\SalesApp und die Bibliothek unter C:\SalesApp\Bibliotheken gespeichert hat, kann Access den Verweis zur Bibliothek wiederherstellen. Ein anderer Trick bei der Arbeit mit Bibliotheksdatenbanken besteht darin, den RefLibPaths-Schlüssel der Windows-Registrierung zu benutzen. Wenn ein Schlüssel RefLibPaths in der Windows-Registrierung existiert, wird Access die in diesem Schlüssel angegebenen Pfade überprüfen, um Verweise wiederherzustellen. Dieser Trick funktioniert folgendermaßen: 1. Richten Sie einen Schlüssel RefLibPaths im Unterverzeichnis HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\9.0\Access ein, falls er nicht schon existiert. 2. Lassen Sie den Schlüssel ausgewählt und wählen Sie BEARBEITEN|NEU|ZEICHENFOLGE. 3. Geben Sie den Namen der Bibliotheksdatenbank als Namen der neuen Zeichenfolge ein. 4. Wählen Sie BEARBEITEN|ÄNDERN. 5. Geben Sie den Pfad der Bibliothek als den gewünschten Wert ein. 6. Wiederholen Sie die Schritte 2 bis 5 für jede Bibliothek. Dies ist eine sinnvolle Verfahrensweise, wenn Sie eine Anwendung verteilen wollen, die mehrere Bibliotheksdatenbanken enthält. Sie können einen Ort für die Bibliotheksdatenbanken bestimmen und dann in der Windows-Registrierung auf ihn verweisen. Sie können diese Einträge sogar automatisch erstellen lassen, indem Sie das Windows API oder die VBA-Speicheroption benutzen. In Abbildung 29.7 sehen Sie den Schlüssel RefLibPath mit einem Eintrag für die Bibliothek Chap29Lib.mdb. Sie können den Schlüssel RefLibPaths in der Windows-Registrierung mit Hilfe des Setup-Assistenten einrichten. Dies ist zwar der einfachste Weg hierfür, setzt aber voraus, dass Sie Ihre Anwendung mit dem Setup-Assistenten weitergeben.
29.3.4
Eine Referenz mit Hilfe von VBA-Code erstellen
Access 2000 ermöglicht es Ihnen, Bibliotheksverweise mit Hilfe von VBA-Code zu erstellen. Hierfür benutzen Sie die Methode AddFromFile. Diese Methode AddFromFile wird auf die References-Auflistung angewandt, die von ihrer Funktionalität und
1032
Kapitel 29: Eigene Bibliotheken erstellen
Abbildung 29.7: Der Schlüssel RefLibPath in der Windows-Registrierung
ihrem Aufbau her den anderen Access-Auflistungen ähnelt und eine Verbindung zu Verweisen einer Datenbank liefert. Die Methode AddFromFile aus der ReferencesAuflistung akzeptiert eine Zeichenfolge als Parameter. Diese Zeichenfolge enthält den Namen des hinzuzufügenden Bibliotheksverweises. Listing 29.2 zeigt den Code, mit dem man einen Bibliotheksnamen und einen Verweis einfügt. Listing 29.2:
Auffinden von Bibliotheken und Erstellen entsprechender Verweise
Function CreateLibRef (strLibName) Dim ref As Reference On Error GoTo CreateLibRef_Err ´ Erstellen eines neuen Verweises Set ref = References.AddFromFile (strLibName) CreateLibRef = True Exit_CreateLibRef: Exit Function CreateLibRef_Err: Dim intAnswer As Integer Dim strLocation As String IntAnswer = MsgBox ("Library Not Found, Attempt to Locate?", _ VbYesNo, Error) If intAnswer = vbYes Then StrLocation = InputBox ("Please Enter the Location of the Library") Resume Else CreateLibRef = False GoTo Exit_CreateLibRef
Fehlersuche in einer Bibliotheksdatenbank
1033
End If End Function
Die Routine beginnt mit dem Aufruf einer Fehlerbehandlungsroutine. Anschließend wird ein Verweisobjekt auf das Ergebnis der Methode AddFromFile gesetzt, die auf die References-Auflistung angewendet wird. Ist diese Methode erfolgreich, wird der Verweis erstellt und die Funktion gibt den Wert True zurück. Ansonsten wird der Benutzer gefragt, ob er die Bibliotheksdatenbank selbst suchen will. Wenn er dies wünscht, wird er gefragt, wo sich die Bibliotheksdatenbank befindet und der Code wird wiederum versuchen, einen Verweis herzustellen. Entscheidet sich der Benutzer dagegen, den Ort der Bibliothek anzugeben, wird die Routine mit dem Rückgabewert False beendet.
29.4
Fehlersuche in einer Bibliotheksdatenbank
Sie können eine Bibliotheksdatenbank öffnen und überprüfen wie jede andere Datenbank auch. Sie sollten zwar die Bibliotheksfunktionen stets auf diese Weise überprüfen, doch ist es auch wichtig, dass Sie die Datenbank als Bibliothek testen. Sie sollten also die Datenbank, nachdem Sie sämtliche Fehler beseitigt haben, von einer anderen Datenbank aus als Bibliotheksdatenbank aufrufen und überprüfen. Sollten Sie Änderungen an der Bibliotheksdatenbank vornehmen wollen, während Sie von einer anderen Datenbank auf sie zugreifen, können Sie folgendermaßen vorgehen: 1. Überprüfen Sie, ob die Bibliotheksdatenbank in EXTRAS|VERWEISE so verzeichnet ist, wie bereits in »Einen expliziten Verweis erstellen« besprochen. 2. Klicken Sie im Modulentwurfsfenster auf das Symbol OBJEKTKATALOG. 3. Wählen Sie die Bibliotheksdatenbank, deren Code Sie bearbeiten wollen, aus dem Menü PROJEKT/BIBLIOTHEK (siehe Abbildung 29.8) aus. 4. Wählen Sie die zu bearbeitende Klasse aus dem Listenfeld KLASSEN aus. 5. Wählen Sie das zu bearbeitende Element aus dem Listenfeld ELEMENTE aus.
VON
6. Klicken Sie auf DEFINITION ANZEIGEN (die Schaltfläche mit dem auf das Feld deutenden Pfeil) oder doppelklicken Sie auf das Element, dessen Code Sie einsehen wollen. Sie gelangen dadurch in das richtige Modul und die richtige Prozedur der Bibliotheksdatenbank. Sie können nun die erforderlichen Änderungen am Code der Datenbank vornehmen.
1034
Kapitel 29: Eigene Bibliotheken erstellen
Abbildung 29.8: Anpassen der Bibliotheksdatenbank mit Hilfe des Objektkatalogs
29.5
Eine Access-Bibliothek sichern
Es gibt viele Access-Bibliotheken, die auf dem Markt frei verkauft werden. Ob Sie nun eine Bibliotheksdatenbank vermarkten oder sie nur innerhalb Ihrer Organisation oder an Ihre Kunden weitergeben, Sie sollten darauf achten, Ihren Bibliothekscode zu sichern. Dies verhindert den Zugriff auf den Code. Es ist äußerst ratsam, Ihre Bibliothek abzusichern, wenn Sie planen, sie weiterzugeben. Es geht hier nicht nur darum, sein geistiges Eigentum zu schützen, sondern auch darum, einen Schutz vor aufdringlichen Benutzern herzustellen, die erst versuchen, den Code zu verändern und Sie dann in Erwartung einer Dienstleistung anrufen. Sicherheit wird genauer in Kapitel 33 besprochen.
29.5.1
Für die Praxis
Eine Bibliothek für Ihre Anwendung erstellen Nun, da Sie sich mit Bibliotheksdatenbanken und ihren Reizen auskennen, sollten Sie einmal versuchen, die allgemeinen Funktionen des Zeit- und Abrechnungssystems zu extrahieren und in einer Bibliotheksdatenbank unterzubringen. In diesem Abschnitt werden wir dieses Ziel Schritt für Schritt verfolgen.
Eine Access-Bibliothek sichern
1035
Dieser Vorgang wurde für CHAP29.MDB bereits abgeschlossen. Die zugehörige Bibliotheksdatenbank heißt CHAP29LIBRARY.MDA. Wenn Sie diesen Ablauf als Übung durchnehmen wollen, kopieren Sie CHAP26.MDB und befolgen Sie die weiteren Schritte. Um die allgemeinen Funktionen des Zeit- und Abrechnungssystems zu extrahieren und in einer Bibliotheksdatenbank unterzubringen, gehen Sie folgendermaßen vor: 1. Richten Sie eine neue Datenbank ein, die später die Bibliotheksdatenbank wird. Importieren Sie die Module basUtils, basGenericErrorHandler, basWinAPI sowie das Formular frmError in die Bibliotheksdatenbank. 2. Entfernen Sie folgende drei Routinen aus dem Modul basUtils in der Bibliotheksdatenbank: RunReport, GetCompanyInfo und CreateInstances. Nehmen Sie an, dass diese Routinen rein der Anwendungsdatenbank zugewiesen und nicht verschoben werden sollen, so dass sie ein Teil der Bibliothek würden. 3. Wählen Sie DEBUGGEN|KOMPILIEREN, damit Sie keine Kompilierungsfehler in der Bibliotheksdatenbank haben. 4. Öffnen Sie die Anwendungsdatenbank. 5. Löschen Sie basGenericErrorHandler, basWinAPI und frmError aus der Anwendungsdatenbank. 6. Löschen Sie die folgenden sechs Subroutinen aus dem Modul basUtils in der Anwendungsdatenbank: IsLoaded, FlipEnabled, ImportantKey, AreTablesAttached, LastOccurence und TryAgain. 7. Wählen Sie EXTRAS|VERWEISE, um auf die Bibliotheksdatenbank zuzugreifen. 8. Wählen Sie DEBUGGEN|KOMPILIEREN, um mögliche Kompilierfehler in der Anwendungsdatenbank zu entfernen. 9. Überprüfen Sie die Anwendung, um deren fehlerfreies Arbeiten zu gewährleisten. Um die Anwendung vollständig zu überprüfen, müssen Sie durch bewusstes Einfügen eines Fehlers auch die Fehlerbehandlung testen. Benennen Sie die Datenbank CHAP19DATA.MDB neu, um die Verbindungsroutinen zu überprüfen. Verschieben Sie noch ein weiteres Datenbankelement zur Bibliotheksdatenbank: das Berichtsformular für die Auswahlkriterien. Dieses Formular ist allgemein gültig und kann von einer großen Anzahl der Anwendungen benutzt werden, die Sie erstellen. Gehen Sie folgendermaßen vor, um das Formular frmReportDateRange zur Bibliotheksdatenbank zu verschieben: 1. Öffnen Sie die Bibliotheksdatenbank und importieren Sie das Formular frmReportDateRange.
1036
Kapitel 29: Eigene Bibliotheken erstellen
2. Erstellen Sie ein Modul mit dem Namen basGenericForms und fügen Sie ihm die Unterroutine OpenReportDateRange hinzu. Da es nicht möglich ist, ein Formular in der Bibliotheksdatenbank direkt zu öffnen, müssen Sie zunächst eine Unterroutine innerhalb der Bibliotheksdatenbank erstellen, welche das Formular für Sie öffnet. 3. Öffnen Sie die Anwendungsdatenbank und entfernen Sie das Formular frmReportDateRange. 4. Verändern Sie die jeweiligen Objekte in der Anwendungsdatenbank folgendermaßen: Sub OpenReportDateRange(strOpenArg As String) DoCmd.OpenForm "frmReportDateRange", , , , , acDialog, _ strOpenArg End Sub
Das Verschieben des Formulars frmReportDateRange von einer Bibliotheksdatenbank geht mit der Anpassung dreier Berichte in der Anwendungsdatenbank einher: rptProjektBillingsByWorkCode, rptClientBillingsByProjekt und rptEmployeeBillingsByProjekt. Die Behandlungsroutine für das Open-Ereignis des Berichts RptProjektBillingsByWorkCodes sollte wie folgt verändert werden: Private Sub Report_Open(Cancel As Ineger) Call OpenReportDateRange("rptProjektBillingsByWorkCode") If Not IsLoaded("frmReportDateRange") Then Cancel = True End If End Sub
Anstatt das Formular direkt zu öffnen, was ohnehin nicht gelänge, da es sich in einer Bibliotheksdatenbank befindet, müssen Sie dazu die Bibliotheksroutine OpenReportDateRange aufrufen. Der Parameter strOpenArg der Unterroutine OpenReportDateRange wird als OpenArgs-Parameter des Formulars frmReportCriteria eingesetzt. Die entsprechenden Veränderungen müssen Sie an den Berichten rptClientBillingsByProject und rptEmployeeBillingsByProject vornehmen. Sie sollten den Code zum Ereignis Open des Berichts rptClientBillingsByProject entsprechend Listing 29.3 verändern. Listing 29.3:
Anpassen des Codes für das Ereignis Open des Berichts rptClientBillingsByProject
Private Sub Report_Open(Cancel As Integer) Call OpenReportDateRange("rptClientBillingsbyProject") If Not IsLoaded("frmReportDateRange") Then Cancel = True Else Select Case Forms!frmReportDateRange!optDetailLevel.Value Case 1 Me.Caption = Me.Caption & " – Summary Only"
Eine Access-Bibliothek sichern
1037
Me.lblTitle.Caption = Me.lblTitle.Caption & " – Summary Only" Me.Detail.Visible = False Case 2 Me.Caption = Me.Caption & " – Detail Only" Me.lblTitle.Caption = Me.lblTitle.Caption & " – Detail Only" Me.GroupHeader0.Visible = False Me.GroupFooter1.Visible = False Me.CompanyNameDet.Visible = True Case 3 Me.Caption = Me.Caption & " – Summary and Detail" Me.lblTitle.Caption = Me.lblTitle.Caption & " – Summary and Detail" Me.CompanyNameDet.Visible = False End Select End If End Sub
Bearbeiten Sie die Routine für das Ereignis Open des Berichts rptEmployeeBillingsByProject- folgendermaßen: Private Sub Report_Open(Cancel As Integer) Call OpenReportDateRange("rptEmpployeeBillingsByProject") If Not IsLoaded("frmReportDateRange") Then Cancel = True End If End Sub
Nachdem Sie die allgemeinen Funktionen der Anwendung zur Bibliotheksdatenbank verschoben haben, können Sie versuchen, eine weitere Anwendungsdatenbank mit den gleichen Eigenschaften zu erstellen.
Generatoren, Assistenten und Menü-Add-Ins einsetzen
Kapitel
Hier lesen Sie:
Hilfsmittel-Aufbau und Installation Generatoren verwenden Assistenten verwenden Menü-Add-Ins verwenden
30.1
Hilfsmittel – Aufbau und Installation
Add-Ins sind Hilfsmittel, mit denen die Funktionalität von Access erhöht wird. Sie werten die Access-Arbeitsumgebung auf, indem sie schwierige Aufgaben leichter zu bewerkstelligen machen. Sie können Add-Ins für eigene Zwecke oder andere Benutzer in Ihrer Organisation herstellen. Es mag sich vielleicht sogar für Sie anbieten, Add-Ins als Bestandteil Ihrer Anwendung weiterzugeben, so dass andere Benutzer ihre eigenen Datenbankobjekte herstellen können. Wenn Sie sehr engagiert sind, stellen Sie sogar Add-Ins für den Verkauf als Access-Drittanbieter her. Microsoft Access unterstützt drei Arten von Add-Ins: Generatoren, Assistenten und Menü-Add-Ins, die alle ihre Vorteile und Verwendungen haben. Wenn Sie beginnen, ein Add-In zu entwerfen, müssen Sie sich zunächst entscheiden, ob Sie einen Generator, Assistenten oder ein Menü-Add-In herstellen wollen. Mit dieser Entscheidung wird das Design sowie die Art der Installation des Add-Ins bestimmt. In diesem Kapitel geht es um den Aufbau und die Installation jeder der drei Arten eines Add-Ins.
1040
30.2
Kapitel 30: Generatoren, Assistenten und Menü-Add-Ins einsetzen
Generatoren verwenden
Ein Generator ist ein Add-In, mit dessen Hilfe ein Benutzer einen Ausdruck oder ein anderes Datenelement konstruieren kann. Generatoren werden von Benutzern am häufigsten zur Festlegung der Eigenschaften eines Datenbankobjektes benutzt. Generatoren bestehen zumeist aus einem einzelnen Dialogfeld, das erscheint, nachdem der Benutzer auf die Schaltfläche mit den drei Punkten rechts neben dem Ereignis auf der Eigenschaftenseite geklickt hat. Der Ausdrucks-Generator ist ein Beispiel für einen Generator, der erscheint, wenn Benutzer die Steuerelementquelle eines Textfeldes in einem Formular festlegen. Access unterstützt drei Arten von Generatoren:
Eigenschaftengeneratoren Steuerelementgeneratoren Ausdrucksgeneratoren
30.2.1
Entwurfsrichtlinien
Beim Entwurf eines eigenen Generators sollte nach Möglichkeit eine Konsistenz mit den bereits vorhandenen Access-Generatoren vorhanden sein. Daher müssen Sie wissen, wie ein Generator in Access aufgebaut ist. Um Generatoren zu entwerfen, die mit bereits vorhandenen Generatoren konform sind, merken Sie sich folgende Richtlinien:
Setzen Sie die AutoCenter-Eigenschaft des Generators auf JA. Entfernen Sie Datensatzmarkierer und Navigationsschaltflächen. Entfernen Sie Bildlaufleisten. Bleiben Sie beim Einfügen von Objekten auf dem Formular konsistent. Platzieren Sie zum Beispiel die OK- und ABBRECHEN-Schaltflächen in jedem Generator an derselben Stelle.
Bauen Sie Formulare als Dialogfelder auf.
30.2.2
Einen Generator erstellen
Nun sind Sie mit einigen Grundsätzen über den Aufbau von Generatoren vertraut und können Ihren ersten Generator selbst erstellen. Wofür ein Generator eingesetzt wird, ist ganz Ihrer Vorstellung überlassen. Um dies zu verdeutlichen, beginnt dieser Abschnitt mit einem einfachen Generator, der den Benutzer um die Auswahl eines besonderen Effekts für ein Textfeld bittet. Drei allgemeine Schritte sind beim Erstellen eines Generators erforderlich: 1. Schreiben Sie eine Generatorfunktion.
Generatoren verwenden
1041
2. Entwerfen Sie ein Generatorformular. 3. Registrieren Sie den Generator. Die folgenden Abschnitte gehen weiter auf jeden dieser Schritte ein. Eine Generatorfunktion schreiben Access ruft die Generatorfunktion bei jedem Start eines Generators auf. Es wird zunächst das Generatorformular und dann ein Wert für die jeweilige Eigenschaft angezeigt. Listing 30.1 ist ein Beispiel für eine Generatorfunktion. Sie finden es in CHAP30LIB.MDA im Modul basBuilders der beiliegenden CD-ROM. Listing 30.1:
Erstellen einer Generatorfunktion
Function SpecialEffect(strObject As String, _ StrControl As String, _ StrCurrentValue As String) On Error GoTo SpecialEffect_Err DoCmd.OpenForm FormName:="frmSpecialEffect", _ WindowMode:=acDialog, _ OpenArgs:=strCurrentValue If SysCmd(acSysCmdGetObjectState, acForm, _ "frmSpecialEffect") = acObjStateOpen Then Select Case Forms!frmSpecialEffect.optSpecialEffect.Value Case 1 SpecialEffect = "Flat" Case 2 SpecialEffect = "Raised" Case 3 SpecialEffect = "Sunken" Case 4 SpecialEffect = "Etched" Case 5 SpecialEffect = "Shadowed" Case 6 SpecialEffect = "Chiseled" End Select DoCmd.Close acForm, "frmSpecialEffect" Else SpecialEffect = strCurrectValue End If SpecialEffect_Exit: Exit Function SpecialEffect_Err: MsgBox "Error # " & ": " & Err.Description Resume SpecialEffect_Exit End Function
1042
Kapitel 30: Generatoren, Assistenten und Menü-Add-Ins einsetzen
Eine Generatorfunktion muss drei voreingestellte Argumente erhalten und den Wert für die festzulegende Eigenschaft zurückgeben. Die drei voreingestellten Argumente sind:
strObject – Name der Tabelle, Abfrage des Formulars, Berichts oder Moduls, in dem der Generator arbeitet
strControl – Name des Steuerelements, auf das die Eigenschaft angewandt wird strCurrentValue – Momentaner Eigenschaftswert Auch wenn die Namen der Argumente willkürlich gewählt sind, können ihre Datentypen, Positionen und Inhalte nicht verändert werden. Die Werte für die drei Argumente werden von Access automatisch eingesetzt. Die Funktion SpecialEffect öffnet das Formular frmSpecialEffect. Das Formular wird im Dialogmodus geöffnet und der momentane Wert der Eigenschaft wird als OpenArgs-Wert eingesetzt. In Abbildung 30.1 sehen Sie das Formular frmSpecialEffect. Der folgende Code gehört zum Ereignis Click der Befehlsschaltfläche cmdOKAY: Private Sub cmdOK_Click() Me.Visible = False End Sub
Beachten Sie, dass die Routine die Eigenschaft Visible des Formulars auf false setzt. Der Code hinter der Schaltfläche cmdCancel sieht wie folgt aus: Private Sub cmdCancel_Click() DoCmd.Close End Sub
Mit diesem Code wird das Formular frmSpecialEffect geschlossen.
Abbildung 30.1: Das Formular zum Auswählen eines Spezialeffekts
Generatoren verwenden
1043
Nachdem der Benutzer auf OK oder CANCEL geklickt hat, wird der Code in der Funktion SpecialEffect ausgeführt. Die Funktion benutzt die Funktion SysCmd, um festzustellen, ob das Formular frmSpecialEffect geladen ist. Sie können auch die benutzerdefinierte Funktion IsLoaded hierfür benutzen. Wenn das Formular frmSpecialEffect immer noch geladen ist, muss der Benutzer einen Spezialeffekt ausgewählt und auf OK geklickt haben. Da das Formular immer noch geöffnet ist, kann die Funktion feststellen, welche Option vom Benutzer ausgewählt wurde. Die Case-Anweisung in der Funktion SpecialEffect wertet den Wert der Optionsgruppe opSpecialEffect im Formular frmSpecialEffect aus und setzt den ausgegebenen Wert der Funktion der jeweiligen Zeichenkette gleich, je nachdem, welche Optionsschaltfläche vom Benutzer ausgewählt wurde. Wenn der Benutzer des Generators zum Beispiel die zweite Optionsschaltfläche auswählt (mit dem Wert 2), antwortet die Funktion SpecialEffect die Zeichenkette Raised (erhöht) zurück. Nachdem der Wert der Optionsschaltfläche ausgewertet und der ausgegebene Wert festgelegt wurde, wird das Formular frmSpecialEffect nicht mehr länger benötigt und daher geschlossen. Wählt der Benutzer auf dem Formular frmSpecialEffect, gibt die Funktion SysCmd den Wert False zurück. Der Rückgabewert der Funktion SpecialEffect wird mit strCurrentValue gleichgesetzt, wobei es sich um den ursprünglichen Eigenschaftswert handelt. Der Eigenschaftswert wird hier also nicht verändert. Ein Generatorformular erstellen Sie haben zwar den Code hinter dem Click-Ereignis und den Schaltflächen OK und CANCEL auf dem Formular frmSpecialEffect kennen gelernt, jedoch noch nichts über den Aufbau des Formulars oder die Idee, die hinter diesem Generator steckt. Gewöhnlich steht Ihnen kein Assistent zur Verfügung, wenn die SpezialeffektEigenschaft aus dem Eigenschaftenfenster festgelegt wird. Es ist zwar recht einfach, Spezialeffekte vorzugeben, jedoch nicht so einfach, sich daran zu erinnern, wie jeder Effekt aussieht. Der benutzerdefinierte Spezialeffekt-Generator ist vor diesem Hintergrund entworfen worden. Es ermöglicht Benutzern dieses Generators, sich jeden Effekt anzusehen, bevor sie sich für einen entscheiden. Die Eigenschaften des Formulars sind recht einfach gehalten. Die Eigenschaft Modal wurde auf JA gesetzt und die Datensatzwähler, Navigationsschaltflächen und Bildlaufleisten wurden entfernt. Die Eigenschaft Automatisch zentrieren des Formulars wurde ebenfalls auf JA gesetzt. Dem Formular wurden sechs Textfelder hinzugefügt, von denen jedes einen anderen Spezialeffekt zugewiesen bekommen hat. Außerdem wurde dem Formular eine Optionsgruppe hinzugefügt. Diese Gruppe hat einen Wert, der davon abhängt, welche Optionsschaltfläche gewählt wurde. Die Eigenschaft Standard der OK-Schaltfläche wurde auf Ja gesetzt, so dass diese Schaltfläche automatisch gewählt wird. Die Eigenschaft ABBRECHEN der Schaltfläche ABBRECHEN ist auf JA gesetzt, so dass der Code hinter der Schaltfläche ABBRECHEN ausgeführt wird, wenn ESC gedrückt wird, . Der Code zu den Click-Ereignissen der Schaltflächen OK und ABBRECHEN wurde bereits im vorhergehenden Abschnitt erläutert.
1044
Kapitel 30: Generatoren, Assistenten und Menü-Add-Ins einsetzen
Dieser Generator kann durch den in Listing 30.2 gezeigten Code weiter verbessert werden. Listing 30.2:
Ausbauen des Generators
Private sub Form_Load() `Den Wert der Optionsgruppe auf `den aktuellen Wert der Eigenschaft setzen Select Case Me.OpenArgs Case "Flat" Me.optSpecialEffect.Value = 1 Case "Raised" Me.optSpecialEffect.Value = 2 Case "Sunken" Me.optSpecialEffect.Value = 3 Case "Etched" Me.optSpecialEffect.Value = 4 Case "Shadowed" Me.optSpecialEffect.Value = 5 Case "Chiseled" Me.optSpecialEffect.Value = 6 End Select End Sub
Diese Unterroutine gehört zum Load-Ereignis des Generatorformulars und lädt den Wert der Optionsgruppe auf den aktuellen Wert der Eigenschaft (der als ein OpenArg übergeben wurde). Das Formular frmSpecialEffect ist zwar nicht besonders aufregend, zeigt aber gut, dass Sie ein Formular erstellen können, das den Vorgang des Festlegens eines Eigenschaftswerts automatisiert, wie komplex das Formular auch sein mag. Bislang haben Sie aber noch keinen Einstieg für den Generator angeboten. Wenn die Eigenschaft SPEZIALEFFEKT ausgewählt wird, erscheint keine Schaltfläche mit drei Punkten, d.h., Sie haben noch keinen Zugriff auf den Generator. Einen Generator registrieren Bevor ein Generator benutzt werden kann, muss er zunächst registriert werden. Dafür gibt es zwei Möglichkeiten:
Sie nehmen die nötigen Einträge in der Windows-Registrierung manuell vor. Sie richten die Bibliotheksdatenbank so ein, dass der Add-In-Manager diesen Eintrag für Sie vornimmt. Der Windows-Registrierung Einträge manuell hinzufügen Um der Windows-Registrierung Einträge hinzuzufügen, sind vier Schritte nötig:
Generatoren verwenden
1045
1. Sollte kein Registrierungsschlüssel für die Eigenschaft bestehen, für die Sie den Generator erstellen, fügen Sie die Eigenschaft unter EIGENSCHAFTSASSISTENTEN als Unterschlüssel hinzu. 2. Fügen Sie einen weiteren Unterschlüssel für den Generator hinzu. 3. Fügen Sie vier voreingestellte Registrierungswerte für den Schlüssel hinzu. 4. Legen Sie den richtigen Wert für jeden Wertnamen fest. Die vier Namen der Werte, die für den Unterschlüssel erstellt werden müssen, sind Can Edit, Description, Function und Library. In Tabelle 30.1 werden diese Namen für den Registrierungsunterschlüssel erklärt. Name des Werts
Typ des Werts
Zweck
Can Edit
DWORD
Ermöglicht dem Generator das Verwenden und Verändern eines Werts
Description
String
Gibt eine Beschreibung eines Unterschlüssels an, welche in dem Dialogfeld erscheint, das automatisch aufgerufen wird, sobald für eine Eigenschaft mehr als ein Generator existiert
Function
String
Name der Generatorfunktion
Library
String
Name der Bibliothek, welche die Generatorfunktion enthält
Tabelle 30.1: Werte des Unterschlüssels in der Registrierung
Nun haben Sie einen Überblick über den Vorgang erhalten und es wird Zeit, im Detail über diese Schritte zu sprechen. Im Folgenden wird ein Generator mit dem Namen SpecialEffect erstellt, den Sie in der Bibliotheksdatenbank CHAP30LIB.MDA im Verzeichnis C:\AccessLibs finden: 1. Um den Registrierungs-Editor aufzurufen, wählen Sie START|AUSFÜHREN IN DER TASKLEISTE. GEBEN SIE regedit ein und klicken Sie auf OK. Hierdurch wird der Registrierungs-Editor aufgerufen. 2. Suchen Sie den Schlüssel HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\9.0\ Access\Wizards\Property Wizards (siehe Abbildung 30.2). 3. Stellen Sie fest, ob ein Unterschlüssel mit dem Namen der Eigenschaft, für die Sie den Generator (hier: SpecialEffect) erstellen, vorhanden ist. Wenn dies der Fall ist, gehen Sie zu Punkt 6. 4. Wählen Sie BEARBEITEN|NEU|SCHLÜSSEL. 5. Geben Sie den Eigenschaftsnamen als Namen des neuen Schlüssels (hier: SpecialEffect) ein.
1046
Kapitel 30: Generatoren, Assistenten und Menü-Add-Ins einsetzen
Abbildung 30.2: Der Registrierungsschlüssel Property Wizards
6. Lassen Sie den neuen Schlüssel ausgewählt und gehen Sie wieder auf BEARBEITEN|NEU|SCHLÜSSEL. 7. Geben Sie einen selbsterklärenden Namen für Ihren Generator ein (hier: SpecialEffectGenerator). 8. Wählen Sie BEARBEITEN|NEU|DWORD-WERT. 9. Geben Sie Can Edit als Namen des Werts ein. 10. Wählen Sie BEARBEITEN|NEU|ZEICHENFOLGE. 11. Geben Sie Description als neuen Namen des Werts ein. 12. Wählen Sie BEARBEITEN|NEU|STRING-WERT. 13. Geben Sie Function als neuen Namen dieses Werts ein. 14. Wählen Sie BEARBEITEN|NEU|ZEICHENFOLGE. 15. Geben Sie Library als Namen des Werts ein. 16. Doppelklicken Sie auf den Wert CAN EDIT. Das Dialogfeld DWORD-WERT BEARBEITEN erscheint (siehe Abbildung 30.3). 17. Geben Sie 1 als Wert ein und klicken Sie auf OK. 18. Doppelklicken Sie auf den Wert Description. Das Dialogfeld ZEICHENFOLGE BEARBEITEN erscheint (siehe Abbildung 30.4).
Generatoren verwenden
1047
Abbildung 30.3: Das Dialogfeld DWORD-Wert bearbeiten
Abbildung 30.4: Das Dialogfeld Zeichenfolge bearbeiten
19. Geben Sie die Beschreibung ein, die der Benutzer des Generators sehen soll, wenn der Eigenschaft mehr als ein Generator zugewiesen wurde. Klicken Sie auf OK . 20. Doppelklicken Sie auf den Wert Function. Geben Sie den Namen der Generatorfunktion (hier: SpecialEffect) ein. Klicken Sie auf OK. 21. Doppelklicken Sie auf den Wert Library. Geben Sie den Namen und den Ort der Bibliotheksdatenbank ein (hier: C:\Windows\Application Data\Microsoft\Addins). Die Eingabe des Pfads ist nicht erforderlich, wenn die Bibliothek im Access-Ordner gespeichert ist. Abbildung 30.5 zeigt die vollständigen Registrierungseinträge. Jetzt sollte der Generator einsatzfähig sein. Um ihn zu überprüfen, müssen Sie Access beenden und wieder aufrufen. Wenn alle Registrierungseinträge richtig waren, können Sie den Generator einsetzen. Um ihn zu überprüfen, öffnen Sie eine beliebige Datenbank (nicht jedoch die Bibliotheksdatenbank), erstellen ein neues Formular und fügen ein Textfeld hinzu. Wählen Sie dann auf der Registerkarte FORMAT des Eigenschaftenfensters die Eigenschaft Spezialeffekt aus. Anschließend erscheint rechts neben der Spezialeffektauswahl eine Schaltfläche mit drei Punkten (siehe Abbildung 30.6). Sobald Sie auf diese Schaltfläche klicken, erscheint das Generatorformular. Wählen Sie einen Spezialeffekt aus und klicken Sie auf OK. Der von Ihnen ausgewählte Spezialeffekt erscheint nun in der Spezialeffekteigenschaft.
1048
Kapitel 30: Generatoren, Assistenten und Menü-Add-Ins einsetzen
Abbildung 30.5: Die gesamten für das Hinzufügen des Generators in der Registrierung erforderlichen Einträge
Abbildung 30.6: Den benutzerdefinierten Generator verwenden
Wenn Sie nicht genau dem Format für die Wertenamen gefolgt sind, erscheint die Meldung MICROSOFT ACCESS KANN DEN ASSISTENTEN, DEN GENERATOR ODER DAS ADD-IN NICHT STARTEN (siehe Abbildung 30.7). Sie müssen den Registrierungseintrag korrigieren. Die Erstellung von Registrierungseinträgen automatisieren Eine Alternative zum manuellen Bearbeiten der Windows-Registrierung ist, die Bibliotheksdatenbank so einzurichten, dass der Add-In-Manager die Registrierungseinträge für Sie übernimmt. Dazu muss der Bibliotheksdatenbank eine Tabelle mit dem Namen USysRegInfo hinzugefügt werden. Gehen Sie folgendermaßen vor:
Generatoren verwenden
1049
Abbildung 30.7: Diese Fehlermeldung erscheint, falls der Eintrag in der Registrierung ungültig ist
1. Tabellen, deren Namen mit Usys oder Msys beginnen, sind Systemtabellen und per Voreinstellung verborgen. Der erste Schritt besteht also darin, Systemtabellen anzuzeigen. Gehen Sie, während die Bibliotheksdatenbank geöffnet bleibt, auf EXTRAS|OPTIONEN. Klicken Sie auf der Registerkarte ANSICHT auf SYSTEMOBJEKTE und danach auf OK. Abbildung 30.8 zeigt die Datenbank mit in der Objektliste ausgewählten Tabellen.
Abbildung 30.8: Die Registerkarte Tabellen mit den sichtbaren Systemobjekten
2. Als nächstes importieren Sie eine bestehende USysRegInfo-Tabelle. Hierfür klicken Sie mit der rechten Maustaste auf das Datenbankfenster und wählen IMPORTIEREN. Wechseln Sie mit Hilfe des Dialogfeldes IMPORTIEREN in das Verzeichnis \Programme\MS Office 2000\Office\1031 und zur Datei ACWZMAIN.MDE. Dies ist eine
1050
Kapitel 30: Generatoren, Assistenten und Menü-Add-Ins einsetzen
Bibliotheksdatei, die mit Access geliefert wird. Wählen Sie die Datei ACWZMAIN.MDE aus und klicken Sie auf IMPORTIEREN. 3. Es erscheint das Dialogfeld OBJEKTE IMPORTIEREN (siehe Abbildung 30.9). Wählen Sie die Tabelle USysRegInfo aus und klicken Sie auf OK. Eine Kopie der Tabelle USysRegInfo wird nun Ihrer Bibliotheksdatenbank hinzugefügt.
Abbildung 30.9: Mit dem Dialogfeld Objekte importieren können Sie die Tabelle USysRegInfo in Ihre Bibliotheksdatenbank einfügen
4. Öffnen Sie mit einem Doppelklick die Tabelle USysRegInfo im Datenbankfenster. 5. Entfernen Sie alle vorhandenen Einträge in der Tabelle. 6. Der Tabelle USysRegInfo müssen charakteristische Einträge hinzugefügt werden. In Abbildung 30.10 können Sie diese Einträge sehen, in Tabelle 30.2 werden sie erläutert. Fügen Sie diese Einträge hinzu und schließen Sie die Tabelle.
Abbildung 30.10: Die vollständige Tabelle mit den Einträgen für die Registrierung
7. Öffnen Sie die Datenbank, die auf das Add-In zugreift. 8. Wählen Sie EXTRAS|ADD-INS|ADD-IN-MANAGER aus. Das Dialogfeld ADD-INMANAGER erscheint (siehe Abbildung 30.11). 9. Klicken Sie auf die Schaltfläche HINZUFÜGEN, um in das Dialogfeld ÖFFNEN zu kommen. Hier können Sie nach Ihrem Add-In suchen oder aus einem vorgegebenen Verzeichnis auswählen.
Assistenten einsetzen
1051
Abbildung 30.11: Das Dialogfeld Add-In-Manager
10. Wählen Sie das von Ihnen gewünschte Add-In aus und klicken Sie auf OK. Hierdurch wird das von Ihnen ausgewählte Add-In dem Dialogfeld ADD-IN-MANAGER hinzugefügt und ausgewählt. 11. Klicken Sie auf SCHLIESSEN. Jetzt kann das Add-In von Ihnen benutzt werden. Feldname
Beschreibung
SubKey
Der Wertname des Unterschlüssels in der Registrierung, der dem hinzuzufügenden Wert entspricht
Type
Der Typ des Werts des Unterschlüssels, den Sie erstellen (String, Binary oder DWORD)
ValName
Der Wertname des Eintrags
Value
Der mit dem Wertnamen zu assoziierende Wert
Tabelle 30.2: Die Struktur der Tabelle USysRegInfo
30.3
Assistenten einsetzen
Ein Assistent besteht aus einer Reihe von Dialogfeldern. Er hilft einem Benutzer Schritt für Schritt durch den Prozess, ein Datenbankobjekt zu erstellen. Ein Assistent erleichtert es einem Benutzer, eine komplexe Aufgabe zu lösen. Sie haben vielleicht bereits mit Assistenten wie dem Formular-Assistenten, Bericht-Assistenten oder dem Datenbank-Assistenten gearbeitet. Access 2000 unterstützt die Entwicklung verschiedener, auf individuelle Bedürfnisse zugeschnittener Assistenten:
Tabellen-Assistenten Abfrage-Assistenten Formular-Assistenten Bericht-Assistenten
1052
Kapitel 30: Generatoren, Assistenten und Menü-Add-Ins einsetzen
Eigenschafts-Assistenten Steuerelement-Assistenten
30.3.1
Entwurfsrichtlinien
Die Richtlinien des Aufbaus von Assistenten entsprechen fast genau denen der Generatoren. Der Hauptunterschied besteht darin, dass Assistenten den Benutzer für gewöhnlich mit einer Reihe von modalen Dialogfeldern konfrontieren, während ein Generator meist aus nur einem modalen Dialogfeld besteht. Sämtliche Daten müssen dem Assistenten eingegeben werden, bevor der Benutzer das letzte Dialogfeld schließen kann.
30.3.2
Einen Assistenten erstellen
Das Erstellen eines Assistenten ist aufwendiger als das eines Generators. Ein Assistent benötigt ein mehrseitiges Formular und eine Routine, die Datenbankobjekte erstellen kann. Stellen Sie sich einen Assistenten vor, der ein einfaches Formular erstellt. Dieser Assistent umfasst zwei modale Dialogfelder, die in Abbildung 30.12 und Abbildung 30.13 zu sehen sind. Im ersten Dialogfeld gibt der Benutzer eine Formularüberschrift, den Namen des Formulars und den Text ein, der auf dem neuen Formular erscheinen wird. Mit dem zweiten Dialogfeld kann der Benutzer in das Formular OK- und ABBRECHEN-Schaltflächen einbetten. Das mehrseitige Formular und sämtliche Routinen, die zu dessen Nutzung notwendig sind, befinden sich in der Datenbank CHAP30LIB.MDA der beiliegenden CD-ROM.
Abbildung 30.12: Schritt 1 des Assistenten für benutzerdefinierte Formulare
Assistenten einsetzen
1053
Jede Seite des Assistenten enthält Routinen, die für einen reibungslosen Ablauf des Assistenten sorgen. Das Formular heißt frmGetFormInfo. Auf der ersten Seite dieses mehrseitigen Formulars hat der Benutzer die Möglichkeit, CANCEL, NEXT oder FINISH zu wählen. Der Code der Schaltfläche CANCEL sieht folgendermaßen aus: Private Sub cmdCancel1_Click() DoCmd.Close End Sub
Abbildung 30.13: Schritt 2 des Assistenten für benutzerdefinierte Formulare
Dieser Code beendet das Assistenten-Formular. Es werden keine weiteren Aktionen unternommen, da der Vorgang abgebrochen wurde. Klickt der Benutzer auf NEXT, wird folgender Code ausgeführt: Private Sub cmdNext1_Click() DoCmd.GoToPage 2 Me.Caption = "My Form Wizard – Step 2" End Sub
Dieser Code geht weiter zur zweiten Seite des Formulars und verändert dessen Überschrift, um damit anzuzeigen, dass sich der Benutzer beim zweiten Schritt des Assistenten befindet. Der Code der Schaltfläche FINISH sieht wie folgt aus: Private Sub cmdFinish1_Click() If CreateCustomForm() Then MsgBox "Form created Successfully" DoCmd.Close Else MsgBox "Unable to Create Form"
1054
Kapitel 30: Generatoren, Assistenten und Menü-Add-Ins einsetzen
EndIf End Sub
Dieser Code ruft die Funktion CreateCustomForm auf, die benötigt wird, um das Formular zu erstellen. Die Funktion CreateCustomForm wird im weiteren Verlauf dieses Abschnitts eingehender besprochen. Gibt die Funktion den Wert True zurück, wird das Assistentenformular geschlossen und ein Text angezeigt, der bestätigt, dass der Vorgang erfolgreich abgeschlossen wurde. Andernfalls wird angezeigt, dass das Formular nicht erfolgreich erstellt werden konnte und der Benutzer verbleibt weiterhin im Assistenten. Die zweite Seite des Formulars enthält ähnliche Unterroutinen. Der Code der Schaltfläche BACK sieht folgendermaßen aus: Private Sub cmdBack2_Click() DoCmd.GoToPage 1 Me.Caption = "My Form Wizard – Step 1" End Sub
Dieser Code bewirkt das Zurückgehen zur ersten Seite des Formulars. Wählt der Benutzer die Schaltfläche CANCEL, tritt folgender Code in Kraft: Private Sub cmdCancel2_Click() DoCmd.Close End Sub
Mit diesem Code wird das Formular geschlossen, d.h. es werden keine weiteren Schritte unternommen. Klickt der Benutzer auf FINISH, wird die Routine zum Ereignis Click der Schaltfläche cmdFinish2 ausgeführt: Private Sub cmdFinish2_Click() Call cmdFinish1_Click End Sub
Dieser Code ruft den Code des Klick-Ereignisses der cmdFinish1-Schaltfläche auf. Die Funktion CreateCustomForm (die sich im Modul basWizards der Bibliotheksdatenbank befindet) enthält den Code, der schließlich das neue Formular generiert (siehe Listing 30.3). Listing 30.3:
Die Funktion CreateCustomForm generiert das Formular.
Function CreateCustomForm() As Boolean On Error GoTo CreateCustomForm_Err Dim frmNew As Form Dim ctlNew As Control 'Ein neues Formular erstellen und mehrere Eigenschaften festlegen Set frmNew = CreateForm()
Assistenten einsetzen
frmNew.Caption = Forms!frmGetFormInfo.txtFormCaption frmNew.RecordSelectors = False frmNew.NavigationButtons = False frmNew.AutoCenter = True 'Auf dem neuen Formular ein Bezeichnungsfeld anlegen 'Mehrere Eigenschaften setzen Set ctlNew = CreateControl(frmNew.Name, acLabel) CtlNew.Caption = Forms!frmGetFormInfo.txtLabelCaption CtlNew.Width = 3000 CtlNew.Height = 1000 CtlNew.Top = 1000 CtlNew.Left = 1000 'Bestimmen, ob der Benutzer eine OK-Schaltfläche haben möchte 'Wenn dies so ist, die Schaltfläche hinzufügen 'und einige Eigenschaften setzen 'Eine Routine für das Ereignis Click der Schaltfläche hinzufügen If Forms!frmGetButtons.chkOk.Value = -1 Then Set ctlNew = CreateControl(frmNew.Name, acCommandButton) CtlNew.Caption = "OK" CtlNew.Width = 1000 CtlNew.Height = 500 CtlNew.Top = 1000 CtlNew.Left = 5000 CtlNew.Name = "cmdOK" CtlNew.Properties("OnClick") = "[Event Procedure]" CtlNew.Module.InsertText "Sub cmdOK_Click()" & vbCrLf & _ VbTab & "DoCmd.Close acForm, """ & _ Forms!frmGetFormInfo.txtFormName & _ """" & vbCrLf & "End Sub" End If 'Bestimmen, ob der Benutzer eine OK-Schaltfläche haben möchte 'Wenn dies so ist, die Schaltfläche hinzufügen 'und einige Eigenschaften setzen 'Eine Routine für das Ereignis Click der Schaltfläche hinzufügen If Forms!frmGetButtons.chkCancel.Value = -1 Then Set ctlNew = CreateControl(frmNew.Name, acCommandButton) CtlNew.Caption = "Cancel" CtlNew.Width = 1000 CtlNew.Height = 500 CtlNew.Top = 2000 CtlNew.Left = 5000 CtlNew.Name = "cmdCancel" CtlNew.Properties("OnClick") = "[Event Procedure]" FrmNew.Module.InsertText "Sub cmdCancel_Click()" & "End Sub" End If
1055
1056
Kapitel 30: Generatoren, Assistenten und Menü-Add-Ins einsetzen
'Bei Eingabe eines Formularnamens das Formular speichern If Not IsNull(Forms!frmGetFormInfo.txtFormName) Then DoCmd.Save , Forms!frmGetFormInfo.txtFormName End If 'Falls keine Fehler aufgetreten sind, True zurückgeben CreateCustomForm = True Exit Function CreateCustomForm_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description CreateCustomForm = False Exit Function End Function
Der Code beginnt mit dem Erstellen von Objektvariablen für das Formular und Steuerobjektvariablen. Die Formularobjektvariable wird auf den von der Funktion CreateForm ausgegebenen Wert gesetzt. Die Funktion CreateForm erstellt ein neues Formularobjekt, für das dann mehrere Eigenschaften vorgegeben werden: Caption (Beschriftung), RecordSelectors (Datensatzmarkierer), NavigationButtons (Navigationsschaltflächen) und AutoCenter (Automatisch zentrieren). Als nächstes benutzt die Funktion die Funktion CreateControl, um ein neues Bezeichnungsfeld zu erstellen, wobei der Verweis auf das neue Feld den Namen ctlNew erhält. Dann werden die Eigenschaften Beschriftung (Caption), Breite (Width), Höhe (Height), Oben (Top) und Links (Left) des Bezeichnungsfelds festgelegt. Hat der Benutzer angegeben, dass eine OK-Schaltfläche erstellt werden soll, so wird dies nun ausgeführt und es werden die Eigenschaften Beschriftung (Caption), Breite (Width), Höhe (Height), Oben (Top), Links (Left), Name (Name) und Eigenschaften (Properties) gesetzt. Mit der Methode InsertText wird der Code für das Click-Ereignis der Befehlsschaltfläche eingefügt. Soll eine CANCEL-Schaltfläche vorhanden sein, werden die gleichen Eigenschaften hierfür festgelegt. Hat schließlich der Benutzer auch einen Namen für das neue Formular angegeben, wird dieses mit Save gespeichert. Es bestehen verschiedene Möglichkeiten, Formulare, Berichte sowie Steuerelemente für Formulare und Berichte zu erstellen und zu entfernen. So kann zum Beispiel ADO-Code benutzt werden, um Tabellen und Abfragen zu erstellen, zu verändern oder zu entfernen. Mit Funktionen und ADO-Code können Datenbankobjekte je nach Bedarf verändert werden. Eine nähere Erläuterung von ADO finden Sie in Kapitel 12.
30.3.3
Vorbereiten des Assistenten auf seine Verwendung
Assistenten müssen, wie auch Generatoren, der Windows-Registrierung hinzugefügt werden, bevor sie verwendet werden können. Die Registrierung kann direkt verändert werden, doch es besteht auch die Möglichkeit, Einträge über die Tabelle USysRe-
Menü-Add-Ins verwenden
1057
gInfo vorzunehmen. In Abbildung 30.14 sehen Sie den vollständigen Registrierungseintrag für den benutzerdefinierten Formular-Assistenten.
Der Name der Funktion lautet MyCustomForm und stellt den Einstieg zum Assistenten dar. Der Bibliotheksschlüssel legt den Namen der Bibliotheks-Add-In-Datenbank fest, welche die Einstiegsfunktion enthält. Der Schlüssel Description legt fest, was im Dialogfeld NEUES OBJEKT erscheint. Letztendlich legt der Indexschlüssel die Stelle fest, in der der Assistent im Dialogfeld NEUES OBJEKT erscheint. Die Funktion MyCustomForm, die sich im Modul basWizards befindet, ruft einfach das Formular frmGetFormInfo auf, das den Assistenten ausführt: Function MyCustomForm(strRecordSource As String) As Variant DoCmd.OpenForm FormName:="frmGetFormInfo", WindowMode:=acDialog End Function
Abbildung 30.14: Registrierungseinträge für den Formular-Assistenten
30.4
Menü-Add-Ins verwenden
Menü-Add-Ins sind allgemeine Hilfsmittel, mit denen Sie Arbeiten ausführen können, die sich meist auf mehrere Objekte oder Access selbst auswirken. Datenbankteiler und -dokumentierer sind Beispiele für Menü-Add-Ins. Zugriff auf Menü-Add-Ins erhalten Sie über EXTRAS|ADD-INS.
1058
30.4.1
Kapitel 30: Generatoren, Assistenten und Menü-Add-Ins einsetzen
Entwurfsrichtlinien
Menü-Add-Ins stehen Benutzern immer zur Verfügung, wenn sie Zugriff auf das Menü EXTRAS haben. Menü-Add-Ins benötigen im Gegensatz zu Assistenten oder Generatoren keinen bestimmten Kontext. Daher sind sie nicht von den momentanen Aktionen eines Benutzers abhängig.
30.4.2
Ein Menü-Add-In erstellen
Menü-Add-Ins werden genau wie Assistenten erstellt. Der Unterschied zeigt sich in der Installation des Add-Ins. Ein Menü-Add-In muss unter HKEY_LOCAL_MACHINE\ SOFTWARE\Microsoft\Office\9.0\Access\Menu Add-Ins registriert werden. Hierfür können Sie die Registrierung direkt verändern oder stattdessen die Tabelle USysRegInfo benutzen. Abbildung 30.15 zeigt die Registrierung mit den richtigen Einträgen, um den früher in diesem Kapitel erstellten Formular-Assistenten als Add-In aufzurufen. In Abbildung 30.16 sehen Sie, wie Sie die Registrierung automatisch vornehmen lassen können, indem Sie die Tabelle USysRegInfo benutzen. Die Tabelle USysRegInfo enthält drei Einträge. Alle drei Einträge bestimmen den richtigen Platz im Registrierungsbaum, um den neuen Schlüssel hinzuzufügen. Der erste Eintrag enthält den Unterschlüssel und ein Null-Zeichen und der zweite den Wert Expression sowie den Namen der Anfangsfunktion als Wert. Beachten Sie, dass dem Ausdrucksnamen ein Gleichheitszeichen vorangestellt ist und dahinter Klammern folgen. Die Anführungszeichen in den Klammern sind notwendig, da diese Anfangsfunktion ein Argument voraussetzt. Der dritte und letzte Eintrag enthält den Wert Library (engl. Bibliothek) und den Namen der Bibliothek als Wert. Dies ist alles, was Sie tun müssen, um einen Assistenten in ein Menü-Add-In umzuwandeln.
30.4.3
Für die Praxis
Eigene Add-Ins entwerfen Welche Art von Generatoren, Assistenten und Menü-Add-Ins Sie erstellen, hängt von Ihren konkreten Anforderungen ab. Um das eben Gelernte zu vertiefen, enthält dieser Abschnitt jeden notwendigen Schritt, um einen Generator zu erstellen, der Ihnen hilft, Gültigkeitsmeldungen hinzuzufügen. Beim Aufrufen das Generators erscheint das Dialogfeld GENERATOR AUSWÄHLEN (siehe Abbildung 30.17). Dieses Dialogfeld erscheint, weil Sie zwei Generatoren erstellen werden: Einen, der dem Benutzer eine Liste freundlicher Meldungen zur Auswahl anbietet und einen zweiten, der eine Liste unfreundlicher Meldungen zur Verfügung stellt. Entscheidet sich der Benutzer für den »freundlichen« Generator, erscheint das Dialogfeld, das Sie in Abbildung 30.18 sehen. Wählt der Benutzer hingegen den anderen Generator aus, erscheint das Dialogfeld aus Abbildung 30.19. Die erste Anfangsfunktion finden Sie im Modul basBuilders und den gedruckten Code in Listing 30.4.
Menü-Add-Ins verwenden
1059
Abbildung 30.15: Registrierungseinträge für das Menü-Add-In
Abbildung 30.16: Die USysRegInfoEinträge für das Menü-Add-In
Abbildung 30.17: Das Dialogfeld Generator auswählen Listing 30.4:
Die erste Anfangsfunktion
Function ValidTextPolite(strObject As String, _ StrControl As String, _ StrCurrentValue As String) On Error GoTo ValidText Polite_Err DoCmd.OpenForm FormName:="frmPolite", _ WindowMode:=acDialog, _
1060
Kapitel 30: Generatoren, Assistenten und Menü-Add-Ins einsetzen
Abbildung 30.18: Der Generator für höfliche Meldungen
Abbildung 30.19: Der Generator für unhöfliche Meldungen OpenArgs:=strCurrentValue If SysCmd(acSysCmdGetObjectState, acForm, _ "frmPolite") = acObjStateOpoen Then Select Case Forms!frmPolite.optPolite.Value Case 1 ValidTextPolite = "The Incorrect Value Was Entered" Case 2 ValidTextPolite = "The Computer Cannot Comprehend Your Entry" Case 3 ValidTextPolite = "I'm Sorry, Could You Please Try Again" Case 4 ValidTextPolite = "Please Make Another Selection" Case 5 ValidTextPolite = "Amount Too High" Case 6 ValidTextPolite = "Amount Too Low" End Select DoCmd.Close acForm, "frmPolite" Else
Menü-Add-Ins verwenden
1061
ValidTextPolite = strCurrentValue End If ValidTextPolite_Exit: Exit Function ValidTextPolite_Err: MsgBox "Error # " & Err.Number & " & Err.Description Resume ValidTextPolite_Exit End Funtion
Die Funktion ValidTextPolite übernimmt alle von einem Generator erforderten Parameter. Sie öffnet das Formular frmPolite modal und reicht die ausgewählte Meldung als OpenArg weiter. Wählt der Benutzer einen Wert aus dem Formular frmPolite aus und klickt auf OK, wird der entsprechende Wert ausgewertet und eine passende Meldung von der Funktion ValidTextPolite zurückgegeben. Der zurückgegebene Wert wird dann zur Meldung des ausgewählten Steuerelements. In Listing 30.5 wird der Code zum Ereignis Load von frmPolite gezeigt. Listing 30.5:
Der Code zum Ereignis Load des Formulars frmPolite
Private Sub Form_Load() 'Den Wert der Optionsgruppe auf den aktuellen Wert 'der Eigenschaft setzen Select Case Me.OpenArgs Case "The Incorrect Value was Entered" Me.optPolite.Value = 1 Case "The Computer Cannot Comprehend Your Entry" Me.optPolite.Value = 2 Case "I'm Sorry, Could You Please Try Again" Me.optPolite.Value = 3 Case "Please Make Another Selection" Me.optPolite.Value = 4 Case "Amount Too High" Me.optPolite.Value = 5 Case "Amount Too Low" Me.optPolite.Value = 6 End Select End Sub
Mit diesem Code wird sichergestellt, dass der von der Optionsschaltfläche des Formulars frmPolite wiedergegebene Wert dem Text entspricht, der zu dem Zeitpunkt in der Gültigkeitseigenschaft des aktuellen Steuerelements eingegeben ist. Die Anfangsfunktion ValidTextRude ähnelt der Methode ValidTextPolite. Listing 30.6 zeigt die Anfangsfunktion ValidTextRude, die sich im Modul basBuilders befindet.
1062
Listing 30.6:
Kapitel 30: Generatoren, Assistenten und Menü-Add-Ins einsetzen
Die Anfangsfunktion ValidTextRude
Function ValidTextRude(strObject As String, _ StrControl As String, _ StrCurrentValue As String) On Error GoToVaidTextRude_Err DoCmd.OpenForm FormName:="frmRude", _ Windowmode:=acDialog, _ OpenArgs:=strCurrentValue If SysCmd(acSysCmdGetObjectState, acForm, _ "frmRude") = asObjStateOpen Then Select Case Forms!frmRude.optRude.Value Case 1 ValidTextRude = "Get a Clue Dude" Case 2 ValidTextRude = "What the Heck do You Think You're Doing?" Case 3 ValidTextRude = "Give Me a Break!!" Case 4 ValidTextRude = "I'm a Computer, I'm not an Idiot!!" Case 5 ValidTextRude = "Read the Manual Dude" Case 6 ValidTextRude = "You Really Think I Believe That?" End Select DoCmd. Close acForm, "frmRude" Else ValidTextRude = strCurrentValue End If ValidTextRude_Exit: Exit Function ValidTextRude_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description Resume ValidTextRude_Exit End Function
Die Routine zum Ereignis Load von frmRude entspricht dem von frmPolite, wie in Listing 30.7 zu sehen ist. Listing 30.7:
Das Load-Ereignis von frmRude
Private Sub Form_Load() 'Den Wert der Optionsgruppe auf den aktuellen Wert 'der Eigenschaft setzen Select Case Me.OpenArgs Case "Get a Clue Dude!"
Menü-Add-Ins verwenden
1063
Me.optRude.Value = 1 Case "What the Heck Du You Think You're Doing" Me.optRude.Value = 2 Case "Give Me a Break!!" Me.optRude.Value = 3 Case "I'm a Computer, I'm not an Idiot!" Me.optRude.Value = 4 Case "Read the Manual Dude" Me.optRude.Value = 5 Case "You Reallly Think I Belive That?" Me.optRude.Value = 6 End Select End Sub
Um den Generator zu erstellen, gestalten Sie beide Formulare so, dass sie wie die in Abbildung 30.18 und 30.19 aussehen. Beziehen Sie für jedes Formular wie oben gezeigt das Ereignis Load mit ein. Der Code, der hinter der OK-Schaltfläche jedes Formulars liegt, setzt die Eigenschaft Visible des Formulars auf False. Der Code der ABBRECHEN-Schaltfläche jedes Formulars schließt das jeweilige Formular. Geben Sie den Optionsgruppen die Namen optPolite und optRude, damit der Code in jedem Formular fehlerfrei arbeitet. Sie können die zwei Anfangsfunktionen ValidTextPolite und ValidTextRude in jedem Code-Modul der Bibliotheksdatenbank speichern. Als letztes müssen die zwei Generatoren registriert werden. Sobald das Add-In im ADDINS-Dialogfeld ausgewählt wird, sorgen die Einträge in der USysRegInfo (siehe Abbildung 30.20) für die Registrierung des Generators. Diese Tabelle befindet sich in der Datenbank CHAP30LIB.MDA.
Abbildung 30.20: Die Registrierungseinträge für die Generatoren höflicher und unhöflicher Meldungen
Access und das Internet
Kapitel
Hier lesen Sie:
Neuerungen von Access im Zusammenhang mit dem Internet Datenbankobjekte als HTML speichern Verknüpfungen mit HTML-Dateien HTML-Dateien importieren Zwischen statischen und dynamischen HTML-Formaten abwägen Mit Active Server Pages (.ASP-Dateien) arbeiten Mit HTX/IDC-Dateien arbeiten Testen der ASP- und HTX/IDC-Dateien Mit HTML-Vorlagen arbeiten Daten an einen FTP- oder HTTP-Server senden Hyperlinks nutzen Die Symbolleiste Web Replikation über das Internet implementieren
31.1
Neuerungen von Access im Zusammenhang mit dem Internet
Access 2000 verfügt über zahlreiche Merkmale, die es vereinfachen, Anwendungen für das Internet oder ein Intranet zu entwickeln. Es können Anwendungen erstellt werden, die dynamische oder gleichbleibende Informationen in das Internet oder das Intranet der eigenen Organisation bringen. Hyperlinkfelder ermöglichen es, Internet- und Intranet-Adressen in Access-Tabellen zu speichern, und Hyperlinks in For-
1066
Kapitel 31: Access und das Internet
mularen erleichtern es, direkt aus Ihren Formularen zu bestimmten Internet- oder Intranet-Seiten zu gelangen. Zu den neuen Eigenschaften von Access 2000 gehören Datenzugriffsseiten. Datenzugriffsseiten ermöglichen es, auf schnelle und einfache Weise Webansichten Ihrer Datenbank zu erstellen. Dieses Kapitel lotet das Leistungsvermögen von Access und dessen Integration in Internet und Intranet aus. Im Kapitel 32 geht es dann ausschließlich um die Erstellung von aktiven Datenseiten.
31.2
Datenbankobjekte als HTML speichern
Eine der vermutlich leistungsfähigsten Funktionen von Access ist die Fähigkeit, Datenbankobjekte als HTML-Dokumente abzuspeichern (HTML − Hypertext Markup Language). Tabellendaten, Abfrage-Ergebnisse, Formulare und Berichte können alle als HTML veröffentlicht werden. Jedes dieser Objekte wird in den nun folgenden Abschnitten besprochen.
31.2.1
Tabellendaten als HTML speichern
Wenn Tabellendaten als HTML gespeichert werden, lässt sich dies im HTMLDateiformat bewerkstelligen, so dass die Dateien problemlos im Web veröffentlicht werden können. Befolgen Sie diese Schritte: 1. Klicken Sie in der Objektliste des Datenbankfensters auf TABELLEN. 2. Klicken Sie auf die Tabelle, deren Daten Sie als HTML speichern wollen. 3. Wählen Sie DATEI|EXPORTIEREN, um das Dialogfeld EXPORTIEREN VON TABELLE NACH zu öffnen. 4. Wählen Sie im Listenfeld DATEITYP den Eintrag HTML-DOKUMENTE (*.HTML; *.HTM) aus. 5. Wählen Sie einen Dateinamen und Speicherort für das HMTL-Dokument. 6. Klicken Sie auf SPEICHERN, um den Vorgang zu beenden. Die Datei wird nun in HTML exportiert und kann von jedem beliebigen Browser gelesen werden. Sie können auch den HTML-Quelltext einsehen.
31.2.2
Abfrage-Ergebnisse als HTML speichern
Die Möglichkeit, Abfrage-Ergebnisse als HTML abzuspeichern, bedeutet, dass nicht alle Felder und Datensätze als HTML-Datei abgespeichert werden müssen. Sie können sogar Zusammenfassungen und andere komplexe Abfragen als HTML speichern. Ein Abfrage-Ergebnis als HMTL zu speichern ähnelt dem Speichern einer Tabelle als HTML: 1. Klicken Sie in der Objektliste des Datenbankfensters auf ABFRAGEN.
1067
Datenbankobjekte als HTML speichern
Abbildung 31.1: Die als HTML gespeicherte Tabelle tblCustomers
Abbildung 31.2: Der Quelltext der als HTML gespeicherten Tabelle tblCustomers
2. Klicken Sie auf die Abfrage, deren Ergebnisse Sie als HTML speichern wollen. 3. Wählen Sie DATEI|EXPORTIEREN, um das Dialogfeld EXPORTIEREN ABFRAGE NACH zu öffnen.
VON
1068
Kapitel 31: Access und das Internet
4. Wählen Sie im Listenfeld DATEITYP den Eintrag HTML-DOKUMENTE (*.HTML; *.HTM) aus. 5. Wählen Sie einen Dateinamen und Speicherort für das HTML-Dokument aus. 6. Klicken Sie auf SPEICHERN, um den Vorgang abzuschließen.
31.2.3
Formulare als HTML speichern
Es kann nur das Datenblatt eines Formulars als HTML gespeichert werden, da HTML-Dateien statisch sind. Sie verändern sich nicht, sobald die Daten in der Datenbank verändert werden, noch können die Daten der HTML-Datei bearbeitet werden. Gehen Sie folgendermaßen vor, um das Datenblatt eines Formulars als HTML zu speichern: 1. Klicken Sie in der Objektliste des Datenbankfensters auf FORMULARE. 2. Klicken Sie auf das Formular, dessen Ergebnisse Sie als HTML speichern wollen. 3. Wählen Sie DATEI|EXPORTIEREN, um das Dialogfeld EXPORTIEREN VON FORMULAR NACH zu öffnen. 4. Wählen Sie im Listenfeld DATEITYP den Eintrag HTML-DOKUMENTE (*.HTML; *.HTM) aus. 5. Wählen Sie einen Dateinamen und Speicherort für das HTML-Dokument aus. 6. Klicken Sie auf SPEICHERN. Nun gelangen Sie in das Dialogfeld HTML-AUSGABEOPTIONEN. 7. Wählen Sie eine beliebige HTML-Vorlage aus, die auf das HTML-Dokument angewendet werden soll. Mit HTML-Vorlagen können Sie auf einfache Weise ein durchgängig gleichbleibendes Design für Ihre Web-Publikationen festlegen. Klicken Sie auf OK.
31.2.4
Berichte als HTML speichern
Berichte und deren Formatierungen können ebenfalls als HTML gespeichert werden. Dies ist ein eleganter Weg, um Informationen auf einer Internet- oder IntranetSeite zu veröffentlichen. Um einen Bericht als HTML herauszugeben, gehen Sie wie folgt vor: 1. Klicken Sie in der Objektliste des Datenbankfensters auf BERICHTE. 2. Klicken Sie auf den Bericht, dessen Ergebnisse Sie als HTML speichern wollen. 3. Wählen Sie DATEI|EXPORTIEREN, um das Dialogfeld EXPORTIEREN VON BERICHT NACH zu öffnen. 4. Wählen Sie im Listenfeld DATEITYP den Eintrag HTML-DOKUMENTE (*.HTML; *.HTM) aus.
Verknüpfungen mit HTML-Dateien
1069
5. Wählen Sie einen Dateinamen und Speicherort für das HTML-Dokument aus. 6. Klicken Sie auf SPEICHERN, um in das Dialogfeld HTML-AUSGABEOPTIONEN zu gelangen. 7. Wählen Sie eine beliebige HTML-Vorlage aus, die auf das HTML-Dokument angewendet werden soll. Klicken Sie auf OK. In Abbildung 31.3 sehen Sie einen als HTML veröffentlichten Bericht. Da der Bericht über mehrere Seiten geht, werden mehrere HTML-Dateien erstellt. Jede Seite des Berichts ist verknüpft, so dass ein Benutzer auf einfache Weise mit Hilfe der Hyperlinks ERSTER, VORHERIGER, NÄCHSTER und LETZTER, die beim Speichern automatisch generiert werden, von Seite zu Seite springen kann.
Abbildung 31.3: Betrachten des rptCustomersWebBerichts als HTML
31.3
Verknüpfungen mit HTML-Dateien
Genau wie Sie Verknüpfungen mit dBase-Tabellen, Paradox-Tabellen oder ODBCDatenquellen erstellen können, können Sie dies mit HTML-Dateien: 1. Klicken Sie mit der rechten Maustaste in das Fenster der Datenbank und wählen Sie TABELLEN VERKNÜPFEN. Hierdurch wird das Dialogfeld VERKNÜPFEN geöffnet. 2. Wählen Sie im Listenfeld DATEITYP den Eintrag HTML-DOKUMENTE (*.HTML; *.HTM) aus.
1070
Kapitel 31: Access und das Internet
3. Wählen Sie die zu verknüpfende HTML-Datei aus und klicken Sie auf VERKNÜPFEN. Dadurch wird der HTML-Verknüpfungs-Assistent aufgerufen (siehe Abbildung 31.4) 4. Geben Sie als erstes an, ob die erste Zeile Spaltenüberschriften enthält. Sie können sich dabei an dem von Access vorgeschlagenen Layout orientieren.
Abbildung 31.4: Der erste Schritt des HTML-VerknüpfungsAssistenten
5. Klicken Sie auf WEITERE, um genauere Informationen über die verknüpfte Tabelle anzugeben. Daraufhin öffnet sich das Dialogfeld VERKNÜPFUNGSSPEZIFIKATION (siehe Abbildung 31.5). Hier wählen Sie aus, welche Felder Sie in der Verknüpfung sehen wollen, und geben andere Informationen wie zum Beispiel Datumstrennzeichen oder andere an. Wenn Sie alles ausgewählt haben, klicken Sie auf OK. 6. Klicken Sie auf WEITER, um mit dem HTML-Verknüpfungs-Assistenten fortzufahren. Als nächstes wählen Sie einen Feldnamen und Datentyp für jedes Feld der HTML-Datei aus. Klicken Sie danach auf WEITER. 7. Als letztes geben Sie einen Namen für die verknüpfte Tabelle an. Klicken Sie anschließend auf FERTIG STELLEN. 8. Es wird gemeldet, dass die Tabelle erfolgreich verknüpft wurde. Die Tabelle erscheint im Fenster der Datenbank mit einem Symbol, das andeutet, dass es sich um eine HTML-Datei handelt (31.6).
Verknüpfungen mit HTML-Dateien
1071
Abbildung 31.5: Im Dialogfeld Verknüpfungsspezifikation können Sie Einzelheiten über die verknüpfte Tabelle angeben
Abbildung 31.6: Das mit einem HTMLDokument verknüpfte Datenbankfenster
Die verknüpfte HTML-Datei kann von jeder anderen Tabelle aus eingesehen und abgefragt werden. Es ist allerdings nicht möglich, Informationen in der verknüpften Datei zu bearbeiten.
1072
31.4
Kapitel 31: Access und das Internet
HTML-Dateien importieren
Die Informationen in einer HTML-Datei können importiert und zu einer üblichen Access-Tabelle werden. So importiert man eine HTML-Datei: 1. Klicken Sie mit der rechten Maustaste in das Fenster der Datenbank und wählen Sie IMPORTIEREN aus. Hierdurch wird das Dialogfeld IMPORTIEREN geöffnet. 2. Wählen Sie im Listenfeld DATEITYP den Eintrag HTML-DOKUMENTE (*.HTML; *.HTM) aus. 3. Wählen Sie die HTML-Datei aus, die Sie importieren wollen, und klicken Sie auf IMPORTIEREN. Daraufhin erscheint der HTML-IMPORT-ASSISTENT. Dieser Assistent entspricht fast völlig dem Verknüpfungs-Assistenten. 4. Geben Sie zunächst an, ob die erste Zeile Spaltenüberschriften enthält. Sie sehen auch hier ein von Access vorgeschlagenes Layout für die importierte Tabelle. 5. Klicken Sie auf WEITER, um genauere Informationen über die importierte Tabelle anzugeben. Daraufhin öffnet sich das Dialogfeld IMPORTSPEZIFIKATION. Hier wählen Sie aus, welche Felder in der importierten Tabelle enthalten sein sollen, und geben andere Informationen wie zum Beispiel Datumstrennzeichen oder andere an. Wenn Sie alles ausgewählt haben, klicken Sie auf OK. 6. Klicken Sie auf WEITER. Als nächstes wählen Sie aus, ob die Informationen als neue Tabelle gespeichert oder einer bereits bestehenden Tabelle hinzugefügt werden sollen. Klicken Sie danach auf WEITER. 7. Wählen Sie nun einen Feldnamen und Datentyp für jedes Feld der HTML-Datei aus. Sie können auch bestimmen, ob Access einen Index für das jeweilige Feld erstellen oder ob das Feld vielleicht vollkommen ausgeschlossen werden soll. Klicken Sie danach auf WEITER. 8. Nun müssen Sie einen Primärschlüssel für die importierte Tabelle bestimmen. Andernfalls wird Access für Sie einen Primärschlüssel festlegen (31.7). Klicken Sie danach auf WEITER. 9. Geben Sie der verknüpften Tabelle als letztes einen Namen. Wenn Sie sich fragen, ob die importierte Tabelle in Normalform vorliegt, können Sie die Tabellenanalyse aufrufen, nachdem der Importvorgang abgeschlossen wurde. Klicken Sie zum Schluss auf FERTIG STELLEN. 10. Es wird angezeigt, dass die Tabelle erfolgreich importiert wurde. Die Tabelle kann nun wie jede Access-Tabelle im Fenster der Datenbank eingesehen werden.
Zwischen statischen und dynamischen HTML-Formaten abwägen
1073
Abbildung 31.7: Angeben eines Primärschlüssels für Ihre neue Tabelle
31.5
Zwischen statischen und dynamischen HTMLFormaten abwägen
Viele Leute kennen die Unterschiede zwischen dem Veröffentlichen von statischen und dynamischen Daten nicht genau. »Statische Daten« verändern sich nicht. Wenn Sie Informationen veröffentlichen wollen, die sich selten oder überhaupt nicht verändern, sollten Sie eine statische Webseite erstellen. Die dafür erforderlichen Schritte wurden bereits am Anfang dieses Kapitels besprochen. Die Informationen konnten bisher nur verändert werden, indem sie neu veröffentlicht und neu ins Web hochgeladen wurden. »Dynamische Daten« andererseits verändern sich durchaus. Sie sollten Ihre Daten in einem dynamischen Format speichern, wenn es klar ist, dass sie sich stetig verändern und Ihre Webanwendung mit Hilfe eines Formulars neue Daten abfragen und speichern muss. Um dynamische Webdaten zu veröffentlichen, haben Sie verschiedene Möglichkeiten. Eine Lösung wären aktive Datenseiten, die in Kapitel 32 beschrieben werden. Wie dieses Kapitel erläutert, sind aktive Datenseiten eher auf das Internet als das Intranet ausgerichtet. Im Internet können Ihre Objekte anstatt im HTML-Format auch als ASP-Dateien oder im IDC/HTX-Dateiformat veröffentlicht werden. ASP ist die Abkürzung von »Active Server Page«. Active Server ist Bestandteil vom Microsoft Internet Information Server 3.0 und neueren Versionen. ASP-Dateien beinhalten Folgendes:
1074
Kapitel 31: Access und das Internet
ODBC-Verbindungsinformationen, wie zum Beispiel Dateiquellennamen, Benutzernamen und Kennwörter
Eine oder mehrere Abfragen in Form von SQL-Anweisungen Vorlagen für das Layout der späteren HTML-Datei VBScript-Routinen mit Verweisen auf ActiveServer-Steuerelemente Mit einer ASP-Datei können Sie ein Objekt veröffentlichen und installieren. Der Microsoft Internet Information Server benutzt auf Nachfrage des Webbrowsers VBScript-Code und ruft die Active-Server-Steuerelemente auf. Mit Hilfe des ODBCTreibers und der ASP-Datei öffnet er dann die Datenbank, geht durch die in der ASP-Datei gespeicherten Abfragen und legt die Ergebnisse und HTML-Tags in der ASP-Datei innerhalb einer HTML-Datei ab. Die HTML-Datei wird dann zur Anzeige an den Webbrowser zurückgeschickt. Wenn Sie das IDC/HTX-Dateiformat auswählen, werden zwei Dateien erstellt: Die HTX-Datei, bei der es sich um eine HTML-Erweiterungsdatei handelt, besitzt alle Formatmarken und Angaben, die benötigt werden, um die Abfrage-Ergebnisse zu formatieren. Die IDC-Datei ist eine Internet-Datenbankverbindungsdatei und enthält eine SQL-Anweisung sowie andere vom Microsoft Information Server benötigte Informationen, um eine Verbindung zur ODBC-Datenquelle wie zum Beispiel Ihre Access-Datenbank (MDB) aufzubauen. Der ODBC-Datenquellenname, der Name des Benutzers sowie das Kennwort sind alle in der IDC-Datei gespeichert, Daten im eigentlichen Sinne sind aber nicht enthalten. Nachdem Sie ein Datenbankobjekt veröffentlicht und mit Hilfe eines Web-Publishing-Servers (z.B. dem Microsoft Internet Information Server (IIS)) im Web installiert haben, wird die Access-Datenbank vom IIS mit dem ODBC-Treiber und der IDC-Datei auf Anfrage eines Browsers geöffnet. Die in der IDC-Datei gespeicherten Abfragen werden ausgeführt und das Ergebnis sowie die HTX-Datei in einer HTML-Datei gespeichert, die dann wiederum zur Ansicht zum Webbrowser geschickt wird.
31.6
Mit Active Server Pages (ASP-Dateien) arbeiten
Folgende Schritte müssen unternommen werden, um Daten in eine ASP-Datei auszugeben: 1. Wählen Sie das Datenbankobjekt aus, das Sie exportieren wollen. 2. Wählen Sie DATEI|EXPORTIEREN. Sie gelangen in das Dialogfeld EXPORTIEREN VON OBJEKT. 3. Wählen Sie im Listenfeld DATEITYP den Eintrag MICROSOFT-ACTIVE-SERVERPAGES (*.ASP). Klicken Sie auf SPEICHERN. Nun erscheint das DIALOGFELD MICROSOFT ACTIVE SERVER PAGES-AUSGABEOPTIONEN (31.8).
Mit HTX/IDC-Dateien arbeiten
1075
4. Klicken Sie auf DURCHSUCHEN, um gegebenenfalls eine HTML-Vorlage auszuwählen. 5. Legen Sie eine ODBC-Datenquelle fest. Diese Datenquelle muss in der Windows-Systemsteuerung eingerichtet sein und vom Webserver benutzt werden, um auf Daten innerhalb der Access-Datenbank zugreifen zu können. 6. Legen Sie den Benutzer und das Kennwort fest, über die die Verbindung aufgebaut wird. 7. Klicken Sie auf OK, um die ASP-Datei auszugeben.
Abbildung 31.8: Das Dialogfeld Microsoft Active Server PagesAusgabeoptionen für die Auswahl notwendiger Angaben, um Ihr Datenbankobjekt im ASPDateiformat auszugeben
31.7
Mit HTX/IDC-Dateien arbeiten
Folgende Schritte sind notwendig, um Daten in HTX/IDC-Dateien auszugeben: 1. Wählen Sie das Datenbankobjekt aus, das Sie exportieren wollen. 2. Wählen Sie DATEI|EXPORTIEREN. Es erscheint das Dialogfeld EXPORTIEREN VON OBJEKT. 3. Wählen Sie im Listenfeld DATEITYP den Eintrag MICROSOFT IIS 1-2 (*.HTX; *.IDC) aus und klicken Sie auf SPEICHERN. Sie gelangen in das Dialogfeld HTX/ IDC-AUSGABEOPTIONEN (31.9). 4. Klicken Sie auf DURCHSUCHEN, um gegebenenfalls eine HTML-Vorlage auszuwählen. 5. Legen Sie eine ODBC-Datenquelle fest. Diese Datenquelle muss in der Windows-Systemsteuerung eingerichtet sein und vom Webserver benutzt werden, um auf Daten innerhalb der Access-Datenbank zuzugreifen.
1076
Kapitel 31: Access und das Internet
6. Legen Sie den Namen des Benutzers und das Kennwort fest, über die die Verbindung aufgebaut wird. 7. Klicken Sie auf OK, um die HTX- und IDC-Dateien auszugeben.
Abbildung 31.9: Im Dialogfeld HTX/IDCAusgabeoptionen können Sie die für das Ausgeben Ihres Datenbankobjektes im HTX/ IDC-Format erforderlichen Optionen angeben
31.8
Testen der ASP- und HTX/IDC-Dateien
Da ASP- sowie IDC/HTX-Dateiformate vom Server bearbeitet werden müssen, um ein HTML-Dokument auszugeben, müssen Sie folgende Schritte unternehmen, um die Dateien auf Ihrem Webserver zu testen: 1. Installieren Sie entsprechende Software auf dem Rechner, der als Webserver (hier: Microsoft Internet Information Server) fungieren soll. 2. Richten Sie ein Verzeichnis unter dem Hauptverzeichnis des Webservers ein. 3. Legen Sie Berechtigungen für das Verzeichnis fest. IIS3.0 sollte AusführenBerechtigungen besitzen, IIS4.0 oder eine neuere IIS-Version sollten ScriptBerechtigungen haben. 4. Kopieren Sie die ASP- oder IDC/HTX-Dateien in das Verzeichnis. Kopieren Sie weiterhin alle damit zusammenhängenden Dateien wie Grafiken oder verknüpfte Dateien dorthin. 5. Legen Sie eine ODBC-Datenquelle fest, die auf die Datenbank mit den Daten verweist, die Sie veröffentlichen wollen. Die Datenquelle muss als System-DSN auf dem Webserver erkannt werden und der Datenquellname (Data Source Name – DSN) muss mit der Datenquelle übereinstimmen, die Sie in den Dialogfeldern Microsoft ACTIVE SERVER PAGES-AUSGABEOPTIONEN oder HTX/IDCAUSGABEOPTIONEN festgelegt haben. Überprüfen Sie, ob der Benutzername und das Kennwort mit den Textfeldern BENUTZERNAME und BENUTZERKENNWORT der Dialogfelder MICROSOFT ACTIVE SERVER PAGES AUSGABEOPTIONEN oder HTX/IDC-AUSGABEOPTIONEN übereinstimmen.
Mit HTML-Vorlagen arbeiten
1077
6. Da ASP- sowie IDC/HTX-Dateiformate eine Bearbeitung auf Seiten des Servers voraussetzen, muss beim Testen das HTTP-Protokoll benutzt werden. In Abbildung 31.10 sehen Sie, dass das HTTP-Protokoll benutzt wird, um die tblCustomers.idc-Datei zu verarbeiten. Die Webadresse, die im Browser zum Einsatz kommt, um die IDC-Datei zu verarbeiten, lautet in diesem Fall http://presario/ customerdata/tblcustomers.idc. Die ASP- und IDC/HTX-Dateiformate werden zwar beide in diesem Kapitel behandelt, werden aber nicht in gleichem Maße verwendet. Die ASP-Technologie wird in immer größerem Maße eingesetzt und von Microsoft Visual InterDev6.0 unterstützt, während das IDC/HTX-Format von Microsoft eigentlich nur aus Gründen der Abwärtskompatibilität benutzt wird. Überlegen Sie, ob es umsichtig ist, IDC/ HTX-Technologie einzusetzen.
Abbildung 31.10: Das HTTP-Protokoll wird für das Zugreifen auf ASP- und IDC/ HTX-Dateien auf Webservern verwendet
31.9
Mit HTML-Vorlagen arbeiten
HTML-Vorlagen helfen Ihnen, Ihren verschiedenen Webseiten ein durchgängiges Design zu verschaffen. Sie bieten Ihnen die Möglichkeit, ohne großen Aufwand das Erscheinungsbild einer Webseite zu verbessern und Ihre Webanwendung übersichtlicher zu gestalten. HTML-Vorlagen können Logos, Hintergrundbilder und Standard-Navigationsschaltflächen enthalten.
1078
Kapitel 31: Access und das Internet
Eine HTML-Vorlage ist eine Datei, die HTML-Tags und für Access eindeutige Token einhält. Diese Tags und Token geben Access vor, wo Daten eingefügt werden sollen. Wenn Sie eine Tabelle, ein Formular oder einen Bericht in eine HTML-Datei konvertieren, können Sie eine Vorlage festlegen, die dem Objekt zugewiesen wird. Wenn Sie ein Objekt in ein dynamisches HTML-Format konvertieren und ihm eine Vorlage zuweisen, wird diese während der Ausgabe mit der HTX- oder ASP-Datei zusammengeführt. Abbildung 31.11 zeigt die mit der Datei cajun.htm (in Microsoft Office enthalten) formatierte Datei tblCustomers.idc.
Abbildung 31.11: Die mit der Vorlage cajun.htm formatierte Datei tblCustomer.idc
31.10
Daten an einen FTP- oder HTTP-Server senden
Manchmal ist es notwendig, ein Datenbankobjekt von oder zu einem FTP- oder HTTP-Server zu importieren, zu verknüpfen oder zu exportieren. FTP (File Transfer Protocol) ist ein Protokoll, das Dateien ohne Verbindung zu einem Netzwerk-Server über das Internet verschicken kann. Beim Hypertext Transfer Protocol (HTTP) handelt es sich um ein Internet-Protokoll, das sich ein wenig hinter den Kulissen aufhält und einen Client die Dokumente, die in HTML oder anderen Formaten geschrieben sind, über das Internet einsehen lässt. Wie Objekte zu einem FTP-Server importiert, von ihm exportiert und mit ihm verknüpft werden, wird in den folgenden Abschnitten besprochen.
Daten an einen FTP- oder HTTP-Server senden
1079
31.10.1 Daten auf FTP- und HTTP-Servern importieren bzw. entsprechende Verknüpfungen erstellen Das Importieren von bzw. das Verknüpfen mit FTP- und HTTP-Servern funktioniert ähnlich, so dass in diesem Abschnitt beide Vorgänge zusammen erläutert werden. Gehen Sie folgendermaßen vor: 1. Um Daten auf einen FTP-Server zu importieren oder Verknüpfungen zu erstellen, klicken Sie mit der rechten Maustaste in das Fenster der Datenbank. 2. Wählen Sie IMPORTIEREN, um Daten zu importieren, bzw. TABELLEN VERKNÜPFEN, um Daten zu verknüpfen. Hierdurch wird entweder das Dialogfeld IMPORTIEREN oder das Dialogfeld VERKNÜPFEN aufgerufen. 3. Wählen Sie im Listenfeld DATEITYP den Eintrag HTML-DOKUMENTE (*.HTML; *.HTM). 4. Um Daten auf einem HTTP-Server zu importieren oder Verknüpfungen zu erstellen, geben Sie die Internetadresse (z.B. http://www.mcgpc.com/ employee.html) im Dateinamenfeld ein. Sie können auch den Pfeil rechts neben dem Listenfeld und dann INTERNETADRESSEN (FTP) anklicken. Wählen Sie dann die Adresse Ihrer Wahl aus. 5. Klicken Sie auf IMPORTIEREN, um das HTML-Dokument zu importieren, bzw. auf VERKNÜPFEN, um eine Verknüpfung zu erstellen. Befolgen Sie dann die Anweisungen des Assistenten, um den Vorgang zum Abschluss zu bringen. Eine verknüpfte HTML-Tabelle ist wie eine Momentaufnahme der ursprünglichen Datenquelle, so dass Sie keine Veränderungen am Original sehen können, solange es geöffnet bleibt. Um Ihre Kopie der HTML-Tabelle auf den neuesten Stand zu bringen, müssen Sie die Tabelle zunächst schließen, um sie dann wieder zu öffnen. Außerdem sind die Daten nicht aus Microsoft Access heraus aktualisierbar.
31.10.2 Ein Objekt auf einen FTP-Server exportieren Ein Datenbankobjekt auf einen Datenbank-Server zu exportieren, entspricht im Grunde genommen dem Kopieren von Daten über das Internet. Hierfür unternehmen Sie folgende Schritte: 1. Klicken Sie mit der rechten Maustaste auf ein Objekt im Fenster der Datenbank und wählen Sie EXPORTIEREN. Sie gelangen nun in das Dialogfeld EXPORTIEREN VON OBJEKT. 2. Öffnen Sie mit einem Mausklick das Listenfeld DATEITYP und wählen Sie FTPSPEICHERORTE. 3. Wählen Sie den Ort aus und klicken Sie auf EXPORTIEREN.
1080
31.11
Kapitel 31: Access und das Internet
Hyperlinks nutzen
Hyperlinks sind in Access 2000 äußerst leistungsfähig. Sie ermöglichen es Ihnen, aus Ihrer Anwendung heraus ins Internet, Intranet oder zu einer anderen Datei zu gelangen. Hyperlinks können in Tabellenfeldern gespeichert oder direkt in Formularen und Berichten untergebracht werden.
31.11.1
Hyperlinks in Tabellen speichern
Mit Hilfe des neuen Hyperlink-Feldtyps können Sie problemlos URLs (Internetoder Intranet-Adressen) und UNCs (Adressen in einem Netzwerk oder auf einer lokalen Festplatte) in den Datensätzen Ihrer Tabelle speichern. Um einen Hyperlink zu erstellen, wählen Sie im Listenfeld FELDDATENTYP den Eintrag HYPERLINK aus, während Sie den Aufbau einer Tabelle betrachten. Die in diesem Feld gespeicherten Daten werden als Hyperlink-Adresse verwendet.
31.11.2 Hyperlinks in Formulare und Berichte einfügen Obwohl Hyperlinks Ihnen die Möglichkeit eröffnen, jedem Eintrag einer Tabelle URLs und UNCs zuzuweisen, können Ihre Benutzer durch die Fähigkeit, Hyperlinks auf Formularen und Berichten zu platzieren, auf einfache Weise von Ihren Formularen und Berichten zu anderen Bereichen Ihrer Anwendung und URLs und UNCs gelangen. Hyperlinks können einfachen Schaltflächen, Beschriftungen und Bildelementen zugewiesen werden, da jedes dieser Steuerelemente die Eigenschaften Hyperlinkadresse und Hyperlink-Unteradresse besitzt (31.12). Die HyperlinkAdresse beinhaltet den URL- oder UNC-Pfad, während die Hyperlink-Unteradresse einen besonderen Ort im URL oder UNC benennt. Wenn zum Beispiel die UNC auf eine Access-Datenbank hindeutet, weist die Hyperlink-Unteradresse vielleicht auf ein Formular innerhalb dieser Datenbank.
Abbildung 31.12: Befehlsschaltflächen, Bezeichnungsfelder und Bild-Steuerelemente verfügen über Eigenschaften für Hyperlink-Adressen und -Unteradressen
Die Symbolleiste Web
1081
Der einfachste Weg, Hyperlink-Adressen und -Unteradressen festzulegen besteht darin, in das Eigenschaftenfeld für die Hyperlink-Adresse und dann auf die Schaltfläche mit den drei Punkten zu klicken. Dadurch wird das Dialogfeld HYPERLINK EINFÜGEN aufgerufen. Hier können Sie auf DURCHSUCHEN klicken, um die Hyperlinkadresse und Hyperlink-Unteradresse herauszufinden. Die Eigenschaften werden automatisch für Sie ausgefüllt (31.13).
Abbildung 31.13: Verwenden Sie das Dialogfeld Hyperlink einfügen, um auf einfache Weise die Eigenschaften Hyperlink-Adresse und Hyperlink-Unteradresse anzugeben
31.12
Die Symbolleiste Web
Die Symbolleiste WEB steuert alle Hilfsmittel, die Sie für die Navigation im Web benötigen, und ermöglicht Ihnen, auf schnelle und einfache Weise Folgendes zu tun:
von Seite zu Seite zu navigieren die angezeigte Seite zu aktualisieren im Internet zu surfen Ihre bevorzugten Adressen zu speichern zu Ihren bevorzugten Adressen zu navigieren zu einem bestimmten URL zu navigieren Wie jede andere Symbolleiste kann sie jederzeit aufgerufen werden, um die Navigation im Internet zu vereinfachen.
1082
31.13
Kapitel 31: Access und das Internet
Replikation über das Internet implementieren
Der Replikations-Manager von Access 2000 kann auf einem Internet- oder IntranetServer installiert werden, so dass Replikate mit solchen auf dem Server synchronisiert werden können. Das Replikat auf dem Internet- oder Intranet-Server wird als HubReplikat bezeichnet, da alle anderen Replikate mit ihm synchronisiert werden. Während des Synchronisierens nimmt jeder Client eine HTTP-Verbindung mit dem Internet- oder Intranet-Server auf. Direkte Synchronisation kann nicht über das Internet erfolgen. Statt dessen agiert ein FTP-Verzeichnis auf dem Server als Arbeitsordner für eine indirekte Synchronisation. Dies funktioniert wie folgt: 1. Der Client erstellt eine Datei mit allen Informationen über Entwurfs- oder Datenänderungen seit der letzten Synchronisation der Replikate. 2. Diese Datei wird am Ort der FTP-Datei auf dem Internet- oder Intranet-Server abgelegt. 3. Der Synchronizer des Internet- oder Intranet-Servers nimmt die Änderungen am lokalen Replikat vor und erstellt dann eine Datei mit allen Informationen über alle Entwurfs- und Datenänderungen seit der letzten Synchronisation. Diese Veränderungen werden außerdem in der FTP-Datei gespeichert. 4. Der Server überträgt den Namen der Datei und deren Speicherort zurück an den Client. 5. Der Client überträgt nun die Änderungsdatei vom Server via FTP an den ClientArbeitsplatzrechner. Alle in der Datei genannten Änderungen werden dann auch am Client-Replikat vorgenommen. Der Client benötigt keinen Synchronizer, da Jet und die Windows-DLLs für die Synchronisation sorgen.
Datenzugriffsseiten verwenden
Kapitel
Hier lesen Sie:
Datenzugriffsseiten verstehen Datenzugriffsseiten erstellen Wichtige Eigenschaften einer Datenzugriffsseite anpassen Ändern der Eigenschaften zur Navigation in den Datensätzen Gruppierte Datenzugriffsseiten erstellen Datenzugriffsseiten mit VBScript ausbauen
32.1
Datenzugriffsseiten verstehen
Datenzugriffsseiten sind eine Neuerung von Access 2000. Mit Hilfe von Datenzugriffsseiten können Sie schnell und einfach eine Webansicht Ihrer Daten erstellen. Datenzugriffsseiten sind äußerst flexibel und skalierbar. Die einfachste Datenzugriffsseite kann genauso einfach erstellt werden wie ein Access-Formular. Außerdem können Sie den Microsoft Script Editor (MSE) verwenden, um Ihre Datenzugriffsseiten in leistungsfähige Webseiten zu verwandeln. Der wohl größte Nachteil von Datenzugriffsseiten besteht darin, dass sie ausschließlich auf Rechnern betrachtet werden können, auf denen sowohl der Internet Explorer 5 als auch Microsoft Office installiert ist. Datenzugriffsseiten sind somit für Intranet-Anwendungen hervorragend geeignet, eignet sich jedoch kaum für das Internet. Datenzugriffsseiten können sowohl innerhalb eines Intranets als auch über das Internet verwendet werden, wenn der Client über die IE5/Office-Erweiterungen verfügt.
1084
32.2
Kapitel 32: Datenzugriffsseiten verwenden
Datenzugriffsseiten erstellen
Für das Erstellen von Datenzugriffsseiten gibt es vier unterschiedliche Möglichkeiten:
mit der AutoSeite-Funktion mit einem Assistenten auf der Grundlage einer vorhandenen Webseite von Grund auf
32.2.1
Erstellen einer Datenzugriffsseite mit der Funktion AutoPage
Halten Sie sich an die folgenden Schritte, um eine Datenzugriffsseite mit dem AutoSeite-Werkzeug zu erstellen: 1. Klicken Sie im Datenbankfenster in der Liste der Objekte auf SEITEN. 2. Klicken Sie im Datenbankfenster auf die Schaltfläche NEU. Daraufhin erscheint das Dialogfeld NEUE DATENZUGRIFFSSEITE. 3. Wählen Sie die Tabelle bzw. Abfrage aus, auf der die Datenzugriffsseite basieren soll. 4. Wählen Sie in der Liste mit den Optionen für das Erstellen einer Datenzugriffsseite AUTOSEITE: EINSPALTIG aus (siehe Abbildung 32.1). 5. Klicken Sie auf OK. Die Datenzugriffsseite wird nun erstellt (siehe Abbildung 32.2).
Abbildung 32.1: Im Dialogfeld Neue Datenzugriffsseite können Sie eine Methode auswählen, die Sie für das Erstellen einer neuen Datenzugriffsseite verwenden wollen
1085
Datenzugriffsseiten erstellen
Abbildung 32.2: Diese Datenzugriffsseite wurde basierend auf der Tabelle tblClients mit der Funktion AutoSeite erstellt
32.2.2
Eine Datenzugriffsseite mit einem Assistenten erstellen
Um eine Datenzugriffsseite mit einem Assistenten zu erstellen, gehen Sie folgendermaßen vor: 1. Klicken Sie im Datenbankfenster in der Liste der Objekte auf SEITEN. 2. Doppelklicken Sie auf die Option ERSTELLT EINE DATENZUGRIFFSSEITE UNTER VERWENDUNG DES ASSISTENTEN. Daraufhin erscheint der Seiten-Assistent (siehe Abbildung 32.3). 3. Wählen Sie die Tabelle bzw. Abfrage aus, auf der Ihre Datenzugriffsseite basieren soll. In Abbildung 32.3 wurde die Tabelle tblClients ausgewählt. 4. Wählen Sie die Felder aus, die auf der Datenzugriffsseite erscheinen sollen. In Abbildung 32.3 wurden die Felder ClientID, CompanyName, ContactFirstName, ContactLastName, ContactTitle, OfficePhone, IntroDate und HomePage ausgewählt. Klicken Sie auf die Schaltfläche WEITER, um fortzufahren. 5. Fügen Sie der Seite die gewünschten Gruppierungsebenen hinzu (siehe Abbildung 32.4). Beachten Sie, dass mit Gruppierungsebenen versehene Datenzugriffsseiten ausschließlich gelesen werden können. Klicken Sie auf WEITER, um fortzufahren. 6. Geben Sie für die auf der Seite erstellten Datensätze eine Sortierreihenfolge an (siehe Abbildung 32.5). In der Abbildung wurde die Seite nach dem Feld ContactLastName in Kombination mit dem Feld ContactFirstName sortiert. Klicken Sie auf WEITER, um fortzufahren.
1086
Kapitel 32: Datenzugriffsseiten verwenden
Abbildung 32.3: Hier können Sie die der Datenzugriffsseite hinzuzufügende Tabelle und die entsprechenden Felder auswählen
Abbildung 32.4: Einer Datenzugriffsseite Gruppierungen hinzufügen
7. Auf der letzten Seite des Assistenten werden Sie aufgefordert, einen Namen für Ihre Seite anzugeben. Geben Sie den Titel ein und legen Sie fest, ob Sie die Seite öffnen oder den Aufbau der Seite anpassen möchten. Klicken Sie auf die Schaltfläche FERTIG STELLEN, um den Vorgang abzuschließen. In Abbildung 32.6 sehen Sie die fertige Datenzugriffsseite in der Entwurfsansicht. Die fertige Seite in der Seitenansicht ist in Abbildung 32.7 dargestellt.
Datenzugriffsseiten erstellen
1087
Abbildung 32.5: Auswählen einer Sortierreihenfolge für die auf einer Seite dargestellten Datensätze
Abbildung 32.6: Eine vollständige Datenzugriffsseite in der Entwurfsansicht
Datenzugriffsseiten werden weder in Ihrer Datenbankdatei noch im Rahmen Ihres Projekts gespeichert, sondern als HTML-Dateien. Gehen Sie folgendermaßen vor, um eine Datenzugriffsseite zu speichern: 1. Klicken Sie auf die Schaltfläche SPEICHERN auf der Symbolleiste. Daraufhin erscheint das Dialogfeld DATENZUGRIFFSSEITE SPEICHERN (siehe Abbildung 32.8). 2. Geben Sie einen Namen für das HTML-Dokument ein. In der Abbildung wurde der Name pagClients verwendet. 3. Klicken Sie auf SPEICHERN.
1088
Kapitel 32: Datenzugriffsseiten verwenden
Abbildung 32.7: Eine vollständige Datenzugriffsseite in der Seitenansicht
Abbildung 32.8: Im Dialogfeld Als Datenzugriffsseite speichern können Sie einen Namen und eine Position für das gespeicherte HTML-Dokument angeben
Obgleich die Datenzugriffsseite als eigenständiges Dokument gespeichert wurde, wird sie im Datenbankfenster angezeigt (siehe Abbildung 32.9). Beachten Sie in der Abbildung, dass eine QuickInfo erscheint, in welcher der Name und die Position des gespeicherten HTML-Dokuments angegeben sind. Wenn die Datenzugriffsseite von Microsoft Access aus geöffnet wird, erscheint sie innerhalb der Access-Umgebung als Fenster. Um die Seite so zu betrachten, wie sie in einem Browser erscheinen würde, können Sie die Seite im Datenbankfenster mit der rechten Maustaste anklicken und im Kontextmenü die Option WEBSEITENVORSCHAU auswählen.
1089
Datenzugriffsseiten erstellen
Abbildung 32.9: Eine vollständige Datenzugriffsseite erscheint im Datenbankfenster als Objekt
32.2.3
Erstellen einer Datenzugriffsseite aus einer bestehenden Webseite
Möglicherweise haben Sie bereits ein HTML-Dokument erstellt. Glücklicherweise erlaubt Access 2000 Ihnen das Hinzufügen einer neuen Datenzugriffsseite in ein vorhandenes HTML-Dokument. Gehen Sie folgendermaßen vor, um aus einer bestehenden Webseite eine Datenzugriffsseite zu erstellen: 1. Klicken Sie im Datenbankfenster in der Liste der Objekte auf SEITEN. 2. Doppelklicken Sie auf die Option BEARBEITET EINE VORHANDENE WEBSEITE. Daraufhin erscheint das Dialogfeld WEBSEITE SUCHEN (siehe Abbildung 32.10). 3. Wählen Sie ein vorhandenes HTML-Dokument aus und klicken Sie auf die Schaltfläche ÖFFNEN. Nun können Sie die Seite unmittelbar innerhalb der Umgebung von Microsoft Access verarbeiten.
32.2.4
Eine Datenzugriffsseite von Grund auf erstellen
Obgleich der Asistent für Datenzugriffsseiten sehr leistungsfähig ist, werden Sie Datenzugriffsseiten gelegentlich auch von Grund auf erstellen wollen. Gehen Sie dazu folgendermaßen vor: 1. Klicken Sie im Datenbankfenster in der Liste der Objekte auf SEITEN. 2. Doppelklicken Sie auf die Option ERSTELLT EINE DATENZUGRIFFSSEITE IN DER ENTWURFSANSICHT. Daraufhin erscheint eine leere Datenzugriffsseite (siehe Abbildung 32.11).
1090
Kapitel 32: Datenzugriffsseiten verwenden
Abbildung 32.10: Im Dialogfeld Webseite suchen können Sie ein vorhandenes HTML-Dokument angeben, um es innerhalb der AccessUmgebung zu bearbeiten
3. Fügen Sie der Datenzugriffsseite Steuerelemente hinzu und legen Sie deren Eigenschaften fest.
Abbildung 32.11: Wenn die Datenzugriffsseite in der Entwurfsansicht erstellt wird, erscheint zunächst eine leere Datenzugriffsseite
Möglicherweise haben Sie sich bereits die Frage gestellt, wie Sie in eine von Grund auf erstellte Datenzugriffsseite eine Tabelle Ihrer Datenbank einbinden können. Dies erfolgt etwas anders als das Verknüpfen eines Formulars mit Daten. Gehen Sie folgendermaßen vor: 1. Klicken Sie in der Symbolleiste auf das Symbol FELDLISTE. Daraufhin erscheint das Fenster FELDLISTE (siehe Abbildung 32.12).
Datenzugriffsseiten erstellen
1091
Abbildung 32.12: Das Fenster Feldliste ermöglicht Ihnen, Ihrer Datenzugriffsseite auf einfache Weise Tabellen und Abfragen hinzuzufügen
2. Beachten Sie, dass im Fenster FELDLISTE zwei erweiterbare Listen dargestellt werden: eine mit Tabellen der Datenbank und eine andere mit Abfragen der Datenbank (siehe Abbildung 32.13).
Abbildung 32.13: Im erweiterten Fenster Feldliste sind alle Tabellen und Abfragen Ihrer aktuellen Datenbank aufgeführt
1092
Kapitel 32: Datenzugriffsseiten verwenden
3. Um der Datenzugriffsseite alle Felder einer vorhandenen Tabelle oder Abfrage hinzuzufügen, ziehen Sie eine vollständige Tabelle bzw. Abfrage von der Feldliste auf die Datenzugriffsseite. 4. Sie können der Datenzugriffsseite bestimmte Felder einer Tabelle oder Abfrage hinzufügen, indem Sie die Feldliste erweitern, damit die gewünschte Tabelle bzw. Abfrage angezeigt wird, und einzelne Felder auf die Datenzugriffsseite ziehen. In Abbildung 32.14 wurden die ausgewählten Felder aus der Tabelle tblEmployee in die Datenzugriffsseite eingefügt.
Abbildung 32.14: Diese Datenzugriffsseite enthält Felder, die aus der Tabelle tblEmployees ausgewählt wurden.
Da Datenzugriffsseiten als unabhängige HTML-Dokumente gespeichert werden, ist Access nicht in der Lage, die mit einer bestimmten Datenbank verknüpften Datenzugriffsseiten aufzufinden, wenn die einzelnen Seiten in andere Verzeichnisse verschoben werden, in denen sie nicht ursprünglich erstellt wurden. Das Problem zeigt sich, wenn Sie versuchen, mit den Datenzugriffsseiten zu arbeiten, die mit der Datenbank Chap32Ex.mdb auf der CD-ROM mit den Beispielcodes verknüpft sind. Sie müssen zunächst einen speziellen Code schreiben, damit die Verknüpfungen mit den Seiten hergestellt werden. Die mit Access 2000 ausgelieferte Nordwind-Datenbank umfasst Beispielcode, den Sie in Ihren Anwendungen verwenden können, um diese unterbrochenen Verknüpfungen zu rekonstruieren.
Wichtige Eigenschaften einer Datenzugriffsseite anpassen
32.3
1093
Wichtige Eigenschaften einer Datenzugriffsseite anpassen
Genau wie Formulare und Berichte verfügen auch Datenzugriffsseiten über Eigenschaften. Viele dieser Eigenschaften ähneln jenen von Formularen und Berichten. Die wichtigsten Eigenschaften werden nachfolgend erörtert. Um die Eigenschaften einer Datenzugriffsseite zu verändern, müssen Sie zunächst dafür sorgen, dass die entsprechende Seite ausgewählt ist. Am einfachsten kann die Seite in der Titelleiste ausgewählt werden. Zu den wichtigsten Eigenschaften einer Datenzugriffsseite gehören deren Dateneigenschaften. Diese Eigenschaften sind in Abbildung 32.15 dargestellt und die wichtigsten von ihnen werden im Folgenden näher erörtert.
Abbildung 32.15: Die Dateneigenschaften einer Datenzugriffsseite ermöglichen Ihnen das Regulieren des Verhaltens der Daten, die der Datenzugriffsseite zu Grunde liegen
32.3.1
Die Eigenschaft DataEntry
Die erste Eigenschaft ist die Eigenschaft DataEntry. Standardmäßig weist diese Eigenschaft den Wert False auf. Dies bedeutet, dass sämtliche Datensätze einer innerhalb von Microsoft Access befindlichen oder mit einem Browser betrachteten Datenzugriffsseite verfügbar sind. Wird dieser Wert in True geändert, können zwar neue Datensätze hinzugefügt, bestehende Daten jedoch nicht betrachtet werden (siehe Abbildung 32.16).
1094
Kapitel 32: Datenzugriffsseiten verwenden
Abbildung 32.16: Mit Hilfe der Eigenschaft DataEntry können Sie festlegen, ob die vorhandenen Datensätze verfügbar sein sollen
32.3.2
Die Eigenschaft MaxRecords
Mit Hilfe der Eigenschaft MaxRecords können Sie festlegen, wie viele Datensätze bei einer Verbindung auf den lokalen Computer übertragen werden sollen. Wenn dieser Eigenschaft kein angemessener Wert zugewiesen wurde, werden unter Umständen sehr große Datenmengen über das Internet bzw. über das jeweilige Intranet an den Browser des Benutzers übertragen. Daraus können sich erhebliche Probleme mit der Leistung ergeben. In dieser Eigenschaft sollte deshalb eine maximale Anzahl von Datensätzen angegeben werden, die vom Benutzer problemlos empfangen werden kann.
32.3.3
Die Eigenschaft RecordsetType
Die Eigenschaft RecordsetType kann die Werte dscUpdatetableSnapshot bzw. dscSnapshot annehmen. Wurde dscUpdatetableSnapshot ausgewählt, so können die Daten der entsprechenden Datenzugriffsseite bearbeitet werden. Sollen die Daten ausschließlich gelesen werden können, so ist der Wert dscSnapshot zu verwenden.
32.3.4
Die Eigenschaft UseRemoteProvider
Die Eigenschaft UseRemoteProvider legt fest, ob das Steuerelement DATENHERKUNFT für Datenverbindungen den Microsoft Remote Data Services Provider verwendet. Nur für Seiten, die mit einem Microsoft Internet Information Server unter Verwendung einer HTTP- bzw. HTTPS-Adresse betrachtet werden, kann dieser Eigenschaft der Wert True zugewiesen werden. Gegebenenfalls bezieht der Microsoft Remote Data Services Provider seine Daten, indem er eine HTTP- bzw. HTTPS-Anfrage an den Microsoft Internet Information Server (IIS) sendet. IIS stellt daraufhin die ILE DB-Verbindung mit der Datenbank her.
1095
Ändern der Eigenschaften zur Navigation in den Datensätzen
32.4
Ändern der Eigenschaften zur Navigation in den Datensätzen
Das Steuerlement DATENSATZNAVIGATION einer Datenzugriffsseite ermöglicht Ihnen standardmäßig Folgendes:
übergehen zum nächsten, vorherigen, ersten oder letzten Datensatz übergehen zu einem neuen Datensatz löschen eines bestehenden Datensatzes speichern der an einem Datensatz vorgenommenen Änderungen rückgängigmachen der an einem Datensatz vorgenommenen Änderungen sortieren in auf- oder absteigender Reihenfolge filtern der auf der Datenzugriffsseite angezeigten Daten Gelegentlich ist es günstiger, wenn nicht alle diese Funktionen verfügbar sind. Um die Eigenschaften des Steuerelements DATENSATZNAVIGATION zu verändern, müssen Sie es zunächst auswählen. Klicken Sie dazu in der Entwurfsansicht der Seite auf das Steuerelement. Auf die wichtigsten Eigenschaften können Sie über die Registerkarte ANDERE zugreifen (siehe Abbildung 32.17).
Abbildung 32.17: Die Registerkarte Andere des Eigenschaftenfensters ermöglicht Ihnen das Verändern der wichtigsten Eigenschaften zum Steuern der Navigation in den Datensätzen
1096
32.4.1
Kapitel 32: Datenzugriffsseiten verwenden
Die Eigenschaft RecordSource
Die möglicherweise wichtigste Eigenschaft eines Datensatznavigations-Steuerelements ist die Eigenschaft RecordSource. Diese Eigenschaft wird verwendet, um die Tabelle oder Abfrage anzugeben, welche der Datenzugriffsseite zu Grunde liegt.
32.4.2
Die Eigenschaften ShowNextButton, ShowPrevButton, ShowFirstButton und ShowLastButton
Mit Hilfe der Eigenschaften ShowNextButton, ShowPrevButton, ShowFirstButton und ShowLastButton können Sie festlegen, ob die Schaltflächen NÄCHSTER, VORHERIGER, ERSTER und LETZTER auf dem Datensatznavigations-Steuerelement erscheinen sollen. Diese Eigenschaften bestimmen, in welcher Weise sich der Benutzer innerhalb der auf der Datenzugriffsseite dargestellten Datensätze bewegen kann. Sie können diese Eigenschaften jeweils unabhängig voneinander festlegen. Beispielsweise haben Sie die Möglichkeit, zwar die Schaltflächen NÄCHSTER und VORHERIGER, nicht jedoch die Schaltflächen ERSTER und LETZTER anzeigen zu lassen.
32.4.3
Die Eigenschaft ShowNewButton
Mit Hilfe der Eigenschaft ShowNewButton können Sie festlegen, ob die Schaltfläche NEU auf dem Steuerelement für die Navigation innerhalb der Datensätze erscheinen soll. Falls diese Schaltfläche verwendet wird, kann der Benutzer darauf klicken, um den der Datenzugriffsseite zu Grunde liegenden Daten einen neuen Datensatz hinzuzufügen. Wenn Sie diese Schaltfläche nicht einblenden lassen und auch keine entsprechende benutzerdefinierte Schaltfläche anbieten, kann der Benutzer von der Datenzugriffsseite aus keine neuen Datensätze erstellen.
32.4.4
Die Eigenschaft ShowDelButton
Mit Hilfe der Eigenschaft ShowDelButton können Sie festlegen, ob die Schaltfläche LÖSCHEN auf dem Datensatznavigations-Steuerelement erscheint. Falls diese Schaltfläche verwendet wird, kann der Benutzer darauf klicken, um den aktuellen Datensatz zu löschen. Andernfalls hat der Benutzer keine Möglichkeit, Datensätze zu entfernen, wenn Sie ihm auf der Datenzugriffsseite keine entsprechende benutzerdefinierte Schaltfläche anbieten.
32.4.5
Die Eigenschaft ShowSaveButton
Mit Hilfe der Eigenschaft ShowSaveButton können Sie festlegen, ob die Schaltfläche SPEICHERN auf dem Datensatznavigations-Steuerelement erscheint. Falls diese Schaltfläche verwendet wird, kann der Benutzer darauf klicken, um Änderungen an dem gegenwärtig auf der Datenzugriffsseite angezeigten Datensatz zu speichern. Ansonsten werden vorgenommene Änderungen automatisch gespeichert, sobald der Benutzer zu einem anderen Datensatz wechselt.
Gruppierte Datenzugriffsseiten erstellen
32.4.6
1097
Die Eigenschaft ShowUndoButton
Mit Hilfe der Eigenschaft ShowUndoButton können Sie festlegen, ob die Schaltfläche RÜCKGÄNGIG auf dem Datensatznavigations-Steuerelement erscheint. Falls diese Schaltfläche verwendet wird, kann der Benutzer darauf klicken, um an dem gegenwärtig angezeigten Datensatz vorgenommene Änderungen zurückzunehmen. Ansonsten hat der Benutzer die Möglichkeit, an einem Datensatz vorgenommene Änderungen durch Drücken der Taste [ESC] rückgängig zu machen.
32.4.7
Die Eigenschaften ShowSortAscendingButton und ShowSortDescendingButton
Mit Hilfe der Eigenschaften ShowSortAsceningButton und ShowSortDescendingButton können Sie festlegen, ob die Schaltflächen AUFSTEIGEND SORTIEREN und ABSTEIGEND SORTIEREN auf dem Datensatznavigations-Steuerelement erscheinen. Falls diese Schaltflächen verwendet werden, kann der Benutzer auf das Feld klicken, nach dem sortiert werden soll, und anschließend die entsprechende Schaltfläche anklicken, um die Datensätze in auf- bzw. absteigender Reihenfolge zu sortieren. Ohne diese Schaltflächen hat der Benutzer keine Möglichkeit, die auf der Datenzugriffsseite dargestellten Daten zu sortieren.
32.4.8
Die Eigenschaft ShowToggleFilterButton
Mit Hilfe der Eigenschaft ShowToggleFilterButton können Sie festlegen, ob die Schaltfläche FILTER auf dem Datensatznavigations-Steuerelement erscheint. Wird diese Schaltfläche verwendet, so kann der Benutzer zunächst auf das Feld, nach dem gefiltert werden soll, und anschließend auf diese Schaltfläche klicken, um die der Datenzugriffsseite zu Grunde liegenden Daten nach dem im gegenwärtigen Datensatz ausgewählten Feld zu filtern. In Abbildung 32.18 wurden die Daten beispielsweise so gefiltert, dass ausschließlich die Systemanalysten dargestellt werden. Wenn die Schaltfläche auf dem Datensatznavigations-Steuerelement nicht dargestellt wird, hat der Benutzer keine Möglichkeit, die der Datenzugriffsseite zu Grunde liegenden Datensätze zu filtern (falls Sie keine analoge Funktion über eine benutzerdefinierte Schaltfläche anbieten).
32.5
Gruppierte Datenzugriffsseiten erstellen
Das Gruppieren der auf einer Datenzugriffsseite dargestellten Datensätze ähnelt dem Gruppieren der Datensätze eines Berichts. Gruppierte Datenzugriffsseiten weisen gegenüber gruppierten Berichten folgende Vorteile auf:
Auf der Datenzugriffsseite werden grundsätzlich aktuelle Daten dargestellt.
1098
Kapitel 32: Datenzugriffsseiten verwenden
Abbildung 32.18: Mit Hilfe der Eigenschaft ShowToggleFolterButton können Sie die auf Ihrer Datenzugriffsseite dargestellten Daten filtern
Im Gegensatz zu Berichten sind Datenzugriffsseiten interaktiv. Das bedeutet, dass der Benutzer einer gruppierten Datenzugriffsseite Datensätze stets seinen persönlichen Vorlieben entsprechend gefiltert und sortiert darstellen lassen kann.
Der Betrachter einer per E-Mail empfangenen Datenzugriffsseite sieht beim jeweiligen Öffnen der Nachricht stets die aktuellen Daten. Eine gruppierte Datenzugriffsseite können Sie folgendermaßen erstellen: 1. Klicken Sie im Datenbankfenster in der Liste der Objekte auf SEITEN. 2. Doppelklicken Sie auf die Option ERSTELLT EINE DATENZUGRIFFSSEITE UNTER VERWENDUNG DES ASSISTENTEN. Daraufhin erscheint der Seiten-Assistent. 3. Wählen Sie die Tabelle bzw. Abfrage aus, deren Daten gruppiert dargestellt werden sollen (die 1-Seite der Beziehung). 4. Wählen Sie die Felder der ersten Tabelle oder Abfrage aus, welche auf Ihrer Datenzugriffsseite erscheinen sollen. 5. Wählen Sie die Tabelle oder Abfrage aus, auf der die n-Seite Ihrer Datenzugriffsseite basieren soll. 6. Wählen Sie die Felder der zweiten Tabelle oder Abfrage aus, die auf Ihrer Datenzugriffsseite erscheinen sollen. In Abbildung 32.19 wurden in der Tabelle tblProjects das Feld ProjectName (auf der 1-Seite der Beziehung) und die Felder DateWorked, BillableHours und BillingRate aus der Tabelle tblTimeCardHours ausgewählt. Klicken Sie auf die Schaltfläche WEITER, um fortzufahren. 7. Wählen Sie die Felder aus, nach denen gruppiert werden soll. In Abbildung 32.20 wurden die Daten nach dem Feld ProjectName sortiert. Klicken Sie auf WEITER.
Gruppierte Datenzugriffsseiten erstellen
1099
Abbildung 32.19: Für das Erstellen einer gruppierten Datenzugriffsseite wählen Sie zunächst Felder mehrerer Tabellen aus
Abbildung 32.20: Der DatenzugriffsseitenAssistent ermöglicht Ihnen das Angeben der Felder, nach denen die Daten gruppiert werden sollen
8. Geben Sie an, in welcher Weise die Daten innerhalb der Gruppierung sortiert werden sollen und klicken Sie auf die Schaltfläche WEITER. 9. Geben Sie den Titel der Seite ein und klicken Sie auf FERTIG STELLEN. Die fertige Seite ist in Abbildung 32.21 dargestellt. Wie Sie sehen, werden die Daten automatisch in verkürzter Form angezeigt. Außerdem erscheint nur jeweils ein Projektname (die 1-Seite der Beziehung). Diese beiden Aspekte einer gruppierten
1100
Kapitel 32: Datenzugriffsseiten verwenden
Datenzugriffsseite können problemlos mit Hilfe der Eigenschaften der Gruppe angepasst werden.
Abbildung 32.21: Auf einer gruppierten Datenzugriffsseite werden die Daten reduziert und gruppenweise dargestellt
Die Eigenschaften der Gruppe sehen Sie in Abbildung 32.22. Wurde der Eigenschaft Expanded by Default der Wert Yes zugewiesen, so werden die Daten automatisch im Rahmen einer Gruppierung dargestellt (siehe Abbildung 32.23). Mit Hilfe der Eigenschaft Data Page Size können Sie festlegen, wie viele Datensätze maximal gleichzeitig für eine bestimmte Gruppierungsebene angezeigt werden sollen. In Abbildung 32.24 wurde der Eigenschaft Data Page Size für Gruppierungen der zweiten Ebene der Wert 3 zugewiesen. Das bedeutet, dass bis zu drei ausführliche Datensätze innerhalb jeder Gruppierungsebene dargestellt werden.
32.6
Datenzugriffsseiten mit VBScript ausbauen
Eine der Stärken von Datenzugriffsseiten besteht darin, dass sie mit Mitteln bearbeitet werden können, die über die Möglichkeiten des Seitenentwurfs von Access hinausgehen. Der Microsoft Script-Editor (MSE) erlaubt Ihnen das Erstellen von Scripts zum Erweitern der Funktionen Ihrer Datenzugriffsseiten. Mit Hilfe von MSE können Sie Scripts für Ereignisse der Objekte von Datenzugriffsseiten erstellen. Gehen Sie folgendermaßen vor, um MSE zu öffnen und ein Script für eine Datenzugriffsseite zu erstellen: 1. Öffnen Sie die Datenzugriffsseite.
Datenzugriffsseiten mit VBScript ausbauen
1101
Abbildung 32.22: Mit Hilfe der Eigenschaften einer Gruppe können Sie die Attribute einer Gruppe festlegen
Abbildung 32.23: Mit Hilfe der Eigenschaft für die standardmäßig erweiterte Darstellung einer Gruppe können Sie angeben, ob die Daten auf Gruppenebene automatisch in einem erweiterten Format erscheinen sollen
2. Klicken Sie auf das Symbol TOOLBOX auf der Symbolleiste, damit die Toolbox angezeigt wird (siehe Abbildung 32.25). 3. Fügen Sie der Datenzugriffsseite ein Steuerelement wie beispielsweise eine Befehlsschaltfläche hinzu. Verwenden Sie die Eigenschaft ID, um das Steuerelement bei Bedarf umzubenennen.
1102
Kapitel 32: Datenzugriffsseiten verwenden
Abbildung 32.24: Mit Hilfe der Eigenschaft für die Seitengröße können Sie die maximale Anzahl der gleichzeitig erweitert erscheinenden Datensätze einer bestimmten Gruppe festlegen
Abbildung 32.25: Mit Hilfe der Toolbox können Sie Ihrer Datenzugriffsseite Steuerelemente hinzufügen
4. Klicken Sie mit der rechten Maustaste auf das Steuerelement und wählen Sie die Option MICROSOFT SCRIPT-EDITOR aus. Daraufhin erscheint die in Abbildung 32.26 gezeigte Microsoft Entwicklungsumgebung (MDE). 5. Schauen Sie sich das Fenster SCRIPTGLIEDERUNG genauer an. Möglicherweise müssen Sie zunächst per ANSICHT|ANDERE FENSTER|SCRIPTGLIEDERUNG, durch [Strg]+[Alt]+[S] oder durch das Anklicken der Registerkarte SCRIPTGLIEDERUNG dafür sorgen, dass das Fenster SCRIPTGLIEDERUNG dargestellt wird. Im aktivierten Fenster SCRIPTGLIEDERUNG klicken Sie auf das Pluszeichen, damit die Client-Objekte und -Ereignisse angezeigt werden. 6. Suchen Sie nach dem Objekt, das Sie soeben hinzugefügt haben. 7. Klicken Sie auf das entsprechende Pluszeichen, um die mit dem Objekt verknüpften Ereignisse zu betrachten. In Abbildung 32.27 sind die mit der Befehlsschaltfläche cmdSayHello verknüpften Ereignisse im Scriptgliederungsfenster dargestellt.
Datenzugriffsseiten mit VBScript ausbauen
1103
Abbildung 32.26: Mit dem Microsoft Script-Editor können Sie Ihre Datenzugriffsseiten mit Code versehen, der ausgeführt werden soll, sobald bestimmte Ereignisse auftreten
Abbildung 32.27: Klicken Sie im Scriptgliederungsfenster auf das Pluszeichen, um die Ereignisse eines Objekts zu betrachten
1104
Kapitel 32: Datenzugriffsseiten verwenden
8. Um eine Ereignisroutine einzufügen, doppelklicken Sie auf den Namen des mit Code zu versehenden Ereignisses. Daraufhin wird für das Ereignis eine Ereignisbehandlungsroutine eingefügt. In Abbildung 32.28 wurde für das Ereignis onclick der Befehlsschaltfläche cmdSayHello ein Scriptblock eingefügt. 9. Schreiben Sie den Code, der ausgeführt werden soll, sobald das Ereignis auftritt. In Abbildung 32.29 wird die Anweisung MsgBox verwendet, um die Meldung Hello anzuzeigen, sobald jemand auf die Befehlsschaltfläche cmdSayHello klickt.
Abbildung 32.28: Ein Scriptblock für das onclickEreignis der Befehlsschaltfläche cmdSayHello
32.6.1
Wichtige Ereignisse von Datenzugriffsseiten
Wie Sie gesehen haben, werden Scripts für Datenzugriffsseiten den Objekten einer Seite in Form von Ereignisbehandlungsroutinen hinzugefügt. Wie bei einem AccessFormular handelt es sich bei einer Ereignisbehandlungsroutine um eine Unterroutine oder um eine Funktion, die automatisch ausgeführt wird, sobald ein bestimmtes Ereignis eines Objekts eintritt. Beispielsweise können Sie die folgenden wichtigen Ereignisse programmieren:
Das Ereignis OnRowEnter des Document-Objekts wird ausgelöst, nachdem der aktuelle Datensatz verändert wurde, aber bevor für den neuen Datensatz Felder ausgefüllt werden.
Das Ereignis OnRowExit des Document-Objekts tritt auf, bevor der aktuelle Datensatz verändert wird. Dieses Ereignis wird normalerweise verwendet, um Überprüfungen auf Datensatzebene durchzuführen.
Datenzugriffsseiten mit VBScript ausbauen
1105
Abbildung 32.29: Dieser VBScriptCode bewirkt, dass die Nachricht »Hello« angezeigt wird, sobald das Ereignis onclick der Befehlsschaltfläche cmdSayHello eintritt.
Das Ereignis BeforeCollapse eines Abschnitts wird ausgelöst, bevor ein Abschnitt verkürzt dargestellt wird.
Das Ereignis BeforeExpand eines Abschnitts wird ausgelöst, bevor ein Abschnitt ausführlich dargestellt wird.
Die Ereignisse BeforeNextPage, BeforePreviousPage, BeforeFirstPage und BeforeLastPage des Seitennavigations-Steuerelements treten auf, bevor das Navigations-
Steuerelement mit der nächsten, vorherigen, ersten bzw. letzten Seite fortfährt. All diese Ereignisse können abgebrochen werden, indem der Wert info.return des jeweiligen Ereignisses auf False gesetzt wird.
Das Ereignis Current wird ausgelöst, nachdem ein Abschnitt zum aktuellen Abschnitt wird.
Das Ereignis DataPageComplete tritt auf, sobald nach dem Öffnen einer Seite, nach dem Navigieren oder nach dem Erweitern sämtliche Datenbindungen hergestellt sind. Wie bei den Ereignissen eines Formulars oder Berichts ist es wichtig, die Ereignisse einer Seite zu kennen, damit Sie wissen, wo Ihr Code zu platzieren ist.
32.6.2
VBScript und VBA im Vergleich
Da der Internet Explorer 5.0 VBA nicht verarbeiten kann, müssen entsprechende Scripts in VBScript verfasst werden. VBScript ist eine Untermenge von VBA. Zwi-
1106
Kapitel 32: Datenzugriffsseiten verwenden
schen VBA und VBScript bestehen die nachfolgend aufgelisteten wichtigen Unterschiede, derer Sie sich bewusst sein sollten:
Alle Variablen sind vom Typ Variant. Dies bedeutet, dass Dim-Anweisungen keine Typen umfassen können.
Parameter für Unterroutinen und Funktionen können keine Typen aufweisen. Viele integrierte Funktionen sind zwar in VBA, nicht jedoch in VBScript verfügbar.
Interne Konstanten wie vbYesNo sind in VBScript nicht verfügbar. Konstanten, die Sie innerhalb Ihres Codes verwenden wollen, müssen Sie selbst deklarieren.
32.6.3
VBScript und JavaScript im Vergleich
Scripts für Datenzugriffsseiten können entweder in VBScript oder in JavaScript verfasst werden. Wenn Sie sich mit VBA bereits gut auskennen, wird Ihnen das Erlernen von VBScript sicherlich wesentlich leichter fallen, als dies bei JavaScript der Fall wäre. Wenn Sie allerdings bereits Erfahrungen mit dem Erstellen von Webseiten unter Verwendung von JavaScript gesammelt haben, wollen Sie Ihre Scripts möglicherweise weiterhin in JavaScript schreiben. Zwischen VBScript und JavaScript bestehen im Wesentlichen die folgenden Unterschiede:
VBScript wird vom Objektmodell für Datenzugriffsseiten besser unterstützt. Bestimmte Ereignisse von Seiten werden deshalb nicht erkannt, wenn sie in JavaScript kodiert sind.
Bei JavaScript ist die Groß- und Kleinschreibung signifikant. Deshalb ist JavaScript etwas schwieriger handzuhaben als VBScript.
32.6.4
Für die Praxis
Anwenden des Gelernten auf das Zeit- und Abrechnungssystem Ziehen Sie einige der Formulare des Zeit- und Abrechungssystems in Betracht, die Sie gern innerhalb Ihres Intranets verfügbar machen würden. Versuchen Sie, diese Formulare in Datenzugriffsseiten umzuwandeln und passen Sie den Code entsprechend an, damit er nicht in VBA, sondern in VBScript formuliert ist.
Die Anwendung abrunden
Teil V
33 34 35 36 37
Datenbanksicherheit Fortgeschrittene Sicherheitstechniken Anwendungsdokumentation Ihre Anwendung warten Ihre Anwendung verteilen
Datenbanksicherheit
Kapitel
Hier lesen Sie:
Vom Kennwort bis zur Hochsicherheit Sicherheit auf Freigabe-Ebene implementieren: Ein Datenbank-Kennwort einrichten
Eine Datenbank verschlüssseln Zugriffsrechte auf Benutzerebene einrichten Eine zusätzliche Sicherheitsebene bereitstellen: Eine MDE erstellen Spezielle Fragestellungen
33.1
Vom Kennwort bis zur Hochsicherheit
Nachdem Sie eine ausgereifte Anwendung entworfen und entwickelt haben, sollten Sie sicherstellen, dass die Integrität der Anwendung und der von ihr verwalteten Daten nicht verletzt wird. Microsoft Access stellt Ihnen mehrere Optionen zum Sichern Ihrer Datenbank zur Verfügung. Diese Optionen reichen von einer sehr einfachen Methode, ein Kennwort für die gesamte Datenbank einzurichten, bis zum Einsatz unterschiedlicher Sicherheitsebenen für jedes Objekt in der Datenbank. Je komplizierter Ihre Sicherheitslösung ist, desto schwieriger ist sie zu implementieren. Glücklicherweise können Sie die Komplexität der von Ihnen implementierten Sicherheit auf den Grad an Sicherheit anpassen, den jede spezielle Anwendung benötigt.
1110
33.2
Kapitel 33: Datenbanksicherheit
Sicherheit auf Freigabe-Ebene implementieren: Ein Datenbank-Kennwort einrichten
Die einfachste, am wenigsten ausgefeilte Methode, Sicherheit zu implementieren, besteht darin, der gesamten Datenbank ein Kennwort zuzuweisen. Dies bedeutet, dass jede Person, die Zugriff auf die Datenbank erlangen möchte, dasselbe Kennwort eingeben muss. Nachdem ein Benutzer Zugriff auf die Datenbank erhalten hat, stehen ihm alle Objekte der Datenbank zur Verfügung. Diese Art der Sicherheit wird als »Sicherheit auf Freigabe-Ebene« bezeichnet. Die Sicherheit auf Freigabe-Ebene ist am einfachsten und schnellsten einzurichten. Die Datenbank und ihre Objekte werden nahezu ohne Aufwand gesichert. Diese Methode der Sicherheit ist für ein kleines Unternehmen recht angemessen, wo die Benutzer der Datenbank sichergehen wollen, dass keine unauthorisierten Personen auf die Daten zugreifen können, aber jede Person, die Zugriff auf die Datenbank hat, auf alle ihre Objekte zugreifen kann. Um ein Datenbank-Kennwort zuzuweisen, führen Sie die folgenden Schritte aus: 1. Öffnen Sie die Datenbank, der Sie ein Kennwort zuweisen möchten. Um ein Datenbank-Kennwort zuzuweisen, müssen Sie die Datenbank exklusiv öffnen. Um dies zu bewerkstelligen, wählen Sie im Dialogfeld ÖFFNEN die Option EXKLUSIV ÖFFNEN. 2. Wählen Sie EXTRAS | SICHERHEIT | DATENBANK-KENNWORT ZUWEISEN. Daraufhin erscheint das in Abbildung 33.1 gezeigte Dialogfeld DATENBANK-KENNWORT ZUWEISEN. 3. Geben Sie das Kennwort ein, bestätigen Sie es und klicken Sie anschließend auf OK. Beim Kennwort ist die Groß- und Kleinschreibung zu beachten. Nachdem Sie der Datenbank ein Kennwort zugewiesen haben, werden die Benutzer jedesmal zur Eingabe eines Kennworts aufgefordert, wenn sie die Datenbank öffnen. Abbildung 33.2 zeigt das Dialogfeld KENNWORT ERFORDERLICH, das jedesmal angezeigt wird, wenn die Datenbank geöffnet wird. Nachdem die Benutzer ein gültiges Kennwort eingegeben haben, erhalten sie Zugriff auf die Datenbank und alle ihre Objekte. Tatsächlich können Benutzer sogar das Kennwort entfernen, indem sie EXTRAS | SICHERHEIT | DATENBANK-KENNWORT LÖSCHEN wählen. Das Dialogfeld DATENBANK-KENNWORT LÖSCHEN erfordert nur, dass Benutzer das ursprüngliche Kennwort kennen (siehe Abbildung 33.3). Dieser Abschnitt erläutert alles, was über das Festlegen eines Datenbank-Kennworts zu wissen ist. Obwohl diese Kennwörter sehr leicht zu verstehen und zu implementieren sind, stellen sie auch ein sehr einfaches Konzept dar. Wie Sie sehen können, haben Benutzer entweder Zugriff auf die Datenbank oder nicht, und es ist für jeden Benutzer, der Zugriff auf die Datenbank hat, besonders leicht, deren Kennwort zu ändern oder zu löschen.
Eine Datenbank verschlüsseln
1111
Abbildung 33.1: Das Dialogfeld Datenbank-Kennwort zuweisen
Abbildung 33.2: Das Dialogfeld Kennwort erforderlich
Abbildung 33.3: Das Dialogfeld Datenbank-Kennwort löschen
Wenn Sie das einer Datenbank zugeordnete Kennwort vergessen, besteht in keiner Weise mehr die Möglichkeit, auf die Datenbank und ihre Objekte zuzugreifen. Es ist deshalb äußerst wichtig, dass Sie eine Liste der jeder Datenbank zugeordneten Kennwörter sorgfältig verwalten.
Um einer Datenbank ein Kennwort zuzuweisen, müssen Benutzer in der Lage sein, die Datenbank exklusiv zu öffnen. Sie können im Dialogfeld BENUTZER- UND GRUPPENBERECHTIGUNGEN Benutzern das Recht, eine Datenbank exklusiv zu öffnen, erteilen oder verweigern. Das Zuweisen von Rechten, die es Benutzern oder Gruppen ermöglichen oder verweigern, Datenbanken exklusiv zu öffnen, wird im Abschnitt »Schritt 11: Benutzern und Gruppen Rechte zuweisen« in diesem Kapitel erläutert.
33.3
Eine Datenbank verschlüsseln
Bevor wir uns mit den fortgeschritteneren Methoden für das Sichern einer Datenbank befassen, ist es wichtig, dass Sie verstehen, welche Möglichkeiten Ihnen jede Methode bietet und was Sie damit nicht machen können. Ganz gleich, wie gut Sie die Techniken in diesem Kapitel verstehen und implementieren, Sie werden nicht gegenüber jemandem geschützt sein, der versucht, die in Ihrer Datenbank enthalte-
1112
Kapitel 33: Datenbanksicherheit
nen Daten zu lesen. Es ist wichtig, dass Ihnen bewusst ist, dass auch jemand den Inhalt der Datei mit einem Disk-Editor betrachten kann, nachdem Sie eine Datenbank gesichert haben. Obwohl die Daten in der Datei nicht in einem leicht zu lesenden Format erscheinen werden, sind die Daten vorhanden und können durch nicht autorisierte Personen betrachtet werden. Sie können sich entmutigt fühlen und sich fragen, warum Sie sich um die Sicherheit überhaupt kümmern sollen. Verzweifeln Sie nicht! Glücklicherweise ermöglicht Access es Ihnen, eine Datenbank zu verschlüsseln. Der Verschlüsselungsprozess führt dazu, dass die Daten in der Datenbank nicht mehr von Textverarbeitungsprogrammen, Festplatten-Hilfsprogrammen und anderen Produkten, die Text lesen können, entziffert werden können. Wenn eine Datenbank verschlüsselt ist, kann niemand ihre Daten erkennen. Eine Datenbank kann mit Hilfe der standardmäßigen Access-Menüs oder durch das Schreiben einer VBA-Subroutine verschlüsselt werden. In beiden Fällen darf die Datenbank, die Sie verschlüsseln, nicht geöffnet sein. Um eine Datenbank mit Hilfe der Standardmenüs in Access zu verschlüsseln, führen Sie die folgenden Schritte aus: 1. Wählen Sie EXTRAS | SICHERHEIT | DATENBANK VER-/ENTSCHLÜSSELN. 2. Sie gelangen daraufhin in das Dialogfeld DATENBANK VER-/ENTSCHLÜSSELN. Wählen Sie die Datei, die Sie verschlüsseln möchten und klicken Sie dann auf OK . 3. Sie werden zur Eingabe des Namens der verschlüsselten Datenbank aufgefordert. Falls Sie denselben Namen wie die bestehende Datei wählen, löscht Access die ursprüngliche entschlüsselte Datei, nachdem festgestellt wurde, dass der Verschlüsselungsprozess erfolgreich gewesen ist. Es ist immer empfehlenswert, die ursprüngliche Datenbank zu sichern, bevor Sie mit dem Verschlüsselungsprozess beginnen. Dies gewährleistet, dass Ihre Daten nicht verlorengehen, falls während des Verschlüsselungsvorgangs etwas schief geht.
Sie können außerdem eine Datenbankdatei mit Hilfe von Code ver- oder entschlüsseln. Dies wird in Kapitel 34 behandelt.
Wenn Sie eine Datenbank verschlüsseln, wird die gesamte Datenbank (nicht nur die Daten) verschlüsselt. Wenn Sie auf die Daten und die Objekte in der Datenbank zugreifen, muss Access die Objekte entschlüsseln, so dass Benutzer diese verwenden können und dann die Objekte wieder verschlüsseln, wenn die Benutzer die Zugriffe auf die Objekte beendet haben. Unabhängig von der Verschlüsselungsmethode, die Sie verwenden, verringert die verschlüsselte Datenbank die Leistung um etwa 15
Sicherheit auf Benutzerebene einrichten
1113
Prozent. Weiterhin können verschlüsselte Datenbanken von den meisten Hilfsprogrammen für Datenträgerkomprimierung nicht komprimiert werden, da Komprimierungs-Software im Allgemeinen auf sich wiederholende Datenmuster angewiesen ist. Der Verschlüsselungsprozess entfernt etwaige Muster derartig effektiv, dass die meisten Komprimierungsprogramme ineffektiv bleiben. Sie müssen entscheiden, ob die zusätzliche Sicherheit durch die Verschlüsselung die Leistungsminderung und die Unfähigkeit, die Datenbankdatei zu komprimieren, Wert ist.
33.4
Sicherheit auf Benutzerebene einrichten
Für die meisten Unternehmensumgebungen sind Zugriffsrechte auf Freigabe-Ebene nicht ausreichend. Deshalb ist es erforderlich, einen weitergehenden Ansatz für die Sicherung der Objekte in Ihrer Datenbank zu wählen. Die Sicherheit auf Benutzerebene ermöglicht es Ihnen, Benutzern und Gruppen in einer Arbeitsgruppe bestimmte Rechte zu gewähren. Das bedeutet, dass jeder Benutzer oder jede Gruppe verschiedene Berechtigungen für dasselbe Objekt besitzen kann. Bei dieser Sicherheitsmethode startet jeder Benutzer mit der Eingabe eines Benutzernamens und eines Kennworts. Die Jet-Engine überprüft die Gültigkeit des Benutzernamens und des Kennworts und ermittelt die diesem Benutzer zugwiesenen Berechtigungen. Jeder Benutzer verwaltet sein eigenes Kennwort, das in keinem Zusammenhang zu den Kennwörtern von anderen Benutzern steht. Bei dieser Sicherheitsmethode gehören Benutzer zu Gruppen. Sie können Rechte auf der Gruppenebene, auf der Benutzerebene oder auf beiden Ebenen zuweisen. Benutzer erben die Rechte ihrer am wenigsten einschränkenden Gruppe. Dies wird durch die Tatsache hervorgehoben, dass Sicherheit immer aktiv ist. Standardmäßig erhalten alle Benutzer Rechte auf alle Objekte, da jeder Benutzer ein Mitglied der Gruppe namens Benutzer ist. Diese Gruppe besitzt standardmäßig alle Rechte für alle Objekte. Wenn Sie keine Sicherheit implementiert haben, wird jeder Benutzer als Admin-Benutzer angemeldet, der ein Mitglied der Benutzer-Gruppe und der allmächtigen Admins-Gruppe ist. Die Jet-Engine stellt fest, dass der Admin -Benutzer kein Kennwort besitzt und zeigt deshalb keinen Start-Anmeldungsbildschirm an. Da Mitglieder der Benutzer- und der Administratorengruppe standardmäßig Rechte auf alle Objekte erhalten, erscheint es, als ob keine Sicherheit vorhanden wäre. Mit Hilfe der Sicherheit auf Benutzerebene können Sie leicht die Rechte in Bezug auf verschiedene Objekte anpassen und verfeinern. Eine Menge von Benutzern könnte beispielsweise in der Lage sein, Mitarbeiterdatensätze zu betrachten, zu ändern, hinzuzufügen und zu entfernen. Eine andere Gruppe von Benutzern könnte in der Lage sein, nur die Mitarbeiterinformationen zu betrachten. Der letzten Gruppe von Benutzern könnte überhaupt kein Zugriff auf die Mitarbeiterinformationen erlaubt sein oder sie dürften nur auf bestimmte Felder (wie zum Beispiel Name und Adresse) zugreifen. Das Sicherheitsmodell von Access trägt dieser Art von Szenario auf einfache Weise Rechnung.
1114
Kapitel 33: Datenbanksicherheit
Im Folgenden sind die wesentlichen Schritte zur Implementierung der Zugriffsrechte auf Benutzerebene aufgeführt (jeder Schritt wird an späterer Stelle in diesem Kapitel detailliert erläutert): 1. Verwenden Sie den Arbeitsgruppen-Administrator, um eine neue Systemdatenbank einzurichten. 2. Starten Sie Access und ändern Sie das Kennwort des Admin -Benutzers in ein Kennwort mit einer von Null verschiedenen Länge. 3. Erstellen Sie einen neuen Benutzer, welcher der Administrator der Datenbank sein wird. 4. Definieren Sie den Benutzer als Mitglied der Administratorengruppe. 5. Beenden Sie Access, starten Sie es erneut und melden Sie sich als neuer Systemadministrator an. 6. Entfernen Sie den Benutzer Administrator aus der Gruppe Adminstratoren. 7. Weisen Sie dem neuen Systemadministrator ein Kennwort zu. 8. Öffnen Sie die Datenbank, die Sie schützen wollen. 9. Starten Sie den Datensicherheits-Assistenten. 10. Erstellen Sie Benutzer und Gruppen, die aus Mitgliedern der Arbeitsgruppe bestehen, die von der Systemdatenbank definiert wurde. 11. Weisen Sie Benutzern und Gruppen Rechte für einzelne Objekte zu. Viele der zuvor skizzierten Schritte können mit Hilfe des Benutzer-Datensicherheits-Assistenten ausgeführt werden. Obwohl der Datensicherheits-Assistent ein leistungsfähiges Werkzeug darstellt, ermöglicht er nicht den Grad an Flexibilität, der Ihnen zur Verfügung stehen würde, führten Sie die Schritte selbst aus. In diesem Kapitel konzentriere ich mich deshalb auf das Ausführen der einzelnen Schritte ohne den Datensicherheits-Assistenten und gehe dann im Abschnitt »Schritt 9: Den DatensicherheitsAssistenten ausführen« dieses Kapitels detailliert auf den Assistenten ein. Im Verlauf dieses Kapitels gebe ich an, welche Schritte vom Datensicherheits-Assistenten ausgeführt werden.
33.4.1
Schritt 1: Eine Arbeitsgruppe erstellen
Der erste Schritt beim Einrichten von Sicherheit auf Benutzerebene umfasst das Erstellen einer Arbeitsgruppe. Hier können Sie Gruppen und Benutzer definieren, die zu dieser Arbeitsgruppe gehören und diesen Gruppen und Benutzern Rechte zuweisen. Bevor Sie erfahren, wie Gruppen und Benutzer erstellt werden, ist es wichtig für Sie zu verstehen, dass Gruppen und Benutzer nur im Zusammenhang mit
Sicherheit auf Benutzerebene einrichten
1115
einer bestimmten Arbeitsgruppe definiert werden. Stellen Sie sich eine Arbeitsgruppe als eine Gruppe von Benutzern in einer Mehrbenutzerumgebung vor, die Daten und Anwendungen gemeinsam nutzt. Wenn Sie eine neue Arbeitsgruppe einrichten, erstellt Access eine »ArbeitsgruppenInformationsdatei«, in der ein eindeutiger Bezeichner für die Arbeitsgruppe (als WID bezeichnet), Benutzer, Gruppen und Kennwörter für eine bestimmte Arbeitsgruppe gespeichert sind. Alle Anwendungsdatenbanken können dieselbe Arbeitsgruppendatei gemeinsam verwenden oder aber Sie verwalten separate Arbeitsgruppendateien für verschiedene Anwendungsdatenbanken. Die Arbeitsgruppe: Die Datei System.mdw Wie im vorherigen Abschnitt erwähnt, sind die Sicherheitsinformationen für Benutzer und Gruppen in einer Arbeitsgruppen-Informationsdatei gespeichert. Der Standardname für diese Datei lautet System.mdw. Jede Anwendungsdatenbank ist einer bestimmten Arbeitsgruppen-Informationsdatei zugeordnet. Diese Kombination von Informationen, die in der Arbeitsgruppen-Informationsdatei gespeichert sind, und Informationen, die in der Datenbank gespeichert sind, erteilt oder verweigert einzelnen Benutzern den Zugriff auf die Datenbank oder die in ihr enthaltenen Objekte. Mehrere Datenbanken können dieselbe Arbeitsgruppen-Informationsdatei besitzen. Die Arbeitsgruppen-Informationsdatei enthält die folgenden Elemente:
den Namen jedes Benutzers und jeder Gruppe die Liste der Benutzer, aus denen jede Gruppe besteht das verschlüsselte Anmeldungskennwort für jeden Benutzer, der als Teil der Arbeitsgruppe definiert ist
die eindeutigen Sicherheitskennungen (SIDs) für jeden Benutzer und jede Gruppe Eine SID ist eine computergenerierte binäre Zeichenfolge, die jeden Benutzer oder jede Gruppe eindeutig kennzeichnet. Die Systemdatenbank enthält die Namen und SIDs der Gruppen und Benutzer, die Mitglieder dieser bestimmten Arbeitsgruppe sind und deshalb dieselbe Systemdatenbank benutzen. Tatsächlich können Sie sehr viele Arbeitsgruppen-Informationsdateien erstellen. Der Name der gegenwärtig verwendeten Arbeitsgruppen-Informationsdatei ist in der Windows-Registrierung gespeichert. Sie können ihn unter HKEY_LOCAL_MACHINE im Schlüssel namens \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\9.0\Access\Jet\ 4.0\Engines betrachten (siehe Abbildung 33.4).
1116
Kapitel 33: Datenbanksicherheit
Abbildung 33.4: Die aktuelle System-Informationsdatei in der Windows-Registrierung betrachten
Sie können auf die Windows-Registrierung mittels des Hilfsprogramms RegEdit zugreifen. Um RegEdit zu verwenden, wählen Sie im Startmenü die Option AUSFÜHREN und geben dann RegEdit ein. Eine Arbeitsgruppe einrichten Eine Möglichkeit, eine neue Arbeitsgruppe einzurichten, besteht darin, den Arbeitsgruppen-Administrator zu verwenden. Der Arbeitsgruppen-Administrator ist ein eigenständiges Programm, das Sie außerhalb von Microsoft Access ausführen. Um den Arbeitsgruppen-Administrator zu starten, müssen Sie im Startmenü AUSFÜHREN wählen und nach der Datei Wrkgadm.exe suchen. Selbstverständlich können Sie eine Verknüpfung auf dem Desktop hinzufügen, um diese Datei einfacher zu starten. Falls Sie nicht sicher sind, wo die Datei Wrkgadm.exe sich befindet, können Sie den Windows Explorer verwenden, um den Speicherort der Datei zu ermitteln.
Nachdem Sie den Arbeitsgruppen-Administrator gestartet haben, sehen Sie das in Abbildung 33.5 gezeigte Dialogfeld ARBEITSGRUPPEN-ADMINISTRATOR. Im Dialogfeld ARBEITSGRUPPEN-ADMINISTRATOR können Sie eine neue Arbeitsgruppe erstellen oder einer der bereits existierenden Arbeitsgruppen beitreten. Wenn Sie auf die Schaltfläche ERSTELLEN klicken, sehen Sie das in Abbildung 33.6 gezeigte Dialogfeld INFORMATIONEN ZUM ARBEITSGRUPPENBESITZER.
Sicherheit auf Benutzerebene einrichten
1117
Abbildung 33.5: Das Dialogfeld Arbeitsgruppen-Administrator
In diesem Dialogfeld können Sie einen Namen, eine Firma und eine ArbeitsgruppenID eingeben, bei der die Groß- und Kleinschreibung zu beachten ist und die verwendet wird, um die Arbeitsgruppe im System eindeutig zu kennzeichnen. Falls Sie keinen eindeutigen Arbeitsgruppenbezeichner festlegen, ist Ihre Datenbank nicht sicher. Wie Sie sehen werden, kann jeder Ihren Namen und Ihre Firma herausfinden. Falls Sie keine Arbeitsgruppenkennung einrichten, kann jeder eine neue SystemInformationsdatei mit Ihrem Namen und Ihrem Unternehmen erstellen und dabei jegliche von Ihnen implementierte Sicherheit nutzlos werden lassen. Es ist wichtig, dass Sie alle Arbeitsgruppen-Informationen an einem sehr sicheren Ort aufzeichnen und speichern, damit Sie im Notfall die Informationen wiederherstellen können. Nachdem Sie die Informationen für den Besitzer der Arbeitsgruppe eingegeben haben, klicken Sie auf OK. Abbildung 33.7 zeigt das daraufhin erscheinende Dialogfeld ARBEITSGRUPPEN-INFORMATIONSDATEI, in dem Sie den Namen und den Speicherort der Arbeitsgruppen-Informationsdatei eingeben müssen.
Abbildung 33.6: Das Dialogfeld Informationen zum Arbeitsgruppenbesitzer
Das Dialogfeld ARBEITSGRUPPEN-INFORMATIONSDATEI ermöglicht es Ihnen, den Namen und den Speicherort der Arbeitsgruppendatei einzugeben. Nachdem Sie den Namen einer neuen Arbeitsgruppendatei eingegeben und auf OK geklickt haben, werden Sie aufgefordert, die Informationen zu bestätigen (siehe Abbildung 33.8). Sie
1118
Kapitel 33: Datenbanksicherheit
Abbildung 33.7: Das Dialogfeld Arbeitsgruppen-Informationsdatei
haben an dieser Stelle eine letzte Gelegenheit, Informationen zu ändern. Klicken Sie auf OK, um die Informationen zu bestätigen. Anschließend wird Ihnen mitgeteilt, dass die Arbeitsgruppe erfolgreich erstellt wurde. Sie können dann auf BEENDEN klicken, um den Arbeitsgruppen-Administrator zu schließen.
Abbildung 33.8: Das Dialogfeld Arbeitsgruppeninformation bestätigen
Sie können den später in diesem Kapitel beschriebenen Datensicherheits-Assistenten verwenden, um eine neue Arbeitsgruppen-Informationsdatei zu erstellen. Der Datensicherheits-Assistent fordert Sie zur Eingabe der Informationen auf, die zum Erstellen der Arbeitsgruppen-Informationsdatei erforderlich sind. Es spielt keine Rolle, ob Sie sich dafür entscheiden, eine Arbeitsgruppen-Informationsdatei mit Hilfe des Arbeitsgruppen-Administrators oder aber mit dem Datensicherheits-Assistenten zu erstellen; die Ergebnisse sind dieselben. Einer anderen Arbeitsgruppe beitreten Wenn verschiedene Gruppen von Benutzern in Ihrer Firma mit völlig unterschiedlichen Anwendungen arbeiten, finden Sie es möglicherweise angebracht, mehrere Arbeitsgruppen-Informationsdateien zu erstellen. Um auf eine Datenbank zuzugreifen, die mit einer bestimmten Arbeitsgruppen-Informationsdatei korrekt gesichert wurde, muss der Benutzer ein Mitglied dieser Arbeitsgruppe sein. Falls derselbe Benutzer Zugriff auf mehrere Datenbanken verlangt, die jeweils einer anderen Arbeitsgruppen-Informationsdatei zugeordnet sind, könnte es für den Benutzer erforderlich sein, einer anderen Arbeitsgruppe beizutreten. Dies kann mit Hilfe des
Sicherheit auf Benutzerebene einrichten
1119
Arbeitsgruppen-Administrators oder durch eine Verknüpfung auf dem Desktop bewerkstelligt werden, die eine bestimmte Datenbank einer Arbeitsgruppendatei zuordnet. Desktop-Verknüpfungen werden eingehend in Kapitel 37 behandelt. Um mittels des Arbeitsgruppen-Administrators einer anderen Arbeitsgruppe beizutreten, führen Sie die folgenden Schritte aus: 1. Starten Sie den Arbeitsgruppen-Administrator. 2. Klicken Sie auf die Schaltfläche BEITRETEN. Daraufhin erscheint das Dialogfeld ARBEITSGRUPPEN-INFORMATIONSDATEI. 3. Suchen Sie den Namen der Arbeitsgruppendatei, der Sie beitreten wollen. Sie können dazu auf die Schaltfläche DURCHSUCHEN klicken. 4. Klicken Sie auf OK. Wie in Abbildung 33.9 zu sehen, erhalten Sie die Meldung, dass Sie sich erfolgreich der Arbeitsgruppe angeschlossen haben. 5. Klicken Sie anschließend auf BEENDEN, um den Arbeitsgruppen-Administrator zu schließen. Abbildung 33.9: Bestätigung, dass einer Arbeitsgruppe erfolgreich beigetreten wurde
33.4.2
Schritt 2: Das Kennwort für den Administrator-Benutzer ändern
Nachdem Sie eine neue Arbeitsgruppe erstellt haben, können Sie nun die Anmeldung für die Arbeitsgruppe durch das Hinzufügen eines Kennworts für den Administrator-Benutzer ändern. Dies ist erforderlich, damit Access Ihnen das Dialogfeld ANMELDEN anzeigt, wenn Sie das Produkt starten. Wenn der Administrator kein Kennwort besitzt, wird dieses Dialogfeld niemals erscheinen. Ohne das Dialogfeld ANMELDEN werden Sie nie in der Lage sein, sich als Sie selbst anzumelden. Um das Kennwort für den Adminstrator-Benutzer zu ändern, starten Sie Access und wählen EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENKONTEN. Daraufhin erscheint das Dialogfeld BENUTZER- UND GRUPPENKONTEN. Es spielt dabei keine Rolle, in welcher Datenbank Sie sich währenddessen befinden. Tatsächlich müssen Sie überhaupt keine Datenbank geöffnet haben, da das Kennwort, welches Sie erstellen, sich auf die Arbeitsgruppen-Informationsdatei und nicht auf eine Datenbank bezieht. Das Dialogfeld BENUTZER- UND GRUPPENKONTEN ermöglicht es Ihnen, Benutzer zu erstellen und zu löschen sowie deren Gruppenzugehörigkeiten zuzuweisen. Außerdem können Sie Gruppen erstellen und löschen sowie ein Anmeldungskennwort für Microsoft Access aufrufen.
1120
Kapitel 33: Datenbanksicherheit
Es ist wichtig zu verstehen, dass Sie Benutzer und Gruppen für die gesamte Arbeitsgruppe festlegen, auch wenn Sie dieses Dialogfeld von einer bestimmten Datenbank aus aufrufen. Das bedeutet, dass Sie, wenn Sie ein Kennwort zuweisen, während Sie ein Mitglied der Standard-Arbeitsgruppe SYSTEM.MDW sind und andere in Ihrem Netzwerk dieselbe System-Arbeitsgruppendatei verwenden, in hohem Maße überrascht sein werden, dass allen Benutzern in Ihrem Netzwerk ein Anmeldungsdialog gezeigt wird, wenn sie versuchen, Access zu starten. Falls Sie dies nicht wollen, müssen Sie eine neue System-Arbeitsgruppendatei erstellen, bevor Sie die Sicherheit einrichten. Wenn Sie sicher sind, der korrekten Arbeitsgruppe anzugehören und das Dialogfeld BENUTZER- UND GRUPPENKONTEN sehen, können Sie nun dem Admin-Benutzer ein Kennwort zuweisen. Klicken Sie in diesem Dialogfeld auf die Registerkarte ANMELDUNGSKENNWORT ÄNDERN, wie in Abbildung 33.10 gezeigt.
Abbildung 33.10: Das Dialogfeld Anmeldungskennwort ändern
Weisen Sie ein neues Kennwort zu und bestätigen Sie es anschließend. (Es gibt kein altes Kennwort, sofern Sie sich nicht das alte Kennwort als Leerzeichen vorstellen.) Klicken Sie dann auf ZUWEISEN, um ein Kennwort für den Administrator-Benutzer einzurichten. Sie sind nun in der Lage, einen neuen Benutzer zu erstellen, der die Datenbank verwalten wird. Falls Sie den Datensicherheits-Assistenten verwenden, um Ihre Datenbank zu sichern, ändert der Assistent das Kennwort für den Admin-Benutzer. Dies gewährleistet, dass der Dialog ANMELDEN erscheint, wenn die vom Datensicherheits-Assistenten erstellte Arbeitsgruppendatei verwendet wird.
Sicherheit auf Benutzerebene einrichten
33.4.3
1121
Schritt 3: Einen Administrator-Benutzer erstellen
Nachdem Sie dem Administrator ein Kennwort zugewiesen haben, können Sie nun einen neuen Administrator-Benutzer erstellen. Sie können dies vom Dialogfeld BENUTZER- UND GRUPPENKONTEN aus durchführen. Access enthält zwei vordefinierte Gruppen: die Administratoren-Gruppe und die Benutzer-Gruppe. Die Administratoren-Gruppe ist das Gruppenkonto des Systemadministrators. Diese Gruppe enthält automatisch ein Mitglied namens Admin. Mitglieder der AdministratorenGruppe besitzen die unwiderrufliche Fähigkeit, Mitgliedschaften von Benutzern und Gruppen zu ändern und Kennwörter zu löschen, so dass jeder, der ein Mitglied der Administratoren-Gruppe ist, in Ihrem System uneingeschränkte Rechte besitzt. Die Administratoren-Gruppe muss zu jedem Zeitpunkt mindestens ein Mitglied enthalten. Es ist besonders wichtig, eine eindeutige Arbeitsgruppen-ID im ArbeitsgruppenAdministrator zu erstellen. Andernfalls können Mitglieder anderer Arbeitsgruppen ihre eigenen Arbeitsgruppendateien erstellen und sich selbst Berechtigungen für Ihre Datenbankobjekte erteilen. Weiterhin ist es wichtig, sicherzustellen, dass der AdminBenutzer nicht Besitzer irgendwelcher Objekte ist und keine expliziten Berechtigungen besitzt. Da der Admin -Benutzer in allen Arbeitsgruppen derselbe ist, stehen alle Objekte jedem zur Verfügung, deren Besitzer Admin ist oder für die er Berechtigungen besitzt, wenn eine andere Kopie von Microsoft Access oder Visual Basic verwendet wird. Das System enthält außerdem bereits eine vordefinierte Gruppe »Benutzer«. Dies ist die Standardgruppe, die sich aus allen Benutzerkonten zusammensetzt. Alle Benutzer werden automatisch der Benutzer-Gruppe hinzugefügt und können aus dieser nicht entfernt werden. Die Gruppe »Benutzer« besitzt alle Berechtigungen für alle Objekte. Genauso wie der Admin-Benutzer ist auch die Benutzer-Gruppe in allen Arbeitsgruppen dieselbe. Es ist deshalb besonders wichtig, dass Sie Maßnahmen ergreifen, um alle Rechte von der Benutzer-Gruppe zu entfernen und somit sicherstellen, dass die Objekte in der Datenbank richtig gesichert sind. Glücklicherweise übernimmt der Datensicherheits-Assistent, der später in diesem Kapitel behandelt wird, die Aufgabe, alle Rechte von der Benutzer-Gruppe zu entfernen. Da Rechte nicht von der Administratoren-Gruppe entfernt werden können und der AdminBenutzer in allen Arbeitsgruppen derselbe ist, muss ein anderer Benutzer erstellt werden. Dieser neue Benutzer wird für die Verwaltung der Datenbank verantwortlich sein. Um einen neuen Benutzer für die Verwaltung der Datenbank zu erstellen, wählen Sie im Dialogfeld BENUTZER- UND GRUPPENKONTEN die Registerkarte BENUTZER. Falls Sie das Dialogfeld nach dem letzten Schritt geschlossen haben, wählen Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENKONTEN. Genauso wie beim Zuweisen des Kennworts für den Admin -Benutzer spielt es auch hier keine Rolle, in welcher Datenbank Sie sich dabei befinden. Es ist lediglich wichtig, dass Sie ein Mitglied der richtigen Arbeitsgruppe sind. Bedenken Sie, dass Sie einen Benutzer für die Arbeitsgruppe
1122
Kapitel 33: Datenbanksicherheit
und nicht für die Datenbank definieren. Abbildung 33.11 zeigt die Registerkarte BENUTZER des Dialogfelds BENUTZER- UND GRUPPENKONTEN. Um einen neuen Administrator-Benutzer einzurichten, klicken Sie auf NEU. Daraufhin erscheint das Dialogfeld NEUE(R) BENUTZER/GRUPPE, welches Sie in Abbildung 33.12 sehen können. Dieses Dialogfeld ermöglicht es Ihnen, den Benutzernamen und eine eindeutige persönliche Identifikationskennung einzugeben. Diese persönliche Identifikationskennung stellt kein Kennwort dar. Der Benutzername und die persönliche Identifikationskennung bilden zusammen die verschlüsselte SID, welche den Benutzer gegenüber dem System eindeutig kennzeichnet. Die Benutzer erstellen ihre eigenen Kennwörter, wenn sie sich beim System anmelden.
Abbildung 33.11: Das Dialogfeld Benutzer- und Gruppenkonten
Abbildung 33.12: Das Dialogfeld Neue(r) Benutzer/Gruppe
Der Datensicherheits-Assistent ermöglicht es Ihnen, einen oder mehrere Administrator-Benutzer für Ihre Datenbank zu erstellen. Tatsächlich erstellt der Datensicherheits-Assistent automatisch einen Benutzer namens Administrator. Dieser Benutzer wird der Besitzer der Datenbank.
Sicherheit auf Benutzerebene einrichten
33.4.4
1123
Schritt 4: Den Administrator-Benutzer als Mitglied der Administratoren-Gruppe definieren
Im nächsten Schritt wird der neue Benutzer als Mitglied der AdministratorenGruppe festgelegt. Dazu wählen Sie im Listenfeld VERFÜGBARE GRUPPEN die Administratoren-Gruppe aus und klicken dann auf HINZUFÜGEN, wobei der neue Benutzer im Listenfeld NAME ausgewählt ist. Der neue Benutzer sollte dann als Mitglied der Administratoren-Gruppe erscheinen, wie in Abbildung 33.13 dargestellt.
Abbildung 33.13: Der Administratoren-Gruppe den neuen Benutzer hinzufügen
Wenn Sie den Datensicherheits-Assistenten verwenden, wird der Benutzer namens Administrator automatisch der Administratoren-Gruppe hinzugefügt. Natürlich können Sie der Administratoren-Gruppe auch andere Benutzer hinzufügen.
33.4.5
Schritt 5: Access beenden und sich als Systemadministrator anmelden
Sie können nun das Dialogfeld BENUTZER- UND GRUPPENKONTEN schließen und Access beenden. Klicken Sie auf OK. Beenden Sie Access und versuchen Sie, das Programm wieder zu starten. Nach dem Versuch, eine Datenbank zu öffnen (oder falls Sie eine neue Datenbank erstellen), gelangen Sie in das in Abbildung 33.14 gezeigte Dialogfeld ANMELDEN. Melden Sie sich als neuer Systemadministrator an. Sie besitzen an dieser Stelle kein Kennwort, sondern nur der Admin-Benutzer besitzt ein Kennwort. Es spielt weiterhin keine Rolle, welche Datenbank geöffnet ist.
1124
Kapitel 33: Datenbanksicherheit
Abbildung 33.14: Das Dialogfeld Anmelden
33.4.6
Schritt 6: Den Administrator-Benutzer aus der AdministratorenGruppe entfernen
Bevor Sie fortfahren, sollten Sie den Administrator-Benutzer aus der Administratoren-Gruppe entfernen. Bedenken Sie, dass der Administrator-Benutzer in jeder Arbeitsgruppe derselbe ist. Da die Administratoren-Gruppe alle Rechte für alle Objekte in der Datenbank besitzt (einschließlich des Rechts, anderen Benutzern und Objekten Berechtigungen zuzuweisen und zu entziehen), wird Ihre Datenbank nicht sicher sein, falls Sie nicht Admin aus der Administratoren-Gruppe entfernen. Um den Administrator-Benutzer aus der Administratoren-Gruppe zu entfernen, führen Sie die folgenden Schritte aus: 1. Wählen Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENKONTEN. 2. Vergewissern Sie sich, dass die Registerkarte BENUTZER ausgewählt ist. 3. Wählen Sie dann aus dem Listenfeld NAME den Administrator-Benutzer aus. 4. Wählen Sie anschließend im Listenfeld MITGLIED VON den Eintrag ADMINISTRATOREN. 5. Klicken Sie danach auf ENTFERNEN. Das Dialogfeld BENUTZER- UND GRUPPENKONTEN erscheint wie in Abbildung 33.15 gezeigt. Wenn Sie den Datensicherheits-Assistenten verwenden, um Ihre Datenbank zu sichern, wird der Administrator-Benutzer automatisch aus der AdministratorenGruppe entfernt. Tatsächlich macht der Datensicherheits-Assistent den AdminBenutzer zu keinem Mitglied einer anderen als der Benutzer-Gruppe (die Gruppe, in der alle Benutzer Mitglieder sein müssen).
33.4.7
Schritt 7: Dem Systemadministrator ein Kennwort zuweisen
Nachdem Sie sich nun als neuer Administrator angemeldet haben, sollten Sie Ihr Kennwort ändern. Falls Sie das Dialogfeld BENUTZER- UND GRUPPENKONTEN geschlossen haben, wählen Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENKONTEN. Klicken Sie dann auf die Registerkarte ANMELDUNGSKENNWORT ÄNDERN. Bedenken Sie, dass Sie nur demjenigen Benutzer ein Kennwort zuweisen können, als der Sie sich angemeldet haben.
Sicherheit auf Benutzerebene einrichten
1125
Abbildung 33.15: Den Administrator aus der Administratoren-Gruppe entfernen
Einer der wirklich angenehmen Aspekte des Datensicherheits-Assistenten besteht darin, dass er es Ihnen ermöglicht, Kennwörter für alle Benutzer zuzuweisen, die Mitglieder der Arbeitsgruppe sind. Dadurch können Sie einiges an Zeit und Aufwand sparen, wenn Sie eine große Anzahl von Benutzern einrichten.
33.4.8
Schritt 8: Die Datenbank öffnen, die Sie schützen wollen
Nach all diesen Maßnahmen können Sie jetzt tatsächlich die Datenbank sichern. Bis zu diesem Zeitpunkt spielte es keine Rolle, welche Datenbank Sie geöffnet hatten. Alles, was Sie bislang getan haben, galt für die Arbeitsgruppe und nicht für eine bestimmte Datenbank. Öffnen Sie nun die Datenbank, die Sie sichern wollen. Im Moment ist der Admin-Benutzer Besitzer der Datenbank und Mitglieder der BenutzerGruppe besitzen Rechte auf alle Objekte in der Datenbank.
33.4.9
Schritt 9: Den Datensicherheits-Assistenten ausführen
Sofern Sie nicht eine brandneue Datenbank erstellen, nachdem Sie alle vorherigen Schritte ausgeführt haben, ist das erste, was Sie tun sollten, um eine vorhandene Datenbank zu sichern, den Datensicherheits-Assistenten zu verwenden. Der Datensicherheits-Assistent ermöglicht es Ihnen, die folgenden Aufgaben auszuführen:
eine Arbeitsgruppen-Informationsdatei erstellen die Datenbankobjekte festlegen, die Sie sichern möchten ein Kennwort für das Visual Basic-Projekt zuweisen auswählen aus vordefinierten Gruppen, die der Assistent erstellt
1126
Kapitel 33: Datenbanksicherheit
den Benutzergruppen gewünschte Rechte zuweisen Benutzer erstellen Gruppen Benutzer zuweisen eine ungeschützte Sicherungskopie Ihrer Datenbank erstellen Um den Datensicherheits-Assistent zu starten, wählen Sie EXTRAS | SICHERHEIT | BENUTZERDATENSICHERHEITS-ASSISTENT. Daraufhin erscheint der erste Schritt des Datensicherheits-Assistenten, der in Abbildung 33.16 zu sehen ist.
Abbildung 33.16: Im ersten Schritt des Datensicherheits-Assistenten müssen Sie eine existierende Arbeitsgruppendatei auswählen oder eine neue ArbeitsgruppenInformationsdatei erstellen
Im ersten Schritt des Datensicherheits-Assistenten müssen Sie eine vorhandene Arbeitsgruppen-Informationsdatei auswählen oder eine neue Arbeitsgruppen-Informationsdatei erstellen. Klicken Sie auf WEITER, um zum zweiten Schritt des Datensicherheits-Assistenten zu gelangen (siehe Abbildung 33.17). Der zweite Schritt fordert Sie auf, die benötigte Information über die Arbeitsgruppen-Informationsdatei anzugeben, die Sie erstellen. Sie werden aufgefordert, einen Dateinamen, eine Arbeitsgruppen-ID (AID), Ihren Namen und den Namen Ihres Unternehmens einzugeben. Sie können die neue Arbeitsgruppendatei als Standardarbeitsgruppendatei auf Ihrem Rechner festlegen oder Access eine Verknüpfung zur gesicherten Datenbank erstellen lassen einschließlich des Namen und des Pfads zur Arbeitsgruppendatei. Der dritte Schritt des Datensicherheits-Assistenten, der in Abbildung 33.18 zu sehen ist, ermöglicht es Ihnen, die Objekte auszuwählen, die Sie schützen wollen. Beachten
Sicherheit auf Benutzerebene einrichten
1127
Abbildung 33.17: Im zweiten Schritt des Datensicherheits-Assistenten müssen Sie die erforderlichen Informationen über die ArbeitsgruppenInformationsdatei eingeben
Sie, dass Sie alle Objekte oder ganz bestimmte Tabellen, Abfragen, Formulare, Berichte oder Makros absichern können. Module sowie der den Formularen und Berichten zu Grunde liegende Code werden separat gesichert. Der vierte Schritt des Datensicherheits-Assistenten ermöglicht es Ihnen, ein VBE-Kennwort festzulegen. Dieses VBE-Kennwort sichert das VBA-Projekt, das alle Code-Module in der Datenbank einschließlich des den Formularen und Berichten zu Grunde liegenden Codes enthält. Der fünfte Schritt des Datensicherheits-Assistenten, der in Abbildung 33.19 dargestellt ist, ermöglicht es Ihnen, auf einfache Weise Gruppenkonten zu erstellen. Wenn Ihre Sicherheitsanforderungen mit denen von einer der Standardgruppen vordefinierten übereinstimmen, können Sie erheblich Zeit sparen, indem Sie den Datensicherheits-Assistenten die erforderlichen Gruppen für Sie erstellen lassen. Beispiele für vordefinierte Gruppen sind Benutzer, die nur die Berechtigung zum Lesen besitzen und alle Daten lesen, aber nicht die Daten oder den Entwurf von Datenbankobjekten ändern können, sowie Projektentwickler, die alle Daten und den Entwurf von Anwendungsobjekten bearbeiten, aber nicht die Struktur von Tabellen oder Beziehungen ändern können. Im sechsten Schritt des Datensicherheits-Assistenten, der in Abbildung 33.20 zu sehen ist, legen Sie fest, welche Berechtigungen Sie der Benutzer-Gruppe erteilen wollen. Dabei darf nicht vergessen werden, dass alle Benutzer Mitglieder der Benutzer-Gruppe sind. Deshalb gelten alle Berechtigungen, die Sie der Benutzer-Gruppe erteilen, für alle Benutzer Ihrer Anwendung. Als allgemeine Regel empfehle ich, der
1128
Kapitel 33: Datenbanksicherheit
Abbildung 33.18: Der dritte Schritt des Datensicherheits-Assistenten ermöglicht es Ihnen, die Objekte auszuwählen, die Sie absichern wollen
Abbildung 33.19: Der fünfte Schritt des Datensicherheits-Assistenten ermöglicht es Ihnen, anhand einer Liste von vordefinierten Gruppenkonten Gruppen zu erstellen
Benutzer-Gruppe überhaupt keine Rechte zuzuweisen. Es ist vielmehr besser, anderen Gruppen Rechte zuzuweisen und dann bestimmte Benutzer als Mitglieder dieser Gruppen zu definieren.
Sicherheit auf Benutzerebene einrichten
1129
Abbildung 33.20: Im sechsten Schritt des Datensicherheits-Assistenten können Sie der Benutzergruppe bestimmte Rechte erteilen
Der siebente Schritt des Datensicherheits-Assistenten ermöglicht es Ihnen, die Benutzer zu definieren, die Ihre Datenbank verwenden werden. In diesem Schritt des Assistenten geben Sie für jeden Benutzer einen Namen, ein Kennwort und eine eindeutige persönliche Identifikationskennung oder PID ein (siehe Abbildung 33.21). Um einen Benutzer hinzuzufügen, geben Sie den Namen, das Kennwort und die PID ein und klicken dann auf BENUTZER ZUR LISTE HINZUFÜGEN. Um einen Benutzer zu löschen, klicken Sie den Benutzer an, den Sie löschen wollen und wählen dann BENUTZER VON DER LISTE LÖSCHEN. Klicken Sie auf WEITER, sobald Sie alle Benutzer definiert haben. Im achten Schritt des Datensicherheits-Assistenten weisen Sie die in Schritt 7 erstellten Benutzer den in Schritt 5 festgelegten Gruppen zu. Um einer Gruppe einen Benutzer zuzuweisen, klicken Sie auf WÄHLEN SIE EINEN BENUTZER AUS UND WEISEN SIE DIESEN EINER GRUPPE ZU. Wählen Sie dann aus dem Listenfeld GRUPPENODER BENUTZERNAME einen Benutzer aus. Klicken Sie anschließend die vordefinierten Gruppen an, denen Sie die ausgewählten Benutzer hinzufügen wollen (siehe Abbildung 33.22). Im letzten Schritt des Datensicherheits-Assistenten müssen Sie den Namen der Backup-Kopie der ungesicherten Datenbank eingeben. Nachdem Sie auf FERTIG STELLEN geklickt haben, ist die existierende Datenbank gesichert und die ursprüngliche ungesicherte Datenbank erhält den für das Backup festgelegten Namen.
1130
Kapitel 33: Datenbanksicherheit
Abbildung 33.21: Der siebente Schritt des Datensicherheits-Assistenten ermöglicht es Ihnen, die Benutzer Ihrer Datenbank zu definieren
Abbildung 33.22: Im achten Schritt des Datensicherheits-Assistenten können Sie Gruppen Benutzer zuweisen
Der Besitzer einer Datenbank kann nicht geändert werden und besitzt immer sämtliche Rechte in der Datenbank. Da der Administrator der Besitzer der Datenbank und in allen Arbeitsgruppen derselbe ist, muss Access alle Datenbankobjekte in eine neue
Sicherheit auf Benutzerebene einrichten
1131
sichere Datenbank kopieren, deren Besitzer der neue Benutzer ist. Der Assistent ist intelligent genug, eine neue sichere Datenbank mit dem ursprünglichen Datenbanknamen sowie ein Backup mit dem von Ihnen angegebenen Namen zu erstellen. Access verändert in keiner Weise die bestehende, nicht geschützte Datenbank. Wenn der Prozess abgeschlossen ist, erscheint der in Abbildung 33.23 gezeigte Sicherheitsbericht.
Abbildung 33.23: Der Bericht des Datensicherheits-Assistenten ist das Ergebnis einer erfolgreich abgeschlossenen Ausführung des Datensicherheits-Assistenten
Nach Beendigung des Vorgangs liefert der Datensicherheits-Assistent Ihnen einen Bericht, der detaillierte Informationen über die erstellte Arbeitsgruppe, die gesicherten Objekte sowie die erstellten Gruppen und Benutzer enthält. Der neue Systemadministrator ist Besitzer der neuen Kopie der Datenbank. Der Benutzer-Gruppe wurden alle Rechte entzogen. Wenn Sie den Bericht schließen, werden Sie aufgefordert, ihn als Momentaufnahme (Snapshot) zu speichern, so dass Sie den Bericht später wieder betrachten können. Da der Bericht wertvolle Informationen über die Arbeitsgruppe und die gesicherte Datenbank enthält, empfehle ich sehr, dass Sie den Bericht speichern. Wenn Sie den Bericht speichern, vergewissern Sie sich, dass Sie ihn an einem sehr sicheren Ort speichern. Mit den im Bericht enthaltenen Informationen ausgestattet könnte ein schlauer Benutzer die Sicherheit Ihrer Datenbank verletzen.
33.4.10 Schritt 10: Benutzer und Gruppen erstellen Nachdem Sie eine Arbeitsgruppe eingerichtet haben und dieser beigetreten sind, können Sie zu jedem beliebigen Zeitpunkt die Benutzer und Gruppen einrichten, die
1132
Kapitel 33: Datenbanksicherheit
Mitglieder der Arbeitsgruppe sein werden. Benutzer repräsentieren einzelne Personen, die auf Ihre Datenbankdateien zugreifen werden. Benutzer sind Mitglieder von Gruppen. Gruppen wiederum sind Kategorien von Benutzern, welche dieselben Rechte besitzen. Rechte können auf Benutzer- oder auf Gruppenebene zugewiesen werden. Unter dem Aspekt der Verwaltung ist es einfacher, alle Rechte auf Gruppenebene zuzuweisen. Dieses Vorgehen beinhaltet jedoch das Kategorisieren der Zugriffsrechte in logische Gruppen und das anschließende Zuweisen von Benutzern zu diesen Gruppen. Wenn Gruppen vernünftig eingerichtet worden sind, wird die Verwaltung des Systems erheblich vereinfacht. Wenn Rechte einer Kategorie von Benutzern geändert werden müssen, können sie auf der Gruppenebene geändert werden. Falls ein Benutzer befördert wird und zusätzliche Rechte benötigt, können Sie diesen Benutzer als Mitglied einer neuen Gruppe festlegen. Das ist wesentlich einfacher, als zu versuchen, für jeden Benutzer getrennte Rechte zu verwalten. Sie können Benutzer und Gruppen mit Hilfe von Front-End-Schnittstellenwerkzeugen oder durch VBA-Code hinzufügen, ändern und entfernen. Dieses Kapitel behandelt, wie Benutzer und Gruppen mittels der Front-End-Schnittstellenwerkzeuge verwaltet werden. Kapitel 34 erläutert, wie Benutzer und Gruppen mit Hilfe von Code verwaltet werden. Unabhängig davon, wie Sie beschließen, Gruppen und Benutzer zu definieren, sollten Sie im Allgemeinen erst Gruppen erstellen und dann die Benutzer den entsprechenden Gruppen zuweisen. Es ist wichtig, die Struktur Ihres Unternehmens sowie Ihrer Anwendung zu beurteilen, bevor Sie den mechanischen Prozess des Hinzufügens der Gruppen und Benutzer beginnen. Gruppen hinzufügen Um eine neue Gruppe hinzufügen, führen Sie die folgenden Schritte aus: 1. Vergewissern Sie sich zunächst, dass Sie der korrekten Arbeitsgruppe angehören. Wählen Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENKONTEN, wobei es keine Rolle spielt, ob gerade eine Datenbank geöffnet ist. 2. Klicken Sie auf die Registerkarte GRUPPEN des Dialogfelds BENUTZERGRUPPENKONTEN.
UND
3. Klicken Sie auf NEU. Daraufhin erscheint das Dialogfeld NEUE(R) BENUTZER/ GRUPPE. 4. Geben Sie den Namen der Gruppe und eine PID ein, welche die Gruppe eindeutig kennzeichnet. 5. Klicken Sie auf OK. 6. Wiederholen Sie die Schritte 3-5 für jede Gruppe, die Sie hinzufügen möchten.
Sicherheit auf Benutzerebene einrichten
1133
Die persönliche Identifikationskennung (PID) ist eine Groß- und Kleinschreibung unterscheidende alphanumerische Zeichenkette, die eine Länge von vier bis 20 Zeichen besitzen kann. Zusammen mit dem Benutzer- oder Gruppennamen kennzeichnet die PID den Benutzer oder die Gruppe eindeutig in einer Arbeitsgruppe. PID-Nummern sollten an einem sehr sicheren Ort gespeichert sein. Geraten diese Informationen in die falschen Hände, kann der Zugriff auf die PID zu einer Sicherheitslücke führen. Falls auf der anderen Seite die Datenbank beschädigt und eine wichtige PID nicht verfügbar ist, kann auf die Daten und Objekte in der Datenbank selbst von Benutzern mit größtmöglicher Berechtigung nicht zugegriffen werden. Benutzer hinzufügen Um über die Benutzerschnittstelle Benutzer hinzuzufügen, führen Sie die folgenden Schritte aus: 1. Wählen Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENKONTEN. 2. Klicken Sie auf die Registerkarte BENUTZER, sofern sie nicht bereits ausgewählt ist. 3. Klicken Sie auf NEU. Daraufhin erscheint das Dialogfeld NEUE(R) BENUTZER/ GRUPPE. 4. Geben Sie den Namen des Benutzers und die dem Benutzer zugeordnete PID ein. Bedenken Sie, dass diese kein Kennwort darstellt, sondern zusammen mit dem Benutzernamen eine eindeutige Kennzeichnung für den Benutzer bildet. 5. Klicken Sie auf OK. 6. Wiederholen Sie die Schritte 3-5 für jeden Benutzer, den Sie definieren wollen. Benutzer den geeigneten Gruppen zuweisen Bevor Sie mit dem letzten Schritt fortfahren, Benutzern und Gruppen Rechte zuzuweisen, sollten Sie jeden Benutzer als Mitglied der geeigneten Gruppe definieren. Sie können einen Benutzer als Mitglied von vielen Gruppen definieren, aber denken Sie daran, dass jeder Benutzer die Rechte seiner am wenigsten einschränkenden Gruppe erhält. Mit anderen Worten, falls ein Benutzer Mitglied sowohl der AdministratorenGruppe als auch einer Gruppe mit der Berechtigung »Nur Lesen« ist, haben die Rechte der Administratoren-Gruppe Vorrang. Um jeden Benutzer der geeigneten Gruppe zuzuweisen, führen Sie die folgenden Schritte aus: 1. Wählen Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENKONTEN. 2. Klicken Sie auf die Registerkarte BENUTZER, sofern diese nicht bereits aktiviert ist. 3. Wählen Sie im Listenfeld NAME den Benutzer aus, für den Sie die Gruppenmitgliedschaft definieren möchten.
1134
Kapitel 33: Datenbanksicherheit
4. Klicken Sie doppelt auf den Namen der Gruppe, zu der Sie den Benutzer hinzufügen möchten, oder klicken Sie einmal auf die Gruppe und dann auf die Schaltfläche HINZUFÜGEN. 5. Wiederholen Sie die Schritte 3 und 4 für jeden Benutzer, dem Sie Gruppenmitgliedschaften zuweisen wollen. Die Abbildung 33.24 zeigt einen Benutzer namens Dan, welcher der Gruppe »Vollständige Berechtigungen« hinzugefügt wurde. Bedenken Sie, dass die von Ihnen erstellten Benutzer und Gruppen für die Arbeitsgruppe als Ganzes und nicht nur für eine bestimmte Datenbank gelten.
Abbildung 33.24: Einen Benutzer der geeigneten Gruppe zuweisen
33.4.11 Schritt 11: Benutzern und Gruppen Rechte zuweisen Bis jetzt haben Sie Gruppen und Benutzer erstellt, aber Sie haben Ihren Gruppen oder Benutzern noch keine Rechte in Bezug auf Objekte in der Datenbank erteilt. Die Lösung besteht darin, jeder Gruppe bestimmte Rechte zuzuweisen und dann sicherzustellen, dass alle Benutzer Mitglieder der geeigneten Gruppen sind. Danach können Sie jeder Gruppe bestimmte Berechtigungen für die Objekte in Ihrer Datenbank zuweisen. Die Benutzer- und Gruppeninformationen werden in der Systemdatenbank verwaltet, die Berechtigungen für Objekte sind in Systemtabellen in der Anwendungsdatenbankdatei (MDB) gespeichert. Nachdem Sie eine Arbeitsgruppe
Sicherheit auf Benutzerebene einrichten
1135
von Benutzern und Gruppen eingerichtet haben, müssen Sie Rechte auf bestimmte Objekte in Ihrer Datenbank zuweisen, indem Sie die folgenden Schritte ausführen: 1. Vergewissern Sie sich, dass die Datenbank geöffnet ist, welche die Objekte enthält, die Sie schützen wollen. 2. Wählen Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENBERECHTIGUNGEN. Daraufhin erscheint das in Abbildung 33.25 dargestellte Dialogfeld. Wenn Sie auf jeden Benutzer im Feld BENUTZER-/GRUPPENNAME klicken, können Sie anhand der Kontrollkästchen im Bereich BERECHTIGUNGEN des Dialogfelds feststellen, dass nur der Administrator Rechte auf alle Objekte besitzt. Der Datensicherheits-Assistent hat automatisch alle Berechtigungen vom Benutzer namens Admin entfernt. Wenn Sie die Option GRUPPEN wählen, können Sie erkennen, dass nur die Administratoren-Gruppe alle Rechte besitzt. (Falls Sie zuvor den Datensicherheits-Assistenten ausgeführt und andere Benutzer und Gruppen hinzugefügt haben, werden diese ebenfalls Rechte besitzen.) 3. Um einer Gruppe Rechte zuzuweisen, wählen Sie die Optionsschaltfläche GRUPPEN. Daraufhin erscheinen im FELD BENUTZER/GRUPPENNAME alle verfügbaren Gruppen. 4. Aus der Liste OBJEKTTYP wählen Sie dann den Objekttyp aus, den Sie sichern wollen. 5. Wählen Sie anschließend im Listenfeld OBJEKTNAME die Namen der Objekte aus, denen Sie Rechte zuweisen wollen. Sie können durch Betätigen der Tasten Strg und Umsch mehrere Objekte auswählen. 6. Aktivieren Sie die entsprechenden Kontrollkästchen im Bereich BERECHTIGUNGEN, um Berechtigungen für die Objekte auszuwählen. Die Typen der verfügbaren Berechtigungen werden im Folgenden erläutert. 7. Wiederholen Sie die Schritte 4-6 für alle Objekte, denen Sie Rechte zuweisen wollen. Es ist zu empfehlen, dass Sie Gruppen die Rechte für Objekte zuweisen und dann einfach Benutzer als Mitglieder der entsprechenden Gruppen festlegen. Beachten Sie, dass Sie die Liste der Objekttypen verwenden können, um die verschiedenen Typen von Objekten zu betrachten, aus denen sich Ihre Datenbank zusammensetzt. Um Berechtigungen in geeigneter Weise erteilen zu können, ist es wichtig, dass Sie die verschiedenen Berechtigungstypen, die zur Verfügung stehen, sowie die Aktionen kennen, welche der Benutzer mit der jeweiligen Berechtigung ausführen kann. In Tabelle 33.1 sind die Typen der verfügbaren Berechtigungen aufgeführt.
1136
Kapitel 33: Datenbanksicherheit
Abbildung 33.25: Das Dialogfeld Benutzer- und Gruppenberechtigungen Berechtigung
Erlaubt dem Benutzer
Öffnen/Ausführen
Öffnen einer Datenbank, eines Formulars oder Berichts oder Ausführen eines Makros
Exklusiv öffnen
Öffnen einer Datenbank mit exklusivem Zugriff
Entwurf lesen
Betrachten von Tabellen, Abfragen, Formularen, Berichten, Makros und Modulen in der Entwurfsansicht
Entwurf ändern
Betrachten und Ändern des Entwurfs von Tabellen, Abfragen, Formularen, Berichten, Makros und Modulen
Verwalten
Festlegen des Datenbank-Kennworts, Replizieren der Datenbank und Ändern der Starteigenschaften (wenn der Benutzer die Berechtigung »Verwalten« für eine Datenbank besitzt). Vollständiger Zugriff auf das Objekt und seine Daten (wenn der Benutzer die Berechtigung »Verwalten« für ein Datenbankobjekt besitzt – wie zum Beispiel eine Tabelle, Abfrage, ein Formular, Bericht, Makro oder Modul). Zuweisen von Berechtigungen für dieses Objekt an andere Benutzer (wenn der Benutzer die Berechtigung »Verwalten« für ein Objekt besitzt)
Daten lesen
Betrachten der Daten in einer Tabelle oder Abfrage
Daten aktualisieren
Betrachten und Ändern von Tabellen- oder Abfragedaten. Jedoch kein Einfügen und Löschen von Datensätzen möglich
Tabelle 33.1: Berechtigungen zuweisen
Eine zusätzliche Sicherheitsebene bereitstellen: Eine MDE-Datei erstellen
Berechtigung
Erlaubt dem Benutzer
Daten einfügen
Hinzufügen von Datensätzen zu einer Tabelle oder Abfrage
Daten löschen
Löschen von Datensätzen in einer Tabelle oder Abfrage
1137
Tabelle 33.1: Berechtigungen zuweisen (Forts.)
Einige dieser Berechtigungen umfassen implizit andere zugeordnete Berechtigungen. Ein Benutzer kann beispielsweise nicht Daten in einer Tabelle aktualisieren, wenn er oder sie nicht die Rechte zum Lesen der Daten und des Entwurfs der Tabelle besitzt, in der sich diese Daten befinden.
33.5
Eine zusätzliche Sicherheitsebene bereitstellen: Eine MDE-Datei erstellen
Access 2000 bietet durch das Erstellen einer MDE-Datei eine zusätzliche Ebene der Sicherheit an. Eine »MDE-Datei« ist eine Datenbankdatei, aus welcher der gesamte bearbeitbare Quellcode entfernt wurde. Das bedeutet, dass der den Formularen, Berichten und Modulen in der Datenbank zu Grunde liegende Quellcode vollständig entfernt wird. Eine MDE-Datei bietet zusätzliche Sicherheit, da die Formulare, Berichte und Module in einer MDE-Datei nicht geändert werden können. Andere Vorteile einer MDE-Datei sind eine geringere Größe und eine optimierte Speicherausnutzung. Um eine MDE-Datei zu erstellen, sind die folgenden Schritte erforderlich: 1. Öffnen Sie die Datenbank, auf der die MDE-Datei basieren wird. 2. Wählen Sie EXTRAS | DATENBANK-DIENSTPROGRAMME | MDE-DATEI LEN. Daraufhin erscheint das Dialogfeld MDE SPEICHERN UNTER.
ERSTEL-
3. Wählen Sie einen Namen für die MDE und klicken Sie anschließend auf OK. Bevor Sie sich eingehender mit MDEs befassen, ist es wichtig, dass Sie sich der damit verbundenen Einschränkungen bewusst sind. Wenn Sie im Voraus planen, werden diese Einschränkungen wahrscheinlich nicht allzu viele Probleme verursachen. Wenn Sie dagegen die Welt der MDEs unwissend betreten, können sie Ihnen viele Sorgen bereiten. Sie sollten an die folgenden Einschränkungen denken:
Der Entwurf der Formulare, Berichte und Module in einer MDE-Datei kann nicht betrachtet oder geändert werden. Tatsächlich können neue Formulare, Berichte und Module nicht zu einer MDE hinzugefügt werden. Es ist deshalb von Bedeutung, die ursprüngliche Datenbank zu speichern, wenn Sie eine MDEDatei erstellen. In der Original-Datenbank nehmen Sie Änderungen an bestehenden Formularen, Berichten und Modulen vor und fügen neue Formulare, Berichte und Module hinzu. Wenn Sie diese Vorgänge abgeschlossen haben, können Sie einfach die MDE neu erstellen.
1138
Kapitel 33: Datenbanksicherheit
Da Sie die MDE jedesmal neu erstellen müssen, wenn Änderungen an der Anwendung vorgenommen werden, ist der Front-End/Back-End-Ansatz der geeignetste beim Umgang mit MDE-Dateien. Das bedeutet, dass die Tabellen in einer standardmäßigen Access-Datenbank enthalten und die anderen Objekte in der MDE-Datei gespeichert sind. Sie können deshalb die MDE neu erstellen, ohne sich Gedanken um die Datensynchronisierung machen zu müssen.
Sie können Formulare, Berichte oder Module nicht in oder aus einer MDE importieren oder exportieren.
Sie können nicht Code ändern, indem Sie Eigenschaften oder Methoden der Access- oder VBA-Objektmodelle verwenden, da MDEs keinen Code enthalten.
Sie können nicht den VBA-Projektnamen der Datenbank ändern. Sie können eine MDE nicht in zukünftige Versionen von Access konvertieren. Es wird erforderlich sein, die Original-Datenbank zu konvertieren und dann die MDE-Datei mit der neuen Version zu erstellen.
Sie können nicht Verweise auf Objektbibliotheken und Datenbanken in einer MDE-Datei hinzufügen oder entfernen. Ebenso können Sie nicht Verweise auf Objektbibliotheken und Datenbanken ändern.
Jede Bibliotheksdatenbank, auf die eine MDE verweist, muss ebenfalls eine MDE sein. Das bedeutet, dass alle drei Datenbanken als MDEs gespeichert sein müssen, wenn Datenbank1 auf Datenbank2 verweist, welche wiederum auf Datenbank3 verweist. Sie müssen zunächst Datenbank3 als MDE speichern, dann von Datenbank2 aus auf sie verweisen und anschließend Datenbank2 als MDE speichern. Danach können Sie von Datenbank1 auf Datenbank2 verweisen und schließlich Datenbank1 als MDE speichern.
Eine replizierte Datenbank kann nicht als MDE gespeichert werden. Die Replikation muss zunächst aus der Datenbank entfernt werden. Das wird erreicht, indem die Replikations-Systemtabellen und -eigenschaften aus der Datenbank entfernt werden. Die Datenbank kann dann als MDE gespeichert werden und die MDE kann repliziert und als Replikatgruppe verfügbar gemacht werden. Jedesmal wenn Änderungen an der Datenbank vorgenommen werden müssen, müssen sie an der Original-Datenbank vorgenommen, erneut als MDE-Datei gespeichert und dann als neue Replikatgruppe wieder zur Verfügung gestellt werden.
Alle Sicherheitsregeln, die für eine Datenbank gelten, sind auch für eine aus dieser Datenbank erstellte MDE-Datei gültig. Um eine MDE aus einer bereits geschützten Datenbank zu erstellen, müssen Sie zunächst der ArbeitsgruppenInformationsdatei beitreten, die der Datenbank zugeordnet ist. Sie müssen für die Datenbank die Berechtigungen Öffnen/Ausführen und Exklusiv öffnen besitzen. Außerdem müssen Sie für alle Tabellen in der Datenbank die Berechtigungen Entwurf ändern und Verwalten besitzen oder Besitzer aller Tabellen in der Daten-
Spezielle Fragestellungen
1139
bank sein. Schließlich müssen Sie für alle in der Datenbank enthaltenen Objekte die Berechtigung zum Lesen des Entwurfs haben.
Falls dem Code innerhalb einer MDE keine Fehlerbehandlung hinzugefügt wurde und ein Fehler auftritt, erscheint keine Fehlermeldung.
Wenn Sie Sicherheitsfunktionen aus der Datenbank entfernen wollen, müssen Sie die Sicherheitsfunktionen aus der Orginal-Datenbank entfernen und die MDE neu erstellen. Solange Sie sich der mit MDEs verbundenen Einschränkungen bewusst sind, können Ihnen MDEs viele Vorteile bieten. Zusätzlich zur natürlichen Sicherheit, die sie bieten, sind die Vorteile hinsichtlich Größe und Leistungsfähigkeit erheblich. MDEs können sehr gut für Demoversionen Ihrer Anwendungen eingesetzt werden. Die Leistung von MDEs ist hervorragend, aber was noch wichtiger ist: Mit Hilfe von VBA-Code können MDEs leicht sowohl zeit- als auch datenbeschränkt gestaltet werden.
33.6
Spezielle Fragestellungen
Obwohl die Erläuterung der Sicherheitsaspekte bislang schon recht gründlich war, wurden ein paar Punkte noch nicht behandelt, welche die Grundlagen der Sicherheitsthematik umgeben. Dazu gehören zusätzliche Aspekte in Bezug auf Kennwörter, Sicherheit im Zusammenhang mit verknüpften Tabellen, Besitzer von Objekten und das Drucken von Sicherheitsinformationen. Diese Themen werden in diesem Abschnitt erörtert.
33.6.1
Kennwörter
Wenn Sie einen Benutzer erstellen, ist diesem Benutzer kein Kennwort zugewiesen. Kennwörter können einem Benutzer nur zugewiesen werden, wenn dieser Benutzer sich im System angemeldet hat. Der Systemadministrator kann das Kennwort eines Benutzers nicht hinzufügen oder ändern. Es ist wichtig, Benutzer zu ermutigen, sich selbst ein Kennwort zuzuweisen, wenn sie sich zum ersten Mal im System anmelden. Mit Hilfe von VBA-Code können die Benutzer gezwungen werden, sich selbst ein Kennwort zuzuweisen. Dies wird in Kapitel 24 behandelt. Alternativ kann der Administrator der Datenbank sich unter jedem Benutzernamen anmelden und jeweils ein Kennwort zuweisen. Obwohl Sie einem Benutzer kein Kennwort zuweisen oder es ändern können, sind Sie jedoch in der Lage, das Kennwort zu löschen. Dies ist notwendig, wenn ein Benutzer sein Kennwort vergisst. Um das Kennwort eines Benutzers zu löschen, führen Sie die folgenden Schritte aus:
1140
Kapitel 33: Datenbanksicherheit
1. Wählen Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENKONTEN, wobei es keine Rolle spielt, ob gerade eine Datenbank geöffnet ist. 2. Wählen Sie aus der Liste NAMEN den Benutzer aus, dessen Kennwort Sie löschen wollen. 3. Klicken Sie auf KENNWORT löschen.
33.6.2
LÖSCHEN,
um das Kennwort des Benutzers zu
Sicherheit und verknüpfte Tabellen
Wenn Sie Ihre Anwendung mit zwei Datenbanken entwerfen (eine für Tabellen und die andere für die restlichen Anwendungsobjekte), ist es notwendig, dass Sie beide Datenbanken schützen. Das Sichern nur der verknüpften Tabellen ist nicht ausreichend! Ein potentielles Problem existiert noch. Wenn ein Benutzer Daten in Ihrer Anwendung hinzufügen, löschen und ändern darf, kann dieser Benutzer die Datenbank, welche die Datentabellen enthält, von außerhalb Ihrer Anwendung öffnen und die Daten ändern, ohne sich in den von Ihnen entworfenen Formularen und Berichten befinden zu müssen. Eine Lösung dieses Problems besteht darin, alle Rechte für die Tabellen zu widerrufen. Bauen Sie alle Formulare und Berichte auf Abfragen auf, deren Eigenschaft Ausführungsberechtigungen auf Besitzer gesetzt wurde. Dadurch ist es für Benutzer kaum noch möglich, die Daten von außerhalb Ihres Systems zu ändern.
33.6.3
Der Besitzer
Bedenken Sie, dass der Benutzer, welcher die Datenbank erstellt, der Besitzer der Datenbank ist. Dieser Benutzer besitzt unwiderrufliche Rechte für die Datenbank. Sie können den Besitzer einer Datenbank nicht ändern, sondern lediglich die Besitzer von Objekten in der Datenbank. Sie können den Besitzer einer Datenbank ändern, falls Sie Rechte in Bezug auf die Objekte besitzen, indem Sie eine neue Datenbank erstellen und alle Objekte aus der anderen Datenbank importieren. Sie können dies mit Hilfe des Datensicherheits-Assistenten durchführen. Standardmäßig ist der Ersteller jedes Objekts in der Datenbank der Besitzer dieses Objekts. Um den Besitzer eines Objekts in der Datenbank zu ändern, führen Sie die folgenden Schritte aus: 1. Wählen Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENBERECHTIGUNGEN, wobei die entsprechende Datenbank geöffnet ist. 2. Klicken Sie auf die Registerkarte BESITZER ÄNDERN (siehe Abbildung 33.26). 3. Wählen Sie im Listenfeld OBJEKTTYP die Objekte, deren Besitzer Sie ändern möchten. Sie können die Tasten STRG und Umschalt betätigen, um mehrere Objekte auszuwählen.
Spezielle Fragestellungen
1141
Abbildung 33.26: Den Besitzer eines Objekts ändern
4. Wählen Sie die Optionsschaltfläche GRUPPEN oder BENUTZER. 5. Wählen Sie den Namen der Gruppe oder des Benutzers aus, die bzw. der zum neuen Besitzer der Objekte wird. 6. Klicken Sie auf BESITZER ÄNDERN. 7. Wiederholen Sie die Schritte 3-7 für alle Objekte, denen Sie einen neuen Besitzer zuweisen wollen.
33.6.4
Zugriffsrechte drucken
Sie können eine Liste aller Benutzer und den Gruppen drucken, in denen Sie Mitglieder sind, indem Sie diese Schritte ausführen: 1. Wählen Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENKONTEN, wobei die entsprechende Datenbank geöffnet ist. 2. Klicken Sie auf BENUTZER UND GRUPPEN DRUCKEN. Daraufhin erscheint das Dialogfeld ZUGRIFFSRECHTE DRUCKEN, das in Abbildung 33.27 zu sehen ist. 3. Wählen Sie eine der Optionen BENUTZER NUR GRUPPEN. 4. Klicken Sie anschließend auf OK.
UND
GRUPPEN, NUR BENUTZER oder
1142
Kapitel 33: Datenbanksicherheit
Abbildung 33.27: Das Dialogfeld Zugriffsrechte drucken
Sie können mit Hilfe des Datenbank-Dokumentierers, der in Kapitel 35 erläutert wird, die Rechte für verschiedene Objekte drucken.
33.6.5
Für die Praxis
Das Zeit- und Abrechnungssystem sichern Nachdem Sie nun die Schritte kennen gelernt haben, die erforderlich sind, um eine Access-Datenbank angemessen zu sichern, können Sie das erworbene Wissen auf das Zeit- und Abrechnungssystem anwenden: 1. Starten Sie zunächst den Arbeitsgruppen-Administrator (Wrkgadm.exe). Klicken Sie auf die Schaltfläche ERSTELLEN, um eine neue Arbeitsgruppe zu erstellen. 2. Geben Sie Ihren Namen und Ihre Firma ein. Geben Sie als Arbeitsgruppen-ID TimeBillApp ein, wie in Abbildung 33.28 gezeigt. Klicken Sie dann auf OK.
Abbildung 33.28: Informationen für eine neue Arbeitsgruppe eingeben
3. Nennen Sie die Arbeitsgruppen-Datenbank Time.MDW und klicken Sie auf OK. Bestätigen Sie den Pfad zur neuen Arbeitsgruppe, wie es in Abbildung 33.29 zu sehen ist. 4. Beenden Sie den Arbeitsgruppen-Administrator und starten Sie Access. 5. Wählen Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENKONTEN.
Spezielle Fragestellungen
1143
Abbildung 33.29: Einen Namen und Pfad für eine neue Arbeitsgruppen-Informationsdatei festlegen
6. Klicken Sie in diesem Dialogfeld auf NEU und fügen Sie einen Benutzer namens PCGuru hinzu. Geben Sie PCGuru die persönliche Identifikationskennung HeadCheese, wie in Abbildung 33.30 zu sehen. Klicken Sie anschließend auf OK.
Abbildung 33.30: Den Namen und eine persönliche ID für einen neuen Benutzer eingeben
7. Klicken Sie auf HINZUFÜGEN >>, um PCGuru zur Gruppe der Administratoren hinzuzufügen, wie in Abbildung 33.31 gezeigt. 8. Klicken Sie danach auf die Registerkarte ANMELDUNGSKENNWORT ÄNDERN. 9. Weisen Sie dem Admin-Benutzer das neue Kennwort NoPower zu und klicken Sie dann auf ZUWEISEN. 10. Klicken Sie anschließend auf die Registerkarte BENUTZER. 11. Wählen Sie im Listenfeld NAME den Eintrag Admin aus. 12. Entfernen Sie Admin aus der Administratoren-Gruppe, wie in Abbildung 33.32 dargestellt. 13. Beenden Sie Access und starten Sie das Programm erneut. Öffnen Sie die Datenbank Chap33 und melden Sie sich als PCGuru an (ohne Kennwort). 14. Wählen Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENKONTEN. 15. Klicken Sie danach auf die Registerkarte ANMELDUNGSKENNWORT ÄNDERN. 16. Weisen Sie PCGuru das Kennwort TheGuru zu. 17. Wählen Sie EXTRAS | SICHERHEIT | BENUTZERDATENSICHERHEITS-ASSISTENT.
1144
Kapitel 33: Datenbanksicherheit
Abbildung 33.31: Einer Gruppe einen Benutzer hinzufügen
Abbildung 33.32: Einen Benutzer aus einer Gruppe entfernen
18. Wählen Sie dann AKTUELLE ARBEITSGRUPPENINFORMATIONSDATEI ÄNDERN und klicken Sie auf WEITER. 19. Klicken Sie auf WEITER, um zu bestätigen, dass Sie alle Objekte sichern wollen. 20. Fügen Sie die Gruppen NUR LESEBERECHTIGTE BENUTZER und AKTUALISIERUNGSBERECHTIGTE BENUTZER hinzu und klicken Sie auf WEITER.
Spezielle Fragestellungen
1145
21. Klicken Sie erneut auf WEITER, um zu bestätigen, dass die Benutzer-Gruppe keine Berechtigungen besitzen soll. 22. Fügen Sie die folgenden Benutzer hinzu: Dan, Alexis, Brendan, Amanda und Mimi. Weisen Sie gegebenenfalls persönliche IDs und Kennwörter zu und klicken Sie anschließend auf WEITER. 23. Fügen Sie Dan und Alexis der Gruppe DATEN AKTUALISIEREN hinzu. Fügen Sie dann Mimi und Amanda der Gruppe NUR LESEBERECHTIGTE BENUTZER hinzu. Fügen Sie schließlich Brendan zur Administratoren-Gruppe hinzu und klicken Sie auf WEITER. 24. Geben Sie einen Namen für die Sicherungskopie Ihrer Datenbank ein und klicken Sie auf FERTIG STELLEN. 25. Beenden Sie Access und melden Sie sich dann unter jedem der verschiedenen Benutzernamen ein. Versuchen Sie Datensätze in den Tabellen tblClients und tblProjects zu lesen, zu ändern, hinzuzufügen und zu löschen. Vergewissern Sie sich, dass die Sicherheit wie geplant implementiert wurde. Vergessen Sie nicht, dass Sie im Falle verknüpfter Tabellen in die verknüpfte Datenbank wechseln müssen, um diese Tabellen zu schützen.
Fortgeschrittene Sicherheitstechniken
Kapitel
Hier lesen Sie:
Gruppen mit Hilfe von Code verwalten Benutzer mit Hilfe von Code verwalten Alle Gruppen und Benutzer auflisten Mit Kennwörtern arbeiten Berechtigungen für Objekte mit Hilfe von Code zuweisen und widerrufen Mit Hilfe von Abfragen Sicherheit auf Feldebene erreichen Benutzer und Gruppen von der Erstellung von Objekten ausschließen Sich als ein anderer Benutzer anmelden, um verbotene Aufgaben auszuführen Client-Server-Anwendungen schützen
34.1
Sicherheit für Gruppenarbeit
Sie können unter Umständen nicht immer verfügbar sein, um Sicherheitsfunktionen für die Benutzer Ihrer Anwendung einzurichten. Eine Alternative besteht natürlich darin zu gewährleisten, dass die Benutzer ihre eigenen Kopien von Access erwerben und sie dann zu informieren, wie mit Hilfe der Benutzerschnittstelle die Sicherheit verwaltet wird. Die Sicherheitsfunktionen in Access sind jedoch sehr komplex, so dass diese Lösung nicht sehr praktisch ist. Wenn Sie Ihre Anwendung einer großen Gruppe von Benutzern zur Verfügung stellen, ist dieses Vorgehen überhaupt nicht möglich. Glücklicherweise können Sie in Ihren Anwendungs-Code die Fähigkeit integrieren, alle Aspekte der Sicherheit direkt zu verwalten. Es ist wichtig, dass Sie Ihren Administrator-Benutzern die Fähigkeit geben, Sicherheit für ihre Arbeitsgruppen einzurichten und zu verwalten. Das reicht vom Erstellen einer Front-EndSchnittstelle bis zu den von Access bereitgestellten Sicherheitsfunktionen. Hinter den Kulissen können Sie ADO-Code (ADO – ActiveX Data Objects) verwenden, um die Sicherheitsfunktionen zu implementieren.
1148
Kapitel 34: Fortgeschrittene Sicherheitstechniken
34.2
Gruppen mit Hilfe von Code verwalten
Kapitel 33 erläutert, wie wichtig es ist, logische Gruppen von Benutzern zu erstellen und diesen Gruppen dann Rechte zuzuweisen. Der Administrator Ihrer Anwendung will eventuell Gruppen hinzufügen oder entfernen, nachdem Sie Ihre Anwendung zur Verfügung gestellt haben. Sie können Gruppen-ADOs verwenden, um Gruppenkonten zur Laufzeit zu erstellen und zu verwalten.
34.2.1
Eine Gruppe hinzufügen
Sie fügen eine Gruppe mittels der Methode Append aus der Groups-Auflistung hinzu, die Bestandteil des ADOX-Catalog-Objekts ist. Abbildung 34.1 zeigt ein Formular, das Benutzer befähigt, Gruppen hinzuzufügen und zu entfernen.
Abbildung 34.1: Dieses Formular ermöglicht es Administrator-Benutzern, Gruppen hinzuzufügen und zu entfernen
Dieses Formular heißt frmMaintainGroups und ist in der Datenbank CHAP34EX.MDB enthalten, die sich auf der CD-ROM mit dem Beispiel-Code befindet. Listing 34.1 zeigt den Code, welcher der Schaltfläche ADD zu Grunde liegt. Listing 34.1:
Eine Gruppe hinzufügen
Private Sub cmdAdd_Click() Dim boolSuccess As Boolean If IsNull(Me.txtGroupName) Then MsgBox "You Must Fill In Group Name Before Proceeding" Else boolSuccess = CreateGroups() If boolSuccess Then MsgBox "Group Created Successfully" Else MsgBox "Group Not Created" End If
Gruppen mit Hilfe von Code verwalten
1149
End If End Sub
Dieser Code testet, ob der Gruppenname eingegeben wurde. Falls dies der Fall ist, wird die Funktion CreateGroups aufgerufen. In Abhängigkeit vom Rückgabewert von CreateGroups wird der Benutzer benachrichtigt, ob die Gruppe erfolgreich erstellt wurde. Listing 34.2 verwendet die Methode Append der Groups-Auflistung, um der Arbeitsgruppe eine neue Gruppe hinzuzufügen. Listing 34.2:
Die Funktion CreateGroups fügt eine Gruppe hinzu
Function CreateGroups() As Boolean On Error GoTo CreateGroups_Err Dim cat As ADOX.Catalog CreateGroups = True Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection cat.Groups.Append (Me.txtGroupName) CreateGroups_Exit: Set cat = Nothing Exit Function CreateGroups_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description CreateGroups = False Resume CreateGroups_Exit End Function
Die Funktion verwendet eine Catalog-Variable. Die Catalog-Variable ist Bestandteil der Microsoft ADO Extension for DDL and Security (ADOX). Sie müssen auf die ADOX-Bibliothek verweisen, bevor Sie die Catalog-Variable verwenden können. Das Beispiel setzt die Eigenschaft ActiveConnection der Catalog-Variablen auf die dem aktuellen Projekt zugeordnete Verknüpfung. Nachdem die Verbindung eingerichtet ist, wird die Methode Append der Groups-Auflistung des Catalog-Objekts verwendet, um die Gruppe hinzuzufügen. Diese Methode übernimmt einen Parameter, den Namen der Gruppe. Die Methode Append fügt dem Katalog eine neue Gruppe hinzu, wenn sie auf die Groups-Auflistung angewandt wird. Die Funktion verwendet den Wert in txtGroupName als Namen der hinzuzufügenden Gruppe. Nach Ausführung dieser Routine können Sie überprüfen, ob eine neue Gruppe zur Arbeitsgruppe hinzugefügt wurde, indem Sie EXTRAS | SICHERHEIT | BENUTZER- UND GRUPPENKONTEN wählen. Die neu erstellte Gruppe sollte in der Gruppenliste auf der Gruppenseite erscheinen.
1150
34.2.2
Kapitel 34: Fortgeschrittene Sicherheitstechniken
Eine Gruppe entfernen
Der Code zum Entfernen einer Gruppe ist dem zum Hinzufügen einer Gruppe erforderlichen Code sehr ähnlich. Listing 34.3 zeigt den Code, welcher der Befehlsschaltfläche cmdRemove zu Grunde liegt. Listing 34.3:
Eine Gruppe entfernen
Private Sub cmdRemove_Click() Dim boolSuccess As Boolean If IsNull(Me.txtGroupName) Then MsgBox "You Must Fill In Group Name Before Proceeding" Else boolSuccess = RemoveGroups() If boolSuccess Then MsgBox "Group Removed Successfully" Else MsgBox "Group Not Removed" End If End If End Sub
Diese Routine gewährleistet, dass der Gruppenname eingegeben wurde und ruft dann die Funktion RemoveGroups auf. Eine entsprechende Meldung wird angezeigt, die mitteilt, ob die Gruppe erfolgreich entfernt wurde. Listing 34.4 zeigt die Funktion RemoveGroups. Listing 34.4:
Die Funktion RemoveGroups entfernt eine Gruppe
Function RemoveGroups() On Error GoTo RemoveGroups_Err Dim cat As ADOX.Catalog RemoveGroups = True Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection cat.Groups.Delete Me.txtGroupName.Value RemoveGroups_Exit: Set cat = Nothing Exit Function RemoveGroups_Err: If Err.Number = 3265 Then MsgBox "Group Not Found" Else MsgBox "Error # " & Err.Number & ": " & Err.Description
1151
Benutzer mit Hilfe von Code verwalten
End If RemoveGroups = False Resume RemoveGroups_Exit End Function
Die Funktion RemoveGroups verwendet die Methode Delete der Groups-Auflistung des Catalog-Objekts und übernimmt den Wert in txtGroupName als Namen der zu entfernenden Gruppe. Falls die Gruppe nicht existiert, tritt ein Fehler mit der Nummer 3265 auf und es erscheint eine entsprechende Fehlermeldung.
34.3
Benutzer mit Hilfe von Code verwalten
Sie wollen wahrscheinlich nicht nur Gruppen, sondern auch Benutzer mit Hilfe von Code verwalten. Das in Abbildung 34.2 dargestellte Formular frmMaintainUsers veranschaulicht diesen Prozess.
Abbildung 34.2: Dieses Formular ermöglicht es AdministratorBenutzern, Benutzer hinzuzufügen und zu entfernen
34.3.1
Benutzer hinzufügen
Sie fügen einen Benutzer mittels der Methode Append der Users-Auflistung des Catalog-Objekts hinzu. Das Formular frmMaintainUsers, das auch in CHAP34EX.MDB zu finden ist, enthält eine Befehlsschaltfläche namens cmdAddUsers, die einen Benutzer hinzufügt. Listing 34.5 zeigt den dafür benötigten Code. Listing 34.5:
Einen Benutzer hinzufügen
Private Sub cmdAdd_Click() Dim boolSuccess As Boolean If IsNull(Me.txtUserName) Then MsgBox "You Must Fill In User Name Before Proceeding" Else boolSuccess = CreateUsers(Me.txtUserName.Value, _ Nz(Me.txtPassword.Value, ""))
1152
Kapitel 34: Fortgeschrittene Sicherheitstechniken
If boolSuccess Then MsgBox "User Created Successfully" Else MsgBox "User Not Created" End If End If End Sub
Dieser Code prüft, ob der Benutzername eingegeben wurde und ruft dann die in Listing 34.6 definierte Funktion CreateUsers auf. Die Funktion CreateUsers und alle in diesem Kapitel vorkommenden Funktionen befinden sich im Modul basSecurity in der Beispieldatenbank Chap34Ex.mdb.
Listing 34.6:
Die Funktion CreateUsers erstellt einen Benutzer
Function CreateUsers(UserName As String, _ Password As String) As Boolean On Error GoTo CreateUsers_Err Dim cat As ADOX.Catalog CreateUsers = True Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection cat.Users.Append UserName, Password CreateUsers_Exit: Set cat = Nothing Exit Function CreateUsers_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description CreateUsers = False Resume CreateUsers_Exit End Function
Diese Routine erstellt eine Catalog-Variable. Sie setzt die Eigenschaft ActiveConnection des Catalog-Objekts auf die dem aktuellen Projekt zugeordnete Verbindung. Danach ruft sie die Methode Append der Users-Auflistung des Catalog-Objekts auf, um den Benutzer zum Katalog hinzuzufügen.Die Werte in den Steuerelementen txtUserName und txtPassword werden der Methode Append als Argumente übergeben. Die Methode Append wird auf die Users-Auflistung des Katalogs angewandt, um den Benutzer zur Auflistung hinzuzufügen.
Benutzer mit Hilfe von Code verwalten
34.3.2
1153
Einer Gruppe Benutzer zuweisen
Bis jetzt haben Sie einen Benutzer hinzugefügt, aber den Benutzer noch keiner Gruppe zugewiesen. Betrachten Sie nun, wie Sie einen Benutzer zu einer vorhandenen Gruppe hinzufügen können. Listing 34.7 zeigt den Code, welcher der Schaltfläche cmdAssign auf dem Formular frmMaintainUsers zu Grunde liegt. Listing 34.7:
Einer Gruppe einen Benutzer zuweisen
Private Sub cmdAssign_Click() Dim boolSuccess As Boolean If IsNull(Me.txtUserName) Or IsNull(Me.txtGroupName) Then MsgBox "You Must Fill In User Name and Group Name Before Proceeding" Else boolSuccess = AssignToGroup(Me.txtUserName.Value, _ Me.txtGroupName.Value) If boolSuccess Then MsgBox "User Successfully Assigned to Group" Else MsgBox "User Not Assigned to Group" End If End If End Sub
Dieser Code stellt sicher, dass die beiden Textfelder txtUserName und txtGroupName ausgefüllt werden und ruft dann die Funktion AssignToGroup auf, die versucht, den Benutzer der angegebenen Gruppe zuzuweisen. Listing 34.8 zeigt die Funktion AssignToGroup. Listing 34.8:
Die Funktion AssignToGroup weist einen Benutzer einer Gruppe zu
Function AssignToGroup(UserName As String, _ GroupName As String) On Error GoTo AssignToGroup_Err Dim cat As ADOX.Catalog AssignToGroup = True Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection cat.Groups.Append GroupName cat.Users(UserName).Groups.Append _ GroupName AssignToGroup_Exit: Set cat = Nothing Exit Function
1154
Kapitel 34: Fortgeschrittene Sicherheitstechniken
AssignToGroup_Err: Select Case Err.Number Case -2147467259 'Gruppe existiert bereits Resume Next Case 3265 MsgBox "Group Not Found" Case Else MsgBox "Error # " & Err.Number & ": " & Err.Description End Select AssignToGroup = False Resume AssignToGroup_Exit End Function
Dieser Code erstellt eine Catalog-Objektvariable. Die Eigenschaft ActiveConnection des Catalog-Objekts wird auf die Eigenschaft Connection des aktuellen Projekts gesetzt. Die Methode Append der Groups-Auflistung des Katalog-Objekts wird verwendet, um die Gruppe zur Groups-Auflistung des Katalogs hinzuzufügen. Falls die Gruppe bereits existiert, wird der auftretende Fehler ignoriert. Schließlich wird die Methode Append auf die Groups-Auflistung des User-Objekts des Catalog-Objekts angewendet, um den Benutzer der Gruppe hinzuzufügen. Beachten Sie, dass der Benutzername als Item-Element der Users-Auflistung angegeben ist, auf die verwiesen wird (der Parameter UserName). Die Gruppe, zu der der Benutzer hinzugefügt wird, wird durch den Wert des Parameters GroupName angegeben.
34.3.3
Benutzer aus einer Gruppe entfernen
Genauso wie Sie Benutzer zu Gruppen hinzufügen können, werden Sie die Benutzer auch aus den Gruppen entfernen wollen. Der Code in Listing 34.9 liegt der Befehlsschaltfläche cmdRevoke auf dem Formular frmMaintainUsers zu Grunde. Listing 34.9:
Einen Benutzer aus einer Gruppe entfernen
Private Sub cmdRevoke_Click() Dim boolSuccess As Boolean If IsNull(Me.txtUserName) Or IsNull(Me.txtGroupName) Then MsgBox "You Must Fill In User Name and Group Name Before Proceeding" Else boolSuccess = RevokeFromGroup(Me.txtUserName.Value, _ Me.txtGroupName.Value) If boolSuccess Then MsgBox "User Successfully Removed from Group" Else MsgBox "User Not Removed from Group" End If End If End Sub
Benutzer mit Hilfe von Code verwalten
1155
Dieser Code gewährleistet, dass die Namen des Benutzers und der Gruppe auf dem Formular eingetragen sind und ruft dann die Funktion RevokeFromGroup auf, die in Listing 34.10 definiert ist. Listing 34.10: Die Funktion RevokeFromGroup entfernt einen Benutzer aus einer Gruppe Function RevokeFromGroup(UserName As String, _ GroupName As String) On Error GoTo RevokeFromGroup_Err Dim cat As ADOX.Catalog RevokeFromGroup = True Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection cat.Users(UserName).Groups.Delete _ GroupName RevokeFromGroup_Exit: Set cat = Nothing Exit Function RevokeFromGroup_Err: If Err.Number = 3265 Then MsgBox "Group Not Found" Else MsgBox "Error # " & Err.Number & ": " & Err.Description End If RevokeFromGroup = False Resume RevokeFromGroup_Exit End Function
Diese Prozedur richtet ein Catalog-Objekt ein und setzt dessen Connection-Eigenschaft auf die dem aktuellen Projekt zugeordnete Verbindung. Sie entfernt dann den angegebenen Benutzer aus der Gruppe, indem die Methode Delete der Groups-Auflistung des User-Objekts ausgeführt wird. Beachten Sie, dass das Item-Element der referenzierten Users-Auflistung im Parameter UserName festgelegt ist, der vom Textfeld txtUserName übergeben wird, und die Gruppe, aus welcher der Benutzer gelöscht wird, durch den Parameter GroupName angegeben ist, der vom Textfeld txtGroupName übergeben wird.
1156
34.3.4
Kapitel 34: Fortgeschrittene Sicherheitstechniken
Benutzer entfernen
Gelegentlich wollen Sie einen Benutzer vollständig entfernen. Die Schaltfläche cmdRemove auf dem Formular frmMaintainingUsers führt diese Aufgabe durch, wie in Listing 34.11 gezeigt. Listing 34.11: Einen Benutzer löschen Private Sub cmdRemove_Click() Dim boolSuccess As Boolean If IsNull(Me.txtUserName) Then MsgBox "You Must Fill In User Name Before Proceeding" Else boolSuccess = RemoveUsers(Me.txtUserName.Value) If boolSuccess Then MsgBox "User Removed Successfully" Else MsgBox "User Not Removed" End If End If End Sub
Dieser Code benötigt lediglich einen Benutzernamen, um fortzufahren. Falls ein Benutzername angegeben wurde, wird die in Listing 34.12 definierte Funktion RemoveUsers aufgerufen. Listing 34.12: Die Funktion RemoveUsers löscht einen Benutzer Function RemoveUsers(UserName As String) On Error GoTo RemoveUsers_Err Dim cat As ADOX.Catalog RemoveUsers = True Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection cat.Users.Delete UserName RemoveUsers_Exit: Set cat = Nothing Exit Function RemoveUsers_Err: If Err.Number = 3265 Then MsgBox "User Not Found" Else MsgBox "Error # " & Err.Number & ": " & Err.Description End If
Alle Gruppen und Benutzer auflisten
1157
RemoveUsers = False Resume RemoveUsers_Exit End Function
Die Funktion RemoveUsers wendet die Methode Delete auf die Users-Auflistung des Katalogs an. Diese entfernt den Benutzer aus der Arbeitsgruppe.
34.4
Alle Gruppen und Benutzer auflisten
Abbildung 34.3 zeigt eine erweiterte Version des Formulars frmMaintainUsers, die mit frmMaintainAll bezeichnet ist. Das Formular frmMaintainAll, welches sich in CHAP34EX.MDB befindet, befähigt den Benutzer, andere Benutzer hinzuzufügen und zu entfernen, Benutzer zu Gruppen zuzuweisen und Benutzern Kennwörter zu geben. Die Textfelder GROUPS und USERS wurden durch Kombinationsfelder ersetzt, so dass der Benutzer vorhandene Benutzer und Gruppen betrachten und aus diesen auswählen kann.
Abbildung 34.3: Dieses Formular ermöglicht es AdministratorBenutzern, Benutzer, Gruppen und Kennwörter zu verwalten
34.4.1
Alle Gruppen auflisten
Die Funktion ListGroups ist die Callback-Funktion, die verwendet wird, um das cboGroups-Kombinationsfeld auszufüllen. Callback-Funktionen werden in Kapitel 9 detailliert behandelt. Listing 34.13 erstellt eine Liste von bestehenden Gruppen in der Arbeitsgruppe. Listing 34.13: Die Funktion ListGroups erstellt eine Liste von allen Gruppen Function ListGroups(ctl As Control, vntID As Variant, _ lngRow As Long, lngCol As Long, intCode As Integer) _ As Variant Dim cat As ADOX.Catalog Dim grp As ADOX.Group
1158
Kapitel 34: Fortgeschrittene Sicherheitstechniken
Dim intCounter As Integer Static sastrGroups() As String Static sintNumGroups As Integer Dim varRetVal As Variant varRetVal = Null Select Case intCode Case acLBInitialize ' Initialisieren. Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection sintNumGroups = cat.Groups.Count ReDim sastrGroups(sintNumGroups – 1) For Each grp In cat.Groups sastrGroups(intCounter) = grp.Name intCounter = intCounter + 1 Next grp varRetVal = sintNumGroups Case acLBOpen 'Geöffnet varRetVal = Timer 'Eindeutige ID erzeugen. Case acLBGetRowCount 'Anzahl der Zeilen. varRetVal = sintNumGroups Case acLBGetColumnCount 'Anzahl der Spalten. varRetVal = 1 Case acLBGetColumnWidth 'Spaltenbreite. varRetVal = -1 '-1 erzwingt die Verwendung der Standardbreite. Case acLBGetValue 'Daten ermitteln. varRetVal = sastrGroups(lngRow) End Select ListGroups = varRetVal End Function
Der Kern der Funktion ListGroups besteht darin, dass sie die Eigenschaft Count der Groups-Auflistung des Katalogs verwendet, um zu bestimmen, wie viele Gruppen im Katalog enthalten sind. Diese Anzahl wird von der Callback-Funktion verwendet, um zu bestimmen, wie viele Zeilen im Kombinationsfeld erscheinen werden. Beachten Sie insbesondere die Zeile For Each grp In cat.Groups. Dieser Code durchläuft jedes Gruppenobjekt in der Groups-Auflistung des Katalogs. Die Eigenschaft Name des Group-Objekts wird zum Kombinationsfeld hinzugefügt.
34.4.2
Alle Benutzer auflisten
Das Auflisten aller Benutzer entspricht im Wesentlichen dem Auflisten aller Gruppen (siehe Listing 34.14).
Alle Gruppen und Benutzer auflisten
1159
Listing 34.14: Die Funktion ListUsers erstellt eine Liste von allen Benutzern Function ListUsers(ctl As Control, vntID As Variant, _ lngRow As Long, lngCol As Long, intCode As Integer) _ As Variant Dim cat As ADOX.Catalog Dim usr As ADOX.User Dim intCounter As Integer Static sastrUsers() As String Static sintNumUsers As Integer Dim varRetVal As Variant varRetVal = Null Select Case intCode Case acLBInitialize 'Initialisieren. Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection sintNumUsers = cat.Users.Count ReDim sastrUsers(sintNumUsers – 1) For Each usr In cat.Users sastrUsers(intCounter) = usr.Name intCounter = intCounter + 1 Next usr varRetVal = sintNumUsers Case acLBOpen 'Geöffnet varRetVal = Timer 'eindeutige ID erzeugen. Case acLBGetRowCount 'Anzahl der Zeilen. varRetVal = sintNumUsers Case acLBGetColumnCount 'Anzahl der Spalten. varRetVal = 1 Case acLBGetColumnWidth 'Spaltenbreite. varRetVal = -1 '-1 erzwingt die Verwendung der standardbreite. Case acLBGetValue 'Daten ermitteln. varRetVal = sastrUsers(lngRow) End Select ListUsers = varRetVal End Function
Dieser Code prüft die Count-Eigenschaft der Users-Auflistung des Catalog-Objekts, um zu bestimmen, wie viele Benutzer existieren. Die Zeile For Each usr In wrk.Users durchläuft jeden Benutzer in der Users-Auflistung. Der Name jedes Benutzers wird zu einem Datenfeld hinzugefügt, das verwendet wird, um das Kombinationsfeld cboUsers auszufüllen.
1160
Kapitel 34: Fortgeschrittene Sicherheitstechniken
34.5
Mit Kennwörtern arbeiten
Sehr oft muss der Administrator-Benutzer Kennwörter von Benutzern hinzufügen, entfernen oder ändern. Mit Hilfe der Benutzerschnittstelle können Sie lediglich das Kennwort des gegenwärtig angemeldeten Benutzers ändern. Bei der Verwendung von Code können Sie jedoch das Kennwort eines jeden Benutzers ändern, sofern Sie die Rechte eines Administrators besitzen.
34.5.1
Benutzern Kennwörter zuweisen
Das Formular frmMaintainAll ermöglicht es dem Administrator-Benutzer, dem im Kombinationsfeld ausgewählten Benutzer ein Kennwort zuzuweisen. Listing 34.15 zeigt den Code dafür. Listing 34.15: Das Kennwort eines Benutzers ändern Private Sub cmdPassword_Click() Dim boolSuccess As Boolean If IsNull(Me.cboUserName.Value) Then MsgBox "You Must Fill In User Name and Password Before Proceeding" Else boolSuccess = AssignPassword() If boolSuccess Then MsgBox "Password Successfully Changed" Else MsgBox "Password Not Changed" End If End If End Sub
Diese Routine gewährleistet, dass ein Benutzername eingegeben worden ist, und ruft dann die Funktion AssignPassword auf, die sich im Formular frmMaintainAll befindet, wie in Listing 34.16 zu sehen ist. Listing 34.16: Die Funktion AssignPassword ändert das Kennwort eines Benutzers Function AssignPassword() On Error GoTo AssignPassword_Err Dim cat As ADOX.Catalog Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection AssignPassword = True cat.Users(Me.cboUserName.Value).ChangePassword _ "", Nz(Me.txtPassword.Value)
Mit Kennwörtern arbeiten
1161
AssignPassword_Exit: Set cat = Nothing Exit Function AssignPassword_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description AssignPassword = False Resume AssignPassword_Exit End Function
Die Funktion AssignPassword verwendet die Methode ChangePassword des im Kombinationsfeld cboUserName angegebenen User-Objekts, das ein Teil der Users-Auflistung ist. Der erste Parameter, das alte Kennwort, wird absichtlich leer gelassen. Mitglieder der Administratorengruppe können alle Kennwörter außer ihrem eigenen ändern, ohne das alte Kennwort kennen zu müssen. Der zweite Parameter, das neue Kennwort, ist der im Textfeld txtPassword eingegebene Wert. Die Funktion Nz legt das neue Kennwort als eine Zeichenkette der Länge Null fest, falls der Administrator-Benutzer kein neues Kennwort festgelegt hat.
34.5.2
Benutzer ohne Kennwörter auflisten
Oftmals möchte ein Administrator-Benutzer einfach eine Liste von allen Benutzern erhalten, die keine Kennwörter besitzen. Diese Liste kann recht einfach mit Hilfe von VBA-Code und ADOs erzeugt werden. Abbildung 34.4 zeigt das Formular frmMaintainPasswords, das sich in der Datenbank CHAP34EX.MDB befindet.
Abbildung 34.4: Dieses Formular ermöglicht es AdministratorBenutzern, Benutzer zu erkennen, die keine Kennwörter besitzen
Wenn das Formular geladen wird, verwendet das Listenfeld eine Callback-Funktion, um eine Liste aller Benutzer anzuzeigen, die kein Kennwort besitzen. Listing 34.17 zeigt den Code für das Formular frmMaintainPasswords.
1162
Kapitel 34: Fortgeschrittene Sicherheitstechniken
Listing 34.17: Benutzer ohne Kennwörter ermitteln Function ListUsers(ctl As Control, vntID As Variant, _ lngRow As Long, lngCol As Long, intCode As Integer) _ As Variant On Error GoTo ListUsers_Err Dim cat As ADOX.Catalog Dim conn As ADODB.Connection Dim usr As ADOX.User Dim intCounter As Integer Dim boolNoPass As Boolean Static sastrUsers() As String Static sintNumUsers As Integer Dim varRetVal As Variant varRetVal = Null Select Case intCode Case acLBInitialize ' Initialisieren. Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection sintNumUsers = cat.Users.Count ReDim sastrUsers(sintNumUsers – 1) For Each usr In cat.Users boolNoPass = True Set conn = New ADODB.Connection conn.Open CurrentProject.Connection, usr.Name, "" If boolNoPass Then sastrUsers(intCounter) = usr.Name intCounter = intCounter + 1 End If Next usr varRetVal = sintNumUsers Case acLBOpen 'Geöffnet varRetVal = Timer 'eindeutige ID erzeugen. Case acLBGetRowCount 'Anzahl der Zeilen. varRetVal = sintNumUsers Case acLBGetColumnCount 'Anzahl der Spalten. varRetVal = 1 Case acLBGetColumnWidth 'Spaltenbreite. varRetVal = -1 '-1 erzwingt die Verwendung der Standardbreite. Case acLBGetValue 'Daten ermitteln. varRetVal = sastrUsers(lngRow) End Select ListUsers = varRetVal
Mit Kennwörtern arbeiten
1163
ListUsers_Exit: Set cat = Nothing Set usr = Nothing Exit Function ListUsers_Err: If Err.Number = -2147217843 Then boolNoPass = True Resume Next Else MsgBox "Error # " & Err.Number & ": " & Err.Description Resume ListUsers_Exit End If End Function
Der Kern des Codes befindet sich in der For...Each-Schleife. Der Code durchläuft jeden Benutzer in der Users-Auflistung. Zunächst wird der Wert des Flags boolNoPass auf True gesetzt. Dann erstellt der Code einen neuen Katalog und versucht, sich beim neuen Katalog anzumelden, indem die Name-Eigenschaft des aktuellen Benutzerobjekts und ein Kennwort verwendet werden, das eine Zeichenkette der Länge Null darstellt. Falls ein Fehler auftritt, setzt der Code zur Fehlerbehandlung das Flag boolNoPass auf False. Der Fehler -2147467259 gibt an, dass das Kennwort nicht gültig war, was bedeutet, dass der Benutzer ein Kennwort besitzen muss, da die Anmeldung nicht erfolgreich war. Andernfalls kann der Benutzer kein Kennwort besitzen und wird deshalb zum Listenfeld hinzugefügt.
34.5.3
Sicherstellen, dass Benutzer Kennwörter besitzen
Sie wollen eventuell sicherstellen, dass Benutzer, die sich bei Ihrer Anwendung anmelden, ein Kennwort besitzen. Sie können dies mit Hilfe des in Listing 34.18 gezeigten Codes erreichen. Listing 34.18: Sicherstellen, dass die Benutzer Ihrer Anwendung Kennwörter besitzen Function AutoExec() Dim cat As ADOX.Catalog Dim usr As ADOX.User Dim strPassword As String Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection Set usr = cat.Users(CurrentUser) On Error Resume Next usr.ChangePassword "", "" If Err.Number = 0 Then strPassword = InputBox("You Must Enter a Password Before Proceeding", _ "Enter Password")
1164
Kapitel 34: Fortgeschrittene Sicherheitstechniken
If strPassword = "" Then DoCmd.Quit Else usr.ChangePassword "", strPassword End If End If AutoExec = True End Function
Die Funktion AutoExec kann vom Startformular Ihrer Anwendung aus aufgerufen werden. Sie setzt eine User-Objektvariable auf CurrentUser, indem der Rückgabewert der Funktion CurrentUser als der Benutzer genommen wird, nach dem in der UsersAuflistung zu suchen ist. Die Funktion CurrentUser gibt eine Zeichenkette zurück, welche den Namen des aktuellen Benutzers enthält. Wenn eine Objektvariable auf den korrekten Benutzer zeigt, versucht der Code, ein neues Kennwort für den Benutzer festzulegen. Bei der Änderung des Kennworts des aktuellen Benutzers müssen sowohl das alte als auch das neue Kennwort an die Methode ChangePassword des User-Objekts übergeben werden. Falls das alte Kennwort nicht korrekt ist, tritt ein Fehler auf. Dies zeigt an, dass der Benutzer ein Kennwort besitzt und nichts Spezielles geschehen muss. Falls hingegen kein Fehler auftritt, wissen Sie, dass kein Kennwort existiert, und der Benutzer wird zur Eingabe eines Kennworts aufgefordert. Falls der Benutzer kein Kennwort angibt, wird die Anwendung beendet. Andernfalls wird dem Benutzer ein neues Kennwort zugewiesen. Sie können ein Beispiel für die Nützlichkeit dieser Funktion im Modul basUtils in der Datenbank Chap34ExNoPass.MDB finden, die sich auf Ihrer CD-ROM mit dem Beispiel-Code befindet.
34.6
Berechtigungen für Objekte mit Hilfe von Code zuweisen und widerrufen Häufig wollen Sie Berechtigungen für Objekte mit Hilfe von Code zuweisen und widerrufen. Erneut können Sie dies leicht mittels ADO-Code bewerkstelligen. Das Formular in Abbildung 34.5 ist mit frmTableRights bezeichnet und befindet sich in der Datenbank CHAP34EX.MDB.
Der Code in Listing 34.19 weist der Gruppe, die im Listenfeld GRUPPENNAME ausgewählt ist, Rechte zum Betrachten der Tabelle zu, die im Listenfeld TABELLE AUSWÄHLEN bestimmt wurde.
Berechtigungen für Objekte mit Hilfe von Code zuweisen und widerrufen
1165
Abbildung 34.5: Dieses Formular ermöglicht es AdministratorBenutzern, Gruppen Rechte zuzuweisen Listing 34.19: Ansichtsrechte zuweisen Private Sub cmdViewRights_Click() Dim cat As ADOX.Catalog Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection cat.Groups(Me.cboGroupName.Value).SetPermissions _ Me.lstTables.Value, _ ObjectType:=adPermObjTable, _ Action:=adAccessSet, _ Rights:=adRightRead End Sub
Die Methode SetPermissions des Group-Objekts wird verwendet, um die Berechtigungen für die Tabelle einzurichten. Die Rechte für die Tabelle werden der im Kombinationsfeld cboGroupName angegebenen Gruppe erteilt. Die Tabelle, für die die Rechte erteilt werden, ist im Listenfeld lstTables festgelegt. Der Objekttyp, für den die Rechte zugewiesen werden, wird durch den Parameter ObjectType bestimmt. Die Konstante adPermObjTable wird verwendet, um den Objekttyp als Tabelle festzulegen. Der Parameter Action kennzeichnet den Typ der ausgeführten Aktion. Die Konstante adAccessSet wird verwendet, um anzuzeigen, dass die Rechte eingerichtet wurden. Der Parameter Rights dient der Angabe der erteilten Rechte. Die Konstante adRightRead wird verwendet, um der Tabelle Leserechte zuzuweisen. Tabelle 34.1 führt die Berechtigungskonstanten für Abfragen und Tabellen auf.
1166
Kapitel 34: Fortgeschrittene Sicherheitstechniken
BerechtigungsKonstante
Erteilt die Berechtigung für
adRightDelete
Löschen von Zeilen aus der Tabelle oder Abfrage
adRightInsert
Einfügen neuer Zeilen in die Tabelle oder Abfrage
adRightReadDesign
Lesen der Definition der Tabelle oder Abfrage
adRightUpdate
Ändern von Tabellen- oder Abfragedaten
adRightRead
Lesen von in der Tabelle oder Abfrage gespeicherten Daten. Schließt außerdem implizit die Berechtigung zum Lesen der Definition der Tabelle oder Abfrage ein
adWriteDesign
Ändern der Definition der Tabelle oder Abfrage
adRightWithGrant
Erteilen von Berechtigungen für das Objekt
adRightAll
Alle Rechte auf dem Objekt
Tabelle 34.1: Die Berechtigungskonstanten für Abfragen und Tabellen
Listing 34.20 zeigt ein Beispiel, in dem die Konstante adRightRead mit der Konstanten adRightUpdate mittels eines nach Bits gezählten OR kombiniert wird. Die Konstante adRightUpdate impliziert nicht, dass der Benutzer auch die Tabellendefinition und -daten lesen kann. Wie Sie vermuten können, ist es schwierig, Daten zu bearbeiten, wenn Sie diese nicht lesen können. Sie müssen deshalb die Konstante adRightRead mit der Konstante adRightUpdate kombinieren, um es dem Benutzer oder der Gruppe zu ermöglichen, Tabellendaten zu lesen und zu ändern. Listing 34.20: Benutzerrechte ändern Private Sub cmdModifyRights_Click() Dim cat As ADOX.Catalog Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection cat.Groups(Me.cboGroupName.Value).SetPermissions _ Me.lstTables.Value, _ ObjectType:=adPermObjTable, _ Action:=adAccessSet, _ Rights:=adRightRead Or adRightUpdate End Sub
Eine Datenbank mit Hilfe von Code verschlüsseln
34.7
1167
Eine Datenbank mit Hilfe von Code verschlüsseln
Kapitel 33 erläutert, wie Sie mit Hilfe der Benutzerschnittstelle eine Datenbank verschlüsseln können. Wenn eine Datenbank nicht verschlüsselt ist, ist sie nicht wirklich sicher, da ein schlauer Benutzer einen Disk-Editor verwenden kann, um die Daten in der Datei zu betrachten. Wenn Sie Ihre Anwendung mit der Laufzeitversion von Access verteilen und Ihren Benutzern die Möglichkeit geben wollen, die Datenbank zu verschlüsseln, müssen Sie für die Durchführung des Verschlüsselungsprozesses ADO-Code schreiben. Der Code sieht wie folgt aus: Sub Encrypt(strDBNotEncrypted As String, strDBEncrypted As String) Dim je As New JRO.JetEngine je.CompactDatabase Sourceconnection:="Data Source=" _ & strDBNotEncrypted & ";", _ Destconnection:="Data Source=" & strDBEncrypted & _ "; Jet OLEDB:Encrypt Database=True" End Sub
Diese Subroutine erhält zwei Parameter. Der erste Parameter ist der Name der Datenbank, die Sie verschlüsseln wollen. Der zweite ist der Name, den Sie der verschlüsselten Datenbank zuweisen möchten. Die Methode CompactDatabase wird auf dem JetEngine-Objekt ausgeführt. Diese Methode übernimmt ebenfalls zwei Parameter: den Namen der zu verschlüsselnden Originaldatenbank und den Namen für die neue verschlüsselte Datenbank. Beachten Sie, dass die Datenquelle für die Zieldatenbank Informationen enthält, die anzeigen, dass Sie die Datenbank in komprimierter Form verschlüsseln möchten.
34.8
Mit Hilfe von Abfragen Sicherheit auf Feldebene erreichen
Access selbst bietet zunächst keine Sicherheit auf Feldebene. Sie können die Sicherheit auf Feldebene jedoch mit Hilfe von Abfragen erzielen. Dies funktioniert folgendermaßen: Sie geben dem Benutzer oder der Gruppe keine Rechte für die Tabelle, die Sie schützen wollen. Stattdessen geben Sie dem Benutzer oder der Gruppe Rechte für eine Abfrage, welche nur die Felder enthält, die der Benutzer sehen darf. Normalerweise würde dies nicht funktionieren, da Benutzer die Daten im AbfrageErgebnis nicht lesen können, wenn es Ihnen nicht auch möglich ist, die der Abfrage zu Grunde liegenden Tabellen einzusehen. Der Trick besteht in einer Abfrageoption namens WITH OWNERACCESS OPTION. Diese Option für eine Abfrage gewährt dem die Abfrage ausführenden Benutzer die Rechte,
1168
Kapitel 34: Fortgeschrittene Sicherheitstechniken
die der Eigentümer der Abfrage besitzt. Die Gruppe Staff hat beispielsweise keine Rechte in Bezug auf die Tabelle tblEmployees. Die Gruppe Supervisors hat für diese Tabelle die Berechtigungen Entwurf lesen, Daten lesen und Daten aktualisieren. Der Eigentümer der Abfrage qryEployees ist die Gruppe Supervisors, wie in Abbildung 34.6 gezeigt. Abbildung 34.7 zeigt die Abfrage selbst. Beachten Sie in dieser Abbildung, dass die Eigenschaft Run Permissions auf den Wert Owners gesetzt wurde. Abbildung 34.8 zeigt die resultierende SQL-Ansicht. Beachten Sie die WITH OWNERACCESS OPTION-Klausel am Ende der SQL-Anweisung. Wenn ein Mitglied der Gruppe Staff (das keine anderen Rechte auf tblEmployees besitzt) die Abfrage ausführt, erbt dieses Mitglied die Fähigkeit der Gruppe Supervisors, die Tabellendaten lesen und ändern zu können.
Abbildung 34.6: Die Abfrage, deren Eigentümer die Gruppe Supervisors ist
Abbildung 34.7: Die Entwurfsansicht einer Abfrage, wobei Run Permissions auf Eigentümer gesetzt ist
1169
Benutzer und Gruppen von der Erstellung von Objekten ausschließen
Abbildung 34.8: Die SQL-Ansicht einer Abfrage, wobei Run Permissions auf Eigentümer gesetzt ist
34.9
Benutzer und Gruppen von der Erstellung von Objekten ausschließen
Sie wollen möglicherweise die Mitglieder einer Arbeitsgruppe davon ausschließen, neue Datenbanken oder bestimmte Datenbankobjekte erstellen zu können. Benutzer von der Erstellung von Datenbanken oder anderen Objekten auszuschließen kann nur mit Hilfe von VBA-Code erreicht werden.
34.9.1
Benutzer und Gruppen von der Erstellung von Objekten ausschließen
Sie wollen eventuell Benutzer davon ausschließen, bestimmte Typen von Objekten zu erstellen. Beispielsweise wollen Sie, dass Benutzer keine neuen Tabellen, Abfragen oder andere Objekte in Ihrer Anwendung oder Datenbankdatei erstellen können. Listing 34.21 veranschaulicht diesen Prozess. Listing 34.21: Benutzer von der Erstellung anderer Objekte ausschließen Sub NoTables(strGroupToProhibit) On Error GoTo NoTables_Err Dim cat As ADOX.Catalog Set cat = New ADOX.Catalog cat.ActiveConnection = CurrentProject.Connection cat.Tables.Refresh cat.Groups(strGroupToProhibit).SetPermissions Null, _ adPermObjTable, adAccessDeny, adRightCreate
NoTables_Exit: Set cat = Nothing Exit Sub
1170
Kapitel 34: Fortgeschrittene Sicherheitstechniken
NoTables_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description Resume NoTables_Exit End Sub
Der Code verwendet die Methode SetPermissions der Groups-Auflistung des CatalogObjekts, um die Berechtigungen für neue Tabellen festzulegen. Die in diesem Beispiel verwendeten Parameter verweigern Rechte zum Erstellen von Tabellen für die im Aufruf der Funktion festgelegte Gruppe.
34.10 Sich als ein anderer Benutzer anmelden, um verbotene Aufgaben auszuführen Obwohl Sie vielleicht nicht wollen, dass bestimmte Benutzer in der Lage sind, bestimmte Aufgaben auszuführen, wollen Sie gelegentlich hinter die Kulissen schauen und die Aufgabe für die Benutzer erledigen. Wie Sie im vorherigen Abschnitt gesehen haben, können Sie einen Benutzer von der Erstellung neuer Tabellen und Abfragen ausschließen. Das ist gut, außer wenn Sie in eine Situation geraten, in der Ihr Code erfordert, dass eine temporäre Tabelle erstellt werden muss. In dieser Situation können Sie sich zeitweilig als ein anderer Benutzer anmelden, den Vorgang ausführen und sich dann wieder abmelden.
34.11
Client-Server-Anwendungen schützen
Es ist wichtig zu verstehen, dass Sicherheit für Client-Server-Anwendungen auf dem Back-End-Datenbankserver angewendet werden muss. Sie können IDs und Kennwörter für die Anmeldung von den Benutzern zur Laufzeit anfordern und diese als Teil der Verbindungszeichenfolge dem Datenbankserver übergeben, aber die Sicherheitsfunktionen von Access selbst interagieren in keiner Weise mit Client-ServerDaten. Fehler, die vom Back-End zurückgegeben werden, müssen durch Ihre Anwendung behandelt werden.
34.12 Sicherheit und Replikation Datenbanksicherheit kann nicht auf replizierten Datenbanken, sondern nur auf Benutzerebene implementiert werden. Alle Replikate erben die Sicherheit, welche für den Hauptentwurf (Designmaster) gilt. Replizieren Sie nur die Datenbankdatei. Replizieren Sie jedoch niemals die Sicherheitsinformationsdatei (System.mdw). Stellen Sie statt dessen sicher, dass genau dieselbe Sicherheitsinformationsdatei an jedem Standort verfügbar ist, an dem das Replikat verwendet wird. Sie können dies erreichen, indem Sie eine Kopie der Datei an jedem Ort erstellen.
Sicherheit und Replikation
1171
Ein Benutzer muss die Berechtigung »Verwalten« für eine Datenbank besitzen, um die folgenden Aufgaben auszuführen:
Konvertieren einer nicht replizierbaren Datenbank in eine replizierbare Datenbank
Erstellen eines Replikats des Designmaster ein lokales Objekt replizierbar machen ein replizierbares Objekt lokal machen
34.12.1 Für die Praxis Fortgeschrittene Techniken für Ihre Anwendung einsetzen Die fortgeschrittenen Techniken, die Sie in das Zeit- und Abrechnungssystem integriert haben, sind davon abhängig, wieviel Verantwortung Sie der Anwendung für das Implementieren von Sicherheit geben wollen. Möglicherweise wollen Sie Sicherheit von außerhalb der Anwendung implementieren, anstatt direkt in die Anwendung einzubauen. Falls Sie wollen, können Sie alle in CHAP34EX.MDB enthaltenen Formulare direkt zum Zeit- und Abrechnungssystem hinzufügen. Außerdem können Sie den Code in der Routine AutoExec (der im Abschnitt »Sicherstellen, dass Benutzer Kennwörter besitzen« erläutert wird) zum Zeit- und Abrechnungssystem hinzufügen, so dass Sie Benutzer, welche die Anwendung ausführen, zwingen können, sich selbst ein Kennwort zuzuweisen.
Anwendungsdokumentation
Kapitel
Hier lesen Sie:
Für Systempflege, zum Nachschlagen Ihrer Anwendung die Dokumentation selbst überlassen Der Datenbank-Dokumentierer Routinen zum Erstellen eigener Dokumentationen schreiben
35.1
Für Systempflege, zum Nachschlagen
In der Vergangenheit, genaugenommen zur Zeit der Großrechner und der stark formalisierten und zentralisierten EDV-Abteilungen, war die Dokumentation eine obligatorische Notwendigkeit für die Vollendung einer Anwendung. Heutzutage scheint es, als würden alle möglichen Leute Anwendungen entwickeln: Verwaltungsassistenten, Geschäftsführer, Verkaufsleiter, EDV-Profis usw. Noch schlimmer aber ist, dass auch viele von uns, die wir uns zur Gruppe der Experten zählen, noch eine formale Ausbildung in der Systementwicklung genossen haben. Schließlich ist die Anforderung, eine Anwendung zu erstellen und zum Laufen zu bringen und danach zur nächsten Anwendung überzugehen, dringlicher denn je zuvor. Als Ergebnis all dieser Faktoren kann man den Eindruck gewinnen, dass die Dokumentation ins Abseits geraten ist. Trotz dieser Gründe, warum scheinbar keine Dokumentation mehr stattfindet, ist es heute immer noch genauso wichtig, die eigene Anwendung zu dokumentieren, wie zu den Zeiten der Großrechner. Eine ordentliche Dokumentation bietet Ihnen und Ihren Benutzern folgende Vorteile:
Sie erleichtert Ihnen und anderen die Systempflege. Sie hilft, den Zweck und die Funktionsweise jedes Objekts in der Anwendung festzuhalten.
1174
Kapitel 35: Anwendungsdokumentation
Dieses Kapitel befasst sich mit den verschiedenen Möglichkeiten, wie Sie Ihre Anwendung dokumentieren können. Dabei lernen Sie nicht nur, wie Sie Ihre Anwendungsobjekte, sondern auch wie Sie Ihren Anwendungscode dokumentieren sollten.
35.2
Ihrer Anwendung die Dokumentation selbst überlassen
Glücklicherweise befindet sich im Lieferumfang von Access ein hervorragendes Werkzeug, das Ihnen beim Dokumentieren Ihrer Datenbank hilfreich zur Hand geht: der Datenbank-Dokumentierer. Obwohl Sie dieses Werkzeug ohne besondere Vorbereitung verwenden können, kann etwas Mühe und Vorausschau beim Erstellen Ihrer Anwendungskomponenten den Wert der vom Datenbank-Dokumentierer gelieferten Ausgabe beträchtlich erhöhen.
35.2.1
Ihre Tabellen dokumentieren
Der Datenbank-Dokumentierer druckt sämtliche Feld- und Tabellenbeschreibungen, die im Laufe des Tabellenentwurfs eingegeben wurden. Abbildung 35.1 zeigt eine Tabelle in der Entwurfsansicht. Beachten Sie die Beschreibungen für die Felder ClientID und StateProvince. Diese Beschreibungen stellen zusätzliche Informationen bereit, die aus der bloßen Betrachtung der Feldnamen nicht unbedingt hervorgehen. Außerdem enthält das Fenster TABELLENEIGENSCHAFTEN eine Eigenschaft Beschreibung. Diese Eigenschaft wird in die Dokumentation der Tabelle aufgenommen, wenn sie im Datenbank-Dokumentierer gedruckt wird.
Abbildung 35.1: Dokumentieren einer Tabelle durch Einfügen von Beschreibungen für jedes Feld und Verwenden des Dialogfeldes Tabelleneigenschaften
Das Eingeben einer Tabellenbeschreibung erweitert aber nicht nur die Ausgabe des Datenbank-Dokumentierers für Tabellen, sondern es hilft Ihnen und den Benutzern Ihrer Datenbank auch beim Umgang mit den zu Ihrer Anwendung gehörenden
Ihrer Anwendung die Dokumentation selbst überlassen
1175
Tabellen. Abbildung 35.2 zeigt das Datenbankfenster nach der Eingabe von Beschreibungen für die Tabellen. Beachten Sie, dass die Beschreibungen für jede einzelne Tabelle im Datenbankfenster aufgeführt werden.
Abbildung 35.2: Das Datenbankfenster mit den Tabellenbeschreibungen
35.2.2
Ihre Abfragen dokumentieren
So wie Sie die Ausgabe des Datenbank-Dokumentierers für Tabellen erweitern können, haben Sie dieselbe Möglichkeit auch bei Abfragen. Abbildung 35.3 zeigt das Fenster ABFRAGEEIGENSCHAFTEN. Wie Sie sehen können, enthält die Eigenschaft Beschreibung in diesem Fall eine ausführliche Beschreibung des Zwecks der Abfrage. Im Gegensatz dazu stellt Abbildung 35.4 die Beschreibung einer einzelnen Spalte in einer Abfrage dar. Sowohl die Beschreibung der Abfrage als auch die der Felder erscheint innerhalb der Ausgabe des Datenbank-Dokumentierers.
Abbildung 35.3: Dokumentieren einer Abfrage mit Hilfe der Eigenschaft Beschreibung
1176
Kapitel 35: Anwendungsdokumentation
Abbildung 35.4: Dokumentieren einer Spalte in einer Abfrage
35.2.3
Ihre Formulare dokumentieren
Das Dokumentieren beschränkt sich nicht nur auf Tabellen und Abfragen. Ein Formular besitzt ebenfalls eine Eigenschaft Beschreibung, auf die allerdings nicht über die Entwurfsansicht eines Formulars zugegriffen werden kann. Um die Beschreibungseigenschaft eines Formulars zu betrachten oder zu bearbeiten, gehen Sie wie folgt vor: 1. Gehen Sie ins Datenbankfenster, so dass dieses aktiv wird. 2. Klicken Sie mit der rechten Maustaste auf das Formular, dem Sie eine Beschreibung hinzufügen möchten. 3. Wählen Sie den Menüeintrag EIGENSCHAFTEN. Daraufhin erscheint das Dialogfeld EIGENSCHAFTEN FÜR FORMULAR, das Sie in Abbildung 35.5 sehen. 4. Geben Sie in das Textfeld BESCHREIBUNG eine Beschreibung ein. 5. Klicken Sie auf OK. Die von Ihnen eingegebene Beschreibung erscheint zum einen, wie in Abbildung 35.6 gezeigt, im Datenbankfenster und zum anderen in der Ausgabe des Datenbank-Dokumentierers.
Abbildung 35.5: Sie können das Dialogfeld Eigenschaften für Objekte verwenden, um jedes Objekt in der Datenbank zu dokumentieren
Ihrer Anwendung die Dokumentation selbst überlassen
1177
Abbildung 35.6: Das Datenbankfenster mit einer Beschreibung eines Formulars
35.2.4
Ihre Berichte dokumentieren
Berichte werden in exakt derselben Weise dokumentiert wie Formulare. Sie verfügen über eine Eigenschaft Beschreibung, die im Dialogfeld EIGENSCHAFTEN FÜR BERICHT eingegeben werden muss. Um auf dieses Dialogfeld zuzugreifen, müssen Sie auch in diesem Fall mit der rechten Maustaste im Datenbankfenster auf das Objekt klicken und dann EIGENSCHAFTEN auswählen.
35.2.5
Ihre Makros dokumentieren
Makros können wesentlich ausführlicher dokumentiert werden als Formulare und Berichte. So haben Sie zum Beispiel die Möglichkeit, jede einzelne Makrozeile mit einem Kommentar zu versehen, wie es in Abbildung 35.7 zu sehen ist. Dadurch erreichen Sie nicht nur eine Dokumentierung durch den Datenbank-Dokumentierer, sondern Ihre Makrokommentare werden bei der Konvertierung eines Makros in ein VBA-Modul auch zu Code-Kommentaren. Neben der Dokumentierung jeder Makrozeile können Sie dem Makro außerdem eine Beschreibung hinzufügen. Wie bei Formularen und Berichten erreichen Sie das, indem Sie das Makro im Datenbankfenster mit der rechten Maustaste anklicken und im Kontextmenü EIGENSCHAFTEN auswählen.
35.2.6
Ihre Module dokumentieren
Ich kann nicht genug betonen, wie wichtig es ist, Ihre Module zu dokumentieren. Ein Mittel dafür sind Kommentare. Natürlich braucht aber nicht jede Programmzeile kommentiert zu werden. Ich dokumentiere vielmehr all die Bereiche im Code, die nicht für sich selbst sprechen. Kommentare helfen mir, wenn ich mir den Code später noch einmal anschaue, um Veränderungen und Erweiterungen vorzunehmen. Ferner stellen sie für all jene eine große Hilfe dar, die meinen Code warten müssen
1178
Kapitel 35: Anwendungsdokumentation
Abbildung 35.7: Ein Makro durch das Einfügen einer Beschreibung für jede einzelne Zeile dokumentieren
und schließlich geben sie dem Benutzer Anhaltspunkte darüber, was die Anwendung überhaupt macht. Kommentare werden mit Ihren Code-Modulen ausgedruckt, wie wir später in diesem Kapitel im Abschnitt über den Datenbank-Dokumentierer sehen werden. Wie jedes andere Objekt auch können Sie ein Modul mit der rechten Maustaste anklicken und ihm eine Beschreibung zuweisen.
35.2.7
Mit Hilfe von Datenbankeigenschaften die gesamte Datenbank dokumentieren
Neben der Möglichkeit, Ihren Datenbankobjekten Beschreibungen zuzuweisen, lässt Sie Microsoft Access auch die Datenbank als Ganzes dokumentieren, indem Sie Datenbankeigenschaften festlegen. Dazu wählen Sie DATEI|DATENBANKEIGENSCHAFTEN oder klicken mit der rechten Maustaste auf die Titelleiste des Datenbankfensters und wählen DATENBANKEIGENSCHAFTEN. Daraufhin erscheint das Dialogfeld DATENBANKEIGENSCHAFTEN, das in Abbildung 35.8 gezeigt wird. Wie Sie sehen können, enthält dieses Dialogfeld die Registerkarten ALLGEMEIN, ZUSAMMENFASSUNG, STATISTIK, INHALT und ANPASSEN. Im Folgenden werden die Registerkarten des Dialogfeldes DATENBANKEIGENSCHAFbeschrieben:
TEN
Allgemein – Die Registerkarte ALLGEMEIN zeigt allgemeine Informationen über Ihre Datenbank an. Hierzu gehören das Erstellungsdatum, das Datum der letzten Änderung und des letzten Zugriffs, der Speicherort, die Größe, der MS-DOSName und die Dateiattribute der Datenbank. Es ist nicht möglich, Informationen auf der Registerkarte ALLGEMEIN zu bearbeiten.
Zusammenfassung – Die Registerkarte ZUSAMMENFASSUNG, die Sie in Abbildung 35.9 sehen, enthält bearbeitbare Informationen, welche die Datenbank und ihre Aufgaben beschreiben. Diese Registerkarte umfasst den Datenbanktitel, das Thema und Kommentare über die Datenbank. Außerdem finden Sie dort eine
Ihrer Anwendung die Dokumentation selbst überlassen
1179
Abbildung 35.8: Die Registerkarte Allgemein des Dialogfeldes Datenbankeigenschaften
Hyperlinkbasis, d.h. eine Basisadresse für alle relativen Links, die in die Datenbank eingefügt werden. Bei diesen kann es sich um eine Internetadresse (URL) oder um einen Dateipfad (UNC) handeln.
Statistik – Die Registerkarte STATISTIK enthält statistische Informationen über die Datenbank, wie zum Beispiel ihr Erstellungsdatum sowie die Daten der letzten Änderung und des letzten Zugriffs.
Inhalt – Die Registerkarte INHALT, die in Abbildung 35.10 zu sehen ist, führt alle in der Datenbank enthaltenen Objekte auf.
Anpassen – Die Registerkarte ANPASSEN versetzt Sie in die Lage, für die Datenbank benutzerdefinierte Eigenschaften festzulegen. Dies ist besonders nützlich, wenn Sie es mit einer großen Organisation und einer Vielzahl von Datenbanken zu tun haben und Sie in der Lage sein wollen, alle Datenbanken mit bestimmten Eigenschaften zu suchen.
1180
Kapitel 35: Anwendungsdokumentation
Abbildung 35.9: Die Registerkarte Zusammenfassung des Dialogfeldes Datenbankeigenschaften
Abbildung 35.10: Die Registerkarte Inhalt des Dialogfeldes Datenbankeigenschaften
1181
Der Datenbank-Dokumentierer
35.3
Der Datenbank-Dokumentierer
Der Datenbank-Dokumentierer ist ein sehr elegantes Werkzeug, das zum Lieferumfang von Microsoft Access gehört und Ihnen die Möglichkeit gibt, für jedes Objekt in Ihrer Datenbank eine mehr oder weniger umfassende Dokumentation zu erzeugen. Um den Datenbank-Dokumentierer zu verwenden, gehen Sie wie folgt vor: 1. Stellen Sie sicher, dass das Datenbankfenster aktiv ist. 2. Wählen Sie EXTRAS|ANALYSE|DOKUMENTIERER. Es erscheint das Dialogfeld Dokumentierer, das in Abbildung 35.11 zu sehen ist.
Abbildung 35.11: Sie können den DatenbankDokumentierer benutzen, um zu bestimmen, welche Objekte dokumentiert werden sollen
3. Klicken Sie die entsprechende Registerkarte an, um den Objekttyp auszuwählen, den Sie dokumentieren wollen. Zum Dokumentieren einer Tabelle wählen Sie zum Beispiel die Registerkarte TABELLEN. 4. Aktivieren Sie das Kontrollkästchen links von jedem Objekt, das dokumentiert werden soll. Sie können auch die Schaltfläche ALLE AUSWÄHLEN anklicken, um alle Objekte des gewünschten Typs auszuwählen. 5. Klicken Sie die Schaltfläche OPTIONEN, um die Dokumentationsdetails für jedes Objekt zu ändern. Je nach Objekttyp werden verschiedene Optionen angezeigt. Die Optionen des Datenbank-Dokumentierers sind Gegenstand des nächsten Abschnitts in diesem Kapitel. 6. Wiederholen Sie die Schritte 3-5, um alle Datenbankobjekte auszuwählen, die Sie dokumentieren wollen. 7. Klicken Sie auf OK, um die Dokumentation schließlich zu erstellen.
1182
Kapitel 35: Anwendungsdokumentation
Um alle Objekte in der Datenbank zu dokumentieren, klicken Sie zunächst auf die Registerkarte ALLE OBJEKTTYPEN und dann die Schaltfläche ALLE AUSWÄHLEN.
Es kann ein wenig dauern, bis Access die angeforderte Dokumentation generiert hat, insbesondere wenn viele Objekte ausgewählt wurden. Aus diesem Grund sollten Sie mit der Dokumentierung nicht beginnen, wenn Sie kurz danach Ihren Computer brauchen. Während Access diese Aufgabe verrichtet, ist das Umschalten zu einer anderen Anwendung nämlich schwierig, wenn nicht sogar unmöglich – dies hängt ganz davon ab, über wieviel Speicher und Prozessorleistung Ihr System verfügt.
Um die Eigenschaften der Datenbank oder die Beziehungen zwischen den Tabellen in der Datenbank zu dokumentieren, aktivieren Sie die Registerkarte AKTUELLE DATENBANK und wählen dort EIGENSCHAFTEN oder BEZIEHUNGEN. Nachdem Sie die gewünschten Objekte und Optionen ausgewählt und auf OK geklickt haben, erscheint das Fenster OBJEKTDEFINITION. Sie können die Seitenansicht verwenden, um die Dokumentationsausgabe für die ausgewählten Objekte zu betrachten (siehe Abbildung 35.12). Diese Seitenansicht entspricht jedem anderen Seitenansichtsfenster, d.h., Sie können sich jede Seite der Dokumentation ansehen und die Dokumentation auf einem Drucker ausdrucken.
Abbildung 35.12: Das Seitenansichtsfenster Objektdefinition
Der Datenbank-Dokumentierer
35.3.1
1183
Die Optionen des Datenbank-Dokumentierers verwenden
Der Datenbank-Dokumentierer gibt für jedes ausgewählte Objekt standardmäßig eine große Menge von Informationen aus. Beispielsweise wird jedes Steuerelement auf einem Formular mit allen seinen Eigenschaften dokumentiert. Auf diese Weise kann es leicht passieren, dass schon für wenige Datenbankobjekte mehr als 50 Seiten Dokumentation entstehen. Neben dem Aspekt der enormen Papierverschwendung ist diese Fülle von Daten kaum noch zu überblicken. Glücklicherweise können Sie jedoch den Grad der Dokumentation für jede Objektkategorie geeigneter festlegen. Klicken Sie dazu im Dialogfeld DOKUMENTIERER einfach auf die Schaltfläche OPTIONEN. Abbildung 35.13 zeigt das Dialogfeld Tabellendefinition drucken. Beachten Sie, dass Sie dort festlegen können, ob für Tabellen Eigenschaften, Beziehungen und Berechtigungen für Benutzer und Gruppen mit dokumentiert werden sollen. Ferner bietet Ihnen dieses Dialogfeld die Möglichkeit, die Einzelheiten für jedes Feld anzugeben: NICHTS, NAMEN, DATENTYPEN UND GRÖSSEN sowie NAMEN, DATENTYPEN, GRÖSSEN UND EIGENSCHAFTEN. Für Tabellenindizes stehen Ihnen schließlich folgende Optionen zur Verfügung: NICHTS, NAMEN UND FELDER sowie NAMEN, FELDER UND EIGENSCHAFTEN.
Abbildung 35.13: Sie können das Dialogfeld Tabellendefinition drucken verwenden, um die zu dokumentierenden Aspekte einer Tabelle festzulegen
Wenn Sie die Registerkarte ABFRAGEN auswählen und dann auf OPTIONEN klicken, erscheint das Dialogfeld ABFRAGEDEFINITION DRUCKEN, das Sie in Abbildung 35.14 sehen. Hier können Sie festlegen, in welchem Maße die ausgewählten Abfragen dokumentiert werden sollen. So haben Sie die Möglichkeit, für die Abfrage Eigenschaften, SQL, Parameter, Beziehungen und Berichtigungen für Benutzer und Gruppen auszugeben. Ferner können Sie bestimmen, welche Daten für jede Spalte und die Indizes der Abfrage einzubeziehen sind.
1184
Kapitel 35: Anwendungsdokumentation
Abbildung 35.14: Sie können das Dialogfeld Abfragedefinition drucken verwenden, um die zu dokumentierenden Aspekte einer Abfrage festzulegen
Die Optionen für Formulare und Berichte sehen ähnlich aus. Abbildung 35.15 zeigt das Dialogfeld FORMULARDEFINITION DRUCKEN, in dem Sie vorgeben können, ob für das Formular Eigenschaften, Code und Berechtigungen für Benutzer und Gruppen zu drucken sind. Für jedes Steuerelement auf dem Formular stehen Ihnen folgende Optionen zur Verfügung: NICHTS, NAMEN sowie NAMEN UND EIGENSCHAFTEN. Das Dialogfeld BERICHTSDEFINITION DRUCKEN bietet dieselben Möglichkeiten. Beide Dialogfelder stellen außerdem eine Befehlsschaltfläche EIGENSCHAFTEN bereit, mit deren Hilfe Sie die auszudruckenden Eigenschaften nach Kategorien (ANDERE, EREIGNIS, DATEN und FORMAT) festlegen können. Diese Funktion bietet Ihnen die Möglichkeit, sich auf die für Sie interessanten Eigenschaftenkategorien zu beschränken.
Abbildung 35.15: Sie können das Dialogfeld Formulardefinition drucken verwenden, um die zu dokumentierenden Aspekte eines Formulars festzulegen
Mit Hilfe von Code eine eigene Dokumentation erstellen
1185
Was Makros angeht, so können Sie entscheiden, ob Sie die Eigenschaften, Aktionen und Argumente oder Berechtigungen für Benutzer und Gruppen drucken wollen, während Sie für Module aus den Optionen EIGENSCHAFTEN, CODE und BERECHTIGUNGEN FÜR BENUTZER UND GRUPPEN wählen können. Wie Sie sehen, bietet der Datenbank-Dokumentierer ein enormes Maß an Flexibilität. Natürlich macht der Dokumentierer aber nur Sinn, wenn Sie zuvor die entsprechenden Objekteigenschaften (zum Beispiel die Beschreibung) ausgefüllt haben, denn er kann nur ausgeben, was auch vorhanden ist.
35.3.2
Andere Arten von Dokumentation erstellen
Nachdem Sie die Dokumentation erstellt haben und sie im Vorschaufenster OBJEKTDEFINITION erschienen ist, können Sie sie in andere Formate exportieren. Wählen Sie dazu im Vorschaufenster DATEI|EXPORTIEREN. Daraufhin erscheint das Dialogfeld EXPORTIEREN VON BERICHT, das Sie in Abbildung 35.16 sehen. Beachten Sie, dass Ihnen als Ausgabeformate Microsoft Excel, HTML, Textdateien, ein RTFDateiformat und ein Snapshot-Format zur Verfügung stehen. Geben Sie den Dateinamen ein, wählen Sie den Dateityp und klicken Sie anschließend auf SPEICHERN. Wenn Sie im Dialogfeld EXPORTIEREN VON BERICHT das Kontrollkästchen AUTOSTART aktivieren, erstellt der Dokumentierer die Datei und startet dann die geeignete Anwendung wie zum Beispiel den Internet Explorer, falls Sie diese Anwendung als Standard für die Dateinamenerweiterung HTML bzw. HTM festgelegt haben. In ähnlicher Weise startet der Dokumentierer Microsoft Excel, wenn Sie als Dateityp Microsoft Excel ausgewählt haben und in der Registrierung Excel mit XLS-Dateien verknüpft ist. Immer erscheint die Ausgabe direkt in der geeigneten Anwendung. Dasselbe gilt auch für alle anderen Dateitypen, wobei RTF und TXT in der Registrierung üblicherweise mit Word und dem Editor assoziiert sind.
35.4
Mit Hilfe von Code eine eigene Dokumentation erstellen
In den meisten Fällen reichen die vom Datenbank-Dokumentierer bereitgestellten Optionen völlig aus. Es kann aber auch vorkommen, dass Sie mit dem vom Datenbank-Dokumentierer ausgewählten Format nicht einverstanden sind – oder was noch wichtiger ist, Eigenschaften von Datenbankobjekten dokumentieren wollen, auf die nicht über die Benutzerschnittstelle zugegriffen werden kann. In diesen Fällen können Sie die Datenbankobjekte mit Hilfe von Code aufzählen und sie in einem benutzerdefinierten Berichtsformat dokumentieren. ADO bietet Ihnen die Möglichkeit, beliebige Objekte in Ihrer Datenbank aufzuzählen. Listing 35.1 zeigt ein Beispiel dafür.
1186
Kapitel 35: Anwendungsdokumentation
Abbildung 35.16: Sie können das Dialogfeld Exportieren von Bericht benutzen, um das Dateiformat festzulegen, in das die Objektdefinition ausgegeben werden soll Listing 35.1:
Mit Hilfe von ADO die Tabellenobjekte in einer Datenbank aufzählen
Sub EnumerateTables() Dim Dim Dim Dim
conn As New Connection adoCat As New ADOX.Catalog adoTbl As New ADOX.Table strSQL As String
DoCmd.SetWarnings False Set conn = CurrentProject.Connection adoCat.ActiveConnection = conn For Each adoTbl In adoCat.Tables If adoTbl.Type = "Table" Then strSQL = "INSERT INTO tblTableDoc" _ & "(TableName, DateCreated, LastModified) " _ & "Values (""" & adoTbl.Name & """, #" _ & adoTbl.DateCreated & "#, #" _ & adoTbl.DateModified & "#) " DoCmd.RunSQL strSQL End If Next adoTbl DoCmd.SetWarnings True End Sub
Mit Hilfe von Code eine eigene Dokumentation erstellen
1187
Die Routine EnumerateTables, die Sie im Modul basDocument der Datenbank CHAP35EX.MDB auf Ihrer Beispiel-CD-ROM finden, dokumentiert verschiedene Informationen über die Tabellen in der Datenbank. Sie verwendet den ADOXKatalog und Tabellenobjekte sowie eine For...Each-Schleife, um alle Tabellendefinitionen in der Datenbank zu durchlaufen. Für jede Tabelle wird bestimmt, ob die Typeigenschaft der Tabelle auf »Tabelle« gesetzt ist, was bedeutet, dass es sich um eine Standardtabelle handelt (und nicht um eine Systemtabelle oder um eine Abfrage). Anschließend führt die Routine eine SQL-Anweisung aus, die sämtliche in Erfahrung gebrachten Informationen über die Tabellendefinition in eine Tabelle tblTableDoc einfügt. Diese Tabelle kann danach als Grundlage für einen Bericht herangezogen werden. Natürlich ist es mit derselben Technik möglich, durch Benutzung der geeigneten Schleifen und Eigenschaften zusammen mit dem ADOX-Objektmodell jede beliebige Information über absolut jedes Objekt in der Datenbank zu bestimmen.
35.4.1
Für die Praxis
Das Gelernte auf das Zeit- und Abrechnungssystem anwenden Lernen Sie die verschiedenen Optionen des Datenbank-Dokumentierers anhand des Zeit- und Abrechnungssystems einmal in der Praxis kennen, indem Sie sie ausprobieren. Achten Sie beim Ändern der Optionen für jeden Objekttyp auf die Unterschiede in der Ausgabe. Wenn Ihre Ambitionen noch weiter gehen, versuchen Sie eine Routine zu schreiben, welche die Objekte in der Datenbank aufzählt.
Ihre Anwendung warten
Kapitel
Hier lesen Sie:
Weg mit ungenutztem Speicher Ihre Datenbank komprimieren
36.1
Weg mit ungenutztem Speicher
Obwohl der Wartungsaufwand mit Microsoft Access nicht allzu gewaltig ausfällt, müssen Sie ein wichtiges Verfahren kennen, mit dessen Hilfe Sie sicherstellen können, dass Sie Ihre Datenbank mit optimaler Effizienz warten. Dieses Verfahren wird als Komprimieren bezeichnet. Das Komprimieren einer Datenbank bedeutet, dass Sie aus einer Datenbank (bzw. aus der MDB-Datei) ungenutzten Speicherplatz entfernen. Der Vorgang an sich sowie die verschiedenen Möglichkeiten, wie Sie die Komprimierung durchführen können, werden in diesem Kapitel behandelt.
36.2
Ihre Datenbank komprimieren
Beim täglichen Umgang mit einer Datenbank nimmt diese stetig an Größe zu. Um die hohe Leistungsfähigkeit der Anwendung zu erhalten, verschiebt Access das Entfernen verworfener Seiten aus der Datenbank, bis Sie die Datenbankdatei explizit komprimieren. Dies wiederum bedeutet, dass der von gelöschten Objekten belegte Speicherplatz (der beim Hinzufügen von Daten und anderen Objekten zur Datenbank und beim Entfernen von Daten und Objekten aus der Datenbank zwangsläufig entsteht) nicht unmittelbar wieder freigegeben wird. Die Konsequenz daraus ist nicht nur eine sehr umfangreiche Datenbankdatei, sondern aufgrund von Fragmentierung schließlich auch eine starke negative Beeinträchtigung der Geschwindigkeit. Das Komprimieren einer Datenbank bewirkt Folgendes:
Es wird der gesamte Speicherplatz zurückgewonnen, der von gelöschten Daten und Datenbankobjekten belegt wurde.
1190
Kapitel 36: Ihre Anwendung warten
Es kommt zu einer Neustrukturierung der Datenbankdatei, so dass die Seiten jeder Tabelle in der Datenbank fortlaufend abgelegt sind. Dies führt zu einer besseren Geschwindigkeit, weil Tabellendaten beim Umgang mit Tabellen nacheinander auf dem Datenträger zu finden sind.
Es werden alle Zählfelder zurückgesetzt, so dass der nächste Wert genau um Eins größer ist als der letzte ungelöschte Zählerwert. Wenn Sie beim Testen der Datenbank viele Datensätze hinzufügen, die Sie beim Übergang in den täglichen Arbeitsablauf wieder löschen, setzt das Komprimieren der Datenbank alle Zählerstände zurück auf 1.
Es kommt zur Aktualisierung der Tabellenstatistiken, die von der Jet-Engine beim Ausführen von Abfragen verwendet werden, und das System sorgt dafür, dass alle Abfragen bei der nächsten Ausführung neu kompiliert werden. Diese beiden Aspekte sind sehr wichtig. Falls der Tabelle nämlich Indizes hinzugefügt wurden oder sich der Umfang der Tabellendaten drastisch geändert hat, würde die Abfrage nicht mehr effektiv ausgeführt. Die Ursache für diese Beeinträchtigung der Leistung besteht darin, dass in solchen Fällen der von Jet für die Ausführung genutzte gespeicherte Abfrageplan auf ungenauen Informationen basiert. Beim Komprimieren der Datenbank werden alle Tabellenstatistiken und der Abfrageplan so aktualisiert, dass sie den aktuellen Zustand der Tabellen in der Datenbank widerspiegeln. Sie sollten in Erwägung ziehen, die Festplatte, auf der die Datenbank gespeichert ist, vor dem Komprimieren zu defragmentieren. Auf diese Weise können Sie sicherstellen, dass für die komprimierte Datenbank eine maximale Menge zusammenhängenden Speicherplatzes zur Verfügung steht.
In früheren Versionen von Access wurde die Datenbankreparatur von einem anderen Hilfsprogramm durchgeführt als die Komprimierung. In Access 2000 hat sich dies jedoch geändert. Beim Komprimieren wird eine Datenbank automatisch auch repariert. Wenn Sie eine Datenbank öffnen, die repariert werden müsste, werden Sie aufgefordert, die Datenbank zu komprimieren. Um eine Datenbank zu komprimieren, können Sie von einer der vier folgenden Methoden Gebrauch machen:
Verwenden Sie die Befehle der Benutzerschnittstelle. Klicken Sie auf ein Symbol, das Sie für den Benutzer eingerichtet haben. Richten Sie die Datenbank so ein, dass sie bei jedem Schließen komprimiert wird. Benutzen Sie die Methode CompactDatabase.
Ihre Datenbank komprimieren
1191
Unabhängig davon, für welche Methode Sie sich entscheiden, müssen die folgenden Bedingungen erfüllt sein:
Der Benutzer, der die Komprimierung durchführt, muss das Recht haben, die Datenbank exklusiv zu öffnen.
Der die Komprimierung durchführende Benutzer muss die Berechtigung besitzen, sämtliche Tabellen in der Datenbank zu verändern.
Die Datenbank muss exklusiv geöffnet werden können, was bedeutet, dass in dieser Zeit kein anderer Benutzer auf die Datenbank zugreifen kann.
Das Laufwerk beziehungsweise der Datenträger im Netzwerk, auf dem die Datenbank gespeichert ist, darf nicht schreibgeschützt sein.
Die Dateiattribute der Datenbank dürfen nicht auf schreibgeschützt gesetzt sein. Es muss sowohl für die Datenbank als auch für die komprimierte Version der Datenbank genügend Speicherplatz verfügbar sein. Dies ist sogar dann erforderlich, wenn die Komprimierung in eine Datenbank mit demselben Namen durchgeführt wird. Es stellt eine sinnvolle Maßnahme dar, die Datenbank vor dem Versuch der Komprimierung zu sichern, da sie durch die Komprimierung beschädigt werden könnte. Missbrauchen Sie die Komprimierung auch nicht als Ersatz für umsichtige Sicherungsabläufe. Die Komprimierung selbst verläuft nicht immer erfolgreich und es ist nichts einfacher als eine anspruchsvoll ausgeführte Datensicherung.
Wenn Access einmal feststellt, dass eine Datenbank beschädigt ist, werden Sie aufgefordert, die Datenbank zu reparieren. Eine solche Situation kann eintreten, wenn Sie versuchen, die beschädigte Datenbank zu öffnen, zu komprimieren, zu verschlüsseln oder zu entschlüsseln. Es kann aber auch vorkommen, dass Access die Beschädigung nicht erkennt und Sie stattdessen vermuten, dass die Beschädigung auf ein unvorhergesehenes Datenbankverhalten zurückzuführen ist. Dies stellt den Moment dar, in dem Sie mit Hilfe der in diesem Kapitel vorgestellten Methoden eine erste Datensicherung vornehmen und die Komprimierung durchführen sollten.
36.2.1
Der Weg über die Benutzerschnittstelle
Die Access-Benutzerschnittstelle bietet einen unkomplizierten Zugriff auf die Komprimierfunktion. Um die aktuell geöffnete Datenbank zu komprimieren, wählen Sie EXTRAS|DATENBANK-DIENSTPROGRAMME|DATENBANK KOMPRIMIEREN UND REPARIEREN. Die Datenbank wird daraufhin geschlossen, komprimiert und wieder geöffnet.
1192
Kapitel 36: Ihre Anwendung warten
Um eine andere als die aktuelle Datenbank zu komprimieren, gehen Sie wie folgt vor: 1. Schließen Sie die geöffnete Datenbank. 2. Wählen Sie EXTRAS|DATENBANK-DIENSTPROGRAMME|DATENBANK KOMPRIMIEREN UND REPARIEREN. Sie gelangen nun in das Dialogfeld DATENBANK KOMPRIMIEREN (siehe Abbildung 36.1).
Abbildung 36.1: Das Dialogfeld Datenbank komprimieren
3. Wählen Sie die zu komprimierende Datenbank aus und klicken Sie auf KOMPRIMIEREN. Daraufhin erscheint das Dialogfeld DATENBANK KOMPRIMIEREN NACH, das Sie in Abbildung 36.2 sehen.
Abbildung 36.2: Das Dialogfeld Datenbank komprimieren nach
Ihre Datenbank komprimieren
1193
4. Legen Sie den Namen für die komprimierte Datenbank fest. (Dies kann der Name der ursprünglichen Datenbank oder ein neuer Name sein. Sollten Sie der Zieldatenbank jedoch denselben Namen geben, vergewissern Sie sich, dass die Datenbank gesichert wurde.) Klicken Sie auf SPEICHERN. 5. Falls Sie denselben Namen ausgewählt haben, werden Sie aufgefordert, die vorhandene Datei zu ersetzen. Klicken Sie auf JA.
36.2.2
Eine Verknüpfung verwenden
Ein sehr einfaches Mittel, um Benutzern eine Möglichkeit zum Komprimieren einer Datenbank an die Hand zu geben, besteht im Erstellen eines Symbols, das die Komprimierung ausführt. Dies lässt sich mit Hilfe der Befehlszeilenoption /Compact bewerkstelligen. Diese Option komprimiert die Datenbank, ohne sie dafür zu öffnen. Die Verknüpfung könnte zum Beispiel wie folgt aussehen: c:\MSOffice\Access\Msaccess.exe c:\Databases\TimeAndBilling.MDB /Compact
Sie können im Anschluss an diese Zeile ein Leerzeichen und dann den Namen einer Zieldatenbank eingeben, wenn Sie nicht wollen, dass die aktuelle Datenbank durch die komprimierte Version überschrieben wird. Falls Sie für die Zieldatenbank einen Pfad festlegen, wird sie standardmäßig in den Ordner Eigene Dateien geschrieben. Das Erstellen der Befehlszeile kann Ihnen abgenommen werden, indem Sie den Setup-Assistenten benutzen, der mit Office 2000 Developer ausgeliefert wird. Diese Möglichkeit wird in Kapitel 37 näher beschrieben. Um die Verknüpfung selbst zu erstellen, gehen Sie wie folgt vor: 1. Öffnen Sie den Ordner, in dem Ihre Anwendung installiert ist. 2. Klicken Sie mit der rechten Maustaste auf das Anwendungssymbol (MDB) für Ihre Datenbank. 3. Wählen Sie VERKNÜPFUNG ERSTELLEN. 4. Klicken Sie mit der rechten Maustaste auf die gerade erstellte Verknüpfung. 5. Wählen Sie EIGENSCHAFTEN. 6. Klicken Sie die Registerkarte VERKNÜPFUNG an. 7. Bearbeiten Sie die Verknüpfung so, dass sie wie im vorangegangenen Beispiel aussieht.
36.2.3
Beim Schließen der Datenbank
Indem Sie die Umgebungsoption BEIM SCHLIESSEN KOMPRIMIEREN verwenden, können Sie festlegen, dass bestimmte Datenbanken bei jedem Schließen komprimiert werden. Eine Datenbank wird dann beim Schließen nur in dem Fall komprimiert,
1194
Kapitel 36: Ihre Anwendung warten
wenn ihre Größe durch das Komprimieren um mindestens 256 KB abnimmt. Um die Umgebungseinstellung BEIM SCHLIESSEN KOMPRIMIEREN zu aktivieren, gehen Sie folgendermaßen vor: 1. Öffnen Sie die zu komprimierende Datenbank und wählen Sie EXTRAS|OPTIONEN. 2. Klicken Sie die Registerkarte ALLGEMEIN des Dialogfeldes OPTIONEN. 3. Markieren Sie das Kontrollkästchen BEIM SCHLIESSEN KOMPRIMIEREN. Obwohl sie in EXTRAS|OPTIONEN gesetzt wird, betrifft die Einstellung BEIM SCHLIESSEN KOMPRIMIEREN nur die beim Auswählen der Option geöffnete Datenbank. Auf diese Weise können Sie sich aussuchen, welche Datenbanken beim Schließen komprimiert werden sollen.
Bedenken Sie, dass auch das Komprimieren beim Schließen voraussetzt, dass alle allgemeinen Bedingungen für das Komprimieren einer Datenbank erfüllt sind. Falls sich in dem Moment, in dem ein Benutzer versucht, die Datenbank zu schließen, zum Beispiel noch andere Benutzer in der Datenbank befinden, erhält der Benutzer, der das Schließen initiiert hat, eine Fehlermeldung.
36.2.4
Komprimieren per Programm
Mit Hilfe der Methode CompactDatabase können Sie eine Datenbank auch von einem Programm aus komprimieren. Diese Methode wird auf einem Member-Objekt der Microsoft Jet and Replication Objects (JRO) genannten Klasse ausgeführt, nämlich auf dem JetEngine-Objekt. Sie übernimmt je eine Verbindungszeichenfolge für die Quelle und das Ziel als Parameter, mit deren Hilfe die Quell- und Zieldatenbanken angegeben werden. Die Parameter Source Connection und Destination Connection dienen außerdem den folgenden Zwecken:
dem Ändern des Speicherorts der Datenbank der Ver- bzw. Entschlüsselung der Datenbank der Konvertierung der Datenbank von einer älteren Jet-Version in eine neuere der Festlegung der Benutzer-ID und des Benutzerkennworts Die Eigenschaft Local Identifier des Parameters Destination Connection wird verwendet, um die Zusammensetzungsreihenfolge zu bestimmen, in der die Daten in der komprimierten Datenbank sortiert werden. Diese Option kommt immer dann zum Einsatz, wenn Sie es mit einer Datenbank zu tun haben, in der die Daten in einer anderen Sprache gespeichert sind und deren Daten in Abhängigkeit einer bestimmten Sprache zusammengestellt werden sollen.
Ihre Datenbank komprimieren
1195
Mit Hilfe der Eigenschaft Jet OLEDB:Encrypt Database des Parameters Destination Connection können Sie festlegen, ob die komprimierte Datenbank verschlüsselt werden soll. Falls Sie diese Eigenschaft nicht festlegen, erhält die komprimierte Datenbank denselben Verschlüsselungszustand wie die ursprüngliche Quelldatenbank. Die Eigenschaft Jet OLEDB:Engine Type des Parameters Source Connection dient der Angabe der Version der zu öffnenden Datenbank, während dieselbe Eigenschaft des Parameters Destination Connection die Version der zu erstellenden neuen Datenbank festlegt. Wird diese Eigenschaft ausgelassen, kommt für die Zieldatenbank die gleiche Version zum Einsatz wie für die Quelldatenbank. Schließlich geben Ihnen die Eigenschaften User ID und Password des Parameters Source Connection die Möglichkeit, den Benutzernamen und das zugehörige Kennwort für eine Datenbank anzugeben, die durch ein Kennwort geschützt ist. Der folgende Code, den Sie im Modul basCompactDB der Datenbank Chap36Ex.MDB finden, komprimiert und verschlüsselt eine Datenbank mit dem Namen Chap36Big.MDB: Sub CompactDB() Dim je As New JRO.jetengine If Len(Dir("c:\my documents\Chap36Small.mdb")) Then Kill "c:\my documents\Chap36Small.mdb" End If je.CompactDatabase SourceConnection:="Data Source=c:\my _ documents\Chap36Big.mdb", _ DestConnection:="Data Source=c:\my documents\Chap36Small.mdb; " & _ "Jet OLEDB:Encrypt Database=True" End Sub
Die komprimierte Datenbank wird den Namen Chap36Small.MDB erhalten. Im Verlauf der Komprimierung wird die Datenbank zudem verschlüsselt. Um diesen Code erfolgreich auszuführen, müssen Sie berücksichtigen, dass die Datenbank Chap36Big geschlossen sein und der die Routine ausführende Benutzer die Berechtigung zum exklusiven Öffnen der Datenbank besitzen muss. Darüber hinaus muss der Benutzer für alle Tabellen in der Datenbank über die Berechtigung Entwurf ändern verfügen. Weil die Methode CompactDatabase auf dem JRO-Jet-Objekt ausgeführt wird, ist es schließlich auch noch erforderlich, dass Sie einen Verweis auf die Microsoft Jet and Replication Objects 2.1 Library aufnehmen. Ein Verweis auf diese Bibliothek wird beim Erstellen einer neuen Access-Datenbank nicht standardmäßig eingefügt. Sie müssen vielmehr den Menübefehl EXTRAS|VERWEISE verwenden, um auf die JRO-Objektbibliothek zu verweisen.
Ihre Anwendung verteilen
Kapitel
Hier lesen Sie:
Eine Applikation für viele Der Package and Deployment Wizard Das Package and Deployment Wizard-Add-In laden Ihre Anwendung zur Ausführung mit einer vollständigen Kopie von Access verteilen
Vollversionen im Unterschied zu Laufzeitversionen von Access Ihre Datenbank für die Verwendung mit der Laufzeitversion von Access vorbereiten
Andere Fragestellungen
37.1
Eine Applikation für viele
Viele Entwickler sind für das Entwerfen von Anwendungen zuständig, die vielen Benutzern zur Verfügung gestellt werden. Die grundlegende Option der Weitergabe besteht darin, dass jeder Benutzer eine Kopie von Access erwerben muss und dann eine Kopie der Datenbankdateien (MDB) erhält, die für die Anwendung erforderlich sind. Der Entwickler kann anschließend zu jedem Benutzer gehen und die Anwendung in geeigneter Weise konfigurieren. Obwohl das Weitergeben einer Anwendung durch Kopieren auf die Rechner aller Benutzer nicht besonders viel an speziellem Wissen seitens des Entwicklers erfordert, ist dieses Vorgehen nicht sehr praktisch. Beispielsweise gibt der Entwickler in vielen Situationen eine Anwendung an Benutzer weiter, die im ganzen Land oder sogar in der ganzen Welt verstreut sind. Viele Access-Anwendungen werden von Hunderten oder Tausenden von Benutzern eingesetzt. In diesen Situationen ist es unerlässlich, ein professionelles Setup-Programm zu verwenden, um die Anwendung korrekt zu
1198
Kapitel 37: Ihre Anwendung verteilen
installieren. Aus diesen Gründen verteilen die meisten Entwickler ihre Anwendungen mit Hilfe des Package and Deployment Wizard, der eine wichtige Komponente von Microsoft Office Developer darstellt.
37.2
Der Package and Deployment Wizard
Der Package and Deployment Wizard ermöglicht es Ihnen, Distributions-Datenträger zu erstellen, die alle zur Ausführung Ihrer Datei erforderlichen Dateien enthalten. Der Package and Deployment Wizard erstellt ein sehr professionell aussehendes Setup-Programm, das Ihre Benutzer ausführen werden, wenn sie Ihre Anwendung installieren wollen. Mit Hilfe des Package and Deployment Wizard können Sie individuell anpassen, was in Ihrer Anwendung inbegriffen ist. Sie können Ihren Benutzern sogar die vertrauten Optionen STANDARD, KOMPRIMIERT und BENUTZERDEFINIERT zur Verfügung stellen, die von der Installation anderer Microsoft-Produkte bekannt sind.
37.3
Das Package and Deployment Wizard-Add-In laden
Bevor Sie den Package and Deployment Wizard verwenden können, müssen Sie das entsprechende Add-In aktivieren. Dazu sind die folgenden Schritte erforderlich: 1. Aktivieren Sie die VBDE (Visual Basic Development Environment). 2. Wählen Sie im Add-In-Menü den Add-In-Manager aus. Daraufhin erscheint das Dialogfeld des Add-In-Managers (siehe Abbildung 37.1). 3. Wählen Sie VBA PACKAGE AND DEPLOYMENT WIZARD. 4. Klicken Sie das Kontrollkästchen GELADEN/ENTLADEN an. 5. Wählen Sie BEIM START LADEN, wenn Sie wollen, dass der Assistent bei jedem Start von Access geladen wird. 6. Klicken Sie anschließend auf OK. Der Package and Deployment Wizard sollte nun als Option im Add-In-Menü erscheinen (siehe Abbildung 37.2).
Das Package and Deployment Wizard-Add-In laden
1199
Abbildung 37.1: Das Dialogfeld des AddIn-Managers ermöglicht es Ihnen, den Package and Deployment Wizard zu laden
Abbildung 37.2: Das Add-InMenü, nachdem das Package and Deployment Wizard-Add-In aktiviert worden ist
1200
37.4
Kapitel 37: Ihre Anwendung verteilen
Ihre Anwendung zur Ausführung mit einer vollständigen Kopie von Access verteilen
Viele Entwickler geben ihre Anwendungen an Endbenutzer weiter, die Microsoft Access besitzen und installiert haben. Diese Benutzer könnten für das Entwerfen eigener Ad-hoc-Abfragen und -Berichte verantwortlich sein. Für diese Benutzer ist es von Bedeutung, dass Sie Ihre Anwendung in geeigneter Weise sichern, den Benutzern Ihrer Anwendung nur diejenige Funktionalität zur Verfügung stellen, die Sie in Ihrer Anwendung integrieren wollen, und Ihrer Anwendung ein professionelles Aussehen geben. Viele der Themen in diesem Kapitel beziehen sich auf Ihre Anwendung, ob Sie nun die Anwendung an Benutzer mit der Laufzeitversion oder mit einer vollständigen Kopie von Access weitergeben. Sie sollten beispielsweise möglichst eine Übersicht, benutzerdefinierte Menüleisten und Symbolleisten in Ihrer Anwendung bereitstellen, ganz gleich ob Sie die Anwendung mit der Laufzeitversion oder mit einer vollständigen Version von Access verteilen.
37.5
Vollversionen im Unterschied zu Laufzeitversionen von Access
Viele Leute nehmen fälschlicherweise an, dass die Verwendung des Package and Deployment Wizard und die Auslieferung ihrer Anwendung mit Hilfe der AccessLaufzeitversion irgendwie bedeutet, dass die Anwendung kompiliert ist. Dies ist überhaupt nicht der Fall! Falls die Datenbank nicht in geeigneter Weise geschützt ist, verhält es sich tatsächlich so, dass jeder seine eigene Kopie von Access installieren und genauso wie Sie die Anwendungsdaten und andere Objekte ändern kann. Das Verwenden des Package and Deployment Wizard und das Weitergeben Ihrer Anwendung mit der Access-Laufzeitversion verändert die Datenbank in keiner Weise. Es gibt Ihnen lediglich die Lizenz, die zur Ausführung Ihrer Anwendung erforderliche Engine frei zur Verfügung zu stellen. Tatsächlich ist die Engine nicht einmal eine modifizierte Version der ausführbaren Access-Datei. Die Datei MSACCESS.EXE, die Sie weitergeben, ist dieselbe wie die MSACCESS.EXE, die Sie verwenden, um Ihre Anwendung zu erstellen. Wenn Sie den Package and Deployment Wizard verwenden, um Installationsdatenträger für Ihre Benutzer zu erstellen, wird dieselbe MSACCESS.EXE, die Sie verwenden, auf die Installationsdatenträger kopiert. Wie kann es hier also einen Unterschied zwischen der Vollund der Laufzeitversion von Access geben? Wenn der Benutzer Ihre Anwendung installiert, wird die Datei MSACCESS.EXE auf den Rechner des Benutzers kopiert. Während dieses Vorgangs überprüft das Installationsprogramm einen Windows-Registrierungs-Lizenzschlüssel, um zu erkennen, ob
Vollversionen im Unterschied zu Laufzeitversionen von Access
1201
der Benutzer eine Kopie von Access besitzt. Falls der Lizenzschlüssel anzeigt, dass der Benutzer keine Kopie von Access besitzt oder falls der Schlüssel nicht existiert, wird der Lizenzschlüssel (der sich aus Ziffern und Buchstaben zusammensetzt) aktualisiert, um anzugeben, dass der Benutzer die Laufzeitversion des Produkts verwenden wird. Wenn Access ausgeführt und der Laufzeit-Lizenzschlüssel gefunden wird, startet das Produkt im Laufzeitmodus. Wenn der Laufzeit-Lizenzschlüssel gefunden wird, verhält sich Access anders als beim Entdecken des vollständigen Lizenzschlüssels. Wenn Sie sich der Unterschiede nicht bewusst sind, werden Sie ziemlich überrascht sein, wenn bestimmte Aspekte Ihrer Anwendung nicht mehr wie erwartet funktionieren. Die folgende Aufzählung ist eine Liste der Beschränkungen der Laufzeitversionen des Produkts:
Das Datenbankfenster ist ausgeblendet. Entwurfsansichten sind ausgeblendet. Integrierte Symbolleisten werden nicht unterstützt. Einige Menüelemente sind nicht verfügbar. Bestimmte Tastenkombinationen sind deaktiviert.
37.5.1
Das Datenbankfenster ist ausgeblendet
Wenn Benutzer Ihre Anwendung mit Hilfe der Laufzeitversion von Access starten, ist das Datenbankfenster nicht sichtbar. Es ist eigentlich vorhanden, aber ausgeblendet, da seine Farben dieselben sind wie die Windows-Hintergrundfarbe. Dies bedeutet, dass Sie mit Hilfe von Code mit dem Datenbankfenster interagieren können, aber die Benutzer Ihrer Anwendung nicht in der Lage sein werden, mit dem Datenbankfenster direkt zu arbeiten. Die Tatsache, dass das Datenbankfenster ausgeblendet wird, kann ein zweischneidiges Schwert sein. Auf der einen Seite hindert es die meisten Benutzer daran, die Objekte in Ihrer Anwendung zu verändern. Auf der anderen Seite liegt die Verantwortung bei Ihnen, eine vollständige Schnittstelle für Ihre Anwendung zu erstellen. Bedenken Sie, dass für Sie als Entwickler das Datenbankfenster einen Ausgangspunkt darstellt. Sie müssen einen anderen Ausgangspunkt sowie Navigationswerkzeuge für Ihre Benutzer bereitstellen, damit diese sich in Ihrer Anwendung bewegen können.
37.5.2
Ausgeblendete Entwurfsansichten
Die Benutzer Ihrer Anwendung werden keinen direkten Zugriff auf Entwurfsansichten haben, was bedeutet, dass sie nicht in der Lage sind, Tabellen, Abfragen, Formulare, Berichte, Makros oder Module zu erstellen oder zu ändern. Sie können jedoch mit Hilfe von Code auch weiterhin alle diese Funktionen zur Verfügung stellen. Sie können einen Assistenten erstellen, der es Ihren Benutzern ermöglicht, zum Beispiel
1202
Kapitel 37: Ihre Anwendung verteilen
alle Aspekte einer Abfrage oder eines anderen Objekts zu definieren und dann die Abfrage (oder ein anderes Objekt) mit Hilfe von ADO-Code (ActiveX Data Objects) zu generieren. Erneut hilft dies, Ihre Anwendung vor unerfahrenen Benutzern zu schützen, doch Sie müssen sicherstellen, dass Ihre Anwendung den Benutzern die benötigten Funktionen zur Verfügung stellt.
37.5.3
Integrierte Symbolleisten werden nicht unterstützt
Integrierte Symbolleisten stehen in der Laufzeitversion von Access überhaupt nicht zur Verfügung, was bedeutet, dass Sie Ihre eigenen Symbolleisten entwerfen und in geeigneter Weise an Ihre Formulare und Berichte anbinden müssen. Dies wird im Abschnitt »Benuterdefinierte Menüs und Symbolleisten hinzufügen« dieses Kapitels erläutert.
37.5.4
Menüelemente sind nicht verfügbar
Integrierte Symbolleisten werden ebenfalls nicht unterstützt, wenn die Laufzeitversion von Access verwendet wird, während Menüs nur verändert erscheinen, nachdem der Laufzeitschlüssel gefunden wurde. Viele Menüelemente werden in der Laufzeitversion ausgeblendet und hindern somit Benutzer daran, Änderungen an Ihrer Anwendung vorzunehmen. Obwohl viele der Menübefehle vor dem Benutzer verborgen werden, kann auf sie mit Hilfe des Befehls DoMenuItem zugegriffen werden. Mit anderen Worten, die Funktionalität ist vorhanden, aber Ihren Benutzern nicht zugänglich.
37.5.5
Deaktivierte Tastenkombinationen
Mehrere Tastenfolgen stehen Ihren Benutzern nicht zur Verfügung, wenn sie Ihre Anwendung mit der Laufzeitversion von Access ausführen. Tabelle 37.1 führt diese Tastenfolgen auf. Tastenfolge
Funktion
(Strg)+(Esc)
Hält die Makro- und Codeausführung an
(ª) (beim Öffnen der Datenbank)
Verhindert die Ausführung des Makros AutoExec und ignoriert Starteigenschaften
(Alt)+(F1)/(F11)
Zeigt das Datenbankfenster an
(F12)
Zeigt das Dialogfeld SPEICHERN UNTER an
(ª)+(F12)
Speichert ein Datenbankobjekt
Tabelle 37.1: Deaktivierte Tastenfolgen
Ihre Datenbank für die Laufzeitversion von Access vorbereiten
1203
Tastenfolge
Funktion
(Strg)+(G)
Zeigt das Testfenster an
(Strg)+(F11)
Schaltet zwischen benutzerdefinierten und eingebauten Symbolleisten um
Tabelle 37.1: Deaktivierte Tastenfolgen (Forts.)
Wie Sie sehen können, sind dies Tastenfolgen, die Sie Ihre Benutzer sehr selten, falls überhaupt, verwenden lassen wollen. Sie können die Deaktivierung dieser Tastenfolgen als positiven Nebeneffekt sehen, der sich aus der Verwendung der Laufzeitversion des Produkts ergibt.
37.6
Ihre Datenbank für die Verwendung mit der Laufzeitversion von Access vorbereiten
Mehrere Schritte sind erforderlich, um Ihre Datenbank für die Verwendung mit der Laufzeitversion von Access vorzubereiten. Obwohl viele dieser Schritte zwingend erforderlich sind, wenn Sie Ihre Anwendung mit der Laufzeitversion weitergeben, sind sie auch generell zu empfehlen, wenn Sie eine professionelle Anwendung entwickeln. Um Ihre Datenbank für die Verwendung mit der Laufzeitversion von Access vorzubereiten, führen Sie die folgenden Schritte aus: 1. Erstellen Sie die Anwendung. 2. Erstellen Sie Hilfedateien und verknüpfen Sie gegebenenfalls die Hilfethemen mit den Objekten der Anwendung. 3. Testen Sie Ihre Anwendung und führen Sie eine Fehlerbehebung durch. 4. Führen Sie die Anwendung aus und testen Sie sie mit dem Befehlzeilenargument /Runtime. 5. Führen Sie den Package and Deployment Wizard aus. 6. Geben Sie die Anwendung weiter. 7. Erstellen Sie ein Paket und verteilen Sie die Anwendung.
37.6.1
Die Anwendung erstellen
Sie müssen sich mit mehreren Dingen befassen, wenn Sie eine Anwendung für die Verwendung mit der Laufzeitversion von Access entwerfen. Obwohl die folgenden Punkte Feinheiten in jeder Anwendung darstellen, sind sie ein unerlässlicher Aspekt bei der Entwicklung einer Anwendung für den Einsatz mit der Laufzeitversion von Access:
1204
Kapitel 37: Ihre Anwendung verteilen
Die Anwendung formulargesteuert entwerfen Fehlerbehandlung in die Anwendung einbauen Benutzerdefinierte Menüs und Symbolleisten in die Anwendung integrieren Startoptionen für die Anwendung festlegen Die Anwendung korrekt sichern Die Anwendung formulargesteuert entwerfen Der erste Schritt bei der Erstellung einer Anwendung, die mit der Laufzeitversion verteilt werden soll, besteht darin, die Anwendung auf Formularen basierend zu erstellen. Das bedeutet, dass alles in der Anwendung formulargesteuert sein muss. Ihre Anwendung sollte im Allgemeinen mit der Anzeige einer Hauptübersicht beginnen. Die Hauptübersicht kann den Benutzer dann zu weiteren Übersichten führen, wie zum Beispiel für die Dateneingabe, für Berichte, die Verwaltung usw. Eine Alternative besteht darin, das am häufigsten verwendete Formular anzuzeigen, wenn die Anwendung gestartet wird. Menü- und Symbolleistenelemente können dann für das Navigieren zu anderen Teilen Ihrer Anwendung verwendet werden. Wenn beispielsweise der hauptsächliche Zweck der Anwendung darin besteht, für eine Vereinigung die Informationen über die Mitgliedschaften zu verwalten, wäre das Startformular das Mitgliedsformular. Auf andere Formulare, wie zum Beispiel das für die Mitgliederzahlungen, würde über ein an das Mitgliedsformular angebundenes Menü zugegriffen. Diese zweite Option bevorzuge ich persönlich. Fehlerbehandlung in die Anwendung einbauen Es ist unbedingt erforderlich, dass Sie die Fehlerbehandlung in Ihre Anwendung einbauen. Falls ein Fehler auftritt, wenn jemand die Laufzeitversion von Access verwendet, und keine Fehlerbehandlung geschieht, wird eine Fehlermeldung angezeigt und der Benutzer gelangt wieder zurück zum Windows-Desktop. Deshalb ist es von entscheidender Bedeutung, dass Sie in alle Ihre Routinen Fehlerbehandlung integrieren. Das Erstellen eines allgemeinen Programms für die Fehlerbehandlung, das Sie bei dieser Aufgabe unterstützt, wird in Kapitel 14 behandelt. Benutzerdefinierte Menüs und Symbolleisten hinzufügen Wie bereits zuvor in diesem Kapitel erwähnt, sind unter der Access-Laufzeitversion eingeschränkte Versionen der standardmäßigen Access-Menüs verfügbar, während Symbolleisten überhaupt nicht vorhanden sind. Sie müssen deshalb Ihren Benutzern die Menü- und Symbolleisten zur Verfügung stellen, die aufgrund der von der Anwendung geforderten Funktionalität notwendig sind. Wie in Kapitel 9 erläutert, können Sie mit Hilfe der Eigenschaft Menüleiste des Formulars eine Menüleiste mit einem Formular verknüpfen (siehe Abbildung 37.3). Wenn eine bestimmte Menüleiste mit einem bestimmten Formular oder Bericht verknüpft ist, erscheint das Menü immer dann, wenn das Formular oder der Bericht zum aktiven Fenster wird. Es ist im Allgemeinen leichter, das Menü eines Formulars
Ihre Datenbank für die Laufzeitversion von Access vorbereiten
1205
oder Berichts auf einem der Standardmenüs in Access aufzubauen und dann auf geeignete Weise Menüelemente hinzuzufügen oder zu entfernen.
Abbildung 37.3: Die Eigenschaft Menüleiste eines Formulars
Sie müssen jede Symbolleiste erstellen, die Sie mit Ihrer Anwendung verwenden wollen. Wie in Kapitel 9 behandelt, können Sie die Symbolleiste, die zusammen mit Ihrem Formular oder Bericht sichtbar sein soll, mit Hilfe der Eigenschaft Symbolleiste des Formulars oder Berichts festlegen. Gelegentlich können Sie es bevorzugen, die anzuzeigenden Symbolleisten mittels Code zu steuern. Mit Hilfe dieser Methode können Sie nach Belieben den Benutzern Zugriff auf Ihre eigenen oder benutzerdefinierte Symboleisten gewähren. Listing 37.1 zeigt den Code für das Ereignis Activate des Formulars oder Berichts. Listing 37.1:
Code für das Ereignis Activate
Private Sub Form_Activate() On Error GoTo Err_Form_Activate Call ToolBarShow("tbrMainForm", True) Me.fsubClients.Requery Exit_Form_Activate: Exit Sub Err_Form_Activate: MsgBox Err.Description Resume Exit_Form_Activate End Sub
1206
Kapitel 37: Ihre Anwendung verteilen
Die Routine für das Ereignis Activate des Formulars frmClients ruft eine benutzerdefinierte Prozedur namens ToolBarShow auf. Der Routine ToolBarShow werden zwei Parameter übergeben: der Name der Symbolleiste, die beeinflusst werden wird, und eine Boolesche Variable, die anzeigt, ob die angegebene Symbolleiste angezeigt oder ausgeblendet werden soll. Listing 37.2 zeigt die Routine ToolBarShow. Listing 37.2:
Die Routine ToolBarShow
Sub ToolBarShow(strToolBar As String, fShow As Boolean) DoCmd.ShowToolbar strToolbar, _ IIf(fShow, acToolbarYes, acToolbarNo) DoCmd.ShowToolbar "Form View", _ IIf(fShow, acToolbarNo, acToolbarWhereApprop) End Sub
Die Routine ToolBarShow ist eine Routine, die sowohl das Anzeigen als auch das Ausblenden von benutzerdefinierten Symbolleisten steuert. Sie erhält eine Zeichenfolge und eine Boolesche Variable. Die Methode Showtoolbar, die im Objekt DoCmd enthalten ist, setzt die Symbolleisten auf sichtbar oder ausgeblendet. Der Befehl bewerkstelligt dies, indem der Name der Symbolleiste und ein Boolescher Wert (beide werden als Parameter übergeben) verwendet werden und die Eigenschaft der Sichtbarkeit für diese Symbolleiste auf True für sichtbar und False für ausgeblendet gesetzt wird, abhängig davon, was der Funktion übergeben wurde. Falls der Routine ToolBarShow beispielsweise die Zeichenfolge tbrMainForm und der Boolsche Wert True übergeben wird, zeigt sie die Symbolleiste tbrMainForm an. Im Fall, dass die Anwendung sowohl mit der Voll- als auch der Laufzeitversion von Access ausgeführt wird, sollten Sie sicherstellen, dass die Standardsymbolleiste ausgeblendet wird, wenn das Formular aktiv ist. Die zweite ShowToolBar-Methode gibt an, dass die Symbolleiste FORMULARANSICHT ausgeblendet wird, wenn Sie die benutzerdefinierte Symbolleiste anzeigen, und im anderen Fall angezeigt wird, wenn Sie die benutzerdefinierte Symbolleiste ausblenden. Das Ereignis Deactivate des Formulars sieht wie folgt aus: Private Sub Form_Deactivate() Call ToolBarShow("tbrMainForm", False) End Sub
Diese Routine blendet die Symbolleiste tbrMainForm aus und zeigt die Symbolleiste FORMULARANSICHT an, wo es angebracht ist. Es ist selbstverständlich wichtig, dass Sie alle Funktionen in Bezug auf Menüs und Symbolleisten ausführen, die von der Anwendung benötigt werden. Dies gewährleistet, dass alle Menü- und Symbolleisten verfügbar sind, wenn und nur wenn sie es sein sollten.
1207
Ihre Datenbank für die Laufzeitversion von Access vorbereiten
Startoptionen festlegen Access 2000 bietet Ihnen mehrere Startoptionen, mit deren Hilfe Sie steuern können, was mit Ihrer Anwendung geschieht, wenn sie geladen wird. Abbildung 37.4 zeigt das Dialogfeld START, welches weitere Optionen enthält. Tabelle 37.2 listet alle Optionen im Dialogfeld START auf.
Abbildung 37.4: Das Dialogfeld Start Option
Funktion
ANWENDUNGSTITEL
Setzt die Eigenschaft AppTitle, so dass ein benutzerdefinierter Titel in der Titelleiste der Anwendung angezeigt wird
ANWENDUNGSSYMBOL
Setzt die Eigenschaft AppIcon, so dass ein benutzerdefiniertes Symbol in der Titelleiste der Anwendung angezeigt wird
MENÜLEISTE
Legt die Eigenschaft StartupMenuBar fest, die angibt, welche benutzerdefnierte Menüleiste standardmäßig angezeigt wird, wenn die Anwendung geladen wird
UNBESCHRÄNKTE MENÜS ANZEIGEN
Legt die Eigenschaft AllowFullMenus fest, welche die Verwendung von Access-Menüs ermöglicht oder einschränkt
STANDARD-KONTEXT-
Setzt die Eigenschaft AllowShortcutMenus, welche die Verwendung von Standard-Kontextmenüs in Access zulässt oder einschränkt (Menüs, auf die mit der rechten Maustaste zugegriffen wird)
MENÜS ZULASSEN
FORMULAR/SEITE ANZEI- Setzt die Eigenschaft StartUpForm, welche das Formular angibt, das GEN angezeigt wird, wenn die Anwendung geladen wird DATENBANKFENSTER ANZEIGEN
Tabelle 37.2: Startoptionen
Setzt die Eigenschaft StartupShowDBWindow, die festlegt, ob das Datenbankfenster sichtbar ist, wenn die Anwendung geöffnet wird
1208
Kapitel 37: Ihre Anwendung verteilen
Option
Funktion
STATUSLEISTE ANZEI-
Setzt die Eigenschaft StartupShowStatusBar, welche festlegt, ob die Statusleiste sichtbar ist, wenn die Anwendung geöffnet wird
GEN
KONTEXTMENÜ-LEISTE
Setzt die Eigenschaft StartupShortcutMenuBar, die eine Menüleiste als standardmäßig angezeigte Kontextmenüleiste (rechte Maustaste) festlegt
EINGEBAUTE SYMBOL-
Setzt die Eigenschaft AllowBuiltInToolbars, die anzeigt, ob Ihren Benutzern eingebaute Symbolleisten zur Verfügung stehen
LEISTEN ZULASSEN
SYMBOLLEISTEN- UND MENÜ-ÄNDERUNGEN ZULASSEN
Setzt die Eigenschaft AllowToolbarChanges, welche festlegt, ob Ihre Benutzer Symbolleisten in der Anwendung individuell anpassen können
ACCESS-SPEZIALTASTEN Setzt die Eigenschaft AllowSpecialKeys, die bestimmt, ob der Benutzer Tasten wie zum Beispiel F11, um das Datenbankfenster anzuzeigen, STRG + F11, um zwischen benutzerdefinierten und eingebauten Symbolleisten zu wechseln, usw. verwenden kann
VERWENDEN
Tabelle 37.2: Startoptionen (Forts.)
Wie Sie vielleicht vermutet haben, sind viele dieser Optionen nur gültig, wenn Sie die Anwendung unter der Vollversion von Access (im Gegensatz zur Laufzeitversion) ausführen. Sie müssen beispielsweise nicht die Option DATENBANKFENSTER ANZEIGEN festlegen, wenn Ihre Anwendung nur unter der Laufzeitversion von Access läuft, da in dieser Version des Produkts das Datenbankfenster nie verfügbar ist, so dass hier diese Option ignoriert wird. Nichtsdestotrotz setze ich gerne diese Optionen, um sicherzugehen, dass die Anwendung sich sowohl in der Voll- als auch in der Laufzeitversion so verhält, wie ich es möchte. Alle Optionen können mit Hilfe des Start-Dialogfelds oder von Code gesetzt werden. Falls Sie Code verwenden, müssen Sie sich vergewissern, dass die Option für das Datenbankobjekt existiert, bevor Sie sie festlegen. Falls die Option nicht existiert, müssen Sie sie zum Datenbankobjekt hinzufügen. Nur Benutzer, welche für die Datenbank die Berechtigung »Verwalten« besitzen, können die Starteigenschaften ändern. Wenn Sie gewährleisten wollen, dass bestimmte Benutzer die Startoptionen einer Datenbank nicht ändern können, müssen Sie sicherstellen, dass sie keine Berechtigung »Verwalten« besitzen. Als Teil der Startoptionen für Ihre Datenbank sollten Sie festlegen, welcher Code, falls überhaupt, beim Laden der Anwendung ausgeführt wird. Sie können dies auf zwei Weisen bewerkstelligen. Sie können die Anwendung mit einem AutoExecMakro starten und dann eine RunCode-Aktion aufrufen, um eine VBA-Prozedur auszuführen. Die andere Option wäre, ein Startformular für die Anwendung festzulegen und
Ihre Datenbank für die Laufzeitversion von Access vorbereiten
1209
dann eine benutzerdefinierte AutoExec-Routine über das Ereignis Open des Startformulars aufzurufen. Ich verwende immer die zweite Option, da diese mehr Steuerungsmöglichkeiten bietet und Sie eine Fehlerbehandlung in das Code-Modul einfügen können, das dem Startformular zu Grunde liegt, während ein AutoExec-Makro keine Fehlerbehandlung enthalten kann. Der in Listing 37.3 gezeigte Code wird vom Ereignis Open des Startformulars für das Zeit- und Abrechnungssystem aufgerufen. Dieser Code und der Rest des in diesem Kapitel erläuterten Codes befinden sich in der Datenbankdatei CHAP37.MDB auf der CD-ROM mit dem BeispielCode. Listing 37.3:
Mit einer Startformular-Routine Optionen festlegen
Sub AutoExec(frmAny As Form) On Error GoTo AutoExec_Err: 'Optionaler Test auf die Laufzeitversion If Not SysCmd(acSysCmdRuntime) _ And CurrentUser <> "Admin" Then MsgBox "You aren't allowed here" Exit Sub End If DoCmd.OpenForm "frmSplash" DoEvents DoCmd.Hourglass True If Not VerifyLink Then If Not ReLink Then MsgBox "You Cannot Run This App Without Locating Data Tables" DoCmd.Close acForm, "frmSplash" DoCmd.Quit End If End If Call GetCompanyInfo DoCmd.Hourglass False If IsLoaded("frmSplash") Then DoCmd.Close acForm, "frmSplash" end If Exit Sub AutoExec_Err: DoCmd.Hourglass False MsgBox "Error # " & Err.Number & ": " & Err.Description Exit Sub End Sub
Diese allgemeine Routine erhält als Parameter ein Formular. Sie verwendet die Methode OpenForm, um ein Formular namens frmSplash zu öffnen. Dann wird ein
1210
Kapitel 37: Ihre Anwendung verteilen
DoEvents-Befehl ausgeführt, um dem Formular Zeit zum Öffnen zu geben. Es wird ein Sanduhr-Mauszeiger angezeigt und die Routine ruft eine benutzerdefinierte Funktion auf, die gewährleistet, dass die Datenbanktabellen erfolgreich verknüpft werden. Diese Routine VerifyLink wird im Abschnitt »Den Prozess der Verknüpfung zu Tabellen automatisieren« in diesem Kapitel behandelt. Falls die Funktion VerifyLink den Wert False zurückgibt, wird die Funktion Relink ausgeführt, um zu versuchen, die unterbrochene Verknüpfung wiederherzustellen. Die Funktion Relink wird in demselben Abschnitt wie die Routine VerifyLink erläutert. Falls die Funktion Relink nicht erfolgreich ist, werden die Benutzer gewarnt, dass sie die Anwendung nicht ausführen können. Das Formular frmSplash wird geschlossen und die Anwendung beendet. Solange die Tabellenverknüpfungen erfolgreich eingerichtet wurden, fährt die AutoExec-Routine fort, eine Routine namens GetCompanyInfo aufzurufen, wo häufig verwendete Informationen in ein Datenfeld geladen werden. Der SanduhrMauszeiger verschwindet und der Eröffnungsbildschirm wird entladen.
Die Anwendung sichern Lassen Sie sich nicht täuschen! Denken Sie daran, dass die Laufzeitversion von Access Ihre Anwendung in keiner Weise schützt. Sie ermöglicht Ihnen lediglich die gebührenfreie Weitergabe. Sie müssen genau dieselben Maßnahmen ergreifen, um Ihre Anwendung unter der Laufzeitversion von Access zu sichern, die Sie auch im Falle der Ausführung mit der Vollversion des Produkts ergreifen. Das Entscheidende dabei ist, dass Sie Maßnahmen ergreifen müssen, um Ihre Anwendung zu sichern, falls Sie wollen, dass die Anwendung und ihre Daten sicher sind. Die Grundlagen der Sicherheit werden in Kapitel 33 und die Feinheiten in Kapitel 34 behandelt. Das Weitergeben Ihrer Anwendung als MDE-Datei bedeutet eine weitere Ebene der Sicherheit, während die Leistungsfähigkeit verbessert und die Größe der Datenbankdatei verringert wird. MDE-Dateien werden im nächsten Abschnitt behandelt. Ihre Anwendung als MDE-Datei verteilen Der Prozess des Erstellens einer MDE-Datei kompiliert alle Module, entfernt sämtlichen Quellcode aus Ihrer Datenbank und komprimiert die Zieldatenbank. Der gesamte Code wird ausgeführt, aber der Benutzer wird nicht in der Lage sein, Formulare, Berichte und Module zu ändern. Abgesehen vom Schutz der Objekte in Ihrer Datenbank reduziert dieser Prozess die Größe der Datenbank und einiges des damit verbundenen Verwaltungsaufwands und verbessert somit die Leistung der Anwendung. Das Erstellen und Verteilen einer MDE-Datei ist nicht so einfach, wie es auf den ersten Blick erscheint. Kapitel 32 behandelt den Vorgang des Erstellens einer MDE-Datei und wichtige Aspekte, die sich im Zusammenhang mit diesem neuen Access-Dateiformat ergeben.
37.6.2
Benutzerdefinierte Hilfe zur Anwendung hinzufügen
Um Ihrer Anwendung den letzten Schliff zu geben und zu gewährleisten, dass die von Ihnen den Benutzern angebotene Hilfe sich auf das bezieht, was die Benutzer in
Ihre Datenbank für die Laufzeitversion von Access vorbereiten
1211
Ihrer Anwendung betrachten, müssen Sie eine benutzerdefinierte Hilfedatei bereitstellen. Das Hinzufügen von Hilfe zu Ihrer Anwendung beinhaltet im Wesentlichen das Erstellen einer RTF-Datei und anderer unterstützender Dateien sowie das Verwenden des Windows Help Workshops, um eine kompilierte Hilfedatei zu erstellen. Sie müssen dann zu den verschiedenen Objekten in Ihrer Anwendung Hilfe hinzufügen. Es sind viele ausgezeichnete Tools verfügbar, die Sie dabei unterstützen können, Ihren Anwendungen benutzerdefinierte Hilfe hinzuzufügen.
37.6.3
Die Anwendung testen und debuggen
Bevor Sie überhaupt versuchen, Ihre Anwendung unter der Laufzeitversion auszuführen, sollten Sie die Anwendung vollständig unter der Vollversion des Produkts testen und evtl. Fehler beheben. Wenn Sie davon überzeugt sind, dass Sie alle Probleme in der Anwendung gelöst haben, können Sie die Anwendung in der Laufzeitumgebung testen.
37.6.4
Die Anwendung mit dem Befehlszeilenschalter /Runtime ausführen und testen
Wenn Sie die Microsoft Office 2000 Developer Tools installiert haben, stellt Microsoft Ihnen eine sehr einfache Möglichkeit zur Verfügung, um zu sehen, wie die Anwendung sich unter der Laufzeitversion von Access verhält, ohne dass Sie tatsächlich Distributions-Datenträger erstellen müssen. Sie können dies mit Hilfe des Befehlszeilenschalters /Runtime bewerkstelligen. Der Schalter /Runtime veranlasst Access, im Laufzeitmodus zu starten. Dies funktioniert so: c:\program files\microsoft office\office\msaccess.exe ==> c:\databases\chap37.mdb /runtime
Nachdem Sie die Anwendung mit dem Schalter /Runtime geladen haben, sollten Sie erneut alle Aspekte der Anwendung testen. Gelegentlich wollen Sie eventuell prüfen, ob die Anwendung mit der Laufzeit- oder der Vollversion des Produkts gestartet wurde. Sie können dies durch den folgenden Code erreichen: If Not SysCmd(acSysCmdRuntime) _ And CurrentUser <> "Admin" Then MsgBox "You aren't allowed here" End If
Wenn die Konstante acSysCmdRuntime übergeben wird, prüft die Funktion SysCmd, ob die Anwendung mit Hilfe der Laufzeitversion von Access gestartet wurde. Falls das Programm mit der Vollversion von Access gestartet wurde und CurrentUser nicht Admin ist, wird eine Meldung angezeigt, die mitteilt, dass der Benutzer nicht befugt ist. Sie können natürlich diese Routine leicht ändern, um die Prüfung in Bezug auf
1212
Kapitel 37: Ihre Anwendung verteilen
andere Benutzer durchzuführen und die Anwendung zu beenden, falls eine nicht berechtigte Person versucht, die Anwendung ohne die Laufzeitversion des Produkts zu starten. Wenn Sie die Laufzeitumgebung auf dem Rechner eines Benutzers simulieren wollen, der Access installiert hat, müssen Sie die Datei mso9rt.dll in das Verzeichnis \program files\common files\microsoft shared\vba\vba6 auf dem Rechner des Benutzers kopieren.
37.6.5
Den Package and Deployment Wizard ausführen
Nachdem Sie Ihre Anwendung vollständig getestet und für die Verteilung vorbereitet haben, können Sie den Package and Deployment Wizard ausführen. Der Package and Deployment Wizard führt Sie durch alle Schritte, die zum Erstellen von Distributions-Datenträgern erforderlich sind, welche alle Komponenten umfassen, die Ihre Anwendung zur Ausführung benötigt. Sie starten den Package and Deployment Wizard über den VBE. 1. Aktivieren Sie den VBE. 2. Wählen Sie im Add-Ins-Menü den Package and Deployment Wizard aus. Abbildung 37.5 zeigt das daraufhin erscheinende Startdialogfeld des Package and Deployment Wizard.
Abbildung 37.5: Das Start-Dialogfeld des Package and Deployment Wizard
Ihre Datenbank für die Laufzeitversion von Access vorbereiten
1213
Den Einführungsbildschirm betrachten Das Startdialogfeld des Package and Deployment Wizard zeigt den Namen des aktiven Projekts an, das vorbereitet wird. Es gibt Ihnen die Möglichkeit, folgende Aktionen auszuführen:
Ihr Projekt in einem vertreibbaren Setup-Programm zusammenfassen eine Abhängigkeitsdatei erstellen die verpackte Anwendung an eine Verteilungs-Site senden Scripts für den Verteilungsprozess umbenennen, löschen und duplizieren Der erste Schritt besteht darin, das Projekt in einem vertreibbaren Setup-Programm zusammenzufassen. Klicken Sie auf die Schaltfläche PACKAGE, um den Prozess zu beginnen. Daraufhin erscheint ein Dialogfeld, das Sie über die Schritte informiert, die Access ausführt, um das Setup-Programm zu erstellen (siehe Abbildung 37.6).
Abbildung 37.6: Der Package and Deployment Wizard informiert Sie über den Fortschritt bei der Erstellung des SetupProgramms
Den zu erstellenden Pakettyp wählen Im zweiten Schritt des Package and Deployment Wizard müssen Sie den Typ des Pakets wählen, das Sie erstellen möchten (siehe Abbildung 37.7). Die Option STANDARD SETUP PACKAGE wird verwendet, um ein Paket zu erstellen, das vom Programm Setup.exe installiert wird. Die Option DEPENDENCY FILE dient der Erstellung einer Liste aller Laufzeitkomponenten, die Ihre Anwendung benötigt. Sie werden im Allgemeinen DEPENDENCY FILE nur wählen, wenn Sie ein anderes Setup-Programm zur Verteilung Ihrer Anwendung verwenden. Wählen Sie den geeigneten Pakettyp und klicken Sie dann auf NEXT.
1214
Kapitel 37: Ihre Anwendung verteilen
Den Ordner auswählen, in dem Ihr Paket zusammengestellt wird Der dritte Schritt des Package and Deployment Wizard fordert von Ihnen die Auswahl des Ordners, in dem Ihr Paket zusammengestellt wird. Sie können das Paket auf einem lokalen Laufwerk oder auf einem Netzwerklaufwerk zusammenstellen. Treffen Sie Ihre Wahl und klicken Sie auf NEXT. Wenn Sie einen existierenden Ordner auswählen, erhalten Sie die Meldung, dass Dateien in diesem Ordner überschrieben werden können. Sie können YES wählen, um fortzufahren, oder NO, um einen anderen Ordner auszuwählen.
Abbildung 37.7: Im zweiten Schritt des Package and Deployment Wizard müssen Sie den Typ des Pakets wählen, den Sie erstellen möchten
Fehlende Abhängigkeitsdatei-Informationen Im vierten Schritt des Package and Deployment Wizard werden alle Dateien aufgelistet, für die keine Abhängigkeitsinformationen gefunden werden konnten (siehe Abbildung 37.8). Diese Liste deutet nicht unbedingt auf ein Problem hin. Sie sagt lediglich aus, dass für die aufgeführten Dateien keine Abhängigkeitsinformationen verfügbar waren. Es ist möglich, dass die aufgelisteten Dateien keine Abhängigkeiten besitzen. Falls die Datei eine Access-Datei ist, erscheint sie fett dargestellt. Sie können auf SCAN klicken, um die Datei nach Abhängigkeiten zu durchsuchen. Wenn Sie sicher sind, dass eine Datei keine Abhängigkeiten besitzt, können Sie ihr Kontrollkästchen anklicken, um dauerhaft zu markieren, dass die Datei keine Abhängigkeiten aufweist. Wenn Sie mit der Liste zufrieden sind, klicken Sie auf OK. Möglicherweise erscheint ein weiteres Dialogfeld, das eine Liste von Dateien anzeigt, für welche die Abhängigkeitsinformationen nicht mehr aktuell sein könnten. Klicken Sie erneut auf OK, um fortzufahren. Falls Sie den Verpackungs- und Weitergabeprozess abbrechen möchten, klicken Sie auf CANCEL.
Ihre Datenbank für die Laufzeitversion von Access vorbereiten
1215
Abbildung 37.8: Im vierten Schritt des Package and Deployment Wizard werden alle Dateien aufgelistet, für die keine Abhängigkeitsinformationen gefunden werden konnten
Dateien hinzufügen, die auf den Distibutions-Datenträgern enthalten sein sollen Der fünfte Schritt des Package and Deployment Wizard ermöglicht es Ihnen, Dateien festzulegen, die Sie zu den Setup-Datenträgern hinzufügen wollen, wie Sie es in Abbildung 37.9 sehen können. Die folgenden Dateitypen können Sie mit Hilfe dieses Dialogfelds hinzufügen:
Anwendungsdatenbanken Datendatenbanken Bibliotheksdateien ActiveX-Steuerelemente (OCX-Dateien) Symboldateien Eröffnungsbildschirme Hilfedateien Registrierungsdateien Lizenzdateien Office-Dokumente Remote-Server-Dateien andere spezielle Dateien, die Sie verteilen müssen
1216
Kapitel 37: Ihre Anwendung verteilen
Abbildung 37.9: Dateien zu den SetupDatenträgern hinzufügen
Führen Sie die folgenden Schritte aus, um eine Datei hinzuzufügen: 1. Klicken Sie im Dialogfeld des Paket- undWeitergabe-Assistenten auf ADD. Daraufhin erscheint das Dialogfeld ADD FILE. 2. Suchen Sie die Datei, die Sie hinzufügen möchten und klicken Sie auf OPEN. 3. Wählen Sie die Option INCLUDE ACCESS RUNTIME, falls Sie Ihre Anwendung mit der Laufzeitversion weitergeben wollen. 4. Wenn Sie alle erforderlichen Dateien hinzugefügt haben, klicken Sie auf NEXT. CAB-Optionen festlegen Eine CAB-Datei ist eine komprimierte Containerdatei für die Dateien Ihrer Anwendung. Im sechsten Schritt des Package and Deployment Wizard können Sie wählen, ob Sie eine einzelne oder mehrere CAB-Dateien erstellen (siehe Abbildung 37.10). Eine einzelne CAB-Datei ist für eine Installation im Netzwerk geeignet, während mehrere CAB-Dateien für eine Disketteninstallation geeignet sind. Falls Sie mehrere CAB-Dateien auswählen, sollten Sie eine CAB-Dateiengröße wählen, die für den Datenträgertyp geeignet ist, den Sie zu verwenden gedenken. Wenn Sie damit fertig sind, klicken Sie auf NEXT. Den Titel für Ihre Installation wählen Im siebten Schritt des Package and Deployment Wizard können Sie einen Installationstitel für Ihre Anwendung wählen (siehe Abbildung 37.11). Dieser Titel erscheint auf dem Eröffnungsbildschirm. Sie können außerdem ein Programm festlegen, das ausgeführt werden soll, wenn die Installation beendet ist. Klicken Sie dann auf NEXT.
Ihre Datenbank für die Laufzeitversion von Access vorbereiten
1217
Abbildung 37.10: Wählen Sie, ob Sie eine oder mehrere CABDateien erstellen wollen
Abbildung 37.11: Einen Titel für Ihre Installation wählen
Zu erstellende Startmenüelemente auswählen Im achten Schritt des Package and Deployment Wizard können Sie Startmenügruppen und -elemente festlegen, die während des Installationsvorgangs erstellt werden (siehe Abbildung 37.12). Klicken Sie auf NEW GROUP, um eine neue Gruppe zu erstellen, und auf NEW ITEM, um ein neues Element zu erstellen. Wenn Sie sich dafür entscheiden, ein neues Element zu erstellen, erscheint das Dialogfeld START MENU ITEM PROPERTIES (siehe Abbildung 37.13). Legen Sie die Attribute NAME,
1218
Kapitel 37: Ihre Anwendung verteilen
TARGET und START IN für das Element fest. Klicken Sie auf OK, um zum Formular START MENU ITEMS zurückzukehren. Klicken Sie dann auf PROPERTIES, um die Attribute NAME, TARGET und START IN für bestehende Verknüpfungen zu ändern. Klicken Sie auf REMOVE, um eine Verknüpfung zu entfernen. Klicken Sie anschließend auf NEXT, wenn Sie alle gewünschten Optionen festgelegt haben.
Abbildung 37.12: Startmenügruppen und -elemente wählen, die während des Installationsvorgangs erstellt werden
Abbildung 37.13: Legen Sie den Namen, das Ziel und den Startpfad für Startmenüelemente fest, die Sie erstellen
Ihre Datenbank für die Laufzeitversion von Access vorbereiten
1219
Installationsorte für enthaltene Dateien auswählen Im neunten Schritt des Package and Deployment Wizard können Sie den Installationsort für die aufgeführten Dateien festlegen (siehe Abbildung 37.14). Klicken Sie in die Spalte INSTALL LOCATION der Datei, die Sie bearbeiten wollen, und ändern Sie dann den Dateiort. Klicken Sie anschließend auf NEXT, wenn Sie den Ort für alle Dateien geändert haben.
Abbildung 37.14: Den Installationsort für die Anwendung auswählen
Gemeinsame Dateien festlegen Im zehnten Schritt des Paket- und Weitergabe-Assistenten können Sie Ihre Anwendungsdateien als gemeinsame Dateien festlegen (siehe Abbildung 37.15). Sie sollten dies für alle diejenigen Anwendungsdateien tun, die von mehr als einem Programm verwendet werden. Gemeinsame Dateien werden nur entfernt, wenn alle Dateien entfernt sind, die diese gemeinsamen Dateien verwenden. Um eine Datei als gemeinsam zu markieren, klicken Sie das entsprechende Kontrollkästchen an. Klicken Sie anschließend auf NEXT, wenn Sie bereit sind fortzufahren. Einen Scriptnamen angeben Im letzten Schritt des Package and Deployment Wizard müssen Sie einen Scriptnamen eingeben (siehe Abbildung 37.16). Alle von Ihnen festgelegten Eigenschaften werden unter dem Scriptnamen gespeichert. Der Scriptname kann verwendet werden, um das Setup jederzeit wieder erstellen zu können. Klicken Sie auf FINISH, wenn Sie bereit sind, das Paket zu erstellen. Ihnen wird mitgeteilt, sobald jeder Schritt des Setup-Vorgangs abgeschlossen ist (siehe Abbildung 37.17). Wenn der Setup-Vorgang beendet ist, erscheint ein Verpackungsbericht (siehe Abbildung 37.18). Dieser Bericht enthält wichtige Informationen über den Status des Verpackungsprozesses.
1220
Kapitel 37: Ihre Anwendung verteilen
Abbildung 37.15: Klicken Sie die Kontrollkästchen derjenigen Anwendungsdateien an, die Sie als gemeinsame Dateien festlegen möchten
Klicken Sie auf SAVE REPORT, um den Bericht gegebenenfalls als Datei zu speichern. Klicken Sie anschließend auf CLOSE. Sie gelangen daraufhin wieder zum ersten Schritt des Package and Deployment Wizard zurück, wo Sie entscheiden können, Ihre Anwendung sofort weiterzugeben.
Abbildung 37.16: Geben Sie einen Scriptnamen ein und klicken Sie auf Finish, um das Paket zu erstellen
Ihre Datenbank für die Laufzeitversion von Access vorbereiten
1221
Abbildung 37.17: Access benachrichtigt Sie über jeden Schritt während des Setups, der zur Erstellung des Pakets ausgeführt wird
Abbildung 37.18: Wenn der Verpackungsprozess beendet ist, erscheint ein Verpackungsbericht
37.6.6
Die Anwendung weitergeben
Bevor Sie mit der Installation der Anwendung auf Arbeitsstationen beginnen können, müssen Sie Ihre Projektpakete an eine Verteilungs-Site weitergeben. Dies wird wiederum mit Hilfe des Package and Deployment Wizard durchgeführt. Führen Sie dazu die folgenden Schritte aus:
1222
Kapitel 37: Ihre Anwendung verteilen
1. Wählen Sie im Startfenster des Package and Deployment Wizard die Option DEPLOY (siehe Abbildung 37.5). 2. Wählen Sie im ersten Schritt des Deploy Wizard das zu verteilende Paket aus. Klicken Sie anschließend auf NEXT. 3. Der zweite Schritt im Abschnitt DEPLOY des Package and Deployment Wizard ermöglicht es Ihnen, die Art der Verteilung festzulegen, die Sie ausführen wollen. Es ist das Verteilen über einen Ordner oder über das Web möglich (siehe Abbildung 37.19). Die folgenden Schritte hängen von der von Ihnen getroffenen Wahl ab. Klicken Sie auf NEXT, nachdem Sie Ihre Wahl getroffen haben.
Abbildung 37.19: Sie können zwischen der Weitergabe in einen Ordner oder über das Web wählen
4. Wenn Sie sich für die Option FOLDER entschieden haben, müssen Sie im dritten Schritt des Package and Deployment Wizard angeben, wo Sie das Paket verteilen wollen. Die Verteilung kann lokal oder an ein Netzwerk erfolgen. Treffen Sie Ihre Wahl und klicken Sie auf NEXT. 5. Im letzten Schritt der Verteilungsphase des Package and Deployment Wizard legen Sie einen Namen für das Verteilungsscript fest (siehe Abbildung 37.20). Dieses Script wird für zukünftige Verteilungen des Pakets verwendet. Klicken Sie anschließend auf NEXT. 6. Wenn der Vorgang abgeschlossen ist, erscheint ein Verteilungsbericht. Klicken Sie auf SAVE REPORT, falls Sie den Bericht speichern möchten, und klicken Sie anschließend auf CLOSE. Sie gelangen wieder zurück zum Startbildschirm des Package and Deployment Wizard.
Ihre Datenbank für die Laufzeitversion von Access vorbereiten
1223
Abbildung 37.20: Legen Sie einen Namen für das Weitergabescript fest und klicken Sie auf Finish
37.6.7
Die Anwendung ausliefern
Das Wichtigste, was Sie tun müssen, wenn Sie Ihre Anwendung verpacken und verteilen, ist das Testen der Anwendung auf einem Rechner, auf dem niemals eine Kopie von Access oder eine Access-Laufzeitanwendung installiert gewesen ist. Dies stellt sicher, dass Ihre Anwendung alle erforderlichen Komponenten enthält. Ich bevorzuge es, einen »jungfräulichen« Rechner zum Testen meiner AnwendungsSetups zur Verfügung zu haben. Die folgenden Schritte führe ich dabei aus: 1. Sicherungskopien der Ordner Windows und Windows\System auf dem Rechner anlegen 2. Installieren meiner Anwendung 3. Testen meiner Anwendung 4. Löschen meiner Anwendung 5. Löschen des gesamten Inhalts im Ordner Windows\System 6. Wiederherstellen des Ordners Windows\System mit Hilfe des Backups Durch Ausführen dieser Schritte stelle ich sicher, dass ich immer einen »sauberen« Rechner besitze, auf dem ich meine Anwendung testen kann. Es ist natürlich zwingend erforderlich, dass Sie alle Aspekte Ihrer Anwendung auf dem Rechner testen, auf dem Sie die Installation Ihrer Setup-Disketten ausgeführt haben.
1224
Kapitel 37: Ihre Anwendung verteilen
Es gibt mehrere Software-Pakete von Drittanbietern, die Sie dabei unterstützen, ein Backup Ihrer Windows-Installation zu erstellen und Ihre Installation wiederherzustellen. Ein bekanntes Paket ist Ghost von Symantec. Wenn Sie bereit sind, den Setup-Vorgang zu testen, führen Sie die folgenden Schritte aus: 1. Wählen Sie im Windows Startmenü den Befehl AUSFÜHREN. 2. Suchen Sie im Dialogfeld AUSFÜHREN die Setup-Dateien, die während der Verteilungsphase des Package and Deployment Wizard erstellt wurden, wie Sie es in Abbildung 37.21 sehen können. Klicken Sie anschließend auf OK.
Abbildung 37.21: Im Startmenü den Befehl Ausführen wählen
3. Nach der Mitteilung über den Fortschritt des Setups erscheint das in Abbildung 37.22 gezeigte Dialogfeld APPLICATION SETUP.
Abbildung 37.22: Das Start-Dialogfeld des Anwendungs-Setups
4. Klicken Sie auf OK, um fortzufahren. 5. Wählen Sie einen Ordner für die Anwendungsinstallation (siehe Abbildung 37.23).
1225
Andere Fragestellungen
Abbildung 37.23: Einen Ordner für die Programminstallation wählen
6. Klicken Sie auf die Befehlsschaltfläche, um die Anwendung in das angegebene Verzeichnis zu installieren. Daraufhin erscheint das Dialogfeld CHOOSE PROGRAM GROUP. Wählen Sie dort eine Programmgruppe aus und klicken Sie anschließend auf CONTINUE. Der Installationsvorgang ist damit beendet. Wenn Sie im Package and Deployment Wizard entschieden haben, Desktop-Verknüpfungen zu erstellen, werden diese automatisch erstellt, wenn das Setup-Programm ausgeführt wird.
37.7
Andere Fragestellungen
Zwei weitere Aspekte hinsichtlich der Verteilung Ihrer Anwendung sind noch nicht behandelt wurden. Zum einen geht es darum zu gewährleisten, dass die Anwendungsdatenbank alle Verknüpfungen zu externen Tabellen einrichten kann. Der zweite Punkt betrifft den Einsatz der Replikation, um Änderungen an Ihrer Anwendung auf effektive Weise weiterzugeben.
37.7.1
Den Prozess der Verknüpfung zu Tabellen automatisieren
Access legt die Speicherorte für Tabellenverknüpfungen fest im Programm-Code ab. Dies bedeutet, dass die Tabellen, wenn Sie Ihre Anwendung auf einem anderen Rechner installieren, nicht erfolgreich verknüpft werden, sofern Sie dort nicht genau dieselbe Verzeichnisstruktur wie auf Ihrem eigenen Rechner haben. Der in Listing 37.4 gezeigte Code prüft, ob die erforderlichen Tabellen verfügbar sind. Falls sie nicht im erwarteten Ordner gefunden werden, versucht die Routine, sie in dem Ordner zu finden, in dem sich auch die Anwendungsdatenbank befindet. Falls sie immer noch nicht gefunden werden können, erhält der Benutzer die Gelegenheit, die Dateien zu suchen. Wenn die Dateien dann immer noch nicht gefunden werden können, wird die Anwendung beendet.
1226
Listing 37.4:
Kapitel 37: Ihre Anwendung verteilen
Die Routine LinkTables
Sub LinkTables() On Error GoTo LinkTables_Err:
'Optionaler Test auf die Laufzeitversion If Not SysCmd(acSysCmdRuntime) _ And CurrentUser <> "Admin" Then MsgBox "You aren't allowed here" Exit Sub End If DoCmd.Hourglass True If Not VerifyLink Then If Not ReLink(CurrentProject.FullName, True) Then Me.dlgCommon.ShowOpen If Not ReLink(Me.dlgCommon.FileName, False) Then MsgBox "You Cannot Run This App Without Locating Data Tables" DoCmd.Close acForm, "frmSplash" DoCmd.Quit End If End If End If Call GetCompanyInfo DoCmd.Hourglass False Exit Sub LinkTables_Err: MsgBox "Error # " & Err.Number & ": " & Err.Description Exit Sub End Sub
Die Routine beginnt mit der Ausführung einer Funktion namens VerifyLink. Diese Funktion ist in Listing 37.5 definiert und befindet sich in der Datei FinalLibrary.MDA auf der CD-ROM mit dem Beispielcode. Die Funktion erstellt zunächst ein ADOX-Katalog-Objekt. Die Eigenschaft ActiveConnection des Katalogobjekts wird auf die Eigenschaft Connection des Objekts CurrentProject gesetzt. Letzteres gibt einen Verweis auf die Datenbank zurück, welche die Bibliothek verwendet, anstatt auf die Bibliothek selbst. Der Kern der Routine ist die For...Next-Schleife. Sie durchläuft jedes Table-Objekt in der Tabellenauflistung des Katalogobjekts. Falls die Tabelle verknüpft ist, wird versucht, auf das erste Feld in der Tabelle zu verweisen. Wenn ein Fehler auftritt, muss die Tabellenverknüpfung getrennt sein. Die Fehlernummer ist von Null verschieden und die Routine
Andere Fragestellungen
1227
beendet die For...Next-Schleife. Da die Funktion zurückgibt, ob die Fehlernummer gleich Null ist oder nicht, wird False zurückgegeben, falls ein Fehler auftritt, und True, falls kein Fehler auftritt. Listing 37.5:
Die Funktion VerifyLink
Function VerifyLink() As Boolean 'Verbindungsinformationen in verknüpften Tabellen überprüfen 'Erforderliche Variablen deklarieren Dim cat As ADOX.Catalog Dim tdf As ADOX.Table Dim strTemp As String 'Objektvariable auf aktuelle Datenbank verweisen lassen Set cat = New ADOX.Catalog With cat Set .ActiveConnection = CurrentProject.Connection 'Bei unterbrochener Verbindung weitermachen On Error Resume Next 'Verknüpfte Tabelle öffnen, um Verbindungsinfos 'zu überprüfen For Each tdf In .Tables If tdf.Type = "LINK" Then strTemp = tdf.Columns(0).Name If Err.Number Then Exit For End If End If Next tdf End With VerifyLink = (Err.Number = 0) End Function
Falls die Funktion VerifyLink den Wert False zurückgibt, wird die Funktion Relink ausgeführt. Die Funktion Relink, die in Listing 37.6 dargestellt ist, erhält zwei Parameter. Der erste Parameter ist der Name der Datenbank, zu der die Funktion eine Verknüpfung aufzubauen versuchen wird. Der zweite Parameter ist eine Variable vom Typ Boolean, die verwendet wird, um anzuzeigen, ob die Datenbank als standardmäßige Datenbank angesehen wird.
1228
Kapitel 37: Ihre Anwendung verteilen
Die Funktion beginnt damit, die Statusleiste zu bearbeiten. Danach werden ein Catalog-Objekt und eine Instanz einer benutzerdefinierten Klasse namens DBInfo erstellt. Die Eigenschaft ActiveConnection des Catalog-Objekts wird gleich der Eigenschaft Connection des aktuellen Projekts gesetzt. Als nächstes wird die Eigenschaft FullName der Klasse DBInfo gleich dem Namen der Datei gesetzt, die der Funktion als Parameter übergeben wird. Die Klasse DBInfo extrahiert den Pfad und den Dateinamen aus dem vollständigen Dateinamen. Genauso wie die Funktion VerifyLink verwendet die Funktion Relink eine For...Next-Schleife, um alle Tabellen in der Datenbank zu durchlaufen. Während sie jede Tabelle durchläuft, versucht die Funktion, eine Verknüpfung zu einer Datenbank mit dem Namen zu errichten, welcher der Funktion Relink als Parameter übergeben wurde. An dieser Stelle kommt der Parameter DefaultData ins Spiel. Wenn die Routine LinkTables die Funktion Relink zum ersten Mal aufruft, übergibt sie den Namen und den Pfad der Anwendungsdatenbank als ersten Parameter und den Wert True für den zweiten Parameter. Die Funktion Relink versucht dann, eine Verknüpfung zu einer Datenbank herzustellen, die sich im selben Ordner wie die Anwendungsdatenbank befindet, wobei aber der Zusatz Data am Ende des Dateinamen angefügt wird. Wenn beispielsweise die Anwendungsdatenbank Membership heißt, sucht die Funktion Relink nach einer Datenbank namens MembershipData im selben Ordner wie die Anwendungsdatenbank. Falls die Suche erfolgreich ist, wird True zurückgegeben, andernfalls False. Ich verwende diese Methode, um zu versuchen, die Verknüpfung wiederherzustellen, da ich normalerweise sowohl die Anwendungs- als auch die Datendatenbanken im gleichen Ordner im Netzwerk eines Clients ablege. Wenn ich dies tue, wende ich eine Namenskonvention an, bei der die Datendatenbank denselben Namen wie die Anwendungsdatenbank besitzt, aber den Zusatz Data trägt. Falls keine Datenbank mit dem erwarteten Dateinamen im Ordner gefunden wird, in dem sich die Anwendungsdatenbank befindet (die Funktion Relink hat False zurückgegeben), verwendet die Routine LinkTables das Common Dialog-Steuerelement, um ein Dialogfeld DATEI ÖFFNEN anzuzeigen. Dies gibt dem Benutzer die Gelegenheit, die Datenbank zu suchen. Der Dateiname und der Pfad, welche der Benutzer im Dialogfeld ausgewählt hat, werden der Routine Relink zusammen mit False als zweitem Parameter übergeben. Da der Benutzer die Datei ausgewählt hat, von der er glaubt, dass sie die Daten enthält, gibt es keinen Grund, dem Dateinamen den Zusatz Data hinzuzufügen. Erneut durchläuft die Routine Relink die Tabellenauflistung des Catalog-Objekts und versucht die getrennten Verknüpfungen wiederherzustellen. Falls dies gelingt, wird True zurückgegeben, andernfalls False. Falls nach dem zweiten Aufruf der Funktion Relink der Wert False zurückgegeben wird, beendet die Routine LinkTables die Access-Anwendung.
Andere Fragestellungen
Listing 37.6:
Die Funktion Relink
Function ReLink(strDir As String, DefaultData As Boolean) _ As Boolean ' Erneutes Verknüpfen einer Access-Tabelle, deren Verbindung getrennt war Dim Dim Dim Dim Dim Dim Dim
cat As ADOX.Catalog tdfRelink As ADOX.Table oDBInfo As DBInfo strPath As String strName As String intCounter As Integer vntStatus As Variant
vntStatus = SysCmd(acSysCmdSetStatus, "Updating Links") Set cat = New ADOX.Catalog Set oDBInfo = New DBInfo With cat .ActiveConnection = CurrentProject.Connection oDBInfo.FullName = strDir strPath = oDBInfo.FilePathOnly strName = Left(oDBInfo.FileName, InStr(oDBInfo.FileName, ".") – 1) On Error Resume Next Call SysCmd(acSysCmdInitMeter, "Linking Data Tables", .Tables.Count) For Each tdfRelink In .Tables intCounter = intCounter + 1 Call SysCmd(acSysCmdUpdateMeter, intCounter) If .Tables(tdfRelink.Name).Type = "LINK" Then tdfRelink.Properties("Jet OLEDB:Link Datasource") = strPath & _ strName & IIf(DefaultData, "Data.Mdb", ".mdb") End If If Err.Number Then Exit For End If Next tdfRelink End With Call SysCmd(acSysCmdRemoveMeter) vntStatus = SysCmd(acSysCmdClearStatus) ReLink = (Err = 0) End Function
1229
1230
37.7.2
Kapitel 37: Ihre Anwendung verteilen
Mit Hilfe der Replikation Ihre Anwendung effizient weitergeben
Sie wollen möglicherweise nicht jedesmal die Setup-Disketten neu erstellen und verteilen, wenn Sie den Entwurf Ihrer Anwendungsdatenbank ändern. Dieses Vorgehen ist nicht nur zeitaufwendig, sondern es ist auch schwierig sicherzustellen, dass jeder Benutzer den Setup-Vorgang ausführt, um die Anwendungsdatenbank zu erhalten. Wenn Ihr Unternehmen vernetzt ist, ist es im Allgemeinen wesentlich effektiver, Aktualisierungen Ihrer Anwendung mit Hilfe von Replikation zu verteilen. Dazu gehört, dass Entwurfsänderungen am Design Master vorgenommen werden und dann eine Synchronisation mit einem Hub erfolgt, nachdem die Änderungen beendet und vernünftig getestet worden sind. Die Replikation wird detailliert im Kapitel 23 behandelt.
37.7.3
Für die Praxis
Das Zeit- und Abrechnungssystem verteilen Die vollständige Zeit- und Abrechnungsanwendung, die auf Ihrer CD-ROM mit dem Beispiel-Code als CHAP37.MDB zu finden ist, wurde geändert, um sie für die Verteilung vorzubereiten. Es wurden Übersichten hinzugefügt, die den Benutzer beim Navigieren in der Anwendung unterstützen, Fehlerbehandlungsroutinen in die meisten der Anwendungsroutinen eingefügt, den Formularen und Berichten der Anwendung benutzerdefinierte Symbol- und Menüleisten hinzugefügt und Startoptionen festgelegt. Die Anwendung wurde vollständig unter der Laufzeitversion des Produkts getestet. Was noch übrig bleibt ist, die Anwendung anständig zu sichern, um den Anforderungen Ihres Unternehmens gerecht zu werden, und die Setup-Disketten zu erstellen.
Anhänge
Teil VI A B
Namenskonventionen Die Buch-CD-ROM
Namenskonventionen
Anhang
Dieser Anhang schlägt Ihnen Namen für Ihre Variablen und anderen Datenbankobjekte vor, deren Logik an die so genannten Reddick VBA Naming Conventions (RBVA) angelehnt ist. Beim Benennen von Variablen spielt es eine große Rolle, dass Sie durch den Namen den Typ und die beabsichtigte Verwendung jeder einzelnen Variablen hervorheben. Damit dies gelingt, gibt es einige Regeln:
Denken Sie immer daran, in Variablennamen Groß- und Kleinschreibung zusammen zu verwenden, wobei jedes Wort bzw. jede Abkürzung innerhalb des Namens mit einem Großbuchstaben beginnen sollte.
Benutzen Sie in Variablennamen keine Unterstriche. Kürzen Sie Variablennamen nur ab, wenn es unbedingt erforderlich ist. Beginnen Sie jeden Variablennamen so, dass der Anfang den Typ der enthaltenen Daten beschreibt. Wenn Sie sich an diese Richtlinien halten, haben Sie einen Großteil des Wegs zu einem präzisen und lesbaren Code bereits hinter sich. Das Format für ein Objekt lautet wie folgt: [Präfixe]Marke[BasisName[Suffixe]]
Ein Präfix wird komplett kleingeschrieben und dient der Angabe zusätzlicher Informationen, wie zum Beispiel des Gültigkeitsbereichs einer Variablen. Auch die so genannte Markierung erscheint in Kleinbuchstaben, wobei es sich bei diesem Kürzel um eine Beschreibung des Objekttyps handelt. Der BasisName wird verwendet, um anzudeuten, was das Objekt repräsentiert. Der erste Buchstabe jedes Worts im BasisNamen wird dabei großgeschrieben. Suffixe sollen, wenn man überhaupt von ihnen Gebrauch macht, zusätzliche Informationen über die Bedeutung des BasisNamens bereitstellen. Ein Beispiel für einen Objektnamen sieht so aus: mstrFirstName
1234
Anhang A: Namenskonventionen
Das Präfix m deutet in diesem Fall an, dass die Variable auf der Modulebene erscheint, die Marke str steht für eine Zeichenfolge (einen String) und der BasisName FirstName weist darauf hin, dass die Variable einen Vornamen enthält. Tabelle A.1 zeigt empfohlene Präfixe für Access-Objektmarken. Präfix
Steuerelementtyp
Beispiel
app
Anwendung
appInfoBase
chk
Kontrollkästchen
chkReadOnly
cbo
Kombinationsfeld
cboLanguages
cmd
Befehlsschaltfläche
cmdRefreshTable
ctl
Steuerelement (allgemein)
ctlAny
ctls
Steuerelemente (allgemein)
ctlsAll
ocx
Benutzerdefiniertes Steuerelement
ocxCalendar
dcm
DoCmd
dcmOpenForm
frm
Formular
frmDataEntryView
frms
Formulare
frmsClientsAndOrders
img
Bild
imgHeadShot
lbl
Etikett
lblShowAllCheckBox
lin
Linie
linDivider
lst
Listenfeld
lstLastTenSites
bas
Modul
basErrorControl
ole
Objektfeld
oleWorksheet
opt
Optionsfeld
optReadOnly
fra
Optionsgruppe (Rahmen)
fraColorSchemes
brk
Seitenumbruch
brkTopOfForm
pal
PaletteButton
palBackgroundColor
prps
Eigenschaften
prpsActiveForm
shp
Rechteck
shpHidableFrame
rpt
Bericht
rptOrders
Tabelle A.1: Namenskonventionen für Access-Objekte
Namenskonventionen
Präfix
Steuerelementtyp
Beispiel
rpts
Berichte
rptsTodaysChanges
scr
Bildschirm
scrSecondSplashScreen
sec
Abschnitt
secOrderDetail
fsub
Unterformular
fsubBillableHours
rsub
Unterbericht
rsubTopFiveSales
txt
Textfeld
txtAdditionalNotes
tgl
Umschaltfläche
tglShowFormatting
1235
Tabelle A.1: Namenskonventionen für Access-Objekte (Forts.)
Tabelle A.2 führt die Präfixmarken für Standard-Variablentypen sowie den von jedem Typ belegten Speicherplatz auf. Präfix
Datentyp
byte oder byt
Speicherplatz
Beispiel
1 Byte
byteArray
bool oder f
Boolean
2 Bytes
boolSecurityClear
int
Integer
2 Bytes
intLoop
lng
Long Integer
4 Bytes
lngEnv
sng
Single
4 Bytes
sngValue
dbl
Double
8 Bytes
dblValue
cur
Currency (Währung) 8 Bytes
curCostPerUnit
dat
Datum und Uhrzeit
8 Bytes
datStartTime
obj
Objekt
verschieden
objActiveObject
str
String
1 Byte pro Zeichen
strFirstName
stf
String (feste Länge)
10 Bytes + 1 Byte pro Zei- stfSocNumber chen
var
Variant
16 Bytes + 1 Byte pro Zei- varInput chen
Tabelle A.2: Marken für die standardmäßigen Datentypen
1236
Anhang A: Namenskonventionen
Die Jet-Engine verwendet Objekte, auf die Sie im VBA-Code möglicherweise verweisen müssen. Tabelle A.3 listet die DAO-Objekttypen (DAO – Data Access Objects bzw. Datenzugriffsobjekte) und ihre standardmäßigen Präfixe auf. Präfix
Objekttyp
cnt
Container (Container)
cnts
Containers
db
Database (Datenbank)
dbs
Databases
dbe
DBEngine
doc
Document (Dokument)
docs
Documents
err
Error (Fehler)
errs
Errors
fld
Field (Feld)
flds
Fields
grp
Group (Gruppe)
grps
Groups
idx
Index (Index)
inxs
Indexes
prm
Parameter (Parameter)
prms
Parameters
pdbe
PrivDBEngine
prp
Property (Eigenschaft)
prps
Properties
qry (or qdf)
QueryDef (Abfragedefinition)
qrys (or qdfs)
QueryDefs
rst
Recordset (Datensatzgruppe)
Tabelle A.3: Präfixe für Jet-Objekte und Jet-Auflistungen
Namenskonventionen
Präfix
Objekttyp
rsts
Recordsets
rel
Relation (Relation oder Beziehung)
rels
Relations
tbl (or tdf)
TableDef (Tabellendefinition)
tbls (or tdfs)
TableDefs
usr
User (Benutzer)
usrs
Users
wrk
Workspace (Arbeitsbereich)
wrks
Workspaces
1237
Tabelle A.3: Präfixe für Jet-Objekte und Jet-Auflistungen (Forts.)
Zusätzlich zur Standardnotation für Variablen gibt es auch Schreibweisen für den Gültigkeitsbereich und die Lebensdauer von Variablen. Diese sollten vor jedem anderen Präfix am Anfang der Variablen aufgeführt werden. Tabelle A.4 zählt die Gültigkeitsbereichs- und Lebensdauerpräfixe auf. Präfix
Beschreibung
(keines)
Lokale Variable, Lebensdauer orientiert sich an der Prozedur
s
Lokale Variable, Lebensdauer richtet sich nach dem Programm (statische Variable)
m
Private (Modul-) Variable, Lebensdauer des Programms
g
Globale Variable, Lebensdauer des Programms
Tabelle A.4: Präfixe für Gültigkeitsbereiche und die Lebensdauer
Tabelle A.5 führt die allgemeinen Benennungskonventionen für die Datenbankobjekte auf. Präfix
Objekttyp
tbl
Tabelle
qry
Abfrage
Tabelle A.5: Präfixe für Datenbankobjekte
1238
Anhang A: Namenskonventionen
Präfix
Objekttyp
frm
Formular
rpt
Bericht
mcr
Makro
bas
Modul
Tabelle A.5: Präfixe für Datenbankobjekte (Forts.)
Es gibt zwei Mengen von Benennungskonventionen, die Sie bei der Namensgebung für bestimmte Datenbankobjekte verwenden können: Benutzen Sie entweder den Präfix für das allgemeine Datenbankobjektpräfix aus der Tabelle oder geben Sie eine der etwas aussagefähigeren Markierungen an, die in Tabelle A.6 aufgeführt sind. Präfix
Suffix
Objekttyp
tlkp
Lookup
Tabelle (Suchen)
qsel
(keines)
Abfrage (Auswahl)
qapp
Append
Abfrage (Anfügen)
qxtb
XTab
Abfrage (Kreuztabelle)
qddl
DDL
Abfrage (DDL)
qdel
Delete
Abfrage (Löschen)
qflt
Filter
Abfrage (Filter)
qlkp
Lookup
Abfrage (Suchen)
qmak
MakeTabelle
Abfrage (Tabellenerstellung)
qspt
PassThru
Abfrage (Pass-Through)
qtot
Totals
Abfrage (Zusammenfassung)
quni
Union
Abfrage (Union)
qupd
Update
Abfrage (Aktualisierung)
fdlg
Dlg
Formular (Dialogfeld)
fmnu
Menu
Formular (Menü)
fmsg
Msg
Formular (Meldung)
Tabelle A.6: Markierungen für bestimmte Datenbankobjekte
Namenskonventionen
Präfix
Suffix
Objekttyp
fsfr
Subform
Formular (Unterformular)
rsrp
SubReport
Formular (Unterbericht)
mmnu
Mnu
Macro (Menü)
Tabelle A.6: Markierungen für bestimmte Datenbankobjekte (Forts.)
1239
Die Buch-CD-ROM
Anhang
Die Begleit-CD zum Buch enthält eine Reihe sehr nützlicher Zusatz-Programme zu Microsoft Access 2000 von amerikanischen Drittanbietern, den Quellcode aus diesem Buch, eine 30-Tage-Testversion des professionellen Englisch-Wörterbuchs »Lingua 2000«, die beiden marktführenden Browser von Microsoft und Netscape, kostenlose Zugangssoftware der Onlinedienste CompuServe und T-Online sowie den Markt&Technik-Produktkatalog.
Installation unter Windows 95 / 98 / NT Diese CD-ROM ist menügesteuert. Hierfür benötigen Sie einen internetfähigen Browser. Sollten Sie auf Ihrem PC noch keinen Browser installiert haben, können Sie zwischen dem Microsoft Internet Explorer 5.0 und dem Netscape Communicator 4.7 wählen. Diese finden Sie im Ordner \DIENSTE\IE5 bzw. \DIENSTE\NETSCAPE. Falls auf Ihrem Rechner Windows 95 / 98 installiert ist und Sie die Funktion Autoplay aktiviert haben, startet das Programm ASTART.EXE automatisch, wann immer Sie die CD in das Laufwerk einlegen. Legen Sie die CD-ROM in Ihr Laufwerk ein. Die Menüoberfläche wird nun automatisch über die Autostart-Funktion von Windows 95 gestartet. Falls bei Ihrem PC die Autostart-Funktion nicht aktiviert ist, können Sie die Menüoberfläche mit einem Doppelklick auf die Datei INDEX.HTM aufrufen.
Stichwortverzeichnis
A Abfrageeigenschaften 441 – Duplikate 442 – Eindeutige Datensätze 442 – Spitzenwerte 442 Abfragen 34, 105, 634, 789 – Abfrageeigenschaften 136, 137 – Abfrageergebnisse 133 – Abfragekriterien 471 – Äußere Verknüpfungen 457 – Assistent 106 – Asynchrone 753 – AUSFÜHREN 109 – Auswahlabfragen 105 – Automatische Anpassung 123 – benennen 112 – Berechnete Felder erstellen 125 – Daten zusammenfassen 128 – Datumsangaben 116 – Duplikatsuche 106 – Entwurfsansicht 106 – Ergebnisse aktualisieren 118 – Ergebnisse sortieren 112 – Ergebnisweitergabe 469 – erzwungene referentielle Integrität 123 – Feld aus Abfrageraster entfernen 110 – Feld in eine bestehende Abfrage einfügen 110
– Feld verschieben 111 – Feldeigenschaften 136 – Felder ausschließen 132 – Felder hinzufügen 107 – Feldlisteneigenschaften 136 – Geschwindigkeit 446 – in Tabellen hinzufügen 107 – Inkonsistenzsuche 106 – kompilieren 445 – Kreuztabellenabfragen 106, 450 – Kriterien 113 – mehrere Tabellen 119 – nach Feldern sortieren 113 – Nullwerte 133 – optimieren 444, 769 – Parameterabfrage 138, 473 – Pass-Through 748 – Pass-Through-Abfragen 468 – Rushmore-Verfahren 448 – Selbstverknüpfungen 459 – speichern 112 – sperren 657 – SQL 460 – Sternchen 109 – Union-Abfragen 467 – Unterabfragen 470 Abfrageoperatoren – < 114 – <= 114
1244
Stichwortverzeichnis
– <> 114 – = 114 – > 114 – >= 114 – And (Und) 114 – Between (Zwischen) 114 – In 114 – Is not Null (Ist nicht Null) 115 – Is Null (Ist Null) 115 – IsNull() 136 – Like (Wie) 114 – Not (Nicht) 115 – Or (Oder) 114 Abfrageplan 194 Abfragesortierung 79 Abfragetechniken 431 – Aktionsabfragen 432 – Aktualisierungsabfragen 432 – Anfügeabfragen 436 – Löschabfragen 434 – Tabellenerstellungsabfragen 437 Abläufe testen 41 Abschnittsereignisse 348 Absicherung 720 Access – Benutzerdefinierte Zähler 678 – Datenaktualisierungsversuche 658 – Datenprojekte 768 – Datensatzaktualisierung 656 – Datensatzsperrung 656, 657 – Front-End 644, 646 – Installation 650 – Laufzeitversion 637, 642 – Lizenzerfordernisse 650 – Projektdatei 646 – Prozedurnamen in Bibliotheken 971 – Replikation 678 – Sperren auf Datensatzebene 658 – Sperrmechanismen 655 – Standardöffnungsmodus 658 – Standardversion 637 Access Data Project 632 Access steuern 957 Access-Anwendungen, Entwicklung 44
Access-Dateiformat 193 Access-Makros 253 Access-Toolbox 932 Active Server Pages 1074 ActiveX 253, 285, 636 – ADO-Datensatzgruppen 486 – ADO-Recordset- Methoden 490 – ADO-Recordset-Eigenschaften 490 – Command-Objekt 484 – Connection-Objekt 481 – CurrentDB() 517 – Datenobjekte 480 – Datensätze 492 – Datensätze filtern 495 – Datensätze finden 497 – Datensätze sortieren 494 – Datensätze verschieben 490 – Datensatzgruppen 491 – Datenzugriffsobjekte 479 – DBEngine 516 – Eigenschaft AbsolutePosition 498 – Eigenschaft Bookmark 499 – Parameter CursorType 486 – Parameter LockType 487 – Parameter Options 488 – Parameterabfragen ausführen 500 – Recordset-Objekt 482 ActiveX Data Objects – siehe ADO 1147 ActiveX-Steuerelemente 184, 907 – Behandlungsroutinen für Ereignisse 915 – Drittanbieter 908 – Eigenschaften 914 – Entwurf 914 – Formularen hinzufügen 911 – ImageList-Steuerelement 933 – Implementieren 934 – installieren 909 – Kalender-Steuerelement 917 – Lizenzierung 934 – Referenz 913 – registrieren 909 – RichText-Steuerelement 927
Stichwortverzeichnis
– Steuerelement Common Dialog 924 – Steuerelement StatusBar 922 – Steuerelement UpDown 920 – TabStrip-Steuerelement 930 – verwenden 908 – Weitergabe 934 ADO 287, 479, 595, 767, 1147, 1161, 1167 – Abfragen erstellen 507 – Beziehungen einrichten 506 – Datenbankobjekte bearbeiten 504 – Datenbankobjekte erstellen 504 – Datensätze ändern 501 – Datensätze hinzufügen 503 – Datensätze löschen 502 – Dokumentationen 1185 – Mehrere Datensätze ändern 502 – Tabellen entfernen 506 – Tabellen hinzufügen 505 – Tabellendaten 500 ADOX 693, 1149 ADP 632 – Berichte 763 – Datei erstellen 798 – erstellen 754 – Formulare 763 – Makros 763 – Module 763 – Verfügbare Funktionen 763 ADP-Dateien 29 Adressetiketten 209 Adressübergabe 967 Änderungs-Batch 809 AID 1126 Aktionen 251 Aktionsabfragen 432, 439, 763 Anweisungen – Debug.Print 549 – Option Explicit 548 Anwendungen – absichern 639 – Arten 25 – auf Formularen aufbauen 639 – ausliefern 1223
1245
– Befehlsleisten 640 – Benutzerdefinierte Hilfen 640 – Client/Server 28 – Fehlerbehandlung integrieren 640 – gesamte Unternehmen 27 – Installation 651 – Intranet/Internet 29 – kleinere Geschäftsbereiche 26 – mehrbenutzerfähig machen 679 – persönliche 26 – Unternehmensabteilungen 27 – verteilen 1197, 1200 – Wartung 1189 – Weitergabe 638 – weitergeben 1221 Anwendungsdatenbank 633 Anwendungsdokumentationen 1173 – Abfragen 1175 – Berichte 1177 – Formulare 1176 – Makros 1177 – Module 1177 – Tabellen 1174 Anwendungsentwurfsmodell 722 API 253 – 16-Bit 979 – 32-Bit 979 – Arbeitsumgebung 980 – Datenbankdatei laden 975 – DLL-Funktionen 970 – Funktionen verwenden 980 – Funktionsaufrufe 969 – Konstanten 972 – Konstanten einfügen 977 – Laufwerkstypen ermitteln 986 – Typen 973 – Typen einfügen 977 – verfügbaren Platz 986 – Viewer 974 Application Programming Interface, siehe API 253 ASP 30 ASP-Dateien 1074
1246
Stichwortverzeichnis
Assistenten – einsetzen 1051 – erstellen 1052 – vorbereiten 1056 Attribute 251 Aufgabenanalyse 44 Auflistung 320, 326 – Auf Elemente zugreifen 898 – Benutzerdefinierte 896 – Elemente durchlaufen 899 – Elemente entfernen 898 – Elemente hinzufügen 897 – erstellen 897 – Objekte 325 Ausdrucks-Generator 127, 185 Ausdrücke 185 Automatisierung 937 – Automatisierungsobjekte anpassen 942 – Automatisierungsobjekte erstellen 940 – Begriffe 938 – Eigenschaften 942 – Excel-Automatisierungsobjekte 947 – Methoden ausführen 943 – Objektvariablen 939 – Objektvariablen deklarieren 942 B Back-End 30, 644, 655, 682, 700, 715 – MDB 722 Back-End-Datenbanken 29 Bandbreite 716 Batch 809, 825 Batch-Aktualisierungen 754 Befehlsleistenbearbeitung 372 Befehlsschaltflächen – aktivieren 331 – deaktivieren 331 Befehlsschaltflächen-Assistent 187, 199 Begrüßungsbildschirme 363, 396 Benennungskonventionen 1233 Benennungsstandards 548 Benutzer-DatensicherheitsAssistent 1114
Benutzerdefinierte Eigenschaften 390 Benutzerdefinierte Methoden 394 Benutzer-ID 700 Benutzerliste 677 Benutzerschnittstelle – Entfernte Tabellen 740 – Komprimierung 1191 Berechtigungen 1164 – adRightAll 1166 – adRightDelete 1166 – adRightInsert 1166 – adRightRead 1166 – adRightReadDesign 1166 – adRightUpdate 1166 – adRightWithGrant 1166 – adWriteDesign 1166 Berichte 37, 205, 310, 634 – 1:n 232 – 1:n-Abfrage 235 – Abfragen 238 – Abschnittsereignisse 408 – als HTML speichern 244 – Aufbau 210 – Berechnete Steuerelemente 231 – Berichtsabschnittsereignisse 403 – Berichts-Assistent 232, 243 – Berichtsfuß 211 – Berichtskopf 211 – Dateneigenschaften 225 – Datenherkunft wechseln 410 – Detailbereich 211 – Entwurfsansicht 38, 215 – Ereignisreihenfolge 403 – Fortgeschrittene Verwendung 399 – Gebundene Steuerelemente 231 – Geschwindigkeit verbessern 242 – gespeicherte Abfragen 242 – Gruppeneigenschaften 240 – Gruppenfuß 211 – Gruppenfußeigenschaften 241 – Gruppenkopf 211 – Gruppenkopfeigenschaften 241 – Gruppierung 238 – Gruppierung hinzufügen 239 – Hyperlink hinzufügen 244
Stichwortverzeichnis
– Internet 243 – Kreuztabellenabfrage 417 – Kreuztabellenbericht 426 – mit Ausdrücken erweitern 231 – neu erstellen 211 – Praktische Anwendungen 410 – Seiteneinträge drucken 423 – Seitenfuß 211 – Seitenkopf 211 – Seitenumbrüche einfügen 230 – Sortiereigenschaften 240 – Sortierreihenfolge 238 – Sortierreihenfolge hinzufügen 239 – sperren 657 – Spezielle Eigenschaften 408 – Steuerelemente auswählen 219 – Steuerelementeigenschaften 227 – Tabellen 231 – Ungebundene Steuerelemente 231 – Unterberichte 237 – Unterberichts-Assistent 236 – Verfügbare Ereignisse 399 – Wiederverwendbarkeit verbessern 242 – Zusammenfassungen 412 Berichts-Assistent 212 Berichtseigenschaften 223 – andere 225 – Beschriftung 224 – Bild 224 – Bild nebeneinander 224 – Bildausrichtung 224 – Bildgrößenmodus 224 – Bildseiten 224 – Bildtyp 224 – Breite 224 – Datensätze sperren 225 – Datumsgruppierung 226 – Drucklayout 225 – Eigenschaftenfenster 224 – Enthält Modul 227 – Formateigenschaften 224 – Gruppe zusammenhalten 224 – Hilfedatei 226
– Hilfekontext-ID 226 – Kontextmenüleiste 226 – Marke 226 – Menüleiste 226 – Palettenherkunft 225 – Raster X 225 – Raster Y 225 – Schneller Laserdruck 226 – Seitenfuß 224 – Seitenkopf 224 – Symbolleiste 226 Berichtselemente – Andere Steuerelemente 223 – Bezeichnungen 220 – Bildsteuerelemente 222 – Gebundene Objektfelder 221 – Linien 220 – Rechtecke 220 – Textfelder 220 – Ungebundene Objektfelder 221 Berichtsentwurfsfenster 215 – Berichtsobjekte am Raster ausrichten 219 – Berichtsobjekte ausrichten 218 – Berichtsobjekte auswählen 217 – Berichtsobjekte in der Größe verändern 219 – Berichtsobjekte verschieben 217 – Eigenschaftenfenster 215 – Felder hinzufügen 216 – Feldliste 215 – Gruppierungsfenster 215 – Objektabstand steuern 219 – Toolbox 215 – Werkzeuge 215 Berichtstypen 205 – Detailberichte 206 – Diagramme 207 – Etiketten 209 – Formulare 209 – Grafiken 207 – Kreuztabellenberichte 207 – Zusammenfassende Berichte 206
1247
1248
Stichwortverzeichnis
Beziehungen 89 – Abrechnungssystem 102 – Aktualisierungsweitergabe an Detailfeld 98 – einrichten 92 – Löschweitergabe an Detaildatensatz 99 – referentielle Integrität 96, 101 – Richtlinien 94 – verändern 96 – Vorteile von 101 – Zeitsystem 102 – zwischen zwei Tabellen einrichten 93 Beziehungstypen 89 – 1:1-Beziehungen 90 – 1:n-Beziehungen 90 – m:n-Beziehungen 91 Bibliotheken, eigene erstellen 1021 Bibliotheksdatenbank 41, 311, 1021 – Bibliotheken kompilieren 1024 – Bibliotheksverweise erstellen 1024 – Code-Module 1022 – Datenbanken vorbereiten 1022 – Explizite Verweise 1028 – Fehlersuche 1033 – Funktionen aufrufen 1025 – Funktionierender Code 1023 – Laufzeitverweise erstellen 1025 – Ortsbestimmungen 1030 – Schlüssel LoadOnStartup 1026 – sichern 1034 – Strukturierung 1022 – Verweise erstellen 1024 Browser 39 C Callback 1161 CBF 254 Client 716 Client/Server 31, 193, 212, 540, 605, 633, 644, 715, 725, 1170 – Access-Datenprojekt 753, 798 – ADO 726 – DAO 725
– DDL 725 – Explizite Transaktionen 825 – Fremdschlüssel 725 – Gespeicherte Prozeduren 726 – Gleichzeitige Benutzer 719 – Höhere Leistung 719 – Implizite Transaktionen 825 – Jet 725 – Kosten und Nutzen 645 – Negative Interaktionen 827 – Netzwerkverkehr 719 – ODBC 725 – OLE DB 725 – Primärschlüssel 726 – Schema 726 – Spalte 725 – Sperrbeschränkungen 827 – SQL 726 – Strategien 765 – Strategien anwenden 774 – Transaktion 726 – Transaktionsverarbeitung 825 – Trigger 726 – Verknüpfte Tabellen 777 – Zeile 726 Client/Server-Anwendungen 28 Code Behind Forms, siehe CBF 254 Code-Module – exportieren 900 – importieren 900 Compact 606 Compiler – externe Funktionen 966 Configure Replication Manager Wizard 853 D DAO 91, 287, 480, 508, 588, 881 – Abfragen erstellen 538 – Beziehungen einrichten 537 – Container-Auflistung 539 – Containers 514 – Database-Objekte 539 – Databases 509
Stichwortverzeichnis
– Datenbankobjekte bearbeiten 535 – Datenbankobjekte erstellen 535 – Datensatzgruppen 517 – Datensatzgruppenobjekte 519 – Dokumente 514 – Errors 516 – Fields 512 – Formular-Container 515 – Groups 509 – Indexes 510 – Parameters 512 – Properties 515 – QueryDefs 511 – Recordset-Eigenschaften 519 – Recordset-Methoden 519 – Recordsets 513 – Relations 513 – Tabellen entfernen 537 – Tabellen hinzufügen 536 – Tabellendaten bearbeiten 531 – TableDefs 510 – Users 509 – Workspaces 508 DAO-Datensätze – Datensatz hinzufügen 534 – Eigenschaft LastModified 535 – einzeln ändern 532 – mehrere verändern 532 – vorhandenen Datensatz löschen 533 DAO-Datensatzgruppen 517 – Anzahl der Datensätze 524 – Beschränkungen 524 – Dateneingabeformulare 540 – Datensätze filtern 526 – Datensätze finden 527 – Datensätze sortieren 525 – Datensätze verschieben 522 – Datensatzzeiger 523 – Dynasets 517 – Eigenschaft AbsolutePosition 528 – Eigenschaft Bookmark 529 – Eigenschaft RecordsetClone 530 – Navigieren durch 523 – öffnen 521 – Parameterabfragen ausführen 531
1249
– Snapshots 518 – Tabellen 518 – Textmarken 529 Data Access Objekts, siehe DAO 91 Datei-Informationsklasse 1002 Daten senden 1078 Datenanalyse 45 Datenbankaufteilung 690, 710 Datenbankdiagramme 760 – erstellen 760 – verändern 761 Datenbank-Dokumentierer 1181 – Optionen 1183 Datenbankeigenschaften 1178 – Allgemein 1178 – Anpassen 1179 – Inhalt 1179 – Statistik 1179 – Zusammenfassung 1178 Datenbanken 30, 642 – Absicherung 643 – komprimieren 1189 – Neustrukturierung 1190 – Replikationsfähigkeit 843 – Startoptionen einbauen 639 – zerlegen 632 Datenbank-Engine 182 Datenbankfenster 31, 211, 1201 Datenbankobjekte 31, 632 – Replikation 842 Datenbank-Provider 664 Datenbanksicherheit 1109 – Admin-Benutzer 1113 – Administrator-Benutzer 1123 – Administrator-Benutzer entfernen 1124 – Administrator-Benutzer erstellen 1121 – Administratoren-Gruppe 1123 – Administrator-Kennwort 1119 – Als Systemadministrator anmelden 1123 – Anderen Arbeitsgruppen beitreten 1118 – Arbeitsgruppen einrichten 1116
1250
– – – – –
Stichwortverzeichnis
Arbeitsgruppen erstellen 1114 Arbeitsgruppen-Administrator 1116 Arbeitsgruppen-ID 1117, 1121 Arbeitsgruppen-Informationen 1117 ArbeitsgruppenInformationsdatei 1115 – Benutzer erstellen 1131 – Benutzer hinzufügen 1133 – Benutzer zuweisen 1133 – Benutzerebene 1113 – Besitzer 1140 – Datenbank öffnen 1125 – Datenbank-Kennwort 1110 – Datensicherheits-Assistent ausführen 1125 – Freigabe-Ebene 1110 – Gruppe Benutzer 1121 – Gruppen 1113, 1120 – Gruppen erstellen 1131 – Gruppen hinzufügen 1132 – Kennwörter 1139 – MDE-Dateien erstellen 1137 – Rechte zuweisen 1134 – Replikatgruppe 1138 – Replikation 1138 – Replikation-Systemtabellen 1138 – Sicherung 1142 – System.mdw 1115 – Systemadministrator Kennwort zuweisen 1124 – Verknüpfte Tabellen 1140 – Verschlüsselung 1111 – Zugriffsrechte drucken 1141 Datenbanktabellen 185 Datenbindungen 914 Datenblätter 32 Dateneigenschaften – Aktiviert 182 – Eingabeformat 182 – Filter anwenden 183 – Gesperrt 182 – Gültigkeitsmeldung 182 – Gültigkeitsregel 182 – Standardwert 182 – Steuerelementinhalt 181
Datenelemente 311 Datenintegrität 811, 822 Datenreplikation 632, 832 Datensätze 46 Datensatzgruppen 41 – .LDB-Datei 676 – Abfragen 660 – Aktualisieren 660, 675 – Erneut Abfragen 675 – Optimistisches Sperren 665, 671 – Pessimistisches Sperren 663, 668 – sperren 663 – Sperrkonflikte 667 – Sperrstatus prüfen 674 – Typen 765 Datensicherheit 101 Datensynchronisierung 1138 Datenträgerkomprimierung 1113 Datenvolumen 718 Datenzugriffsseiten 39, 1083 – aus Webseite erstellen 1089 – Eigenschaften ändern 1095 – Eigenschaften anpassen 1093 – Entwurfsansicht 39 – erstellen 1084 – gruppieren 1097 – Navigation 1095 – VBScript 1100 – verstehen 1083 – wichtige Ereignisse 1104 dBase 704 DDE 254 Debugger 549, 555 – Abbrechen 570 – Aktuellen Wert anzeigen 566 – Anwendungen testen 572 – Aufrufeliste 563 – aufrufen 555 – Ausführung fortsetzen 571 – Automatische Daten-Tipps 566 – Code durchgehen 558 – Direktfenster 572 – Einzelschritt 558 – Haltepunkt 555, 560 – Laufzeitfehler 571
Stichwortverzeichnis
– – – – – – – –
Lokal-Fenster 565 nächste Anweisung festlegen 562 Probleme 572 Prozedur abschließen 562 Prozedurschritt 561 Stack 565 Überwachungsausdruck 555, 565 Überwachungsausdruck bearbeiten 568 – Überwachungsausdruck hinzufügen 567 – Unterbrechen 569 Defragmentieren 1190 Deployment Wizard 914 Designmaster 832 Diagramme erstellen 947 Dialogfelder – Aktenkoffer aktualisieren 849 – benutzerdefinierte 144 – Datenbank synchronisieren 849 – Edit Schedule 863 – Speicherort des neuen Replikats 844 Dialogformulare 364 Dial-Up Networking 832 Direktfenster 549, 551, 554 – Löschen 552 DLL-Funktionen 739 – aufrufen 979 Dokumentation 1174 Druckausgaben 145 DSS 719 Duplexing 720 Dynamic Data Exchange 254 E Eigenschaften 251, 307, 313, 321 – ActiveControl 330 – ActiveForm 330 – ActiveReport 330 – CurrentUser 330 – CursorType 766 – Enabled 331 – Form 330
1251
– Jet OLEDB:Link Provider String 700 – KeyPreview 331 – LockType 767 – Me 330 – mit Objektbezug 330 – Modules 330 – NavigationButtons 333 – Parent 330 – PreviousControl 330 – RecordsetClone 330 – Replizierbar 846 – Report 330 – Screen.ActiveForm 330 – Section 330 – Standardeigenschaften 323 – Wert prüfen 550 – Werte festlegen 551 Elementnummer 320 E-Mail-Adressen 81 Entfernte Synchronisierung 861 Entwurf 45 Entwurfsansichten 1201 Ereignisse 251, 307, 314 – AfterUpdate 803 Etiketten drucken 414 Etiketten-Assistent 209 Excel steuern 943 Externe Daten 681 – aus Datenbanken importieren 686 – Benutzerschnittstelle 685, 690 – dBase 704 – Importieren 682, 685 – Kalkulationstabellen 688 – mit Code importieren 686 – Öffnen 682 – Tabelle öffnen 698 – Temporärer Speicherplatz 706 – Textdaten 705 – Textdaten importieren 688 – Unterstützte Dateiformate 684 – Verbindungsprobleme 706 – Verknüpfen 682 – Verknüpfung 683, 689
1252
Stichwortverzeichnis
F Fehler 41 Fehlerbehandlung 575 – allgemeine Fehlerbehandlungsroutine 589 – Err-Objekt 586 – Errors-Auflistung 588 – Fehler auslösen 586 – Fehler protokollieren 592 – Fehlerbeschreibung 580 – Fehlerereignisprozedur 577 – Fehlerereignisse 577 – Fehlerformular ausdrucken 599 – Fehlerformular erstellen 597 – Fehlerinformationen löschen 584 – Fehlernummer 578, 580 – implementieren 576 – integrieren 600 – On Error-Anweisungen 579 – passende Reaktion 594 – Resume-Anweisungen 582 – verschachtelte Fehlerbehandlungsroutinen 585 Fehlersuche 547 Felddatentypen, Hyperlink 79 Feldeigenschaften 63 – Beschriftung 67 – Eingabe erforderlich 70 – Eingabeformat 65 – Feldgröße 63 – Format 64 – Gültigkeitsmeldung 70 – Gültigkeitsregel 68 – Indiziert 72 – Leere Zeichenfolge 71 – Standardwert 67 – Unicode-Komprimierung 73 Felder 46, 892 Feldlisteneigenschaften 137 Feldtypen 57 – AutoWert 59, 61 – Datum/Uhrzeit 60 – Datum/Zeit 58 – Hyperlink 59, 62, 80
– Ja/Nein 59, 62 – Memo 58 – Memofelder 60 – OLE-Objekt 59 – OLE-Objektfelder 62 – Text 58 – Textfelder 59 – Währung 57, 59, 61 – Zahl 57, 58 – Zahlenfelder 60 FIFO 819 Fokus 311, 330 Fokusübergabe 347 Formatierung, bedingte 170 Formulare 36, 143, 185, 310, 634 – 1:n 189 – Abfragen 193 – anklicken 807 – Anwendungen 198 – Arten 356 – Assistent 147 – Aufbau 146 – Begrenzung 174 – Dateneigenschaften 175, 181 – Datenherkunft 802 – Datenherkunft wechseln 377 – Datensatzgruppe 389 – Endlosformulare 357 – Entwurfsansicht 36, 150 – erstellen 147 – Formular-Assistent 189 – Formularentwurfsfenster 151 – Formularereignisse 336 – Fortgeschrittene Verwendung 335 – gespeicherte Abfragen 194 – HTML 197 – Hyperlink 195 – Internet 195 – Kombinationsfelder zum Suchen 784 – Kundenformular 198 – mehrseitige 358 – Microsoft Active Server Pages 198 – Microsoft Internet Information Server 198
Stichwortverzeichnis
– – – – – – – – – – –
optimieren 770 Projektformular 202 Seiten einfügen 801 sperren 657 Sperrstrategien 660 SQL-Anweisungen 194 Steuerelemente 153 Steuerelemente einfügen 801 Tabellen 189 Ungebundene 678 Unterformular/UnterberichtAssistent 191 – Unterformulare 193 – Zahlungenformular 201 – Zeitkartenformular 200 Formulareigenschaften 171, 172, 183 – Abbrechen 184 – Anfügen zulassen 176 – AutoKorrektur zulassen 183 – Automatisch weiter 184 – Automatisch zentrieren 173 – Bearbeitungen zulassen 176 – Beschriftung 172 – Bild 175 – Bild nebeneinander 175 – Bildausrichtung 175 – Bildgrößenmodus 175 – Bildlaufleisten 173 – Bildtyp 175 – Breite 175 – Daten eingeben 176 – Datenherkunft 175 – Datensätze sperren 176 – Datensatzmarkierer 173 – Drucklayout 175 – Eigenschaftenfenster 171 – Eingabetastenverhalten 183 – Enthält Modul 178 – Entwurfsänderungen zulassen 178 – Filter 176 – Filter zulassen 176 – Formateigenschaften eines Formulars 172 – Gebunden 177
1253
– Größe anpassen 173 – Hilfedatei 178 – Hilfekontext-ID 178 – HilfekontextID 184 – In Reihenfolge 184 – Kontextmenü 178 – Kontextmenüleiste 178, 184 – Löschen zulassen 176 – Makro Wiederholen 184 – Marke 178, 184 – Menüleiste 177 – MinMaxSchaltflächen 174 – Mit Systemmenüfeld 174 – Name 183 – Navigationsschaltflächen 173 – Palettenherkunft 175 – Popup 177 – Rahmenart 173 – Raster X 175 – Raster Y 175 – Recordsettyp 176 – Reihenfolgenposition 184 – Schaltfläche Direkthilfe 174 – Schließen Schaltfläche 174 – Schneller Laserdruck 178 – Sortiert nach 176 – Standard 184 – Standardansicht 172 – Statusleistentext 183, 184 – SteuerelementTip-Text 184 – Symbolleiste 177 – Trennlinien 173 – Unterdatenblatt erweitert 175 – Unterdatenblatthöhe 175 – Vertikal 183 – Zugelassene Ansichten 173 – Zyklus 177 Formularentwurfsfenster 151 – Aktivierreihenfolge bearbeiten 158 – Felder hinzufügen 152 – Formularobjekte auswählen 153 – Objektabstand steuern 158 – Objekte ausrichten 155 – Objekte verschieben 154
1254
Stichwortverzeichnis
– Objektgrößen ändern 157 – Raster 156 – Werkzeuge 151 – Werkzeuge ein- und ausblenden 151 Formularereignisse – Activate 342 – AfterDelConfirm 340 – AfterInsert 337 – AfterUpdate 338 – ApplyFilter 345 – BeforeDelConfirm 339 – BeforeInsert 336 – BeforeUpdate 337 – Click 343 – Close 342 – Current 336 – DblClick 343 – Deactivate 342 – Delete 339 – Dirty 339 – Error 345 – Filter 345 – GotFocus 343 – KeyPress 344 – KeyUp 344 – Load 340 – LostFocus 343 – MouseDown 343 – MouseMove 343 – MouseUp 344 – Open 340 – Reihenfolge 346 – Resize 341 – Timer 345 – Unload 341 Formularfilterung 373 FoxPro 693 Freigabe-Ebene 1110 Fremdschlüssel 90 Fremdschlüsselfelder 71 Front-End 30, 682, 715, 1132, 1147 – Access-Datenprojekt 724 – MDB 722
FTP-Server 1078 Funktionen 886 – Adressübergabe 886 – Alias zuweisen 969 – ausführen 553 – benannte Parameter 890 – integrierte 553 – optionale Parameter 888 – Wertübergabe 886 G Generatoren – Entwurfsrichtlinien 1040 – erstellen 1040 – Generatorformulare 1043 – Generatorfunktion schreiben 1041 – registrieren 1044 – verwenden 1040 Gruppen mit Code verwalten 1148 Gültigkeitsbereiche 548 H Hardware 604 Hardwareanforderungen 43 – Benutzer 44 – Entwickler 43 HTML 81, 195, 244, 609, 707, 1185 – Import-Assistent 707 HTML-Dateien – Formate 1073 – importieren 1072 – Verknüpfungen mit 1069 – Vorlagen 1077 HTML-Dokumente 1066 HTTP-Server 1078 HTX/IDC 30 HTX/IDC-Dateien 1075 Hyperlinks – in Berichten 1080 – in Formularen 1080 – in Tabellen speichern 1080 – nutzen 1080
Stichwortverzeichnis
I Implementierungen 49 Indirekte Synchronisierung 837 Indizes 79, 102 Integrierte Dialogfelder 364 – Eingabefelder 367 – Meldungsfelder 364 Internet 79, 1065 – Replikationen implementieren 1082 ISAM 519, 609, 655, 699 J JavaScript 1106 Jet 4.0 608 Jet-3.0 608 Jet-3.5 608 Jet-Datenbank-Engine 577 Jet-Engine 631, 634, 644, 677, 1113 Jet-Engine 3.0 618 Jet-Engine 3.5 618 Jet-Engine 3.6 618 Jet-Engine 4.0 618 JRO 1194 K Kapselung 531 Kennwörter 700, 701 Klassenmodule 991 – Auflistungen 999 – benutzerdefinierte Auflistungen 998 – Datei-Informationsklasse 1002 – Datenzugriffsklassen 1005 – Eigenschaften hinzufügen 993 – erstellen 993 – Fehlerbehandlung 1016 – Initialize 997 – Instanzen erstellen 997 – Klassenobjekte 994 – Leistungsfähigkeit 991 – Methoden hinzufügen 993 – Systeminformation 1013 – Terminate 998 – verwenden 993 – Vorteile 991
1255
Kombinationsfelder 380 Kommentare 1177 Kompilieroptionen 899 Komprimieren 1189 Komprimierung 1189 – beim Schließen 1193 – per Programm 1194 L Ländertabellen 476 Laufzeit-Engine 631, 635, 642, 651 Laufzeitversion 1200, 1203 – Anwendung sichern 1210 – Anwendung testen 1211 – Benutzerdefinierte Hilfe 1210 – Fehlerbehandlung 1204 – formulargesteuert 1204 – Menüs 1204 – Symbolleisten 1204 Listenfelder 380 Logikfehler 549 M Makros 39, 310, 1185 MDB 632, 642, 722, 1134 MDE 1137 MDE-Dateien 1210 Mehrbenutzeranwendungen 649 – Datenbankaufteilung 653 – Entwurfsstrategien 650 – Verknüpfung mit externen Daten 652 Menü-Add-Ins 1057 – eigene 1058 – erstellen 1058 Menüeinträge verbinden 371 Menüelemente 1202 Menüs – entwerfen 368 – löschen 372 – umbenennen 372 Methoden 251, 307, 316, 321 – ausführen 553 – Open 767 Microsoft Active Server Pages 198
1256
Stichwortverzeichnis
Microsoft ADO Extension for DDL and Security 1149 Microsoft Data Engine 632 Microsoft Internet Information Server 198 Microsoft Jet and Replication Objects 1194 Microsoft Plus! 605 Microsoft-Bibliothek ADO Extension 2.1 for DDL and Security – siehe ADOX 693 Microsoft-IIS-Format 195 Microsoft-ReplikationskonfliktViewer 851 MOD 635, 640 – Code Commenter 637 – Code Librarian 637 – COM Add-in Designer 637 – Data Environment Designer 637 – Data Report Designer 637 – Deployment Wizard 636, 641 – Error Handler 637 – Funktionen 635 – Lizenz 635 – Microsoft Replication Manager 636 – Multi-Code Import/Export 637 – Package Wizard 636, 641 – String Editor 637 – Visual Source Safe 637 – VSS Integration 637 – Windows API Viewer 637 Module 41, 310 – Code-Module 41 MSDE 632, 636 Multithreading 719 N Nachschlage-Assistent 75 Namenskonventionen 548, 695, 879 Normalisierung 45 Nummerierungen 924
O Objektbenennungen 42 Objekte 307, 312 – Auflistungen 325 – Beziehungen 320 – Code-Vorlagen 319 – einfügen 375 – einzelne 326 – For...Each 327 – Funktionen 327 – mehrere 327 – Mehrere Befehle 326 – Objektauflistung 326 – Objektbibliotheken 319 – Objektkatalog 316 – übergeben 327 – Umgang 331 – Unterroutinen 327 – With...End With 326 Objekteigenschaften – Description 586 – HelpContext 586 – HelpFile 586 – LastDLLError 586 – Number 586 – Source 586 Objektkatalog 881 Objektliste 106, 107 Objektmodell 307 – Application-Objekt 308 – CodeData-Objekt 311 – CodeProject-Objekt 311 – CurrentData-Objekt 311 – CurrentProject-Objekt 310 – DataAccessPages-Auflistung 309 – DoCmd-Objekt 312 – Forms-Auflistung 308 – Modules-Auflistung 309 – Reports-Auflistung 309 – Screen-Objekt 311 Objektorientierung 992
Stichwortverzeichnis
Objektvariablen – deklarieren 323 – generische 325 – herkömmliche Variablen 324 – Speicherbereinigung 325 – spezielle 325 – zuweisen 323 OCX-Steuerelemente 908 ODBC 519, 588, 609, 659, 681 – Anzeigeaktualisierungsintervall 659 – BENUTZER-DSN 736 – Benutzer-DSN 735 – Datei-DSN 735 – Datenaktualisierungsintervall 660 – Datenquelle 734 – Datenquelle definieren 734 – Datenquellen-Administrator 734 – Info 736 – SYSTEM-DSN 736 – System-DSN 735 – Treiber 735 – Verbindungs-Pool 736 – Verfolgung 736 ODE 678 Office 2000 Developer – Replikations-Manager 835 OLE 607, 625 OLEDB 609 OLE-Objekte 375, 377 OLE-Steuerelemente 908 OLTP 719 On Error-Anweisungen 579 – On Error GoTo 579 – On Error GoTo 0 581 – On Error Resume Next 581 Online-Transaktionsverarbeitung 719 Optimierung 603 – Abfragen 613, 769 – Abrechnungssystem 626 – Aktionsabfragen 622 – Berichtgestaltung 626 – Bitmap-Bilder 625 – Boolean-Variablen ändern 616
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
1257
Daten 769 Datenbank komprimieren 606 Datensatzgruppen 622 Datentypen 613 Declare-Anweisungen 618 Defragmentierung 605 Denormalisierung 612 Dim-Anweisungen 618 Dynamische Datenfelder 620 Formulare 770 Formulargestaltung 624 Grafikobjekte 625 Hardware 604 Indizes 612 Inline-Code 616 integrierte Auflistungen 616 kleine Datentypen 615 kompilierter Zustand erhalten 623 komprimierte Laufwerke 606 Konstanten 621 Leistungsanalyse 610 Length 617 Lesezeichen 621 Lokaler Betrieb 607 MDE 623 Modulorganisation 623 Normalform 611 Objektvariablen 621 Programmierstil 614 Schlüsselwort Me 620 Software 604 Software-Einstellungen 607 spezielle Objekttypen 615 Standardeigenschaften 625 Standardformatierungen 625 String-Variablen 620 Tabellen 611 Transaktionen 618 Variablen verwenden 619 Variant-Variablen 615 Verweise auf Datenzugriffsobjekte 619 – Verweise auf Eigenschaften 619
1258
– – – – – –
Stichwortverzeichnis
Verweise auf Steuerelemente 619 Virtueller Speicher 606 Vorkompilierte Module 623 Windows 607 With...End With 619 Zeitsystem 626
P Package and Deployment – AbhängigkeitsdateiInformationen 1214 – Add-In 1198 – CAB-Optionen festlegen 1216 – Scriptnamen angeben 1219 – Startmenüelemente auswählen 1217 – Wizard 1198 – Wizard ausführen 1212 Package and Deployment Wizard – Pakete 1213 Packages Wizard 914 Parameter, Options 767 Parameterabfragen 206 Pass-Through 748, 754, 768 – MDB 748 Pass-Through-Abfragen 646 PID 1129, 1133 Popup-Formulare 382 PowerPoint steuern 954 Primärschlüssel 46, 74, 89, 102 Primärschlüsselindex 527, 536 Primärschlüsselwert 678 Projektdateien 29 Projekteigenschaften 901 Prototypen 48 Prozeduren 762 – ausführen 750 – erstellen 750, 752 – gespeicherte 768 Prozedurnamen 971 R Reddick VBA Naming Conventions 1233 Reddick-Namenskonventionen 42
Registerkarten, Steuerelemente hinzufügen 361 Registrierungseinträge automatisieren 1048 Registry 641 Registry-Einträge, Replikation 838 Remote Access Services 832 Replication Manager 678 Replikatgruppen 832, 858 Replikation 1170, 1230 – Access-Benutzerschnittstelle 834 – ADO-Code 835 – Aktenkoffer 835 – Anwendungsaktualisierung 833 – Architektur 836 – AutoWert-Felder 842 – Designmaster 832 – Durchführung 852 – Eignung 834 – Gemeinsame Nutzung von Daten 832 – Hybridtopologie 840 – Konflikte 850 – Latenzgrad 840 – lineare Topologie 840 – Listings 868 – mehrere Replikate 847 – mittels Code 867 – Netzwerkbelastung 833 – partielle 865 – Registry-Einträge 838 – Replikatgruppe 832 – Replikations-Manager 835, 856 – Ringtopologie 839 – Sterntopologie 838 – Synchronizer 836 – Systemtabellen 841 – Topologien 838 – Verbundtopologie 840 – Verfolgungsschicht 836 – verhindern 845 – Verwendungen 832 – Zeit- und Abrechnungssystem 872 Replikations-Manager 835, 852 Replikattypen 869
Stichwortverzeichnis
Resume-Anweisungen 582 – Resume 584 – Resume Next 583 Rollback 674 RTF 1185 Rushmore-Verfahren 448 S Schaltflächen-Assistent 199 Selbstverknüpfungen 459 Server 716 Sicherheit 30 Sicherheitstechniken – Abfragen 1167 – Benutzer 1169 – Benutzer auflisten 1158 – Benutzer aus Gruppe entfernen 1154 – Benutzer entfernen 1156 – Benutzer hinzufügen 1151 – Benutzer mit Code verwalten 1151 – Benutzer ohne Kennwörter auflisten 1161 – Benutzerkennwörter 1163 – Benutzern Kennwörter zuweisen 1160 – Datenbanken mit Code verschlüsseln 1167 – Feldebene 1167 – Fortgeschrittene 1147 – Gruppen 1169 – Gruppen auflisten 1157 – Gruppen Benutzer zuweisen 1153 – Gruppen entfernen 1150 – Gruppen hinzufügen 1148 – Replikation 1170 Sicherung 720 Sichten 743 SID 1115 Skalierbarkeit 30 Snapshot 1131, 1185 Spiegelung 720 SQL 28, 194, 242, 460, 483, 595, 632, 644, 682, 716, 722 – Pass-Through 723 – Server-Sichten 759 – Server-Sichten erstellen 759
1259
– Server-Sichten löschen 759 – Server-Sichten modifizieren 759 – Server-Tabellen 757 – Server-Tabellen anlegen 757 – Server-Tabellen löschen 758 – Server-Tabellen verändern 758 – Verknüpfung 778 SQL-Anweisungen 634 Startoptionen 1207 Steuerelement 159, 892 – ActiveX 329 – Befehlsschaltfläche 329 – berechnete 185 – Beschriftung 227 – Bezeichnungen 160 – Bezeichnungsfeld 329 – Bild 329 – Breite 228 – Dateneigenschaften 229 – Dezimalstellenanzeige 228 – Duplikate ausblenden 228 – ersetzen 169 – Feldliste 164 – Format 227 – Formateigenschaften 179, 227 – gebundene 185 – Gebundenes Objektfeld 329 – Hintergrundart 228 – Hintergrundfarbe 228 – Höhe 228 – Hyperlink-Adresse 227 – Hyperlink-Unteradresse 228 – Ist Hyperlink 229 – Kombinationsfeld 329 – Kombinationsfelder 161 – Kombinationsfelder verwandeln 170 – Kontrollkästchen 165, 329 – Kursiv 228 – Laufende Summe 229 – Linie 329 – Linker Rand 229 – Links 228 – Listenfeld 329 – Listenfelder 164 – Marke 230
1260
Stichwortverzeichnis
– Name 229 – Oben 228 – Oberer Rand 229 – Objektfeld oder Diagramm 329 – Optionsfelder 166 – Optionsgruppe 329 – Optionsgruppen 166 – Optionsgruppen-Assistent 166 – Optionsschaltfläche 329 – Rahmenart 228 – Rahmenbreite 228 – Rahmenfarbe 228 – Rechteck 329 – Rechter Rand 229 – Registerkarte 329 – Schaltflächeneffekte 167 – Schriftart 228 – Schriftbreite 228 – Schriftgrad 228 – Seite 329 – Seitenumbruch 329 – Sichtbar 228 – Spezialeffekt 228 – Steuerelementinhalt 229 – Tabelle/Abfrage 164 – Textausrichtung 228 – Textfarbe 228 – Textfeld 329 – Textfelder 160 – Textfelder verwandeln 169 – Typ 328 – Umschaltfläche 329 – Umschaltflächen 166 – ungebundene 185 – Unterer Rand 229 – Unterformular/-bericht 329 – Unterstrichen 228 – Vergrößerbar 228 – Verkleinerbar 228 – Vertikal 230 – Werteliste 164 – Zeilenabstand 229 Steuerelement-Assistent 161
Steuerelementeigenschaften 179 – Anzeigen 180 – Beschriftung 179 – Bildlaufleisten 180 – Breite 180 – Dezimalstellenanzeige 179 – Format 179 – Hintergrundart 180 – Hintergrundfarbe 180 – Höhe 180 – Hyperlink-Adresse 179 – Hyperlink-Unteradresse 179 – Ist Hyperlink 181 – Kursiv 181 – Linker Rand 181 – Links 180 – Oben 180 – Oberer Rand 181 – Rahmenart 181 – Rahmenbreite 181 – Rahmenfarbe 181 – Rechter Rand 181 – Schriftart 181 – Schriftbreite 181 – Schriftgrad 181 – Sichtbar 180 – Spezialeffekt 180 – Textausrichtung 181 – Textfarbe 181 – Unterer Rand 181 – Unterstrichen 181 – Vergrößerbar 180 – Verkleinerbar 180 – Zeilenabstand 181 Steuerelementereignisse 348 – Daten aktualisieren 355 – Reihenfolge 354 Stripe Sets 720 Symbolleisten – Integrierte 1202 – Web 1081 Synchronisation – Access-Benutzerschnittstelle 848 – Aktenkoffer 848
Stichwortverzeichnis
– Durchführung 861 – Listings 871 – mittels Code 871 – nach Zeitplan 862 – Replikate 848 – Replikations-Manager 861 – Verlauf 863 Synchronisierung – Aktenkoffer 837 – Replikations-Manager 837 Synchronizer 836, 856 – Eigenschaften 863 Systemobjekte 41 Systempflege 49 Systemtabellen 841 T Tabellen 31, 53, 632 – ADO 500 – Beziehungen 33 – entwerfen 54 – Entwurfsansicht 32 – erstellen 53 – Feldnamen 56 – hinzufügen 53 – Namensregeln 56 – Semistatische Tabellen 652 – Statische Tabellen 652 – Temporäre Tabellen 652 – Verbindungsinformationen 698 – Verknüpfte 740 Tabelleneigenschaften 77 – Automatisch 78 – Beschreibung 77 – Filter 78 – Gültigkeitsmeldung 78 – Sortiert nach 78 – Unterdatenblatthöhe 78 – Unterdatenblattname 78 – Verknüpfen Nach 78 – Verknüpfen Von 78 Tabellenverknüpfung, automatisiere 1225 Tastenkombinationen, deaktivierte 1202
Teilreplikation 865 Teilreplikations-Assistent 865 Testen 48 Transaktionen 41 Transaktionsprotokoll 820 Transaktionsverarbeitung 253, 809 – Arbeitsbereiche 815 – Arbeitsspeicher 820 – Atomarität 809 – Client/Server 825 – Datenquelle 815 – Dauerhaftigkeit 810 – Explizite implementieren 813 – Explizite Übernahme von Transaktionen 819 – Formulare 820 – Isolation 810 – Konsistenz 810 – Mehrbenutzerumgebung 820 – Standardverhalten verändern 812 – Transaktionen verschachteln 819 – Vorteile 810 Typbibliothek 285 Typisierung 548 U Umgebung 604 UNC 62, 79, 695 Universal Naming Convention, siehe UNC 62 Unterberichte 237 – Herkunftsobjekt 237 – Vergrößerbar 238 – Verkleinerbar 238 – Verknüpfen nach 238 – Verknüpfen von 237 Unterformulare 193, 388, 790 – Aktivierreihenfolge 193 – Datenherkunft 796 – erstellen 791, 805 – mit Daten füllen 806 – Standardansicht 193 – verbergen 795 Unterformulareigenschaften – Herkunftsobjekt 193
1261
1262
Stichwortverzeichnis
– Verknüpfen nach 193 – Verknüpfen von 193 Unterformular-Steuerelemente 193 Unterroutinen ausführen 553 Upsizing 718, 721, 726 – Absicherung 728 – aktiv vorbereiten 730 – Assistent 721, 730 – AutoWert 727 – Beziehungen 728 – Eigenschaften 729 – Feldnamen 729 – Groß- und Kleinschreibung 729 – Gültigkeitsregeln 728 – Indizes 727 – Reservierte Begriffe 729 – Standardwerte 728 – Tabellennamen 729 – Visual Basic-Code 729 Upsizing-Assistent 645 USV 720 V Variablen 41 – Gültigkeitsbereich 549 – Wert prüfen 550 – Werte festlegen 551 VBA 39, 251, 307, 330, 699, 768 – Access-Konstanten 881 – ActiveX-Datenobjekte 881 – ADO-Konstanten 882 – Bedingte Kompilierung 273 – Bedingtes If 273 – Benutzerdefinierte Konstanten 288 – Benutzerdefinierte Prozeduren 261 – Benutzerdefinierte Typen 876 – Berichtsklassenmodule 260 – Berichtsmodule 254 – Code-Bibliotheken 253 – Code-Module 259 – Compiler-Konstanten 274 – Datenfelder 882, 896 – Datenfelder als Parameter 885 – Datenfelder deklarieren 882, 884
– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
Datenfelder verwenden 882, 884 Datentypen 266 Do While...Loop 276 Do...Loop Until 276 Do...Loop While 276 DoCmd 281 DoCmd-Objekt 902 Dynamische Datenfelder 884 Empty 891 Ereignisprozedur 254, 258, 261 Feste Datenfelder 882 For Each...Next 278 For...Next 277 Formulare 260 Formularmodule 254 Fortgeschrittene Techniken 875 Funktion 254, 259 Gültigkeitsbereich von Prozeduren 261 Gültigkeitsbereiche von Variablen 263, 267 If...Then...Else 271 Immediate If (IIf) 272 Integrierte Funktionen 282 Integrierte Konstanten 879, 881, 902 Interne Konstanten 288 Klassenmodule 254 Kommentare 270 Konstanten 252, 287, 878 Konstanten definieren 879 Lebensdauer von Prozeduren 261 Lebensdauer von Variablen 267 Lokale Variablen 268 Makro-Aktionen 281 Module 255 Modulebene 255 Modulfenster 281 Namenskonventionen 269 Null 892, 902 Objektkatalog 285 Objektmodelle 1138 öffentliche Prozeduren 262 öffentliche Variablen 256, 270 Option Explicit 257
Stichwortverzeichnis
– – – – – – – – – – – – – – – – – –
Parameter übergeben 280 Pass-Through-Abfrage 748 Platzierung von Code 264 private Prozeduren 263 private Variablen 255, 269 Projektnamen 1138 Referenzen erstellen 1031 RETURN VALUES 280 Schleifen 276 Schlüsselwort Public 262 Select Case 275 Speicheroption 1031 Standardmodule 254 Statische Prozeduren 264 Statische Variablen 268 Steuerstrukturen 271 Symbolische Konstanten 287, 878 Symbolische Konstanten, Gültigkeitsbereich 880 – Systemdefinierte Konstanten 879 – Typstrukturen 903 – Typvariablen 877 – Typvariablen abfragen 878 – Unterroutine 254, 259 – Variablen 252, 265 – Variablen deklarieren 265 – Variant-Variablen 266 – VBA-Code 255 – VBA-Konstanten 881 – Verknüpfungen mit externen Tabellen 742 – Werte zurückgeben 280 – With...End With 278 VBA-Bibliothek 286 VBA-Datentypen – Boolean 266 – Byte 266 – Currency 267 – Date 267 – Decimal 267 – Double 266 – Fixed String 267 – Integer 266 – Long Integer 266
– Object Reference 267 – Single 266 – Variable String 267 – Variant 267 VBA-Fehlernummern 579 VBA-Funktionen 282 – DateAdd 284 – DateDiff 284 – DatePart 284 – Format 283 – Instr 283 – Left 283 – Mid 283 – Right 283 – UCase 284 VBA-Werkzeuge 547 VBE 290, 566, 623 – Ansicht Microsoft Access 297 – Code-Fenster 295 – Code-Fenster teilen 299 – Definition 294 – Eigenschaften auflisten 291 – Eigenschaftenfenster 297 – Ersetzen 297 – Hilfe 299 – individuell anpassen 302 – Konstanten auflisten 292 – Lesezeichen 301 – Methoden auflisten 291 – Parameterinfo 293 – Projektfenster 296 – QuickInfo 292 – Registerkarte Allgemein 303 – Registerkarte Editor 302 – Registerkarte Editor-Format 303 – Registerkarte Verankern 304 – Suchen 297 – Werkzeuge 290 – Wort vervollständigen 294 Verbindungen, Verbindungsinformationen 694 Verknüpfungen 722 – Access-Tabellen 690 – aktualisieren 702, 703, 710
1263
1264
Stichwortverzeichnis
– Assistent zur Datenbankaufteilung 690 – Benutzerschnittstelle 690 – Code 693 – einrichten 695 – Komprimierung 1193 – Leistung 706 – löschen 702, 704 – Tabellen 692 Visual Basic for Applications, siehe VBA 40, 251 Visual Basic-Hilfe 578 Visual SourceSafe 834 Vollversionen 1200 W Wartung 1189 Wertübergabe 967
WID 1115 Wiederherstellung 720 Windows-Aktenkoffer 835 Windows-API 41, 253, 1031 – Leistungsfähigkeit 965 Windows-Ereignisse 171 Windows-Registrierung 1044 Windows-Registry 607, 699, 811, 909, 1024 Word steuern 952 Z Zahlungsarchivierung 475 Zeit- und Abrechnungssystem, Replikation 872
Copyright Daten, Texte, Design und Grafiken dieses eBooks, sowie die eventuell angebotenen eBook-Zusatzdaten sind urheberrechtlich geschützt. Dieses eBook stellen wir lediglich als Einzelplatz-Lizenz zur Verfügung! Jede andere Verwendung dieses eBooks oder zugehöriger Materialien und Informationen, einschliesslich der Reproduktion, der Weitergabe, des Weitervertriebs, der Platzierung im Internet, in Intranets, in Extranets anderen Websites, der Veränderung, des Weiterverkaufs und der Veröffentlichung bedarf der schriftlichen Genehmigung des Verlags. Bei Fragen zu diesem Thema wenden Sie sich bitte an: mailto:[email protected]
Zusatzdaten Möglicherweise liegt dem gedruckten Buch eine CD-ROM mit Zusatzdaten bei. Die Zurverfügungstellung dieser Daten auf der Website ist eine freiwillige Leistung des Verlags. Der Rechtsweg ist ausgeschlossen.
Hinweis Dieses und andere eBooks können Sie rund um die Uhr und legal auf unserer Website
(http://www.informit.de) herunterladen