- dbs.uni

Werbung
Automatische Generierung
von Update-Masken
aus Datenbanksichten
Diplomarbeit von
Arnim von Helmolt
im Rahmen des Studiengangs
Mathematik mit der
Studienrichtung Informatik
an der Universität Hannover
Prüfer: Prof. Dr. Udo Lipeck
Hannover, den 2. November 1999
ii
iii
Zusammenfassung
Verschiedene Benutzer und Benutzergruppen eines Datenbanksystems erhalten gewöhnlich nur einen Ausschnit der in der Datenbank vorhandenen Informationen, sei
es aus Sicherheitsgründen oder zur Ausblendung unwichtiger Daten. Sowohl Masken
als auch Sichten haben die Aufgabe, einen bestimmten Ausschnitt der Datenbank
an den Benutzer weiterzugeben. In dieser Arbeit wird untersucht, inwieweit durch
Spezifikation einer SQL-Sicht eine Maske als Benutzerschnittstelle automatisch generiert werden kann und welche Operationen auf dieser möglich sind. Dazu werden
allgemein Änderungsoperationen auf Sichten behandelt und ein eigener Ansatz erarbeitet, der es erlaubt, die Änderungen auf der Sicht eindeutig in Änderungen auf
den zugrundeliegenden Relationen zu übersetzen. Davon ausgehend wird ein Konzept vorgestellt, wie ein Maskengenerator zur Spezifikation der Sicht und der Maske
beschaffen sein muß, um änderbare Masken erzeugen zu können.
iv
Inhaltsverzeichnis
1 Einleitung
1
1.1
Gliederung der Arbeit . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1.2
Zielsetzung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1
1.3
Verwendete Werkzeuge . . . . . . . . . . . . . . . . . . . . . . . . . .
3
2 Das View-Update-Problem
2.1
2.2
2.3
2.4
5
Einführung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
2.1.1
Grundlegende Definitionen und Notationen . . . . . . . . . .
5
2.1.2
Änderungen auf Relationen . . . . . . . . . . . . . . . . . . .
9
2.1.3
Übersetzungen von Änderungen auf Sichten . . . . . . . . . .
10
2.1.4
Beispiele problematischer Fälle . . . . . . . . . . . . . . . . .
11
Übersetzungen mit Hilfe von Sicht-Abhängigkeits-Graphen . . . . . .
14
2.2.1
Grundlagen . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
2.2.2
Sicht-Graphen . . . . . . . . . . . . . . . . . . . . . . . . . .
17
2.2.3
Löschänderungen . . . . . . . . . . . . . . . . . . . . . . . . .
20
2.2.4
Einfügeänderungen . . . . . . . . . . . . . . . . . . . . . . . .
21
2.2.5
Ersetzungsänderungen . . . . . . . . . . . . . . . . . . . . . .
24
Übersicht über weitere Ansätze für die Übersetzung von View-Updates 25
2.3.1
Komplementäre Sichten . . . . . . . . . . . . . . . . . . . . .
25
2.3.2
Der Ansatz der Abstrakten Datentypen . . . . . . . . . . . .
27
2.3.3
Änderung unvollständiger Informationen . . . . . . . . . . . .
28
Bewertung und eigener Ansatz . . . . . . . . . . . . . . . . . . . . .
28
2.4.1
Löschänderungen . . . . . . . . . . . . . . . . . . . . . . . . .
31
2.4.2
Einfügeänderungen . . . . . . . . . . . . . . . . . . . . . . . .
31
vi
INHALTSVERZEICHNIS
2.4.3
Ersetzungsänderungen . . . . . . . . . . . . . . . . . . . . . .
32
2.4.4
Eingeschränkte Übersetzungen . . . . . . . . . . . . . . . . .
33
3 Konzeption eines Maskengenerators
37
3.1
Ausgangsidee und Systemumfang . . . . . . . . . . . . . . . . . . . .
37
3.2
Spezifikation der Sicht . . . . . . . . . . . . . . . . . . . . . . . . . .
40
3.2.1
Schemastruktur und Aufbau der Sicht . . . . . . . . . . . . .
40
3.2.2
Modellierung des Spur- und des Abhängigkeits-Graphen . . .
42
Entwurf der Maske . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
3.3.1
Aufbau einer Maske zu einer Sicht . . . . . . . . . . . . . . .
43
3.3.2
Spezifizierung der Maskenelemente und des Maskenlayouts
.
45
3.3.3
Abbildung der Datentypen . . . . . . . . . . . . . . . . . . .
47
3.3.4
Generieren der Maske . . . . . . . . . . . . . . . . . . . . . .
49
Die Ausführung der Maske und die Anbindung an eine Datenbankinstanz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
3.4.1
Die Datenbankschnittstelle . . . . . . . . . . . . . . . . . . .
49
3.4.2
Interaktion der Maske mit einer Datenbankinstanz . . . . . .
50
3.4.3
Zustände und Operationen einer Maske . . . . . . . . . . . .
51
Der Maskengenerator JForms . . . . . . . . . . . . . . . . . . . . . .
52
3.3
3.4
3.5
4 Die Implementierung eines Gerüsts“ für den Maskengenerator
”
JForms
57
4.1
Die Darstellung des Datenbankschemas und des Sichtschemas . . . .
57
4.2
Pfadsuche im Abhängigkeits-Graphen . . . . . . . . . . . . . . . . .
59
4.3
Der Maskeneditor JForms . . . . . . . . . . . . . . . . . . . . . . . .
61
4.3.1
Auswahl und Einstellungen der Sichtelemente . . . . . . . . .
61
4.3.2
Speichern der Einstellungen in Property-Dateien . . . . . . .
63
Der Ablauf der generierten Maske . . . . . . . . . . . . . . . . . . . .
65
4.4
A Abkürzungen
67
B Programmierung
69
B.1 Ausgewählte Klassendiagramme . . . . . . . . . . . . . . . . . . . . .
69
B.2 Sourcecode zur Pfadsuche in Abhängigkeits-Graphen . . . . . . . . .
75
INHALTSVERZEICHNIS
vii
Abbildungsverzeichnis
78
Literaturverzeichnis
81
viii
INHALTSVERZEICHNIS
Kapitel 1
Einleitung
1.1
Gliederung der Arbeit
In dieser Einleitung wird das Ziel der Arbeit vorgestellt und die verwendeten Werkzeuge kurz beschrieben.
Kapitel 2 gibt einen Überblick über die Problematik von Änderungen auf Sichten.
Nach einer Einführung grundlegender Notationen werden einige Beispiele erläutert.
Anschließend wird der Lösungsansatz von [DB82] vorgestellt, der dieser Arbeit zugrundeliegt. In einer kurzen Übersicht wird auf drei weitere Ansätze hingewiesen,
die aber nicht vertieft werden. Das Kapitel schließt mit einer Bewertung und mit
einem eigenen Ansatz, der für das folgende Konzept verwendet wird.
Die Konzeption in Kapitel 3 steckt den Rahmen der Implementierung eines Maskengenerators ab und zeigt die Struktur einer Realisierung. Es werden die erforderlichen Klassen mit einer Beschreibung ihrer Funktionen und ihren Verbindungen
untereinander vorgestellt.
In Kapitel 4 wird die Umsetzung einiger Klassen aus Kapitel 3 beschrieben, um exemplarisch die Implementierung des Konzepts vorzuführen. Dabei wurden allerdings
nicht alle vorgestellten Klassen realisiert, sondern vielmehr ein Gerüst grundlegender Funktionen angelegt, welches das Konzept berücksichtigt und leicht erweitert
werden kann.
1.2
Zielsetzung
Der Benutzer einer Datenbankanwendung erhält den Zugriff auf Informationen aus
der Datenbank (DB) häufig über Masken oder Tabellen. Während Tabellen gewöhnlich mehrere Tupel darstellen, zeigen Masken in der Regel nur ein Tupel. Zur Bearbeitung der Tupel stehen verschiedene Operationen zur Verfügung, die sich auf ein
oder mehrere Tupel beziehen.
Eine Maske ist die Darstellung eines Teils oder auch aller Attribute einer oder mehrerer Relationen auf dem Bildschirm in Form von Feldern, die einen Bezeichner
(Attributname) und einen Wert (Attributwert) besitzen.
2
Einleitung
Eine Sicht ist eine virtuelle Relation, der eine Anfrage zugrundeliegt und damit
einen Ausschnitt der DB darstellt.
Sowohl Masken als auch Sichten zeigen einen bestimmten Ausschnitt einer DB. Es
ist nun naheliegend, Masken mit korrespondierenden Sichten zu verknüpfen, so daß
jedes Attribut in der Maske ein korrespondierendes Attribut in der Sicht (Quelle)
besitzt. Der Informationsgehalt einer Maske wird demnach durch eine Sicht definiert.
Allgemein sind folgende Operationen auf Masken denkbar:
• suchen (search),
• eingeben (insert),
• löschen (delete) und
• ändern (modify).
Abgesehen von der search Operation können diese zusammenfassend als update bezeichnet werden. Wird ein update auf einer Maske, bzw. auf der korrespondierenden
Sicht ausgeführt, so muß dieses in updates auf den der Sicht zugrundeliegenden Basisrelationen übersetzt werden (View-Update-Problem).
In der vorliegenden Arbeit werden Möglichkeiten untersucht, wie aus einer vorgegebenen Sicht eine korrespondierende Maske erzeugt werden kann, welche Probleme
dabei zu erwarten sind und welche Bearbeitungs-Operationen auf dieser möglich
sind. Dazu müssen die sichtdefinierenden Anfragen klassifiziert und unterschiedlichen Mengen von updates auf den Basisrelationen zugewiesen werden, falls updates
überhaupt auf der Sicht möglich sind. Dabei ist insbesondere das Ziel zu berücksichtigen, eine große Menge von praktikablen Masken in typischen Anwendungen abzudecken. Das View-Update-Problem braucht hier nur für die praktisch relevanten
Fälle betrachtet zu werden. Die dafür benötigten Sichten sollen im Anschluß an die
Untersuchung bisheriger Ansätze für das View-Update-Problem vorgestellt werden.
Insbesondere soll diese Arbeit keine neuen Lösungsmöglichkeiten des View-Update
liefern, sondern vielmehr vom praktischen Blickwinkel beleuchten, wie eine große
Klasse von Sichten als Grundlage für Update-Masken“ verwendet werden kann.
”
Dadurch soll eine Lösung für einen allgemeinen Ansatz der Maskenimplementierung
geliefert werden.
Das Konzept beschreibt zwei Teile: das Entwurfswerkzeug zur Spezifizierung einer
Maske mit der zugrundeliegenden Sicht und die Ausführungsumgebung der zuvor
spezifizierten Maske.
Im Implementierungsteil dieser Arbeit wird das zuvor erarbeitete Konzept in der
Programmiersprache Java realisiert. Durch die JDBC-Schnittstelle von Java kann die
Datenbankunabhängigkeit weitestgehend sichergestellt werden. Zu einer Sicht sollen
Klassen für den sichtbaren Teil der Maske und Klassen, welche die Datenstruktur
enthalten, in Java generiert werden. Diese generierten Klassen sollen Bestandteil
einer in Ansätzen vorbereiteten Klassenstruktur mit den notwendigen BearbeitungsOperationen sein, welche die Ausführungsumgebung darstellt.
1.3 Verwendete Werkzeuge
1.3
Verwendete Werkzeuge
Für die Implementierung wurde das Java Development Kit (JDK) 1.2 unter Solaris
2.7 verwendet, beides von Sun Microsystems. Weiterhin wurde die Blackdown Portierung des JDK 1.1.7v3 sowie das Swing 1.1.1 Paket der Java Foundation Classes
und der Java Compiler Jikes 1.05 von IBM unter Linux Kernel Version 2.2.10 verwendet. Die Datenbankverbindungen erfolgten mittels der JDBC-Treiber von Oracle
an eine Oracle Datenbank 8.0.4 und 8.0.5 sowohl unter Solaris als auch unter Linux.
Diese Arbeit wurde mit LATEX 2ε gesetzt, die UML-Diagramme mit Rational Rose 98
für Solaris.
3
4
Einleitung
Kapitel 2
Das View-Update-Problem
Änderungen auf Sichten werden so realisiert, daß sie in entsprechende Änderungen
auf den Relationen einer Datenbank übersetzt werden. Die dabei auftretenden Probleme werden in diesem Kapitel erläutert. Zunächst werden benötigte Notationen
eingeführt und die Problematik anhand einiger Beispiele illustriert. In dem folgenden
zentralen Abschnitt wird ein Lösungsansatz vorgestellt, der Ausgangspunkt für diese Arbeit ist. Anschließend wird ein kurzer Überblick über weitere Ansätze gegeben
und das Kapitel mit einer Bewertung und einer eigenen Lösung abgeschlossen.
2.1
Einführung
In den folgenden Abschnitten werden die benötigten Definitionen eingeführt und
Begriffe erläutert, auf die später zurückgegriffen wird.
2.1.1
Grundlegende Definitionen und Notationen
Definition 2.1 Eine Domäne oder ein Wertebereich ist eine beliebige Menge von
Elementen eines bestimmten Datentyps.
Ein Wertebereich kann auch Nullwerte enthalten, welche die Bedeutung haben, daß
der Wert unbekannt, also nicht spezifiziert ist.
Definition 2.2 Eine Relation R ist eine endliche Teilmenge des kartesischen Produkts
R ⊆ D1 × . . . × Dn
wobei D1 , . . . , Dn beliebige Wertebereiche sind.
Definition 2.3 Ein Tupel t ist ein Element einer Relation R, in Zeichen t ∈ R.
Wir sagen auch, daß eine Relation R eine endliche Menge von Tupeln ist.
6
Das View-Update-Problem
Definition 2.4 Ein Attribut Ai ist eine Projektionsfunktion
Ai : R −→ Di ,
i = 1, . . . , n
auf die i-te Komponente eines Tupels t ∈ R. Der Wertebereich Di von Ai wird auch
als dom(Ai ) bezeichnet.
Wir schreiben auch t.A für die Projektion des Tupels t ∈ R auf das Attribut A,
bzw. t.X für die Projektion von t auf die Attribute in X = {A1 , . . . , An }. Mit R[X]
bezeichnen wir die Menge der Tupel t.X, also R[X] := {t.X | t ∈ R}.
Definition 2.5 Ein Relationenschema R ist die Menge der Attribute A1 , . . . , An
zu einer Relation R.
Wir schreiben für ein Relationenschema R mit den Attributen A1 , . . . , An auch
R[A1 : D1 , . . . , An : Dn ] und abkürzend auch R[A1 , . . . , An ] oder R[X] mit X =
{A1 , . . . , An }. Mit dom(R) sei das kartesische Produkt dom(A1 ) × . . . × dom(An )
bezeichnet.
Eine Relation R wird auch als Instanz oder Zustand eines Relationenschemas R
bezeichnet. Für die Menge der Zustände von R schreiben wir auch inst(R).
Definition 2.6 Eine Integritätsbedingung cR zu einer Relation R ist eine logische
Funktion
cR : R −→ {true, f alse}
die jedem Tupel t ∈ R einen Wahrheitswert zuordnet.
Definition 2.7 Eine Relation R heißt konsistent bezüglich einer Menge von Integritätsbedingungen CR , falls für alle Tupel t ∈ R und alle Integritätsbedingungen
c ∈ CR c(t) = true gilt.
Wir sagen auch, daß die Relation R die Integritätsbedingungen CR erfüllt oder R
konsistenter Zustand ist.
Definition 2.8 Ein relationales Schema oder Datenbankschema S ist eine endliche
Menge von Relationenschemata {R1 , . . . , Rn }.
Definition 2.9 Ein Datenbankzustand S oder einfach Zustand eines Datenbankschemas S ist eine Funktion s, die jedes Relationenschema R ∈ S auf eine Relation
R ∈ inst(R) abbildet,
S −→ inst(R)
s:
R 7−→ R
Die Menge der Zustände wird mit inst(S) bezeichnet.
Definition 2.10 Ein Datenbankzustand S heißt konsistent bezüglich einer Menge
von Integritätsbedingungen CS , falls die Relationen R ∈ S konsistent bezüglich CS
sind.
2.1 Einführung
7
Definition 2.11 Seien X, Y ⊆ R Attributmengen von R und R ein Zustand von
R. Dann ist Y funktional abhängig von X in R, in Zeichen X →R Y , wenn
∀s, t ∈ R
s.X = t.X ⇒ s.Y = t.Y
gilt.
Wir sagen auch, die Relation R erfüllt die funktionale Abhängigkeit X →R Y . Falls
X →R R gilt, wird X auch Superschlüssel genannt.
Definition 2.12 Seien X, Y ⊆ R Attribute von R. Dann ist Y voll funktional
•
abhängig von X in R, in Zeichen X →R Y , wenn
1. X →R Y und
2. ∀A ∈ X
X \ {A} 9R Y
•
gelten. Falls X →R R gilt, wird X auch Schlüsselkandidat genannt.
X ist in dem Sinne minimal, daß kein Attribut entfernt werden kann, ohne die
funktionale Abhängigkeit zu zerstören.
Definition 2.13 Seien Q und R zwei nicht notwendigerweise verschiedene Relationenschemata mit den Attributmengen X = {X1 , . . . , Xk } ⊆ Q und Y =
{Y1 , . . . , Yk } ⊆ R. Dann erfüllen die zugehörigen Instanzen Q und R die Inklusionsabhängigkeit X ⊆ Y , wenn
∀q ∈ Q ∃r ∈ R
q.X = r.Y
gilt.
Wir schreiben auch Q[X] ⊆ R[Y ] für die Inklusionsabhängigkeit.
Mit den obigen Notationen haben wir die wichtigsten Begriffe zur Beschreibung
von Meta-Daten (Datenbank- und Relationenschemata) und den eigentlichen Daten
(Datenbankinstanz und Relation) eingeführt. Im folgenden kommen wir zu dem in
dieser Arbeit zentralen Begriff der Sicht.
Definition 2.14 Eine Sicht oder ein externes Schema V eines Datenbankschemas
S ist ein Paar (SV , f ), mit dem Datenbankschema SV und einer Funktion f , die
jeden Zustand S ∈ inst(S) auf einen Zustand S 0 ∈ inst(SV ) abbildet:
inst(S) −→ inst(SV )
f:
S
7−→ S 0
f wird die V definierende Funktion genannt und abkürzend wird die Sicht V auch
mit f bezeichnet, wenn die Bedeutung von S und SV bekannt ist.
Sichten werden durch Formulierung von Anfragen auf dem zugrundeliegenden Datenbankschema mit Hilfe der Relationen-Algebra (siehe auch [KE96]) beschrieben.
Sichten können anhand der verwendeten relationalen Operationen eingeteilt werden
in
8
Das View-Update-Problem
• Projektionssichten,
• Selektionssichten,
• Verbundsichten,
• berechnete“ Sichten,
”
• Sichten auf geschachtelten Relationen,
sowie Mischformen von diesen.
Definition 2.15 Eine Sicht V heißt triviale Sicht, falls S = SV und f die Identität
ist.
Definition 2.16 Der Zustand V einer Sicht V ist die Bezeichnung für den Zustand
von SV .
Für Abschnitt 2.2 wird eine Notation benötigt, in der die Bestandteile“ einer Sicht
”
genauer bezeichnet werden. Dafür wird die SQL-Notation zur Definition einer Sicht
benutzt, mit der damit verbundenen Einschränkung auf nur eine Sichtrelation, d. h.
SV besteht nur aus einer Relation. Entsprechend wird die Schreibweise V[Y ] für eine
Sicht verwendet, wobei Y eine Menge von Attributen ist.
Eine Sicht V wird durch das vereinfachte SQL-Statement
create view V as
select <Attribute> from <Relationen> where <Qualifikation>
definiert, wobei
• <Attribute> := Liste von Attributen,
• <Relationen> := Liste von Relationen,
• <Qualifikation> := Kombination boolescher Ausdrücke der Form
<Term><Op><Term>,
• <Term> := Konstante oder Attribut,
• <Op> := <, ≤, >, ≥, =, 6=
ist. In der folgenden Betrachtung wird von dieser vereinfachten SQL-Syntax ausgegangen, eine Erweiterung auf den vollen Sprachumfang ist jedoch durchaus möglich.
Die select-Klausel entspricht in der Relationen-Algebra der Projektion auf die Attribute, die from-Klausel entspricht dem kartesischen Produkt der aufgelisteten Relationen und die where-Klausel der Bedingung in der Selektion.
Wir definieren zu einer Sicht V eines Datenbankschemas S die Mengen der Relationenschemata
TRels(V) = {R ∈ S | ∃a Attribut in <Attribute> und a ∈ R}
und
QRels(V) = {R ∈ S | ∃a Attribut in <Qualifikation> und a ∈ R}
2.1 Einführung
9
mit den zugehörigen Attributmengen
TAttrs(V) = {A | A Attribut in <Attribute>}
und
QAttrs(V) = {A | A Attribut in <Qualifikation>}
und sagen, V ist über den Relationenschemata Rels(V) = TRels(V) ∪ QRels(V) bzw.
<Relationen> definiert.
Definition 2.17 I(V) = {i | Ri ist Relation aus <Relationen>} bezeichne eine
Indexmenge mit der Mächtigkeit p = |I(V)|, V eine Sicht über S = {Ri [Xi ] | i ∈
I(V)} mit den Attributen Y = {Y1 , . . . , Ym } und dem Zustand V . Sei v ∈ V und ti ∈
Ri , i ∈ I(V). Dann ist (ti1 , . . . , tip ) ein Generator von v, wenn QualV (ti1 , . . . , tip ) =
true und TargV (ti1 , . . . , tip ) = v.
Dabei ist
QualV : dom(X1 ) × . . . × dom(Xp ) −→ {true, f alse}
wobei QualV (ti1 , . . . , tip ) = true falls ti1 , . . . , tip der <Qualifikation> genügen und
TargV : dom(X1 ) × . . . × dom(Xp ) −→ dom(Y1 ) × . . . × dom(Ym )
wobei TargV (ti1 , . . . , tip ) das Sichttupel nach Berechnung der <Attribute> mit
ti1 , . . . , tip ist.
2.1.2
Änderungen auf Relationen
Definition 2.18 Eine Änderung auf einer Relation R ist eine Funktion u, die jeder
Relation R ∈ inst(R) eine Relation R0 ∈ inst(R) zuordnet:
u:
inst(R) −→ inst(R)
R
7−→ R0
UR ist die Menge der Änderungen auf R. Folgende Typen von Änderungsoperationen
auf einzelnen Tupeln werden betrachtet:
• Einfügen eines Tupels t in R, u(R) ≡ insR (t) = R ∪ {t}.
• Löschen eines Tupels t ∈ R, u(R) ≡ delR (t) = R \ {t}.
• Ersetzen eines Tupels t ∈ R durch t0 , u(R) ≡ replR (t → t0 ) = (R \ {t}) ∪ {t0 }.
Folgende Mengen von Änderungsoperationen auf Tupelmengen werden betrachtet:
• Einfügen der Tupel T in R, u(R) ≡ insR (T ) = R ∪ T .
• Löschen der Tupel T ⊆ R, u(R) ≡ delR (T ) = R \ T .
• Ersetzen der Tupel T ⊆ R durch T 0 , u(R) ≡ replR (T → T 0 ) = (R \ T ) ∪ T 0 .
10
Das View-Update-Problem
Definition 2.19 Eine Änderung auf einer Datenbankinstanz S ist eine Sequenz von
Änderungen û = u1 . . . un von der Menge der Zustände inst(S) in sich selbst:
inst(S) −→ inst(S)
û :
S
7−→ S 0
mit ui ∈ URi , i = 1, . . . , n, ui Änderung auf einer Relation Ri ∈ RS , wobei ui die
anderen Relation unverändert läßt. Mit US wird die Menge der Änderungen auf S
bezeichnet.
Definition 2.20 Eine Änderung u heißt konsistent, wenn für jeden konsistenten
Zustand S der Zustand u(S) konsistent ist.
Definition 2.21 Sei V = (SV , f ) eine Sicht. Dann wird mit der Änderung u auf V
die Änderung auf SV bezeichnet.
Wir werden im weiteren Verlauf nur konsistente Änderungen betrachten.
2.1.3
Übersetzungen von Änderungen auf Sichten
Änderungen auf den Datenbankinstanzen sind eindeutig auf der Sicht, da diese funktional auf den Datenbankinstanzen definiert ist. Wird eine Änderungsoperation auf
eine Sicht angewendet, so muß diese in Änderungsoperationen auf den die Sicht definierenden Basisrelationen übersetzt werden. Dabei taucht das Problem auf, daß die
Sichtfunktion im allgemeinen nicht bijektiv ist. Bei einer Änderung auf der Sicht muß
also ein zugehöriger Datenbankzustand gefunden werden, der der Sicht entspricht.
Falls die Sichtfunktion nicht injektiv ist, gibt es unter Umständen mehrere zugehörige Datenbankzustände, die der geänderten Sicht entsprechen (Mehrdeutigkeit), falls
sie nicht surjektiv ist, gibt es zu einer Änderung vielleicht keine entsprechende Übersetzung.
Es wird also eine Änderung û auf einer Datenbankinstanz gesucht, die eine vorgegebene Änderung u auf einer Sichtinstanz übersetzt. Wir wollen dabei zwischen
einfachen Übersetzungen und exakten Übersetzungen unterscheiden.
Definition 2.22 Eine Änderung û auf einer Datenbankinstanz S führt eine Änderung u auf einer Sichtinstanz V zur Sicht V = (SV , f ) aus, falls
• u(V ) ≡ insV (t) und t ∈ f (û(S)) oder
• u(V ) ≡ delV (t) und t 6∈ f (û(S)) oder
• u(V ) ≡ replV (t → t0 ) und f (û(S)) ∩ ({t} − {t0 }) = ∅ und t0 ∈ f (û(S)),
wobei t, t0 Tupel sind.
Eine Änderung auf einer Datenbankinstanz entspricht dann der Einfügung des Tupels in die Sicht, wenn dieses Tupel in der durch f aus der geänderten Datenbankinstanz berechneten Sicht enthalten ist. Ebenso entspricht die Änderung an einer
Datenbankinstanz dem Löschen eines Tupels in der Sicht, wenn dieses Tupel in der
durch f aus der geänderten Datenbankinstanz berechneten Sicht nicht enthalten ist.
Eine Ersetzung liegt dann vor, wenn das zu ersetzende Tupel nicht mehr in der Sicht
vorkommt, stattdessen aber das geänderte Tupel.
2.1 Einführung
11
Definition 2.23 Eine Änderung û bezüglich eines Datenbankschemas S führt exakt
eine Änderung u bezüglich einer Sicht V = (SV , f ) aus, falls
VO
f
u
_
_ S
/V0
O
û
f
/ S0
für jeden Zustand S kommutiert. Dies ist der Fall, wenn f (û(S)) = u(V ) und V =
f (S) für alle S.
Definition 2.24 Eine Änderung û ist eine Übersetzung der Änderung
u :⇐⇒ û führt u aus und û ist konsistent.
Definition 2.25 Eine Änderung û ist eine exakte Übersetzung der Änderung
u :⇐⇒ û führt exakt u aus und û ist konsistent.
Bei einer exakten Übersetzung werden Seiteneffekte weitestgehend verhindert. Nicht
ausgeschlossen werden können z. B. Seiteneffekte auf andere Sichten, da nur der Kontext der betrachteten Sicht bekannt ist.1 Seiteneffekte, die durch die exakte Übersetzung ausgeschlossen werden, können aber in bestimmten Fällen wünschenswert
sein.
Weitere Klassifizierungen von Änderungsübersetzungen werden hier nicht betrachtet, können aber durchaus auch interessant sein, z. B. eindeutige Übersetzungen, die
nicht exakt sind.
2.1.4
Beispiele problematischer Fälle
Folgende Beispiele stammen zum großen Teil aus [FC85].
Gegeben sind die Relationenschemata
1. E[EMP,DEP],
2. M[DEP,MGR],
3. S[EMP,SAL,AGE] und
4. E 0 [EMP,DEP]
mit den Zuständen E, M, S und E 0 . Als Integritätsbedingungen sollen die funktionalen Abhängigkeiten EMP →E DEP, DEP →M MGR und EMP →S {SAL,AGE}
sowie die Inklusionsabhängigkeit E[DEP] ⊆ M [DEP] gelten. Die betrachteten Sichtenzustände werden wie folgt berechnet:
1. V1 = σDEP=’Sales’ (E)
2. V2 = σDEP=’Sales’ (M )
3. V3 = πEMP (E)
1
siehe auch Beispiel 6 aus Abschnitt 2.1.4
12
Das View-Update-Problem
4. V4 = πDEP (E)
5. V5 = E ∗ M
6. V6 = E nach DEP gruppiert und beschränkt auf count(EMP) > 2
7. V7 = E ∪ E 0
8. V8 = πEMP,MGR (E ∗ M )
9. V9 = πEMP,DEP,SAL (E ∗ S)
10. V10 = πEMP,DEP (σM.MGR=’Alex’ (E ∗ M ))
Der Datenbankzustand sei:
E
EMP
John
Peter
Alice
DEP
Sales
Finance
Sales
E0
EMP
Joan
DEP
Toys
M
DEP
Sales
Finance
MGR
Mary
Jane
S
EMP
John
Peter
Alice
SAL
100K
130K
100K
AGE
35
32
37
mit den resultierenden Sichten
V1
EMP
John
Alice
V4
V7
V10
V2
DEP
Sales
MGR
Mary
DEP
Sales
Finance
V5
EMP
John
Peter
Alice
DEP
Sales
Finance
Sales
EMP
John
Peter
Alice
Joan
V8
EMP
John
Peter
Alice
MGR
Mary
Jane
Mary
EMP
DEP
Sales
Sales
DEP
Sales
Finance
Sales
Toys
MGR
Mary
Jane
Mary
V3
EMP
John
Peter
Alice
V6
EMP
DEP
V9
EMP
John
Peter
Alice
DEP
Sales
Finance
Sales
DEP
1. Verletzung einer Integritätsbedingung:
• insV1 ((Peter,Sales))
Die Übersetzung insE ((Peter,Sales)) verstößt gegen die funktionale Abhängigkeit EMP →E DEP, da E schon (Peter,Finance) enthält.
• delV2 ((Sales,Mary))
Die Übersetzung delM ((Sales,Mary)) verstößt gegen die Inklusionsabhängigkeit EMP →E DEP, da E noch (John,Sales) enthält. Eine andere
SAL
100K
130K
100K
2.1 Einführung
Übersetzung wäre die Änderungssequenz delE ((x,Sales)) und delM ((Sales,Mary)),
so daß die Inklusionsabhängigkeit gewahrt bleibt, wobei x Platzhalter für
alle Namen ist.
Diese Fälle besitzen keine exakte Übersetzung.
2. Es wird ein Ergebnis erzeugt, welches nicht konform mit der Sichtdefinition
ist:
• insV1 ((Mark,Finance))
Da V1 nur Tupel mit DEP=’Sales’ enthält, würde die Übersetzung
insE ((Mark,Finance)) nicht sichtbar in V1 werden.
In diesem Fall wird zwar eine Änderung auf der zugrundeliegenden Relation
ausgeführt, jedoch führt dies zu keinem Effekt in der Sicht. Bei Beschränkung
auf konsistente Änderungen wird dieser Fall ausgeschlossen.
3. Es wird ein anderes Ergebnis erzeugt, als mit der Operation beabsichtigt:
• replV1 ((John,Sales) → (John,Finance))
Die Übersetzung replE ((John,Sales) → (John,Finance)) hat ein Löschen“
”
des Tupels aus der Sicht V1 zur Folge.
4. Nullwerte müssen eingefügt werden:
• insV3 ((Roger))
Eine sinnvolle Übersetzung könnte insE ((Roger, NULL)) sein, aber es
wäre auch eine beliebige Abteilung anstelle eines Nullwertes möglich.
Durch Integritätsbedingungen wie das Verbieten von Nullwerten oder
Fremdschlüsselbeziehungen können diese Effekte vermieden werden, falls
gewünscht.
5. Attribute außerhalb der Sicht werden verändert:
• delV4 ((Sales))
Bei der Übersetzung mit delE ((x,Sales)), wobei x Platzhalter für alle Namen ist, würden alle Angestellten der Abteilung ’Sales’ gelöscht werden.
Hier sind Effekte außerhalb der Sicht die Folge.
6. Es werden mehrere Tupel auf den zugrundeliegenden Relationen verändert:
• replV4 ((Sales) → (Marketing))
Die Ausführung der Übersetzung replE ((x,Sales) → (x,Marketing)), x
Platzhalter für alle Namen, hat den Effekt, daß alle Mitarbeiter der Abteilung ’Sales’ in die Abteilung ’Marketing’ wechseln. In diesem Fall wird
auch die Sicht V1 beeinflußt.
7. Mehrere in der Sicht befindliche Tupel werden geändert:
• replV5 ((John,Sales,Mary) → (John,Sales,Jane))
Die Ersetzung replM ((Sales,Mary) → (Sales,Jane)) hat in der Sicht V5 den
Effekt, daß alle Mitarbeiter der Abteilung ’Sales’ eine neue Managerin
haben.
8. Eine Menge von Tupeln oder kein Tupel werden geändert:
13
14
Das View-Update-Problem
• insV6 ((Roger,Sales))
Die Übersetzung insE ((Roger,Sales)) bewirkt in der Sicht V6 , daß in der
vorher leeren Sicht drei Tupel auftauchen.
• insV6 ((Roger,Finance))
Hier würde die Übersetzung insE ((Roger,Finance)) keine Auswirkung auf
die Sicht V6 haben.
9. Es gibt mehrere Übersetzungen:
• insV7 ((Roger,Sales))
Das Einfügen des Tupels in E oder2 in E 0 sind gleichwertige Übersetzungen.
• replV8 ((John,Mary) → (John,Jane))
Die Übersetzungen replE ((John,Sales) → (John,Finance)) oder
replM ((Sales,Mary) → (Sales,Jane)) haben den gleichen Effekt auf der
Sicht V8 . Durch Formulierung der funktionalen Abhängigkeit MGR →M
DEP kann diese Mehrdeutigkeit vermieden werden.
• delV9 (x,Sales,y)
Den gleichen Effekt haben auch die beiden Löschoperationen delE (x,Sales)
und {delS (John,y,z), delS (Alice,y,z)}.
2.2
Übersetzungen mit Hilfe von Sicht-AbhängigkeitsGraphen
In [DB78] und [DB82] wird ein Ansatz verfolgt, der untersucht, wie durch Kenntnis
der Abhängigkeiten des der Sicht zugrundeliegenden Datenbankschemas bestimmte
mehrdeutige Übersetzungen vermieden werden können. Dabei braucht nur das Datenbankschema betrachtet werden und die Art Änderung auf der Sicht, sowie die
dabei abhängigen“, in der Änderung spezifizierten Attribute. Eine grundsätzliche
”
Charakterisierung der änderbaren Sichten erfolgt nicht, da die Einschränkungen zu
groß wären. Je nachdem, welche Attribute der Sicht, abhängig vom Änderungstyp,
geändert werden, ist eine Übersetzung möglich oder nicht.
Die Beweise zu den hier getroffenen Aussagen sind in [DB82] nachzulesen.
2.2.1
Grundlagen
Zur Charakterisierung der einem Sichttupel zugrundeliegenden Datenbanktupel werden die Begriffe Quelle und exakte Quelle eingeführt, mit deren Hilfe spezifiziert
werden kann, welche Änderungen an welchen Attributen (exakt) übersetzbar sind.
Im folgenden sei S = {R1 , . . . , Rn } eine Datenbankinstanz und V = f (R1 , . . . , Rn )
die zugehörige Instanz einer Sicht V.
Definition 2.26 Sei v ∈ V und i ∈ I(V). Dann ist ti ∈ Ri , ein Quelltupel von v
genau dann, wenn ti Komponente eines Generators von v ist.
2
Kein ausschließendes oder !
2.2 Übersetzungen mit Hilfe von Sicht-Abhängigkeits-Graphen
Definition 2.27 Sei V 0 ⊆ V beliebig. Sei G die Menge der Generatoren von V 0 .
Für jeden Generator g = (ti1 , . . . , tip ) ∈ G sei A(g) Seine nichtleere Teilmenge von
{(ti ; Ri ) | i ∈ I(V)}. Dann ist jede Obermenge von
A(g) eine Quelle von V 0 in
g∈G
S.
Falls G = ∅, hat V 0 keine Quelle. Betrachte die Sicht V5 in Abschnitt 2.1.4, dann
ist für
V 0 = {(John,Sales,Mary), (Peter,Finance,Jane)}
die Menge der Generatoren
G = {((John,Sales), (Sales,Mary)), ((Peter,Finance), (Finance,Jane))}
.
Seien nun z. B. A(g1 ) = {((John,Sales);E)} und A(g2 ) = {((Finance,Jane);M)},
dann ist A(g1 ) ∪ A(g2 ) = {((John,Sales);E),((Finance,Jane);M)} eine Quelle von
V 0 . Das bedeutet also, daß aus einer Quelle nicht notwendigerweise das Sichttupel
berechnet werden kann. Eine Quelle soll vielmehr anzeigen, daß Teile des zugehörigen
Tupels in der Sicht auftauchen.
Definition 2.28 Sei V 0 ⊆ V beliebig und Q eine Quelle von V 0 , dann sei Qi =
{t ∈ Ri | (t; Ri ) ∈ Q} der Teil der Quelle, der von der Relation Ri kommt.
Definition 2.29 Sei V 0 ⊆ V beliebig und Q eine Quelle von V 0 in S. Dann ist Q
eine exakte Quelle von V 0 , wenn für alle v ∈ V \ V 0 ein Q0 existiert, welches Quelle
von {v} in {R1 \ Q1 , . . . , Rn \ Qn } ist.
Äquivalent zu dieser Definition ist, daß Q eine exakte Quelle von V 0 in S ist, wenn
für alle v ∈ V \ V 0 Q keine Quelle von {v} in S ist. So ist z. B. ((John,Sales);E)
exakte Quelle von (John,Sales,Mary) in Sicht V5 , während ((Sales,Mary);M) zwar
eine Quelle, aber nicht exakt ist, da für (Alice,Sales,Mary) keine Quelle in M \
{(Sales,Mary)} existiert, bzw. (Sales,Mary) auch Quelle von (Alice,Sales,Mary) ist.
Definition 2.30 Sei V 0 ⊆ V beliebig und U eine Änderung auf einem Datenbankschema S mit dem Zustand
S = {R1 , . . . , Rn } und U (S) = {R10 , . . . , Rn0 }. Sei
S
n
Ti = Ri \ Ri0 und T = i=1 {(t; Ri ) | t ∈ Ti }, wobei i = 1, . . . , n.
1. U löscht eine (exakte) Quelle gdw. T eine (exakte) Quelle von V 0 in S ist.
2. U fügt ein Quelltupel von v ∈ dom(V) ein gdw. ein i existiert, so daß t ∈ Ri0 \Ri
ein Quelltupel von v in U (S) ist.
Lemma 2.1 Sei V 0 ⊆ V und f die V definierende Funktion. Dann gilt:
1. Q ist eine Quelle von V 0 in S ⇔ f (R1 \ Q1 , . . . , Rn \ Qn ) ⊆ V \ V 0
2. Q ist eine exakte Quelle von V 0 in S ⇔ f (R1 \ Q1 , . . . , Rn \ Qn ) = V \ V 0
15
16
Das View-Update-Problem
Das Lemma macht deutlich, daß aus der Quelle einer Teilsicht ein Quelltupel nicht
notwendigerweise berechnet werden kann, daß aber bei Entfernen einer Quelle die
Sicht mindestens um die Quelle verringert wird. Bei einer exakten Quelle wird die
Sicht genau um die Teilsicht verringert.
Lemma 2.2 Sei U eine Änderung auf S und v ∈ V . (Dann löscht U eine Quelle
von {v} und U fügt kein Quelltupel von v ein) ⇔ v 6∈ f (U (S)).
Lemma 2.3 Sei U wie oben. Sei v ∈ dom(Y ) \ V , Y Menge der Attribute von V.
Dann fügt U ein Quelltupel von v ein ⇔ v ∈ f (U (S)).
Die beiden Lemmata zeigen die Auswirkungen von Lösch- und Einfügeänderung von
Quellen auf die Sicht.
Für jeden Typ von Änderungsoperationen stellen die folgenden Theoreme den Zusammenhang zwischen Änderungen auf Sichten und Änderungen auf zugehörigen
Quellen dar. Für die Untersuchung, in welchen Fällen (exakte) Übersetzungen von
Sichtänderungen vorhanden sind, bilden die Theoreme die Grundlage.
Theorem 2.1 Sei u die Löschänderung einer Menge von Sichttupeln V u ⊆ V . Dann
ist
1. U eine Übersetzung von u in S ⇔ U löscht eine Quelle von V u ,
2. U eine exakte Übersetzung von u in S ⇔ U löscht eine exakte Quelle von V u .
Theorem 2.2 Sei u die Einfügeänderung einer Menge von Sichttupeln V u in V .
Seien V i = V u \ V und V 0 = V \ V u . Dann ist
1. U eine Übersetzung von u in S ⇔ für alle v ∈ V i fügt U ein Quelltupel ein
und
2. U eine exakte Übersetzung von u in S ⇔
(a) für alle v ∈ V i fügt U ein Quelltupel ein und
(b) für alle v ∈ dom(V) \ (V 0 ∪ V i ) fügt U kein Quelltupel von v ein.
Theorem 2.3 Sei u die Ersetzungsänderung einer Menge von Tupeln V u ⊆ V durch
V r . Sei V 0 = V u \ V r . Dann ist
1. U eine Übersetzung von u in S ⇔
(a) für alle v ∈ V 0 löscht U eine Quelle von {v} und fügt kein Quelltupel von
v ein und
(b) für alle v ∈ V r \ V u fügt U ein Quelltupel von v ein und
(c) für alle v ∈ V r ∩ V u löscht U keine Quelle von {v} oder U fügt ein
Quelltupel von v ein.
2. U eine exakte Übersetzung von u in S ⇔
(a) für alle v ∈ V 0 löscht U eine Quelle von {v} und fügt kein Quelltupel von
v ein und
2.2 Übersetzungen mit Hilfe von Sicht-Abhängigkeits-Graphen
(b) für alle v ∈ V r \ V u fügt U ein Quelltupel von v ein und
(c) für alle v ∈ V \ V 0 löscht U keine Quelle von {v} oder fügt ein Quelltupel
von v ein und
(d) für alle v ∈ dom(V) \ (V ∪ U r ) fügt U kein Quelltupel von v ein.
2.2.2
Sicht-Graphen
Neben den oben beschriebenen semantischen Bedingungen, d. h. den Bedingungen
an die Datenbankzustände für die Übersetzung von Änderungsoperationen, werden
im folgenden syntaktische Bedingungen angegeben. Diese werden anhand von zwei
Graphen formuliert, genauer: zu einer Sicht V wird ein Sicht-Spur-Graph T (V) und
ein Sicht-Abhängigkeits-Graph D(V) konstruiert.3
Definition 2.31 Ein Spur-Graph T (V) ist ein gerichteter Graph, der folgendermaßen aufgebaut wird:
1. Für alle i ∈ I(V) und alle A ∈ Ri füge einen ,-Knoten mit der Bezeichnung
’Ri .A’ ein.
2. Für alle A ∈ TAttrs(V) füge einen 4-Knoten mit der Bezeichnung ’V.A’ ein.
3. Für jede Konstante c aus <Qualifikation> füge einen 4-Knoten mit der
Bezeichnung ’c’ ein.
4. Für jedes Attribut A ∈ TAttrs(V) füge die Kanten (V.A, Ri .A) und (Ri .A, V.A)
ein, wobei Ri .A der Wert aus der Relation Ri ist, aus dem V.A berechnet wird.
5. Für jeden Ausdruck ti .A = tj .B in der <Qualifikation> von V füge die
Kanten (Rj .B, Ri .A) und (Ri .A, Rj .B) ein.
6. Für jeden Ausdruck ti .A = c in der <Qualifikation> von V füge die Kanten
(c, Ri .A) und (Ri .A, c) ein.
E.EMP
E.DEP
V.EMP
V.DEP
M.DEP
M.MGR
V.MGR
Abbildung 2.1: Der Spur-Graph für die Sicht V5 aus Abschnitt 2.1.4
Die Kanten stellen eine Verbindung zwischen den Attributen eines Sichttupels und
den Attributen einer zugehörigen Quelle dar. Im folgenden wird dies noch genauer
dargestellt.
3
Diese werden in [DB82] als view-trace-graph und view-dependency-graph bezeichnet.
17
18
Das View-Update-Problem
Definition 2.32 Wenn in T (V) ein Pfad von einem 4-Knoten V.A zu einem ,Knoten Ri .A existiert, dann ist V.A eine V -Spur von Ri .A. Falls eine Kante zwischen V.A und Ri .A existiert, dann ist V.A eine direkte V -Spur von Ri .A.
Das wesentliche Merkmal von Spuren ist, daß, wenn V.A eine V -Spur von Ri .A und
ti ∈ Ri ein Quelltupel von v ∈ V in S ist, dann ist ti .A = v.A. Um also ein Sichttupel
v mit v.A = a einzufügen, muß ein Tupel ti mit ti .A = a in Ri eingefügt werden.
Falls V.A ein konstanter Knoten ’c’ ist, dann ist v.A = c für alle v ∈ V .
Der Abhängigkeits-Graph D(V ) wird so aufgebaut, daß die Informationen der funktionalen Abhängigkeiten der Integritätsbedingungen CS eines Datenbankschemas in
T (V) eingefügt werden.
Definition 2.33 Ein Abhängigkeits-Graph D(V ) ist ein Spur-Graph T (V), in welchem Kanten wie folgt eingefügt werden:
1. Für jede funktionale Abhängigkeit {B1 , . . . , Bk } →Ri A, k > 1 füge einen FDKnoten wie in Abbildung 2.2 ein. Für k = 1 füge die Kante (Ri .B, Ri .A) ein.
2. Falls ein konstanter Knoten ’c’ V -Spur von Ri .A ist, dann füge für jedes Attribut B aus jeder Relation R ∈ S eine Kante (R.B, Ri .A) ein.
B1
A
Bk
Abbildung 2.2: Ein FD-Knoten zur funktionalen Abhängigkeit {B1 , . . . , Bk } →R A
Die Abbildungen 2.3 und 2.4 zeigen Abhängigkeits-Graphen zu Sicht V5 aus Abschnitt 2.1.4. Dabei sind die gestrichelten Kanten diejenigen, die in den zugehörigen
Spur-Graphen eingefügt werden.
E.EMP
E.DEP
V.EMP
V.DEP
M.DEP
M.MGR
V.MGR
Abbildung 2.3: Der Abhängigkeits-Graph für die Sicht V5 aus Abschnitt 2.1.4
Die zusätzlichen Kanten nach Bedingung 2 in Definition 2.33 von allen Knoten zu
dem konstanten Knoten ’Sales’ kennzeichnen quasi eine funktionale Abhängigkeit.
Diese wird von der Menge der Sichttupel erfüllt. Denn durch die Selektionsbedingung
DEP=’Sales’ ist das Attribut DEP funktional von den anderen Attributen abhängig.
Der gebräuchliche Begriff des Pfads in einem Graphen muß noch auf Mengen von
Knoten und auf FD-Knoten erweitert werden:
2.2 Übersetzungen mit Hilfe von Sicht-Abhängigkeits-Graphen
E.EMP
E.DEP
V.EMP
Sales
M.DEP
19
M.MGR
V.MGR
Abbildung 2.4: Der gleiche Graph wie in Abbildung 2.3, jedoch hat die Sicht die
zusätzliche Selektionsbedingung DEP=’Sales’
Definition 2.34 Seien A, B, C beliebige Knoten und X, Y, Z beliebige Knotenmengen in einem Graph G, wobei ein Knoten D der Knotenmenge {D} gleichzusetzen
ist. Mit Y
G Z bezeichnen wir einen Pfad im Graphen G von Y nach Z, wobei
Pfad“ folgende Bedeutung hat:
”
1. Von jedem Knoten existiert ein Pfad zu sich selbst.
2. Falls die Kante (A, B) existiert, so gibt es einen Pfad von A nach B.
3. Falls es von einer Teilmenge Y 0 ⊆ Y von Knoten einen Pfad zu A gibt, dann
gibt es einen Pfad von Y nach A.
4. Falls es von einer Teilmenge Y 0 ⊆ Y von Knoten einen Pfad zu allen Knoten
Zi ∈ Z gibt, dann gibt es einen Pfad von Y nach Z.
5. Falls es einen Pfad von X nach Y gibt und einen Pfad von Y nach Z, dann
gibt es einen Pfad von X nach Z.
6. Sei F ein FD-Knoten zur funktionalen Abhängigkeit X →R Z. Falls Y
existiert, dann gibt es einen Pfad von Y nach Z.
G
X
Wird der Graph in Abbildung 2.5 betrachtet, so gibt es zwar Pfade
{V.D, V.E}
S.F
V
und
{V.A, V.B, V.C, V.D}
V
S.F
aber
{V.C, V.D} 6
V
S.F.
Pfade über FD-Knoten müssen alle eingehenden Kanten des FD-Knotens enthalten, während es bei Pfaden von normalen Knotenmengen ausreichend ist, daß zwei
Knoten existieren, die durch einen Pfad verbunden sind.
Lemma 2.4 Sei S = {Ri [Xi ] | i = 1, . . . , n} ein Datenbankschema, V[Z] eine Sicht
über S, L ⊆ {X1 , . . . , Xn } und Y ⊆ Z. Dann gilt für alle Generatoren g, g 0 beliebiger
Sichttupel v, v 0
(g.L = g 0 .L ⇒ v.Y = v 0 .Y ) ⇔ (L D(V ) Y )
20
Das View-Update-Problem
R.A
R.B
R.C
R.D
R.E
V.A
V.B
V.C
V.D
V.E
S.E
S.F
V.F
Abbildung 2.5: Der Abhängigkeits-Graph für die Sicht V = πY (R o
nR.E=S.E
S) mit Y = {R.A, R.B, R.C, R.D, R.E, S.F } über den Relationenschemata
R[A, B, C, D, E] und S[E, F ] mit den funktionalen Abhängigkeiten {A, B, C} →R E
und E →S F .
Pfade in D(V ) haben die Eigenschaft, exakte Quellen anzuzeigen. Im Beispiel auf
Seite 15 gibt es z. B. einen Pfad
E.EM P
D(V5 )
V5 .EM P,
während
{M.DEP, M.M GR} 6
D(V5 )
V5 .EM P.
Wie schon auf Seite 15 gesehen ist ((John,Sales);E) exakte Quelle von (John, Sales,
Mary), während dies bei ((Sales,Mary);M) nicht der Fall ist.
Korollar 2.1 Sei Y ⊆ V eine beliebige Menge von Sichtattributen und A ∈ R ∈
Rels(V) beliebiges Attribut. Es ist dann Y →V A ⇔ Y D(V ) A.
Eine funktionale Abhängigkeit zwischen Sichtattributen ist durch das Suchen eines
Pfads im Abhängigkeits-Graph zwischen diesen Attributen zu finden, Pfade sind im
Abhängigkeits-Graph synonym zu funktionalen Abhängigkeiten in den zugrundeliegenden Relationen.
In den folgenden Abschnitten werden Algorithmen für die Übersetzung von Sichtänderungen angegeben und unter welchen Bedingungen die Änderungen exakt sind.
2.2.3
Löschänderungen
Sei V[Z] eine Sicht mit den Attributen Z und Y ⊆ Z eine Teilmenge der Attribute.
Mit V [Y = y] bezeichnen wir die Menge der Tupel aus V , deren Attribute Y =
{Y1 , . . . , Yn } die Werte y = {y1 , . . . , yn } haben. Die Löschänderung wird wie folgt
übersetzt, wobei V u = V [Y = y] die Menge der zu löschenden Tupel in V sein
soll, Y die Menge der in der Löschbedingung spezifizierten Attribute. Der folgende
Algorithmus übersetzt eine Löschänderung auf einer Sicht in eine Löschänderung
auf dem zugrundeliegenden Datenbankschema.
2.2 Übersetzungen mit Hilfe von Sicht-Abhängigkeits-Graphen
Algorithmus 2.1
Für jede Relation R des Schemas R ∈ Rels(V) lösche die Menge
{t ∈ R | t ist Quelle eines v ∈ V u }.
Theorem 2.4 Eine Änderung delV (t) ist exakt übersetzbar ⇔ Xi D(V ) Y , wobei
Y die Attribute der Sicht sind, die in der Löschbedingung auftauchen und Ri [Xi ], i ∈
I(V) die Relationenschemata sind, von denen einige Attribute eine direkte V -Spur
in Y haben. Der Algorithmus 2.1 ist eine exakte Übersetzung, wenn die Bedingungen
zutreffen.
Die Löschoperation auf dem Datenbankschema, die das Theorem 2.4 erfüllt, braucht
nur die exakten Quellen von t zu löschen, dies folgt aus Theorem 2.1. So ist das
Löschen von (John,Sales,*) aus der Sicht V5 auf der Relation E eine exakte Übersetzung, da ein Pfad {E.EM P, E.DEP } D(V5 ) {V.EM P, V.DEP, V.M GR} existiert, während {M.DEP, M.M GR} 6 D(V5 ) {V.EM P, V.DEP, V.M GR} und somit
das Löschen aus der Relation M keine exakte Übersetzung ist. Eine Übersetzung
auf der Relation E ist auch dann noch exakt, wenn die funktionale Abhängigkeit
DEP →M MGR nicht vorhanden ist. Wenn die Löschbedingung nur für das Attribut
EMP formuliert wird, also die Tupel (John,*,*) gelöscht werden, so ist die Übersetzung exakt. Zwar fehlt die Kante von M.DEP nach M.MGR, aber es wird auch nicht
verlangt, daß der Pfad {E.EM P, E.DEP } D(V5 ) V.M GR vorhanden ist.
2.2.4
Einfügeänderungen
Durch das Einfügen eines Tupels können funktionale Abhängigkeiten verletzt werden. Da durch Projektionen in der Sicht beim Einfügen Attribute auch unspezifiziert
sein können, sollen diese Attribute den Wert NULL erhalten. In [DB82] wird die
Einfügeoperation explizit beschrieben. Dabei werden die einzufügenden Tupel aus
den Werten der Sichtattribute gebildet, soweit diese jeweils eine V -Spur sind. Die
verwendete Prozedure reduce dient dazu, daß beim Einfügen eines Sichttupels v
weniger definierte Sichttupel w gelöscht werden.4 Die einzufügenden Tupel werden
nach folgendem Algorithmus gebildet:
Algorithmus 2.2
1. Sei v einzufügendes Tupel in V , für alle Ri [Xi ] ∈ Rels(V) definiere ti ∈
dom(Xi ) für alle A ∈ Xi wie folgt
(a) falls V.A V -Spur von Ri .A und v.A 6= N U LL, dann setze ti .A = v.A
sonst falls ∃L →Ri A ∃t0i ∈ Ri ti .L = t0i .L und t0i .A 6= N U LL, dann setze
ti .A = t0i .A
(b) falls ∃Rj .B Rj .B T (V) Ri .A, dann setze ti .A = tj .B,
sonst setze ti .A = N U LL
2. für alle i ∈ I(V) führe reduce(Ri ∪ {ti }) aus.
Das folgende Theorem gibt die Bedingungen an, unter welchen der Algorithmus eine
(exakte) Übersetzung einer Einfügeänderung auf einer Sicht ist:
4
w ist weniger definiert, wenn w.A = v.A für fast alle Attribute A und sonst w.A = N U LL
21
22
Das View-Update-Problem
Theorem 2.5 Sei V[Y ] eine Sicht über Ri [Xi ], i = 1, . . . , n.
1. Eine Änderung insV (t) ist genau dann übersetzbar, wenn gilt:
(a) falls A1 und A2 V -Spuren des gleichen Attributs Ri .A, v.A1 6= N U LL
und v.A2 6= N U LL sind, dann ist v.A1 = v.A2 , und
(b) QualV (ti1 , . . . , tip ) = true und ti wie im Algorithmus berechnet.
2. Eine Änderung insV (t) ist dann exakt übersetzbar, wenn sie übersetzbar ist und
für alle i ∈ I(V ) Xi D(V ) Y gilt.
Der Algorithmus 2.2 ist eine (exakte) Übersetzung, wenn die Bedingungen zutreffen.
Damit die Übersetzung einer Einfügeoperation die Konsistenz erhält, müssen alle Primärschlüsselattribute eine V -Spur in der Sicht haben, es muß ein Wert für
die Primärschlüsselattribute definiert sein und funktionale Abhängigkeiten müssen
berücksichtigt werden. Damit QualV (ti1 , . . . , tip ) = true gilt, muß die Übersetzung also insbesondere für Attribute, die eine V -Spur haben und in der Sichtbedingung verwendet werden einen Wert spezifizieren. Durch Erweiterung der Theorie unter Berücksichtigung von Inklusionsabhängigkeiten können diese Bedingungen
abgeschwächt werden. Die Bedingung für die exakte Übersetzbarkeit ist eigentlich
zu stark, z. B. ist ein Einfügen in die Sicht aus Abbildung 2.3 nicht möglich, da
{M.MGR, M.DEP} 6 D(V5 ) {V.EMP, V.DEP, V.MGR}. Dies sollte jedoch möglich
sein.
Für die Sicht in Abbildung 2.6 ist eine exakte Übersetzung auf den beiden Relationen
E und S möglich, für das Attribut S.EM P wird der Wert von V.EM P genommen,
da dies eine V -Spur ist.
E.DEP
E.EMP
V.DEP
V.EMP
S.EMP
S.SAL
S.AGE
V.SAL
Abbildung 2.6: Der Abhängigkeits-Graph für die Sicht V9 aus Abschnitt 2.1.4
Zu der Sicht in Abbildung 2.7 gibt es keine Übersetzung, da es zu den Join-Attributen
E.DEP und M.DEP keine V -Spuren gibt, was gegen die Bedingung 1b in Theorem 2.5 verstößt.
Im folgenden soll gezeigt werden, wie die Bedingungen in Theorem 2.5 abgeschwächt
werden können, wenn Inklusionsabhängigkeiten auf dem Datenbankschema vorhanden sind. Angenommen, die Bedingung E[DEP] ⊆ M [DEP] würde nicht gelten und
das Tupel (Joan,Toys) wäre auch in E enthalten. Die Übersetzung von
insV5 ((Bill,Toys,Alex))
2.2 Übersetzungen mit Hilfe von Sicht-Abhängigkeits-Graphen
E.EMP
E.DEP
M.DEP
V.EMP
M.MGR
V.MGR
Abbildung 2.7: Der Abhängigkeits-Graph für die Sicht V8 aus Abschnitt 2.1.4
ist
{insE ((Bill,Toys)), insM ((Toys,Alex))}.
Dies ist aber keine exakte Übersetzung, da nun auch das Tupel (Joan,Toys,Alex) in
der Sicht V5 auftaucht. Funktionale und Inklusionsabhängigkeit reichen aber noch
nicht aus, um eine exakte Übersetzung zu garantieren.
Sei (Toys,NULL) ein Tupel in M und (Chris,Toys) ein Tupel in E. Funktionale
und Inklusionsabhängigkeit sind erfüllt. Fügen wir das Tupel (Bill,Toys,Alex) in die
Sicht V10 ein, so wird durch die Übersetzung der Einfügeoperation zur Einhaltung
der funktionalen Abhängigkeit das Tupel (Toys,NULL) in M durch (Toys,Alex)
ersetzt, was dazu führt, daß auch das Tupel (Chris,Toys) in V10 erscheint. Dies kann
nur durch eine Existenzabhängigkeit verhindert werden, die garantiert, daß für ein
Tupel t ∈ M mit t.DEP 6= N U LL folgt, daß t.M GR 6= N U LL ist.
Definition 2.35 Sei R[X] ein Relationenschema und L1 , L2 ⊆ X Teilmengen von
Attributen aus R. Dann erfüllt die zugehörige Relation R die Existenzabhängigkeit
EXISTR (L1 , L2 ), falls
∀t ∈ R ∀A ∈ L1 t.A 6= N U LL ⇒ ∀B ∈ L2 t.B 6= N U LL
Durch diese Bedingung wird ausgeschlossen, daß Tupel wie (Toys,NULL) in der
Relation M enthalten sind, die zu den beschriebenen Seiteneffekten führen. Theorem 2.5 kann nun weniger restriktiv formuliert werden, zunächst auf zwei Relationen
beschränkt.
Theorem 2.6 Sei V[Y ] eine Sicht über zwei Relationen mit den Schemata R1 [X1 ]
und R2 [X2 ] und es gelten die Bedingungen 1a und 1b von Theorem 2.5. Eine Änderung insV (t) ist dann exakt übersetzbar, wenn sie übersetzbar ist und für eine Permutation (i,j) von (1,2) gilt
1. Xi
D(V)
2. (a) Xj
Y und
D(V)
Y oder
(b) ∃A ∈ Ri ∃B ∈ Rj Ri .A
und EXISTRj (Lj , B ∗ ).
T (V)
Rj .B ∧ Ri [Li ] ⊆ Rj [Lj ] ∧ Lj →Rj B ∗
Dabei sind
Li = {A ∈ Xi | ∃B ∈ Xj ti .A = tj .B ist in der Sichtbedingung erfüllt},
23
24
Das View-Update-Problem
Lj symmetrisch dazu gebildet und
B ∗ = {A ∈ Xj | A ist Attribut in der Sichtbedingung}.
Falls nun die Sicht V als Folge von Sichten V1 , . . . , Vk ausgedrückt werden kann, die
jeweils die Bedingungen in Theorem 2.6 erfüllen, dann ist insV (t) exakt übersetzbar.
Durch die Erweiterung auf Inklusions- und Existenzabhängigkeiten müssen Lösch-,
Einfüge- und Änderungsprozeduren angepasst werden, um diese Integritätsbedingungen zu prüfen. Dies wird hier ausgelassen. Auch die folgende Änderungsprozedur
berücksichtigt dies nicht.
2.2.5
Ersetzungsänderungen
Ähnlich wie beim Einfügen sind beim Ersetzen eines Sichttupels nicht notwendigerweise alle Attribute mit Werten belegt. Die Ersetzungsänderung wird mit folgendem
Algorithmus übersetzt, wobei V u die Menge der Tupel in V sein soll, die durch V r
ersetzt werden und v r ∈ V r ein geändertes Tupel der Sicht. Sei Y ∗ die Menge der
Sichtattribute, die in der Änderungsbedingung spezifiziert sind, W die Menge der
Sichtattribute, deren Werte geändert werden und URels = {Ri | ∃A ∈ Ri ∃B ∈
W B ist V -Spur von A}.
Algorithmus 2.3
1. für alle Ri ∈ URels(V) setze Ti := {ti ∈ Ri | ti ist Quelltupel eines v ∈ V u }
und für alle ti ∈ Ti definiere tri durch
r
v .A A ist V-Spur von Ri .A
r
ti .A =
ti .A sonst
2. für alle Ri ∈ URels(V) und für alle tri aus Schritt 1 und für alle A ∈ Xi
falls ∃L →Ri A ∃t0i ∈ Ri (t0i 6∈ Ti ∧ t0i .L = tri .L) gilt dann setze t0i .A = tri .A
3. für alle Ri ∈ URels(V)
setze Ri =reduce({Ri \ Ti } ∪ Tir ), wobei Tir = {tri | ti ∈ Ti }
Das folgende Theorem formuliert die Bedingungen, unter denen der Algorithmus
eine (exakte) Übersetzung ist:
Theorem 2.7 Sei V[Y ] eine Sicht über Ri , i = 1, . . . , n.
1. Eine Änderung replV (t → t0 ) ist dann übersetzbar, wenn gilt:
(a) falls V.A1 , V.A2 zwei V -Spuren des gleichen Attributs Ri .A sind, dann ist
für alle v ∈ V u v r .A1 = v r .A2 und
(b) falls ein Generator g = (ti1 , . . . , tip ) von v ∈ V u existiert, dann ist g r =
(tri1 , . . . , trip ) Generator von v r , trij , wobei tr = t für alle Tupel t, die nicht
in Algorithmus 2.3 berechnet werden.
2. Eine Änderung replV (t → t0 ) ist dann exakt übersetzbar, wenn sie übersetzbar
ist und
(a) falls für alle Ri [Xi ] ∈ URels(V) ein Pfad Xi
D(V )
Y ∗ existiert, und
2.3 Übersicht über weitere Ansätze für die Übersetzung von View-Updates
(b) falls für alle A ∈ V gilt: falls A ∈ W V -Spur einiger Ri .A ist, die in
einer join-Klausel in <Qualifikation> vorkommen, dann existiert ein
Pfad Xi D(V ) Y .
Der Algorithmus 2.3 ist eine (exakte) Übersetzung, wenn die Bedingungen zutreffen.
Eine notwendige Bedingung für 1b ist, daß v r einen Generator hat, was genau dann
der Fall ist, wenn ti .A<Op>a in der Sichtbedingung vorkommt und Ri .A eine V Spur in W hat. Wenn ti .A<Op>Tj .B in der Sichtbedingung vorkommt, dann hat
Ri .A eine V -Spur D ∈ W genau dann, wenn Rj .B eine V -Spur E ∈ W hat und
v r .D = v r .E gilt. Zur Erhaltung der Konsistenz müssen wie bei der Einfügeoperation
die V -Spuren von Primärschlüsseln ungleich NULL sein und das ersetzende Tupel
darf keine funktionalen Abhängigkeiten in der jeweiligen Relation verletzen. Wie
bei den anderen Änderungsoperationen wird auch bei der Ersetzungsänderung die
exakte Übersetzung im wesentlichen durch die Pfade zwischen den Attributen der
beteiligten Relationen zu den Sichtattributen im Spur- und Abhängigkeits-Graph
bestimmt.
Der hier beschriebene pragmatische Ansatz läßt eine große Anzahl an Sichtänderungen zu, die sehr stark von den Integritätsbedingungen des zugrundeliegenden
Datenbankschemas abhängen. Die Menge der änderbaren Sichten ist durch Formulierung zusätzlicher, oben besprochener Abhängigkeiten sehr zu vergrößern. In
Abschnitt 2.4 wird der Ansatz von [DB82] verwendet und im Hinblick auf das Ziel
dieser Arbeit modifiziert. Durch bestimmte ausgezeichnete Relationen einer Sicht
sollen noch zusätzliche, auf diese Relationen beschränkte Änderungen möglich sein.
Der Begriff der Änderung muß dafür ebenfalls modifiziert werden.
2.3
2.3.1
Übersicht über weitere Ansätze für die Übersetzung
von View-Updates
Komplementäre Sichten
In [BS81] wird ein aus theoretischer Sicht sehr interessant erscheinender und inspirierender Ansatz vorgestellt, der mit komplementären Sichten arbeitet. Dazu wird
zu einer update-Sicht eine konstante komplementäre Sicht festgelegt, die in Komposition mit der update-Sicht den Datenbankzustand vollständig darstellt. In [Lan90]
wird allerdings gezeigt, daß der vorgestellte Übersetzer nur auf trivialen Sichten
definierbar ist. Im folgenden sei dieser Ansatz informal dargestellt.
Definition 2.36 Seien f, g zwei Sichten, dann wird die binäre Relation ≤ wie folgt
definiert
f ≤ g :⇐⇒ g(S) = g(S 0 ) ⇒ f (S) = f (S 0 )
mit S, S 0 beliebige Datenbankinstanzen von S.
Durch ≤ wird eine partielle Ordnung über den Sichten eines Datenbankschemas S
eingeführt. g kann als eine Verfeinerung“ angesehen werden, da g zwischen mehr
”
Datenbankinstanzen unterscheidet“.
”
25
26
Das View-Update-Problem
Definition 2.37 Für eine Sicht f und zwei Datenbankinstanzen S, S 0 ist die Äquivalenzrelation ≡f definiert durch
S ≡f S 0 :⇐⇒ f (S) = f (S 0 )
Definition 2.38 Zwei Sichten f und g heißen äquivalent, in Zeichen f ≡ g, wenn
f ≤ g und g ≤ f .
Wir bezeichnen mit > die Sicht, welche die Identität repräsentiert und mit ⊥ die
Sicht, die jede Instanz von S auf ∅ abbildet. Die durch > und ⊥ repräsentierten
Äquivalenzklassen bilden gerade das maximale und das minimale Element von ≤.
Definition 2.39 Das Kreuzprodukt × auf zwei Sichten f und g ist definiert als
(f × g)(S) = (f (S), g(S))
Definition 2.40 Eine Sicht g ist das Komplement einer Sicht f , falls f × g ≡ >.
Das heißt, daß eine Datenbankinstanz vollständig mit f und g identifiziert werden
kann. Jede Sicht hat trivialerweise > als Komplement, interessant sind daher insbesondere minimale Komplemente.
Eine Übersetzung einer Änderung u einer Sicht f kann mit Hilfe eines Komplements
g durch die Komposition û = (f × g)−1 ◦ u ◦ (f × g) beschrieben werden.
V = (f (S), g(S))
/ V 0 = (u(f (S)), g(S))
u
O
(f ×g)−1
f ×g
S
û
/ S 0 = ((f × g)−1 ◦ u ◦ (f × g))
Im folgenden sollen die Voraussetzungen angegeben werden, für die eine gültige
Übersetzung einer Änderung gefunden werden kann. Sei UV die Menge aller Änderungen auf der Sicht V und US die Menge aller Änderungen auf dem Datenbankschema S. Sei f die definierende Funktion von V.
Definition 2.41 Die Abbildung T : UV → S heißt Übersetzer einer Änderung der
Sicht V in eine Änderung des Datenbankschemas S. Die Änderung T (u) auf S ist
eine Übersetzung von u und wird auch mit Tu bezeichnet.
Definition 2.42 Eine Menge UV von Änderungen auf der Sicht V heißt komplett
falls
1. ∀u, v ∈ UV uv ∈ UV und
2. ∀s ∈ S, ∀u ∈ UV ∃v ∈ UV vuf (s) = f (s).
Definition 2.43 Sei u ∈ UV eine Änderung auf der Sicht V. Eine Übersetzung
Tu ∈ US heißt BS-zulässig, falls
2.3 Übersicht über weitere Ansätze für die Übersetzung von View-Updates
1. f Tu = uf (Konsistenz) und
2. ∀s ∈ S uf (s) = f (s) ⇒ Tu (s) = s.
Definition 2.44 Ein Übersetzer T heißt BS-zulässig, falls
1. ∀u ∈ UV ist T (u) BS-zulässig und
2. ∀u, v ∈ UV T (uv) = T (u)T (v)
In [BS81] wird gezeigt, daß jeder BS-zulässige Übersetzer mindestens ein Komplement konstant läßt und daß durch Angabe eines konstanten Komplements ein BSzulässiger Übersetzer eindeutig bestimmt ist. Die oben genannten Voraussetzungen
sind allerdings sehr restriktiv, so daß z. B. in [Lan90] folgende Aussage gezeigt wird:
Theorem 2.8 Sei S ein unabhängiges5 Datenbankschema und V[X] eine Sicht mit
der Menge UV aller Einfüge- und Löschänderungen in V . Angenommen, es gibt
einen BS-zulässigen Übersetzer für UV , dann sind alle X 0 ∈ X V -Spuren der gleichen
Relation R ∈ S.
Existiert also ein BS-zulässiger Übersetzer, so ist V eine triviale Sicht und damit aus
praktischer Sicht recht uninteressant. Trotzdem kann der Ansatz interessant sein,
wenn eventuell die Voraussetzungen gelockert werden können und in der Spezifizierung des konstanten Komplements weitere Informationen festgelegt werden. Dazu
gibt es aber zur Zeit keine Untersuchungen.
2.3.2
Der Ansatz der Abstrakten Datentypen
Abstrakte Datentypen (ADT) beschreiben Objekte mit den zugehörigen, auf ihnen anwendbaren Operationen, unabhängig von der zugrundeliegenden Implementierung. Stattdessen wird das Verhalten des ADT, also die Wirkung der Operationen
beschrieben. Eine Sicht kann ebenso zu einem ADT erweitert werden, in welchem die
auf der Sicht definierten Operationen aus dem Anwendungskontext zusammengefaßt
werden. Die Semantik der formulierten Sicht führt zur Formulierung der notwendigen
Operationen. Änderungen auf der Sicht sind nur über die vorhandenen Operationen
möglich. Der Sichtdesigner hat die vollständige Kontrolle über die Effekte einer
Änderung, die sich unter Umständen nicht in der Sicht äußern. Unerwünschte Seiteneffekte können ebenfalls besser vermieden werden, indem bestimmte Operationen
nicht angeboten werden.
Dieser Ansatz hat einige bedeutende Vorteile ([FC85]):
1. Mehrdeutigkeiten der Änderungstranslation werden vermieden, da diese durch
die Festlegung der Operation in der Implementierung ausgeschlossen werden
können.
2. Es können genau solche Änderungen auf der Sicht angeboten werden, die dem
Anwendungskontext entsprechen und dadurch besonders benutzerfreundlich
sind.
5
Wird in [Lan90] genauer definiert, besagt, daß S alle funktionalen Abhängigkeiten erfüllt, d. h.
konsistent ist.
27
28
Das View-Update-Problem
3. Integritätsbedingungen können gleich in den Operationen geprüft werden, bzw.
sind sie den Operationen zum Teil inhärent.
Da auf Datenbankobjekte jedoch von verschiedenen Benutzern zugegriffen wird,
müssen zusätzlich Vorkehrungen für den konkurrierenden Zugriff bei der Implementierung der Operationen bedacht werden. Auch ist die Formulierung der nötigen
Operationen mit einigem Arbeitsaufwand verbunden. Erleichtert wird die Implementation durch Konstrukte wie Spracherweiterungen und die Definition von Objekten
als Datenbankobjekte, die das zugehörige DBMS anbietet, z. B. SQL/DS. Dieser
Ansatz wird auch in [TFC83] verfolgt.
2.3.3
Änderung unvollständiger Informationen
Änderungen auf Sichten sind nicht vollständig spezifizierte Änderungen auf den Basisrelationen des zugrundeliegenden Datenbankschemas. Die auszuführenden Änderungen müssen erst noch spezifiziert werden. Daher gibt es einen allgemeineren (und
sehr theoretischen) Ansatz für das View-Update-Problem, der hier nicht weiter verfolgt wird. Es sei auf [AHV95] verwiesen, wo weitere Literaturangaben zu finden
sind.
Die Verwendung von Tabellen mit Bedingungen (conditional tables, c-tables) stellen
Tabellen dar, in denen Bedingungen festgelegt werden, die eine genaue Spezifizierung
bestimmter Änderungen ermöglicht. Dabei sind nur Änderungen erlaubt, die den
Bedingungen der Tabellen genügen.
Wird ein Datenbankschema als die Repräsentierung einer logischen Theorie aufgefaßt, so ergibt sich ein allgemeinerer Ansatz als der der c-tables. Zu einer logischen
Theorie T , also eine Menge logischer Aussagen, wird die Menge der Modelle mit
M od(T ) bezeichnet. Ist |M od(T )| > 1, dann repräsentiert T unvollständige Informationen.
Dieser Ansatz sei hier nur erwähnt, um einen anderen Blickwinkel auf Sichtänderungen zu zeigen, in dem weniger im Vordergrund steht, daß die Sicht eine Funktion
auf einem Datenbankschema ist. Im Umfeld relationaler Datenbanken scheint dieser
Ansatz jedoch weniger interessante Ergebnisse zu liefern.
2.4
Bewertung und eigener Ansatz
Die Betrachtung wesentlicher Lösungsansätze für das View-Update-Problem in den
obigen Abschnitten zeigt die eingeschränkten Möglichkeiten für die automatische
Übersetzung von Änderungsoperationen auf Sichten in Operationen auf den zugrundeliegenden Relationen. Für das hier verfolgte Ziel, die Generierung von Benutzermasken aus zugehörigen Sichten, bedeutet das, daß entweder die verwendbaren
Sichten sehr stark eingeschränkt werden müssen oder die Änderungsfähigkeit auf
andere Weise sichergestellt werden muß.
Der Ansatz der Sicht-Abhängigkeits-Graphen ist für diese Arbeit am interessantesten. Der Zusammenhang zwischen den Sichtattributen und den zugehörigen Quellen
2.4 Bewertung und eigener Ansatz
29
und damit die Bewertung der Änderungsmöglichkeiten wird algorithmisch zugänglich gemacht. Über die Suche von Pfaden in den beschriebenen Graphen können
änderbare Attribute aus der Sichtdefinition identifiziert werden, unabhängig vom aktuellen Datenbankzustand. Für Selektions- und Projektionssichten, die nur auf einer
Relation definiert sind, zeigt der Ansatz exakte Übersetzungen für alle betrachteten
Änderungsoperationen. Bei Verbundsichten ist aus dem Abhängigkeits-Graphen ablesbar, welche Änderungen übersetzbar sind. Im Hinblick auf das Ziel dieser Arbeit,
die Generierung einer Update-Maske zu einer Sicht, sollen einige Einschränkungen
vorgenommen werden. Neben der Struktur des Abhängigkeits-Graphen ist auch die
Form der Änderung entscheidend für die Übersetzbarkeit, insbesondere, welche Attribute und damit welche Quelltupel betroffen sind. In einer Maske sollen daher schon
einige Änderungsmöglichkeiten ausgeschlossen werden. Betrachten wir zunächst als
einfaches Beispiel eine Sicht, in der eine Relation R1 eine Fremdschlüsselbeziehung
zu einer anderen Relation R2 hat. Gegeben seien die Relationenschemata
1. R[NR,DATUM,NAME] für Rechnungen und
2. P[RECHNUNG,POS,ARTIKEL] für zugehörige Rechnungsposten,
die Primärschlüssel
1. NR →R {DATUM,NAME} und
2. {RECHNUNG,POS} →P ARTIKEL,
und der Fremdschlüssel P [RECHNUNG] ⊆ R[NR], der gewährleistet, daß ein Rechnungsposten zu einer Rechnung gehört. Die Sicht V sei folgendermaßen definiert:
V = πY (R o
nNR=RECHNUNG P )
wobei
Y = {R.NAME, R.DATUM, R.NR, P.POS, P.ARTIKEL}
In der Sicht V werden Rechnungen mit den zugehörigen Rechnungspositionen angezeigt. Der in Abbildung 2.8 gezeigte Abhängigkeits-Graph zu V macht deutlich,
welche Änderungsoperationen exakt übersetzbar sind. Werden beim Löschen nur
die Attribute Y spezifiziert, die V -Spuren von P sind, dann ist eine Übersetzung
möglich, da ein Pfad P D(V) Y existiert. Wird zusätzlich ein Attribut spezifiziert,
R.NAME
R.DATUM
R.NR
V.NAME
V.DATUM
V.NR
P.RECHNUNG
P.POS
P.ARTIKEL
V.POS
V.ARTIKEL
Abbildung 2.8: Abhängigkeits-Graph zur Sicht V = πY (R o
nNR=RECHNUNG P )
welches direkte V -Spur eines Attributs von R ist, dann gibt es keinen Pfad von
diesem Attribut zu den Sichtattributen V.POS und V.ARTIKEL. Die Integritätsbedingungen ermöglichen die Übersetzung einer Einfügeänderung, da die Bedingungen
30
Das View-Update-Problem
in Theorem 2.6 erfüllt sind. Die Ersetzungsänderung ist exakt übersetzbar, falls nur
Attribute einer Relation betroffen sind oder keine Join-Attribute geändert werden.
Die mit der formulierten Fremdschlüsselbedingung intendierte Abhängigkeit der Relation P von der Relation R soll besonders berücksichtigt werde. Um Änderungen
auf der Relation R in der oben beschriebenen Weise zuzulassen, muß diese besondere
Bedeutung von R kenntlich gemacht werden, da dies nicht aus der Sichtdefinition und
dem Datenbankschema hervorgeht. Diese Relation soll sogenannte Master-Relation
der Sicht sein, während P sogenannte Child-Relation ist.
Definition 2.45 Sei RM [XM ] eine Relationenschema mit einem Schlüsselkandi•
0
0
daten XM
⊆ XM , so daß eine Instanz RM [XM ] existiert, für die XM
→RM
XM gilt, und RC1 [X1 ], . . . , RCn [Xn ] Relationenschemata, für welche Instanzen
RC1 [X1 ], . . . , RCn [Xn ] existieren, welche die Fremdschlüsselbeziehungen der Form
0 ], . . . , R [X 0 ] ⊆ R [X 0 ] erfüllen, wobei X 0 ⊆ X . Dann heißt
RC1 [X10 ] ⊆ RM [XM
i
Cn
M
n
i
M
RM Master-Relation und jede Relation RCi Child-Relation.
Die in Abschnitt 2.2 vorgestellten Algorithmen und Theoreme werden im folgenden auf Master-Child-Sichten“ angewendet. Dabei interessieren uns nur exakte
”
Übersetzungen, einfache Übersetzungen wollen wir nicht zulassen. Im folgenden
sei S ein Datenbankschema, bestehend aus den Relationenschemata RM [XM ] und
RCi [Xi ], i = 1, . . . , n, zu denen eine Master-Relation RM [XM ] und entsprechende
Child-Relationen RCi [Xi ], i = 1, . . . , n gehören, und V[Y ] eine Equijoin-Sicht der
Form
0 =X 0 . . . o
0 =X 0 RC )
V = πY (RM o
nY 0 =X10 RC1 o
nXM
nXM
n
n
2
0 und X 0 wie in Definition 2.45. Abbildung 2.9 zeigt den Abhängigkeitsmit XM
i
Graphen zu so einer Sicht V.
M.Xl
V.MXl
M.X1
V.MX1
M.Pk
V.MPk
M.P1
C1.P1
V.C1P1
C1.Pk
V.C1Pk
C1.X1
V.C1X1
C1.Xm1
V.C1Xm1
Cn.P1
V.CnP1
Cn.Pk
V.CnPk
Cn.X1
V.CnX1
V.MP1
Cn.Xmn
V.CnXmn
Abbildung 2.9: Abhängigkeits-Graph zu einer Sicht V über der Master-Relation M
mit dem Schlüsselkandidaten X 0 = {P1 , . . . , Pk } und den Child-Relationen Ci .
2.4 Bewertung und eigener Ansatz
2.4.1
31
Löschänderungen
Beim Löschen muß die bestehende Fremdschlüsselbeziehung zwischen Master- und
Child-Relation beachtet werden, so daß beim Löschen eines Tupels aus der MasterRelation auch die zugehörigen Tupel der Child-Relationen gelöscht werden müssen.
Algorithmus 2.4
Für alle R ∈ S, die eine V -Spur in der Menge Y ∗ der Attribute, die in der Löschbedingung spezifiziert sind, definiere
T = {t0 ∈ R | t ist Quelltupel eines v ∈ V [Y = y]}
und
1. falls R Master-Relation, lösche in allen Child-Relationen RCi die Menge
{t | r ∈ T t.Xi0 = r.Y 0 },
2. lösche die Menge T .
Lemma 2.5 Seien S und V[Y ] wie oben. Dann ist Algorithmus 2.4 eine exakte
Übersetzung der Löschänderung u(V ), falls für alle X ∈ R gilt
X
D(V)
Y∗
wobei R ∈ S und ∃R Zustand von R, so daß R Quelltupel eines v ∈ V [Y ∗ = y]
enthält, und Y ∗ die Menge der Attribute, die in der Löschbedingung spezifiziert sind.
Das Lemma 2.5 ist eine Folgerung des Theorems 2.4 aus Abschnitt 2.2 und der
Algorithmus berücksichtigt entsprechende Fremdschlüsselbeziehungen.
2.4.2
Einfügeänderungen
Der Algorithmus zum Einfügen kann unverändert übernommen werden, da dieser
das Einfügen nicht-spezifizierter Attribute beachtet. Die Sicherung der Integritätsbedingung wird vom DBMS sichergestellt.
Algorithmus 2.5
1. Sei v einzufügendes Tupel in V , für alle Ri [Xi ] ∈ Rels(V ) definiere ti ∈
dom(Xi ) für alle A ∈ Xi
(a) falls V.A V -Spur von Ri .A und v.A 6= N U LL dann setze ti .A = v.A
sonst falls ∃L →Ri A ∃t0i ∈ Ri ti .L = t0i .L und t0i .A 6= N U LL dann setze
ti .A = t0i .A
(b) falls ∃Rj .B Rj .B T (V) Ri .A dann setze ti .A = tj .B
sonst setze ti .A = N U LL
2. für alle i ∈ I(V) reduce(Ri ∪ {ti })
Lemma 2.6 Seien S und V[Y ] wie oben. Algorithmus 2.5 ist eine exakte Übersetzung der Einfügeoperation u(V ) falls
32
Das View-Update-Problem
1. falls Y1 und Y2 V -Spuren des gleichen Attributs Ri .X, v.Y1 6= N U LL und
v.Y2 6= N U LL, dann ist v.Y1 = v.Y2 ,
2. QualV (ti1 , . . . , tip ) = true,
3. ∀Ri ∈ S, Ri 6= RM
0 ] und
Ri ∪ {ti } erfüllt Ri [Xi0 ] ⊆ RM [XM
0 , B ∗ ).
4. EXISTRM (XM
0 Schlüsselkandidat von R[M ] und
Dabei ist ti wie in Algorithmus 2.5 berechnet, XM
∗
B = {A ∈ RM | A ist Attribut in der Sichtbedingung}.
Aus Theorem 2.6 folgt unmittelbar Lemma 2.6, da die Sicht über den MasterChild-Relationen und die Master-Child-Relationen die funktionale und die Inklusionsabhängigkeit in der Bedingung des Theorems erfüllen.
2.4.3
Ersetzungsänderungen
Das Ersetzen von Tupeln ist auf Master-Child-Sichten unverändert mit Hilfe des in
Abschnitt 2.2 vorgestellten Algorithmus möglich, da die Sicherung der Integritätsbedingungen vom DBMS sichergestellt wird. Da die zu ersetzenden Tupel genauso
bestimmt sind wie in obigen Abschnitt, ist das Ersetzen in den Master- und ChildRelationen ein unproblematischer Spezialfall.
Algorithmus 2.6
1. für alle Ri ∈ URels(V) setze Ti := {ti ∈ Ri | ti ist Quelltupel eines v ∈ V u }
und für alle ti ∈ Ti definiere tri durch
r
v .A A ist V-Spur von Ri .A,
r
ti .A =
ti .A sonst
2. für alle Ri ∈ URels(V) und für alle tri aus Schritt 1 und für alle A ∈ Xi
falls ∃L →Ri A ∃t0i ∈ Ri (t0i 6∈ Ti ∧ t0i .L = tri .L) dann setze t0i .A = tri .A
3. für alle Ri ∈ URels(V)
setze Ri =reduce({Ri \ Ti } ∪ Tir ), wobei Tir = {tri | ti ∈ Ti }
Lemma 2.7 Seien S und V[Y ] wie oben. Algorithmus 2.6 ist eine exakte Übersetzung der Ersetzungsoperation u(V ) falls
1. V.A1 , V.A2 zwei V -Spuren des gleichen Attributs Ri .A, dann ist für v ∈
V u v r .A1 = v r .A2 ,
2. ein Generator g = (ti1 , . . . , tip ) von v ∈ V u existiert, dann ist g r = (tri1 , . . . , trip )
Generator von v r , trij , wobei tr = t für alle Tupel t, die nicht in Algorithmus 2.3
berechnet werden.
3. falls für alle Ri [Xi ] ∈ URels(V) ein Pfad Xi
D(V )
Y ∗ existiert, und
4. falls für alle A ∈ V gilt: falls A ∈ W V -Spur einiger Ri .A ist, die in einer joinKlausel in <Qualifikation> vorkommen, dann existiert ein Pfad Xi D(V )
Y.
2.4 Bewertung und eigener Ansatz
Lemma 2.7 ist identisch mit Theorem 2.7, angewendet auf ein Datenbankschema mit
Master-Child-Relationen. Das liegt daran, daß die Bedingungen der Beziehung von
Master- und Child-Relationen unabhängig von den Bedingungen des Theorems 2.7
sind und die Übersetzbarkeit primär von der Menge der geänderten Attribute und
der Menge der Attribute in der Änderungsbedingung abhängt.
Die Möglichkeiten der Übersetzung von Sichtänderungen sind bis hier ausreichend
untersucht worden, viel weitergehende Möglichkeiten gibt es zur Zeit in der Theorie
nicht. Eine denkbare Erweiterung wäre die Übertragung des Begriffs der MasterRelation auf die Child-Relationen, die ihrerseits in Beziehung zu Child-Relationen
stehen usw. Dadurch entsteht eine Hierarchie der Relationen, an deren Spitze die
Master-Relation steht, unmittelbar darunter ihre Child-Relationen, darunter deren
Child-Relationen usw. Dieser Ansatz soll hier aber nicht weiter verfolgt werden. Doch
theoretisch sollte diese Verallgemeinerung möglich sein, da die wesentlichen Bedingungen mit den Pfaden in den Sicht-Abhängigkeits-Graphen weiterhin anwendbar
sind und die gleichen Ergebnisse liefert.
Ein anderer Ansatz wäre die Umsetzung der Master-Child-Beziehung durch die
Einführung des nest-Operators auszudrücken, so daß die Hierarchie deutlicher erscheint. Um eine leichte Umsetzung des hier verfolgten Ziels zu haben, wurde der
Ansatz nur auf flachen“ Relationen betrachtet, die von einer großen Anzahl gängi”
ger DBMS unterstützt werden.
2.4.4
Eingeschränkte Übersetzungen
In Hinblick auf die zu generierenden Masken ist die Anzeige weiterer, nicht änderbarer Informationen interessant und soll daher in das Sichtkonzept aufgenommen
werden. Das der Sicht zugrundeliegende Datenbankschema soll dafür neben den
Master- und Child-Relationen noch Partner-Relationen enthalten, die weitere Quellen der Sicht darstellen, aber deren V -Spuren nicht änderbar sind und daher die
Änderbarkeit auf der Sicht nicht beeinflussen. Diese Idee sei an dem Beispiel zu
Anfang dieses Abschnitts erläutert. Das Datenbankschema umfasse die Relationenschemata
1. R[NR,DATUM,NAME],
2. P[RECHNUNG,POS,ARTIKEL] und
3. A[NAME,STRASSE,ORT],
die Primärschlüssel
1. NAME →A {STRASSE,ORT},
2. NR →R {DATUM,NAME} und
3. {RECHNUNG,POS} →P ARTIKEL,
und die Fremdschlüssel
1. R[NAME] ⊆ A[NAME] und
2. P [RECHNUNG] ⊆ R[NR].
33
34
Das View-Update-Problem
Die Sicht V sei durch
V = πY ((R o
n A) o
nNR=RECHNUNG P )
definiert, wobei
Y = {A.STRASSE, A.ORT, A.NAME, R.DATUM, R.NR, P.POS, P.ARTIKEL}
Abbildung 2.10 zeigt den zugehörigen Abhängigkeits-Graph. Es wird angenommen,
daß R Master-Relation, P Child-Relation und A Partner-Relation ist. Dies ist nicht
zwingend vorgeschrieben, durch die Fremdschlüsselbeziehungen ist es auch möglich,
A als Master-Relation zu wählen. Dann ist R zugehörige Child-Relation und P
Partner-Relation. Erst durch Festlegen einer Master-Relation werden die anderen
in der Sicht beteiligten Relationen klassifiziert und anhand der Fremdschlüsselbeziehungen in Child- und Partner-Relationen eingeteilt. Neben den Rechnungsposten
wird jetzt auch die Anschrift einer Rechnung in der Sicht angezeigt. Zwar können in
einem bestimmten Umfang auch Änderungen an den Attributen, die V -Spur von Attributen des Schemas A sind, vorgenommen werden, jedoch soll der Schwerpunkt auf
den Rechnungstupeln liegen und daher Übersetzungen auf die Relationen R und P
eingeschränkt werden. Andernfalls würde z. B. das Löschen eines Sichttupels durch
Angabe allein der Attribute von A die Löschung aller Rechnungen und zugehöriger
Rechnungstupel zu einer Adresse nach sich ziehen. Der Umfang solch einer Änderung
hat also einen relativ großen Seiteneffekt, der zwar der Semantik der formulierten
Änderung entspricht, dessen Konsequenzen aber eventuell nicht überblickt werden.
Daher soll der Fokus auf eine Master-Relation gelenkt werden, die neben eventuell
A.STRASSE
A.ORT
A.NAME
V.STRASSE
V.ORT
V.NAME
R.NAME
R.DATUM
R.NR
V.DATUM
V.NR
P.RECHNUNG
P.POS
P.ARTIKEL
V.POS
V.ARTIKEL
Abbildung 2.10: Abhängigkeits-Graph zur Sicht V = πY ((R o
n A) o
nNR=RECHNUNG
P)
vorhandener Child-Relationen änderbar ist. Alle beteiligten Partner-Relationen stellen nur Kontextinformationen zu einer Master-Relation zur Verfügung, sollen aber
in dieser Sicht statisch bleiben.
Definition 2.46 Sei V[Y ] eine Sicht über dem Datenbankschema
S = {R1 [X1 ], . . . , Rn [Xn ]}.
Sei Rk ⊆ S beliebige Teilmenge von Relationenschemata. Dann ist eine Änderung
u(V ) eingeschränkt auf Rk übersetzbar, wenn die Änderung u(πY ∗ (V )) auf der Sicht
πY ∗ (V ) exakt übersetzbar ist. Dabei ist
Y ∗ = {A ∈ V | ∀R ∈ Rk ∃B ∈ R
A ist V -Spur von B}
die Menge der V -Spuren der Attribute der Schemata aus Rk .
2.4 Bewertung und eigener Ansatz
Eingeschränkte Übersetzungen führen Änderungen nur auf den spezifizierten Relationen aus. Dies entspricht zwar nicht dem eigentlichen Begriff der Übersetzung
einer Sichtänderung, es sollen aber Kontextinformationen in die Sicht aufgenommen
werden, deren Änderbarkeit nicht erlaubt und daher nicht zu untersuchen ist. Unter Berücksichtigung der Bedingungen für die Übersetzbarkeit von Änderungen auf
Master-Child-Sichten sind beliebige Sichten denkbar, deren Änderbarkeit von den
zugrundeliegenden Master- und Child-Relationen abhängt. Die Übersetzungsalgorithmen in diesem Abschnitt brauchen nur in soweit modifiziert werden, daß sie nur
Relationen berücksichtigen, auf denen die Übersetzung eingeschränkt ist.
35
36
Das View-Update-Problem
Kapitel 3
Konzeption eines
Maskengenerators
Nach der Untersuchung der Problematik der Übersetzung von Sichtänderungen wird
jetzt ein Konzept für die Realisierung eines Maskengenerators vorgestellt. Der erzeugten Maske soll eine Sicht zugrundeliegen, so daß Änderungen in der Maske,
d. h. auf den dargestellten Tupeln, als Änderungen auf der Sicht interpretiert werden können. Mit Hilfe des beschriebenen eigenen Lösungsansatzes soll eine solche
Änderung übersetzt werden. Anhand von Anwendungsfällen wird der Systemumfang
abgesteckt. Eine Klassifizierung der Objekte innerhalb des Systems wird anschliessend vorgenommen, die Funktionen der Klassen und ihre Beziehungen untereinander
erläutert und auf Probleme hingewiesen, die bei einer Implementierung zu berücksichtigen sind.
Im folgenden werden Elemente der Unified Modeling Language (UML) für die Beschreibung verwendet. Weitere Informationen zur UML finden sich in [RJB99],
[BRJ99], [JBR99] und [Oes97]. Es wird der Umfang des Systems vorgestellt und
in den darauf folgenden Abschnitten die wesentlichen Bestandteile beschrieben.
3.1
Ausgangsidee und Systemumfang
Die grundlegende Idee ist, daß eine Maske einen Ausschnitt der Informationen einer
Datenbankinstanz darstellt, der von dem Kontext, in dem die Maske verwendet wird,
abhängt. Eine Sicht über den Relationen der Datenbankinstanz soll genau diesen
Ausschnitt berechnen. Der Vorteil einer Sicht ist die Abstraktion der Informationen
von den zugrundeliegenden Relationen, der vereinfachte Zugriff auf relevante Informationen und die Beschränkung des Zugriffs für verschiedene Benutzer(gruppen).
Eine auf der Sicht aufsetzende Maske soll die von dieser Sicht gelieferten Informationen benutzerfreundlich aufbereiten. Die Sicht stellt eine Art Datenstruktur für die
Maske dar, die Maske selbst ist die zugehörige Benutzerschnittstelle. Die dadurch
gewonnene Trennung erlaubt z. B. eine leichtere Änderbarkeit der Benutzerschnittstelle unabhängig von der zugrundeliegenden Datenstruktur und umgekehrt.
Das zu verwendende Datenbanksystem soll relational sein und SQL als Anfrage- und
Modifikationssprache beherrschen.
38
Konzeption eines Maskengenerators
Für die Konzeption ist grundsätzlich zu unterscheiden zwischen dem
1. Maskenentwerfer, der ausgehend von einem vorhandenen Datenbankschema
eine Sicht generiert, die einer Maske zugrundeliegt, deren Aussehen und Verhalten er zusätzlich festlegt, und dem
2. Maskenbenutzer, der als Anwender über die Maske Zugriff auf die Datenbank
erhält und entsprechend den Spezifikationen des Maskenentwerfers Änderungen und Anfragen ausführen darf.
Das zu implementierende System umfaßt dementsprechend zwei Programme, ein
Entwurfswerkzeug für die Sicht- und Maskenspezifikation und eine Ausführungsumgebung, welche die spezifizierte Maske und Bedienelemente für grundlegende Funktionen anbietet. Die Maske wird auf einem möglichen Zustand des Datenbankschemas operieren. In Abbildung 3.1 wird ein Überblick über die möglichen Anwendungsfälle und die Schnittstellen des Systems nach außen skizziert. Im Entwurfs-
Abbildung 3.1: Anwendungsfälle des Maskengenerators und der Ausführungsumgebung der Maske
werkzeug wird die Sicht spezifiziert, die daraufhin im DBS erzeugt werden kann.
Anschließend können Einstellungen zu den Attributen der Sichtrelation vorgenommen werden und das Layout der Maske angegeben werden, indem die Attribute in
der Maske plaziert werden. Es soll die Möglichkeit bestehen, ein Standardlayout der
Maskenelemente automatisch zu generieren. Sind alle Angaben zur Maske gemacht,
3.1 Ausgangsidee und Systemumfang
so kann diese generiert und in der Ausführungsumgebung verwendet oder auch in
eigene Anwendungen integriert werden. Die Ausführungsumgebung ermöglicht dem
Benutzer, Daten auszuwählen, diese zu manipulieren und Daten zu exportieren, z. B.
ein oder mehrere Tupel in einem Report auszudrucken oder über einen geeigneten
Filter in andere Programme wie z. B. Textverarbeitung zu übernehmen. In eine eigene Anwendung integriert ist die Maske voll funktionsfähig, die Anwendung muß
dafür die benötigte Infrastruktur, also den Datenbankzugriff, bereitstellen. Dies wird
durch die Ausführungsumgebung der Maske zwar gewährleistet, es soll jedoch auch
möglich sein, andere Programmumgebungen zu verwenden. Zusätzliche Operationen der Maske können durch Erweiterungen im Quelltext eingefügt werden. Das
legt eine objektorientierte Entwicklung nahe, da dann in Unterklassen die Funktionalität spezialisiert werden kann. Das vorgestellte Konzept ist objektorientiert, soll
aber weitestgehend unabhängig von einer Programmiersprache sein, die nur eine
Vererbungsmöglichkeit bieten muß. Allerdings wird vorausgesetzt, daß eine datenbankunabhängige Schnittstelle vorhanden ist.
Im folgenden werden die Anwendungsfälle konkretisiert, wobei das Konzept für die
Sichtspezifikation, für die Maskenspezifikation und für die Ausführungsumgebung
genauer dargestellt und in Klassendiagrammen der Umfang und die Beziehungen
verdeutlicht werden. Anhand dieser Abgrenzung des Systemumfangs wird das Konzept des Entwurfwerkzeugs erstellt.
Anhand der Anwendungsfälle kann eine Gruppierung der Klassen in Pakete vorgenommen werden. Die Teile des Systems, die allein während des Maskenentwurfs
benötigt werden und nicht während der Laufzeit einer Maske, können in dem Paket jforms zusammengefaßt werden. Dies sind im wesentlichen Klassen, die direkt
mit dem Maskengenerator JForms zusammenhängen. Für den Entwurf und für die
Laufzeit einer Maske werden Klassen benötigt, die zum einen gewisse allgemeine
Funktionen übernehmen und zum anderen Klassen, die im weiteren Sinne mit der
Datenbank zusammenhängen. Innerhalb dieses Konzepts werden Klassen mit allgemeinen Funktionen nur für die Realisierung der Sicht-Graphen benötigt. Diese sollen
in dem Paket graph zusammengefaßt werden. Klassen für die Datenbankinteraktion
werden dem Paket db zugeordnet, welches wegen der komplexen Aufgaben noch weiter unterteilt werden muß. Vorausgesetzt wird eine Datenbankinstanz, deren Schema abfragbar ist. Eine Unterteilung in einen statischen Teil, dem Datenbankschema,
und einen variablen Teil, der Datenbankinstanz, wird durch die Pakete db.scheme
und db.instance realisiert. Die Benutzeroberfläche der Maske sowie Klassen für
die Interaktion mit der Datenbank werden auch innerhalb des Pakets db angesiedelt
und gehören konkret zum Paket db.form. Da die Darstellung von Datenbankwerten in einer Maske durch die Vielzahl verschiedener Datentypen relativ komplex
ist, ist das Zusammenfassen solcher Klassen sinnvoll. Dies geschieht in dem Paket
db.form.field. Abbildung 3.2 zeigt die Abhängigkeiten der Pakete untereinander.
Die Klassen des Pakets jforms sind abhängig von Klassen des Pakets graph, welches
die Klassen zum Aufbau des Spur- und Abhängigkeitsgraphen umfasst und von den
Klassen des Pakets db. Innerhalb des Pakets db sind die Pakete db.instance und
db.form von db.scheme abhängig, da hier alle Strukturinformationen zusammengefaßt sind. Bestandteile der Maske aus dem Paket db.form interagieren mit Klassen
aus db.instance und sind daher von diesen abhängig.
39
40
Konzeption eines Maskengenerators
Abbildung 3.2: Pakete des Maskengenerators und der Ausführungsumgebung
3.2
3.2.1
Spezifikation der Sicht
Schemastruktur und Aufbau der Sicht
Da die Maske auf einer Relation operiert, nämlich der Sichtrelation, kann der Ansatz aus Abschnitt 2.4 als Grundlage genommen werden. Dazu wird eine Relation
des Datenbankschemas als Master-Relation ausgezeichnet, deren Attribute änderbar
sind. Weiter müssen die verwendeten Partner-Relationen ausgewählt werden, welche
die Quellen der in der Sicht gewünschten Attribute liefern. Ein Teil dieser PartnerRelationen werden als Child-Relationen klassifiziert, deren Attribute in der Sicht
ebenfalls änderbar sind. Es sollen keine Einschränkungen des zugrundeliegende Datenbankschemas gemacht werden, jedoch kann die Bestimmung der Child-Relationen
nur funktionieren, wenn diese den beschriebenen Bedingungen der FremdschlüsselBeziehung zur Master-Relation genügen. Die Einteilung in Child- und PartnerRelationen kann automatisch erfolgen, wenn die Fremdschlüssel-Beziehungen bekannt sind. Eventuell ist ein Re-Design des Datenbankschemas vorteilhaft, um die
Funktionalität der zu entwerfenden Maske zu vergrößern.
Da die Generierung der Sicht in SQL erfolgt, entspricht die Auswahl der in der Sicht
verwendeten Relationen der From-Klausel in SQL. Es sollte daher auch möglich
sein, relationenwertige Anfragen anzugeben, die in der From-Klausel formulierbar
sind und keine Relation des Datenbankschemas darstellen, sondern zur Ausführungszeit berechnet werden (berechnete Relation). Allerdings wurde in dieser Arbeit nicht
weiter untersucht, ob dies zu weiteren Problemen führen kann. Es ist jedoch anzunehmen, daß dies unbedenklich ist, wenn solche Relationen als Partner-Relationen
deklariert werden und damit nicht änderbar sind.
Die Auswahl der in der Sicht vorkommenden Attribute aus den angegebenen Relation entspricht der Select-Klausel in SQL. Auch hier ist es möglich, berechnete
Attribute anzugeben. Diese sind jedoch grundsätzlich nicht änderbar, ebenso wie die
Attribute der berechneten Relationen.
Die anzugebende Sichtbedingung entspricht der Where-Klausel in SQL. Fremd-
3.2 Spezifikation der Sicht
schlüsselbeziehungen der angegebenen Relationen werden in der Sichtbedingung automatisch berücksichtigt, indem entsprechende Equi-Joins formuliert werden.
Sind alle Angaben gemacht, so kann die Sicht generiert werden, wobei die Sichtanfrage in SQL aus diesen drei Elementen aufgebaut wird. Welche Änderungen auf
der Sicht durchführbar und in Änderungen auf dem Datenbankschema übersetzbar
sind, hängt von den Beziehungen der beteiligten Relationen und der Änderung selbst
ab. Dafür werden die Graphen aus Kapitel 2 verwendet. Die Beziehungen werden
im Sicht-Abhängigkeits-Graphen deutlich und entsprechend dem Maskenentwerfer
mitgeteilt. Durch Angabe der Master-Relation werden mögliche Child-Relationen
angezeigt, die in die Sicht aufgenommen werden können und deren Attribute ebenfalls änderbar sind. Die Attribute der Relationen der Sicht, die weder Master- noch
Child-Relation sind, also Attribute von den sogenannten Partner-Relationen, sind
nicht änderbar. Sichtänderungen werden nur eingeschränkt auf Master- und ChildRelationen übersetzt.
Das Datenbankschema wird intern durch die Klassen in Abbildung 3.3 dargestellt.
Die Klassen Scheme, Table und Column stellen das vorliegende Datenbankschema
dar, wobei Table und Column einem Scheme angehören und daher als gemeinsame Oberklasse SchemeElement haben. Eine Tabelle (Table) umfaßt keine oder mehrere Spalten (Column) und gehört zu einem Schema (Scheme). Informationen wie
Primärschlüssel, Not-Null-Attribute, Datentypen werden in der Klasse Column dargestellt und sind nicht änderbar. Diese Klassen stellen die Grundlage für den Aufbau
der Sicht dar, da sie die benötigten Informationen zur Verfügung stellen und anhand
derer die Sichtrelationen und Sichtattribute ausgewählt werden. Die Sicht (View) besteht daher aus den Klassen ViewTable und ViewColumn. Ebenso wie beim Schema
haben die Elemente einer Sicht eine gemeinsame Oberklasse ViewElement. Diese
basieren auf Objekten vom Typ Table oder Column aus der Datenbank. Eine ViewTable basiert auf einer Table und ist entweder Master-, Child- oder Partner-Relation
in der Sicht. Durch Auswahl der Sicht-Relationen ist auch die Menge der möglichen
Sicht-Attribute bestimmt, die durch die Klasse ViewColumn dargestellt werden. Diese Klasse, die auf einer Column basiert, ist besonders für den Entwurf der Maske
später entscheidend. Je nach Datentyp von Column ist auch die Darstellung des
Sicht-Attributs ViewColumn unterschiedlich. Die Klasse View ist zentrale Klasse bei
der Sichtdefinition. Parallel zur Auswahl der Sichtelemente werden im Hintergrund
die Sicht-Graphen zu der Sicht aufgebaut, was in Abschnitt 3.2.2 beschrieben wird.
Entsprechend der Model-View-Controller Architektur (siehe auch [ELW98]) stellt die
Klasse View das Modell einer Sicht dar, welches an verschiedenen Stellen in JForms
auf unterschiedliche Art und Weise dargestellt wird. Die Modellklassen ViewTableListModel, ViewColumnListModel und ViewTreeModel sind daher die Schnittstelle von
View zur Benutzerschnittstelle des Maskeneditors JForms.
Über die Klasse MetaScheme soll der Zugriff auf die Klassen des Datenbankschemas
gekapselt werden und ein leichter Zugang zu den enthaltenen Elementen geschaffen
werden. Wichtig ist, das schon im Datenbankschema vorhandene Sichten als Relationen erscheinen, d. h. durch die Klasse Table repräsentiert werden. Die Klasse View
ist die aktuell entworfene Sicht.
41
42
Konzeption eines Maskengenerators
Abbildung 3.3: Übersicht der Klassen zu einem Datenbankschema
3.2.2
Modellierung des Spur- und des Abhängigkeits-Graphen
Da die Algorithmen aus Abschnitt 2.4 verwendet werden, werden Klassen benötigt,
die die notwendigen Graphen implementieren. Parallel zur Spezifizierung der Sicht
wird der zugehörige Spur- und Abhängigkeits-Graph aufgebaut, der auch bei der
Anzeige der Maske für die Kontrolle der möglichen Änderungen verwendet wird.
Abbildung 3.4 zeigt die dafür notwendigen Klassen. Da es sich um gerichtete Gra-
Abbildung 3.4: Übersicht der Klassen zum Aufbau der Sicht-Graphen
phen handelt, gibt es die Oberklasse DirectedGraph, allerdings wird der Spur-Graph
nicht als gerichteter Graph realisiert, da seine Kanten zwar gerichtet sind, dies aber
grundsätzlich in beide Richtungen. Die Oberklasse Graph ist so realisiert, daß beim
Einfügen einer Kante zwischen zwei Knoten die beiden Knoten gegenseitig Vorgänger
und Nachfolger sind. In der Klasse DirectedGraph wird nur eine Kante von einem
Knoten zu seinem Nachfolger eingefügt. Da der Abhängigkeits-Graph die Kanten
des Spur-Graphen umfaßt, wird beim Aufbau eines Abhängigkeits-Graphen parallel
3.3 Entwurf der Maske
der Spur-Graph aufgebaut. Die Klasse View muß also nur den Abhängigkeits-Graph
aufbauen und erhält über diesen Zugriff auf den Spur-Graphen. Für die Übersetzung
einer Einfügeänderung wird explizit ein Pfad im Spur-Graphen gefordert, so daß die
Sicht nicht nur einen Abhängigkeits-Graphen benötigt. Für die drei Knotentypen
gibt es die Klassen ColumnNode für die Relationenattribute, ViewColumnNode für
die Sichtattribute und FDNode für die Knoten, welche funktionale Abhängigkeiten
darstellen. Alle sind Spezialisierungen der Oberklasse MetaSchemeNode, einer Unterklasse von Vertex. Da alle Informationen in den Knoten stehen, d. h. Objekte vom
Typ Column werden in ColumnNodes gespeichert und Objekte vom Typ ViewColum
in ViewColumnNodes, ist eine Modellierung von Kanten nicht notwendig. Die Kanten
werden über die Nachbar-Beziehungen in den Knoten realisiert. Das Einfügen von
Kanten wird durch Angabe zweier zu verbindender Knoten realisiert. In der Klasse
DirectedGraph muß allerdings die Sonderrolle von Pfaden über FD-Knoten bei der
Pfadsuche berücksichtigt werden. Dafür wird eine Modifikation der Breiten-Suche in
Graphen verwendet.
3.3
3.3.1
Entwurf der Maske
Aufbau einer Maske zu einer Sicht
Eine Maske besteht aus einem Informationsteil, der die Werte eines Tupels der Sicht
anzeigt, und aus einem Bedienteil für die Ausführung bestimmter Operationen, um
z. B. die Tupel einer Anfragemenge nacheinander anzuzeigen oder Änderungen eines
Tupels in die Datenbank zu schreiben. Der Bedienteil kann entweder in dem gleichen Fenster wie der Informationsteil der Maske oder aber auch in einem separaten
Fenster untergebracht sein. Der Informationsteil enthält zunächst die Felder eines
Tupels der Sicht.
Jedoch reicht dies nicht aus, um die Beziehung zwischen Master- und Child-Relation
oder auch komplexe Datentypen zufriedenstellend wiederzugeben. In dem Beispiel
mit den Rechnungen und den Rechnungsposten aus Abschnitt 2.4 gibt es zu jeder
Rechnung mehrere Rechnungsposten und in der Sicht ergibt sich eine große Redundanz der Werte der Rechnungsattribute. Idealer ist eine Darstellung, in der zu
einem Rechnungstupel die zugehörigen Posten angezeigt werden, die separat zu den
Werten der Rechnung sind. Dies führt allerdings unweigerlich zu einer Aufteilung“
”
der Sicht, in der die Sichtattribute zur Rechnungsrelation getrennt von den Sichtattributen zur Postenrelation behandelt werden. Wird z. B. eine bestimmte Rechnung
anhand der Rechnungsnummer gesucht, so werden die Anfragen
Select R[X] From V Where Nr=c
und
Select P[Y] From V Where Nr=c
ausgeführt. Die Rechnungstupel könnten z. B. in Form einer Tabelle innerhalb der
Maske zu einer Rechnung angezeigt werden.
Aus diesem Grund muß eine Möglichkeit geschaffen werden, um neben den Werten
einfacher Datentypen, welche in Feldern angezeigt werden, auch komplexe objekt-
43
44
Konzeption eines Maskengenerators
wertige Strukturen anzuzeigen. Diese können z. B. in Form von Submasken oder
eigenen Tabellen in die Maske integriert werden.
Eine Maske Form umfaßt ein Objekt vom Typ FormContainer, welches alle Elemente
enthält, die Werte der Datenbank oder sonstige Informationen darstellen. Die Klasse FormControl ist das Bedienelement der Maske, über welches der Maskenbenutzer
Operationen auf dem angezeigten Tupel in der Maske veranlassen kann. Um das
angezeigte Tupel in der Maske oder auch die Tupelmenge, auf denen die Maske zu
einem bestimmten Zeitpunkt operiert, zu exportieren, also z. B. als Report auszugeben, gibt es die abstrakte Klasse FormOutput, die eine Schnittstelle der Maskendaten
nach außen darstellt. Aufgrund der oben dargestellten Möglichkeit spezieller Darstel-
Abbildung 3.5: Klassenübersicht zum Paket db.form
lungsformen der Beziehung zwischen Master-Child-Informationen enthält eine Maske
oder genauer ein FormContainer neben Objekten des Typs FormField auch Objekte
vom Typ ComplexElement. Um z. B. ein unabhängiges Scrollen oder eine besondere
Form der Änderung zu ermöglichen, besteht eine Beziehung zwischen ComplexElement und einem eigenen Bedienteil des Typs FormControl. Die Klassen Record, Table
und List sind nur Beispiele für mögliche Realisierungen eines ComplexElements. Ein
Record stellt eine Art Submaske dar, z. B. innerhalb einer Rechnung die Darstellung
der Attribute eines Rechnungspostens. Eine Table kann z. B. für die Darstellung aller Rechnungstupel einer Rechnung in tabellarischer Form verwendet werden. Zur
Realisierung von Auswahllisten, deren Inhalt von bestimmten Attributen anderer
3.3 Entwurf der Maske
Relationen abhängen, wie z. B. Fremdschlüsselwerte, kann ein Objekt vom Typ List
verwendet werden. Die vorgestellten Klassen vom Typ ComplexElement benötigen
alle einen Zugriff auf die Datenbank, der unter Umständen unabhängig vom Zugriff
der Sicht ist.
Auch die einfachen Felder vom Typ FormField bieten vielfältige Darstellungsmöglichkeiten, dies zeigt Abbildung 3.6 noch genauer und wird im nächsten Abschnitt beschrieben.
Neben diesen Elementen der Maske, die einen direkten Bezug zu Datenbankwerten haben, sind auch Bestandteile der Maske möglich, die eine bestimmte Aktion
auslösen, sogenannte aktive Elemente (ActiveElement), wie z. B. Buttons. Dies wird
hier nicht weiter verfolgt, grundsätzlich ist aber die Spezialisierung der Klasse Form
möglich, die geeignete zusätzliche Methoden implementiert, um Aufrufe aktiver Elemente zu bearbeiten. Ein Objekt vom Typ ActiveElement kann einfach in das Layout
des FormContainers eingefügt werden. Durch die abstrakte Oberklasse FormContainerElement ist vorgegeben, daß implementierende Unterklassen Angaben zu ihrem
Layout an den FormContainer übergeben.
3.3.2
Spezifizierung der Maskenelemente und des Maskenlayouts
Von den in der Sichtrelation enthaltenen Attributen wird durch die Angabe der
Master-, Child- und Partner-Relationen festgelegt, ob sie änderbar sind oder nicht.
Weitere Angaben, welche das Aussehen und die möglichen Benutzerinteraktionen auf
den Maskenelementen, denen die Sichtattribute zugrundeliegen, festlegen, können im
nächsten Schritt gemacht werden. Dabei sind folgende Angaben für jedes Attribut
möglich:
• Attributwert sichtbar?
• Bezeichnung des Attributs.
• Auswahl des Anzeigeelements, welches den Wert des Attributs darstellen soll
(z. B. einfaches Textfeld, (Auswahl-)Liste, spezielles Datumsfeld, etc.) und die
Eingabe kontrolliert.
• Formatierung (z. B. für Datums- oder Zeitfelder).
• Default-Wert für Einfüge- und Suchoperation, falls der Wert des Attributs vom
Maskenbenutzer nicht spezifiziert wird.
• Nullwerte erlauben (soweit vom DBS erlaubt)?
• Änderungen erlauben (soweit vom DBS und anhand des Sicht-AbhängigkeitsGraphen erlaubt)?
• Suchen erlauben?
Soweit möglich, werden Informationen aus dem DBS hinzugezogen, um bestimmte
Voreinstellungen zu treffen, wie das Verbieten von Änderungen von Primärschlüsseln, Verbieten von Nullwerten bei Not-Null-Attributen etc. Dies ergibt sich aus der
45
46
Konzeption eines Maskengenerators
Sichtdefinition und ist im Maskenentwurf nicht änderbar. In den Klassen des Datenbankschemas Table und Column werden diese Informationen bereitgestellt. Änderungen hierzu müssen konkret am Datenbankschema vorgenommen werden. Da das
Entwurfswerkzeug auch als Bestandteil von Dato1 aufgerufen werden kann, können
solche Änderungen in Dato durchgeführt werden.
Um in der Maske die Tupelwerte anzuzeigen, wird jedem sichtbaren Attribut ein
Anzeigeelement zugeordnet, welches die Darstellung und unter Umständen die Eingabeprüfung des Werts übernimmt. Abbildung 3.6 zeigt die Oberklasse FormField
mit ihren Beziehungen zu Klassen des Datenbankschemas und der Datenbankinstanz, sowie möglichen Unterklassen, welche die Funktionalität implementieren, die
abhängig von dem anzuzeigenden Datentyp ist. Die Menge der Anzeigeelemente ist
Abbildung 3.6: Klassenübersicht zum Paket db.form.field
während des Maskenentwurfs fest vorgegeben. Eine Programmierschnittstelle bietet
allerdings die Möglichkeit, weitere Anzeigeelemente als Unterklassen hinzuzufügen,
so daß auch spezielle Darstellungsarten, z. B. für Bilder oder Audiodaten, ausgewählt
werden können. Das Anzeigeelement legt dabei fest, wie die Darstellung und Validierung der Werte erfolgen soll und welche Bearbeitungsfunktionen erlaubt sind.
Die Klasse FormField hat eine Verbindung zu einem Wert aus der Datenbank in der
Klasse Value und zur Beschreibung der Darstellung eine Verbindung zur Klasse ViewColumn. Der sichtbare Teil wird in einer Unterklasse von Component, einer Klasse
aus dem Java Developer Kit (JDK), dargestellt und der Inhalt von einem Validator überprüft. Um die Parameter in JForms einstellen zu können, gibt es zu jedem
implementierten FormField eine Unterklasse von FieldAdjust, welches die Benutzerschnittstelle für JForms liefert und die Parameter zu einem FormField speichert. Zu
jedem FormField gehören die Attribute visible, searchable,deleteable, insertable und
replaceable, die angeben, ob ein Feld sichtbar ist und ob es für die entsprechenden
1
Dato ist ein Datenbank-Administrations-Tool für beliebige DBMS, entstanden in der Studienarbeit [vH98] und in Java realisiert.
3.3 Entwurf der Maske
Änderungsoperationen spezifiziert werden kann. Die Implementierung eines FormFields muß dies geeignet berücksichtigen.
Für die Darstellung boolescher Werte ist die Klasse StateField gedacht, binäre Daten
haben die gemeinsame Oberklasse BinaryField, von denen als Beispiel die Klassen
ImageField zur Anzeige von Bildern und AudioField zur Darstellung“ von Sound”
Daten. Die Klasse TextField ist Oberklasse zur Darstellung aller Grunddatentypen.
Als Beispiel für mögliche Unterklassen gibt es CharField zur Darstellung von kürzeren
Zeichenketten, LongCharField zur Darstellung von längeren Texten (z. B. als Grundlage für Felder zur Darstellung von HTML-Seiten in der Klasse HTMLField) und
FormatField mit den Unterklassen TimeField, DateField und NumberField zur Darstellung von Uhrzeit, Datum und (formatierten) Zahlen. Die Klasse TimeStampField
besteht aus Datum und Uhrzeit und ist daher Unterklasse von DateField und TimeField. Bei der Realisierung muß die Mehrfachvererbung, die es z. B. in Java nicht gibt,
durch eine geeignete Konstruktion nachgebildet werden, z. B. durch entsprechende
Assoziationen.
Objekte vom Typ ChoiceElement sind Auswahllisten, die eine Auswahl vorgegebener
Werte anzeigen, von denen einer in die Datenbank eingefügt wird, z. B. für die Anrede
oder den Familienstand einer Personen-Relation.
Neben den Anzeigeelementen, welche sich auf Werte der Sicht beziehen, sind weitere
Maskenelemente wie Hintergrundbilder, Trennlinien etc. vorstellbar. Die Anordnung
der Maskenelemente soll in einem graphischen Editor erfolgen, der das spätere Aussehen der Maske sichtbar macht.
Die zu einem Anzeigeelement einstellbaren Werte müssen in geeigneter Form gespeichert, z. B. muß sich zu einem TextField die Breite oder die Änderbarkeit gemerkt
werden. Da die Menge der Anzeigeelemente beliebig erweitern läßt, sind diese Informationen für jedes Element extra zu speichern, eventuell zusammengefaßt in einer
Datei zu einer Sicht.
3.3.3
Abbildung der Datentypen
Die Zuweisung von Werten aus der Datenbank an Objekte geeigneter Java-Klassen
stellt ein eigenes Problem dar, welches hier kurz dargestellt werden soll. Dazu gehört
die Transformation der Datenbankwerte in Werte von Java-Typen und die Transformation des Java-Datentyps in eine bestimmte Form, die dem Benutzer in der Maske
angezeigt wird. So muß ein Datumswert aus der Datenbank im Java Datumsformat
gespeichert werden und in der Maske in einem bestimmten Format angezeigt werden.
Beim Einfügen oder Ändern eines Werts muß die entsprechende Rücktransformation vorgenommen werden. Neben diesen einfachen Datentypen muß insbesondere die
Transformation von komplexen oder objektwertigen Datentypen, wie sie von vielen
aktuellen DBMS unterstützt werden, betrachtet werden. Die JDBC-Schnittstelle2
bietet zwar geeignete Methoden, um Werte auf verschiedene Weise auszulesen. Diese müssen jedoch noch geeignet durch ein FormField oder ComplexElement dargestellt
2
JDBC ist die Java API zur Anbindung von Java Programmen an Datenbanken und besteht
aus einer Menge von Interfaces, die von den entsprechenden Datenbanktreibern realisiert werden.
JDBC ist nach [HCF97] eigentlich ein Warenzeichen, wird aber oft als Abkürzung für Java Database
Connectivity verstanden.
47
48
Konzeption eines Maskengenerators
werden. Die Tabelle 3.1 zeigt eine mögliche Transformation von SQL-Datentypen,
JDBC-Datentypen und Java-Datentypen, sowie den Klassen zur Darstellung dieser
Werte. [HCF97] enthält weiterführende Informationen zu dieser Problematik. InsbeSQL Typ
JDBC Typ
Größe
[byte]
CHAR
CHAR
255
String
CharField
VARCHAR2
VARCHAR
255
String
LongCharField
LONG
LONGVARCHAR
String
LongCharField
NUMBER
NUMERIC
math.BigDecimal
NumberField
NUMBER
DECIMAL
math.BigDecimal
NumberField
NUMBER
BIT
NUMBER
TINYINT
1
byte
1
short
2
NumberField
NUMBER
SMALLINT
2
short
2
NumberField
NUMBER
INTEGER
4
int
4
NumberField
NUMBER
BIGINT
8
long
8
NumberField
NUMBER
REAL
float
4
NumberField
NUMBER
FLOAT
double
8
NumberField
NUMBER
DOUBLE
double
8
NumberField
NUMBER
BINARY
255
byte[]
BinaryField
RAW
VARBINARY
255
byte[]
BinaryField
LONGRAW
LONGVARBINARY
byte[]
BinaryField
DATE
DATE
sql.Date
DateField
DATE
TIME
sql.Time
TimeField
DATE
TIMESTAMP
sql.Timestamp
TimeStampField
1bit
Java Typ
boolean
Größe
[byte]
1bit
FormField
StateField
NumberField
Tabelle 3.1: Zuordnung von Datentypen (JDBC Version 1.0)
sondere ist auch die neuere JDBC Version 2.0 zu beachten, die in Bezug auf komplexe
Datentypen eine Erweiterung erfahren hat. In einer eigenen Property-Datei soll die
Zuordnung abgelegt werden, um mögliche Erweiterungen und neue Masken-Felder
leicht in den JForms integrieren zu können. Das Einlesen und ein Teil der Konvertierung von einem Datenbankformat in ein internes Java-Format wird von den
Unterklassen von Value vorgenommen, die zuständig für das korrekte Auslesen der
Daten ist. Die Schnittstelle zur Datenbank und die Interaktion wird in den Abschnitten 3.4.1 und 3.4.2 beschrieben.
Bei der Formatierung von Werten, wie z. B. beim Datum, kann durch Angabe eines
Formatstrings auch die Eingabe von Werten vom Benutzer auf Richtigkeit überprüft werden. Dafür ist die Verbindung der Klasse FormField zu einem Validator
vorgesehen. Dieser Validator kann in Abhängigkeit des zugehörigen FormField die
Überprüfung vornehmen und nicht zum Format passende Werte zurückweisen. Dadurch ist eine Reaktion auf eine Benutzereingabe unmittelbar nach Eingabe in einem
Feld möglich und nicht erst beim Fehlschlagen des Schreibens des Tupels in die Datenbank. Auch kann hier durch den Formatstring eine Konvertierung vorgenommen
werden, z. B. durch Anfügen von Kürzeln bei einer Nummer zur Identifikation des
Benutzers oder ähnliches.
3.4 Die Ausführung der Maske und die Anbindung an eine Datenbankinstanz
Eine mögliche Erweiterung der Funktionalität von Suchanfragen ist, einem FormField
einen Parser für komplexere Suchausdrücke zuzuweisen. Dieser kann z. B. AND und
OR Verknüpfung von Werten in Suchfeldern ermöglichen.
3.3.4
Generieren der Maske
Sind die Angaben zu Inhalt und Aussehen der Maske vorgenommen, sind also die
Sicht-Attribute durch die Angaben des Maskenentwerfers näher bestimmt, so werden
diese in einer Einstellungsdatei gespeichert. Die Klasse Form benutzt diese Datei mit
den Einstellungen, um das Layout und die Operationen entsprechend des Entwurfs
umzusetzen. Aufgerufen wird die Maske innerhalb der Klasse FormApplication, die
Unterklasse von DBApplication ist und von dieser den Zugriff auf die Datenbank
erbt. Die Klasse FormContainer übernimmt das Layout der Maskenelemente und die
Klasse Form realisiert die Operationen der Maske. Dadurch ist es möglich, Layout
der Maske und Funktionalität auf Programmierebene weitestgehend zu separieren
und eine leichtere Änderbarkeit zu gewährleisten. Zum einen können die Klassen, die
mit der Klasse Form direkt verbunden sind, noch erweitert und ergänzt werden, zum
anderen kann die Menge der Darstellungselemente, die Unterklassen von FormField,
noch erweitert werden.
Die Angaben der einzelnen Anzeigeelemente werden in einer Datei zu einer Maske
gespeichert und für die Darstellung der Maske von der Klasse Form eingelesen. Diese
richtet die Darstellung, also Form, Größe und Position gemäß den Angaben in der
Datei aus.
3.4
3.4.1
Die Ausführung der Maske und die Anbindung an
eine Datenbankinstanz
Die Datenbankschnittstelle
Die Klassen aus Abbildung 3.7 sollen eine Trennung der Maskenumgebung von
der Datenbank-API ermöglichen. Eine Operation liefert entweder eine Tupelmenge zurück oder verwendet eine vorhandene Tupelmenge. Die einzelnen Tupel einer
Tupelmenge bestehen ihrerseits aus mehreren Werten, die aus der Datenbank stammen. Eine Such-, Lösch- oder Ersetzungsänderung wird auf einer Menge von Tupeln
ausgeführt, die einer bestimmten Bedingung genügen, realisiert durch die Klasse
Condition. Da die Maske auf der Sichtrelation operiert, müssen die Operationen auf
der Maske/Sicht in Operationen auf den Relationen der Datenbankinstanz übersetzt
werden. Die Klasse ViewOperation übernimmt diese Übersetzung und implementiert
die in Abschnitt 2.4 vorgestellten Algorithmen.
Die Klasse Operation ist die Oberklasse der konkreten Datenbankoperationen Search,
Insert, Replace und Delete. Über die Klasse Statement der JDBC-Schnittstelle erfolgt
die Anbindung an die Datenbank. Ergebnismengen, von JDBC als ResultSet geliefert, werden in der Klasse TupelSet gekapselt. Diese Menge besteht aus mehreren
Objekten des Typs Tupel. Dieser wiederum umfaßt die eine Menge von Werten,
durch die Klasse Value dargestellt. Die Klasse Value ist abstrakte Oberklasse für
49
50
Konzeption eines Maskengenerators
Abbildung 3.7: Klassenübersicht zum Paket db.instance
alle Klassen, die das Einlesen der Werte entsprechend des Datentyps vornehmen.
Diese Differenzierung wird besonders wichtig beim Einlesen von binären Daten oder
objektwertigen Attributen und erlaubt eine gekapselte Behandlung einer möglichen
Konvertierung. Die enge Beziehung der Klasse Value zur Klasse FormField erlaubt
somit, daß sowohl auf der Ebene der Klasse Form als auch auf der Ebene der Klasse
TupelSet keine besonderen Vorkehrungen zum Einlesen verschiedener Datentypen
vorgenommen werden müssen.
Die Ergebnismenge der Klasse ResultSet der JDBC-Schnittstelle ist, abhängig vom
Treiber des implementierenden Datenbanksystems, nicht immer in beiden Richtungen scrollbar, d. h. die Tupel können unter Umständen nur von vorne nach hinten einmal eingelesen werden. Ein Zurückgehen zum vorigen Tupel ist dann nicht
möglich. Da die Maske jedoch auch das Rückwärtsbewegen in der Ergebnismenge erlaubt, muß die Klasse TupelSet abhängig vom ResultSet das Auslesen und Speichern
der Tupel selbst übernehmen. Die damit verbundenen Probleme wie das Speichern
von großen Ergebnismengen, Performance des Einlesevorgangs etc., sind in einer gesonderten Betrachtung zu untersuchen. Es wird davon ausgegangen, daß die Scrollfunktion in der Klasse TupelSet geeignet implementiert wird bzw. ein JDBC-Treiber
verwendet wird, der das Scrollen in ResultSets erlaubt.
3.4.2
Interaktion der Maske mit einer Datenbankinstanz
Wird die Maske geöffnet, so zeigt sie noch keine Daten an. Der Benutzer bekommt
nach Angabe der Auswahlkriterien die Tupel der Ergebnismenge angezeigt und kann
diese nacheinander sehen und Änderungen vornehmen. Die Anbindung erfolgt wie in
Abbildung 3.8 dargestellt. Über die Maske Form wird eine Operation ViewOperation
auf der Sicht ausgeführt, diese wird in Operationen auf der Datenbankinstanz übersetzt und auf dieser anschließend ausgeführt (mittels Unterklassen von Operation).
Unter Umständen wird eine Menge von Tupeln durch die Klasse TupelSet zurückgeliefert. Ein Tupel liefert die Werte (Value), die in den Feldern (FormField) der Maske
3.4 Die Ausführung der Maske und die Anbindung an eine Datenbankinstanz
Abbildung 3.8: Anbindung der Maske an eine Datenbankinstanz
angezeigt werden. Die Art und Weise der Darstellung hängt von den Vorgaben ab,
die im Maskenentwurf gemacht wurden.
3.4.3
Zustände und Operationen einer Maske
Neben der Darstellung der Werte aus der Datenbank soll die Maske auch Operationen auf den dargestellten Werten ausführen. Die Operationen aus Tabelle 3.2 und 3.3
werden von der Klasse Form implementiert und zum Teil von dem Bedienteil FormControl dem Maskenbenutzer sichtbar gemacht. Die Operationen aus Tabelle 3.2
Operation
Beschreibung
search
Suchen von Tupeln
insert
Einfügen eines neuen Tupels
replace
Ändern des aktuellen Tupels
delete
Löschen des aktuellen Tupels
Tabelle 3.2: Operationen einer Maske auf einer Datenbankinstanz, die in eigenen
Klassen realisiert werden.
werden in dem Package db.instance modelliert, dessen Klassen von der Klasse
Form verwendet werden. Die in Tabelle 3.3 dargestellten Operationen werden von
der Klasse Form entweder selbst implementiert oder über geeignete Schnittstellen
von anderen Klassen übernommen, wie z. B. die Klasse Report, welche eine Möglichkeit des Datenexports realisiert. Reicht der Funktionsumfang nicht aus, so ist es
möglich, weitere Unterklassen einzufügen und z. B. über FormControl oder geeignete
Menüpunkte zugänglich zu machen.
51
52
Konzeption eines Maskengenerators
Operation
Beschreibung
commit
Änderungen in die DB schreiben
cancel
Änderung rückgängig machen
previous
Anzeige des vorigen Tupels
next
Anzeige des nächsten Tupels
export
Exportiere Werte des aktuellen Tupels oder der
aktuellen Auswahl
close
Schließen der Maske
Tabelle 3.3: Weitere Operationen einer Maske, die von der Maske oder von den
anderen Operationen realisiert werden.
Die verschiedenen Operationen der Maske machen unterschiedliche Zustände der
Maske notwendig, z. B. dürfen bei einer Ersetzungsoperation bestimmte Attribute
nicht änderbar sein, bei einer Suchoperation sollen alle Attributwerte bis auf die
Default-Suchwerte leer sein usw. Abbildung 3.9 zeigt die erforderlichen Zustände,
die in Tabelle 3.4 beschrieben sind.
Operation
Beschreibung
VIEW
zeigt die Attribute mit den Werten eines Tupels
der Sicht an.
SEARCH
zeigt die Attribute, nach denen gesucht werden
kann, mit leeren Werten an.
DELETE
zeigt die Werte des Tupels, das gelöscht werden
soll.
INSERT
zeigt die Attribute, die für ein neues Tupel eingegeben werden können, mit leeren oder Defaultwerten an.
REPLACE
zeigt die Attribute, die geändert werden können,
mit den Werten eines Tupels an.
Tabelle 3.4: Zustände einer Maske
Die Maske befindet sich zu Beginn im Suchzustand, um die zu bearbeitende Tupelmenge durch den Benutzer spezifizieren zu lassen. Anschließend wird in den Anzeigezustand gewechselt, der zentrale Zustand der Maske, von dem aus die verschiedenen
Operationen ausgeführt werden können. Durch die Verwendung aktiver Elemente,
wie in Abschnitt 3.3.1 beschrieben, sind weitere Zustände möglich.
3.5
Der Maskengenerator JForms
Für den Entwurf einer Maske wird mit JForms ein Tool zur Verfügung gestellt, welches die Spezifikation einer Sicht unterstützt, Einstellungen der Art und Weise der
Darstellung von Datenbankwerten erlaubt und bei der Gestaltung der Maske behilflich ist. In dieser Arbeit wird allerdings das Augenmerk nur auf die Spezifizierung
der Sicht gelenkt. Abbildung 3.10 zeigt einige Klassen, die hierfür notwendig sind.
3.5 Der Maskengenerator JForms
Abbildung 3.9: Zustandsdiagramm einer Maske vom Typ Form
Es ist sowohl als eigenständiges Tool lauffähig oder über Dato3 als Plug-In aufrufbar
und benutzt dann die Datenbankverbindung von Dato. Die Spezifizierung der Sicht
erfolgt in den beiden Fenstern RelationWindow für die Tabellen der Sicht und AttributeWindow für die Sichtattribute. Im RelationWindow wird das Datenbankschema
der Datenbank gezeigt, an der sich der Benutzer angemeldet hat, und die Tabellen
der Sicht, die aus dem Schema ausgewählt werden können. Intern wird dabei die
Klasse MetaScheme verwendet, welche die notwendigen Informationen über die Datenbankobjekte zur Verfügung stellt. Nach Auswahl einer Relation kann für diese
festgelegt werden, ob sie Master-Relation ist. Falls eine Relation als Master-Relation
gekennzeichnet wird, so werden die restlichen Relationen der Sicht als Child- oder
Partner-Relation klassifiziert, je nachdem, welcher Art eine Fremdschlüsselbeziehung
zur Master-Relation ist. Beim Hinzufügen einer Relation in die Sicht werden automatisch für die Schlüsselbeziehungen zwischen allen Relationen Equi-Joins in die
Sichtbedingung eingefügt.
Welche Attribute in der Sicht verwendet werden, wird im AttributeWindow festgelegt, welches die Sichttabellen und die Attribute anzeigt. Auch die Spezifizierung der
Darstellungsart erfolgt an dieser Stelle, also die Auswahl des geeigneten Anzeigeelements, die Änderbarkeit, Wertebereiche etc., wobei die Anzeigeelemente geeignete
Default-Werte für ihre Einstellungsmöglichkeiten bereithalten. Parallel zur Auswahl
der Sichtelemente wird der Sicht-Abhängigkeits-Graph aufgebaut, aus dem bestimmte Angaben zur Änderbarkeit ablesbar sind. Die Informationen sind in drei Bereiche
eingeteilt. Der erste Bereich enthält Informationen zu dem Attribut der Relation,
die nicht geändert werden können. Im zweiten Bereich wird das Anzeigeelement vom
Typ FormField festgelegt. Je nach Anzeigeelement können unterschiedliche Einstellungen vorgenommen werden, wie z. B. Beschriftung und Größe eines Felds. Zu jedem
FormField ist mindestens einstellbar, ob es sichtbar ist und ob das Attribut für die
Spezifikation der Operationen search, delete, insert und replace verwendet werden
kann. Im dritten Einstellungsbereich wird die Plazierung innerhalb des GridBagLayouts der Maske bestimmt, wobei die unterschiedlichen GridBagConstraints modifiziert
3
siehe [vH98]
53
54
Konzeption eines Maskengenerators
Abbildung 3.10: Die Klassen des Maskengenerators JForms
werden können.
Eine wichtige Erweiterung, die nur erwähnt bleiben soll, ist ein graphischer Editor
für die Maske, in welchem die Maskenelemente vom Typ FormContainerElement plaziert werden können. In Java wird das Layout von graphischen Komponenten von
sogenannten Layout-Managern übernommen, deren flexibelster von der Klasse GridBagLayout dargestellt wird. Da dieser auch von der Klasse FormContainer zur Plazierung seiner Elemente verwendet wird, sollte es möglich sein, den graphischen Editor
auf der Basis des GridBagLayout zu entwerfen und für den Spezialfall des Maskenlayouts anzupassen. Im JavaWorkshop von Sun, einer Java-Entwicklungsumgebung,
ist ein solcher Editor zur Plazierung von Objekten des Typs Component in einem
Container beispielsweise realisiert. Die GridBagConstraints eines Objekts vom Typ
Component bestimmen das Aussehen und die Plazierung innerhalb des Layouts.
Sind die oben beschriebenen Angaben zur Sicht und zur Maske eingegeben worden,
so kann die Sicht erzeugt werden und die Maske angezeigt werden. Die Einstellungen
sind jederzeit änderbar, so werden z. B. Änderungen an den Layout-Parametern eines
Feldes durch Aktualisieren der Maske sichtbar.
Ein Maskenprojekt wird innerhalb eines eigenen Verzeichnisses in Form verschiedener Property-Dateien gespeichert. Dafür muß der Maske ein Name gegeben werden,
der für die Sicht und als Verzeichnisname verwendet wird. Durch Angabe eines Verzeichnisses werden die Property-Dateien des Projekts in einem darunterliegenden
Verzeichnis mit dem Projektnamen gespeichert. Für die Ausführung der Maske muß
eine Objekt vom Typ View erzeugt werden, indem das Projektverzeichnis angegeben
wird. Anschließend wird die Sicht View einem Objekt Form übergeben, welches das
Container Objekt liefert, welches in einem beliebigen Frame angezeigt werden kann.
Dieser ganze Ablauf wird in der Klasse FormApplication vorgenommen, die mit der
Angabe des Projektverzeichnisses gestartet wird. Diese Klasse ist Ausgangspunkt,
3.5 Der Maskengenerator JForms
oder besser Oberklasse für alle Anwendungen, welche Masken verwenden und über
Menüs zusätzliche Funktionen für den Benutzer bereithalten. Für die in der Maske
verwendeten aktiven Elemente wie Buttons kann die zugehörige Realisierung der auszulösenden Operationen z. B. in einer Unterklasse von FormApplication erfolgen bzw.
von dort weiter delegiert werden. Werden innerhalb einer Anwendung viele Masken
mit aktiven Elementen verwendet, so ist auch eine Aufteilung des Event-Handlings
denkbar, indem zu jeder Maske eine Unterklasse von Form erzeugt wird, welche die
Events der Buttons dieser Maske abfängt und auf dieser Ebene die Operationen
ausführt.
55
56
Konzeption eines Maskengenerators
Kapitel 4
Die Implementierung eines
Gerüsts“ für den
”
Maskengenerator JForms
Das in Kapitel 3 vorgestellte Konzept zeigt den Umfang eines Systems Masken”
generator“ und eine mögliche Umsetzung unter Berücksichtigung der theoretischen
Erkenntnisse aus Kapitel 2. Das Konzept wurde im Hinblick auf Erweiterbarkeit
und mit einigen Ausblicken möglicher Erweiterungen entwickelt. Um während des
Designs nicht Anwendungsfälle zu übersehen, die ein anschließendes Re-Design bei
einer Erweiterung notwendig machen, sind in der vorgestellten Klassenstruktur viele Klassen, die als Beispiele für Implementationen dienen. In dieser Arbeit wird
exemplarisch nur ein Teil von dem realisiert, was auf konzeptioneller Ebene schon
ausgearbeitet ist. Dieses Kapitel beschreibt die Implementierung eines Gerüsts und
der Grundfunktionalität der Maske, soweit die Beschreibung des Konzepts nicht
detailliert genug ist.
4.1
Die Darstellung des Datenbankschemas und des
Sichtschemas
Das Meta-Schema, durch die Klasse MetaScheme dargestellt, wird mit der Übergabe
eines Objekts vom Typ DBApplication initialisiert, um über die notwendige Datenbankverbindung zu verfügen. Die Informationen zu den statischen“ Elementen Table
”
und Column werden über die JDBC-Klassen DatabaseMetaData und ResultSetMetaData eingelesen. Da dieser Vorgang relativ zeitaufwendig ist, geschieht dies nur bei
Bedarf. Das Meta-Schema liegt zu Beginn also nicht komplett vor, so daß der Zugriff auf die Elemente gesteuert werden muß. Daher können Objekte vom Typ Table
und Column nicht direkt erzeugt werden, sondern sind über die Klassenmethoden
von MetaScheme zugänglich. Da während der Sichtspezifikation von einem statischen Datenbankschema ausgegangen wird, sind die Attribute dieser Objekte nicht
änderbar. Abbildung 4.1 zeigt die Methoden von MetaScheme und den statischen“
”
Elementen.
Die Sicht vom Typ View wird ebenfalls von MetaScheme geliefert. Diese erzeugt
58
Die Implementierung eines Gerüsts“ für den Maskengenerator JForms
”
Abbildung 4.1: Methodenübersicht zum Meta-Schema
4.2 Pfadsuche im Abhängigkeits-Graphen
sich bei Angabe eines Verzeichnisses aus den Einstellungen der darin enthaltenen
Property-Dateien. Die Klasse View übernimmt die Verwaltung ihrer Elemente selbst,
Sicht-Relationen und Sicht-Attribute sind über die Methoden der View zugänglich.
Eine Änderung der Sicht ist über die entsprechenden Modellklassen möglich, so daß
die Konsistenz der Benutzerschnittstelle leichter sichergestellt werden kann. Beim
Einfügen und Löschen von Sichtrelationen und Sichtattributen werden die Änderungen an den Abhängigkeitsgraphen weitergegeben. In Abbildung 4.2 sind die Methoden zur Sicht und in Abbildung 4.3 die der Sicht-Elemente dargestellt.
Abbildung 4.2: Methodenübersicht der Klasse View
4.2
Pfadsuche im Abhängigkeits-Graphen
In Definition 2.34 haben wir den Begriff des Pfads zwischen Knotenmengen im
Abhängigkeits-Graphen definiert, mit der besonderen Eigenschaft der FD-Knoten.
Der herkömmliche Breiten-Suche-Algorithmus, mit dessen Hilfe man in gewöhnlichen Graphen Pfade suchen kann, ist nur auf Pfade zwischen zwei Knoten definiert.
Daher wurde ein eigener Algorithmus implementiert, der überprüft, ob zwei Knotenmengen laut Definition 2.34 durch einen Pfad verbunden sind.
Ein Knoten n kann drei verschiedene Zustände haben:
59
60
Die Implementierung eines Gerüsts“ für den Maskengenerator JForms
”
Abbildung 4.3: Methodenübersicht der Sicht-Elemente
1. n wurde nicht besichtigt und ist nicht passierbar (Initialzustand),
2. n wurde besichtigt und ist nicht passierbar oder
3. n wurde besichtigt und ist passierbar.
Ein Knoten wurde besichtigt, wenn er das erste Mal im Such-Algorithmus angefaßt“
”
wurde. Diese Markierung ist genau wie beim Breiten-Suche-Algorithmus notwendig,
um nicht durch Zyklen in eine Endlosschleife zu gelangen.
Ein Knoten, der nicht FD-Knoten ist, ist passierbar, wenn er besichtigt wurde und
mindestens ein Vorgänger passierbar ist oder wenn er in der Startmenge der Knoten
ist, von welcher der gesuchte Pfad ausgeht.
Ein FD-Knoten ist passierbar, wenn er besichtigt wurde und alle seine Vorgänger
passierbar sind oder wenn er in der Startmenge der Knoten ist, von welcher der
gesuchte Pfad ausgeht.
Sei FROM die Menge der Knoten, von welcher der gesuchte Pfad ausgehen, TO die
Menge der Knoten, zu welcher der gesuchte Pfad führen soll. Sei NV (not-visited)
die Menge der Knoten, die nicht besichtigt wurden, VNP (visited-not-passable) die
Menge der Knoten, die besichtigt wurden aber nicht passierbar sind und VP (visited-
4.3 Der Maskeneditor JForms
passable) die Menge der Knoten, die besichtigt wurden und passierbar sind. Ein Pfad
existiert genau dann, wenn am Ende des Algorithmus gilt: TO ⊆ VP.
Zu Beginn seien VNP und VP leer, NV enthalte alle Knoten des Graphen. Alle
Knoten von FROM werden in die Menge VP eingefügt und aus der Menge NV
entfernt. Für die Nachfolger der Knoten von FROM untersuche, ob sie passierbar
sind. Falls ja, füge sie in VP ein, ansonsten in VNP. Entferne sie jeweils aus NV
bis NV leer ist. Anschließend führe dies solange mit den Knoten in VNP durch, bis
entweder TO ⊆ VP (Pfad gefunden) oder sich die Mengen VNP oder NV nicht mehr
verkleinern (kein Pfad gefunden).
Im Anhang B.2 ist der Algorithmus in Java umgesetzt, eine Übersicht der Klassenmethoden ist in den Abbildungen B.7 und B.8 im Anhang zu finden.
4.3
Der Maskeneditor JForms
Die Klasse JForms ist die Hauptklasse des Maskeneditors.1 Die Sichtdefinition und
die Einstellungen der Maske erfolgen über diese Klasse. Neben dem Laden und
Speichern der Einstellungen kann die Auswahl der Sicht- und Maskenelemente in
verschiedenen Fenstern vorgenommen werden. Das Layout der Maske kann durch
Einstellung der verschiedenen Parameter des GridBagConstraints verändert werden.
Ein graphischer Editor, der hier nicht realisiert wurde, könnte auf diese Schnittstelle aufsetzen und das GridBagLayout komfortabel per Maus änderbar machen. Die
Sicht-Graphen können ausgegeben werden und nach Angabe zweier Knotenmengen
kann überprüft werden, ob ein Pfad zwischen diesen existiert.
4.3.1
Auswahl und Einstellungen der Sichtelemente
Die Sichtelemente werden in den Fenstern RelationWindow und AttributeWindow2
ausgewählt und spezifiziert. Sie haben eine gemeinsame Oberklasse, welche die ähnliche Darstellung der beiden Fenster bestimmt. Abbildung 4.4 zeigt das Fenster zur
Auswahl der Sicht-Relationen. Im oberen Teil können links beliebige Relationen
beliebiger Schemata in die Sicht aufgenommen werden, die auf der rechten Seite erscheinen. Im unteren Teil ist die Auswahl einer Master-Relation festzulegen, wobei
anschließend die restlichen Relationen in Child- und Partner-Relationen eingeteilt
werden. Diese Einteilung kann nicht manuell geändert werden.
Aus den Sicht-Relationen sind im AttributeWindow die darzustellenden Attribute der
Sicht auswählbar. Zu einem Attribut lassen sich Informationen aus der Datenbank
anzeigen, die jedoch nicht geändert werden können, siehe Abbildung 4.5. Die Einstellungsmöglichkeiten eines FormFields sind in Abbildung 4.6 dargestellt. Im oberen
Teil des Einstellbereichs sind die Einstellungen sichtbar, die zu jedem FormField gemacht werden können, also ob das Feld sichtbar ist und bei welchen Operationen
es spezifiziert werden kann. Das Layout oder die GridBagConstraints, die zu jedem
FormField gehören, werden im dritten Teil des Attribut-Fensters eingestellt, siehe
Abbildung 4.7. Die Default-Werte in diesem Teil können für jedes implementierte
1
2
Das zugehörige Klassendiagramm mit den Methoden ist in Abbildung B.1 im Anhang zu sehen.
Siehe auch die Abbildung B.2 im Anhang.
61
62
Die Implementierung eines Gerüsts“ für den Maskengenerator JForms
”
Abbildung 4.4: Auswahl der Sicht-Relationen
Abbildung 4.5: Auswahl der Sicht-Attribute und Anzeige der DB-Informationen der
entsprechenden Spalte
4.3 Der Maskeneditor JForms
Abbildung 4.6: Einstellungen zu einem FormField
FormField in einer zu dieser Klasse gehörenden Property-Datei gesondert angegeben werden, so daß z. B. einzeilige Textfelder immer horizontal ausgedehnt oder
gestaucht werden3 bei Ändern der Größe der Maske und mehrzeilige Textfelder ihre
Größe sowohl horizontal als auch vertikal anpassen.4 Die vielfältigen Parameter des
GridBagLayouts lassen eine differenzierte Gestaltung der Maske zu.
Sind alle Angaben gemacht, so kann die Sicht erzeugt und das Layout der Maske
angesehen werden. Abbildung 4.8 zeigt eine solche generierte Maske. Eine angezeigte,
generierte Maske kann mit den geänderten Parametern aktualisiert werden, indem
der Button Show Form“ nochmals gedrückt wird. Die Operationen der Maske sind
”
direkt ausführbar, so daß die Funktionalität der Maske gleich überprüft werden kann
und die verschiedenen Stati der Maske sichtbar werden.
4.3.2
Speichern der Einstellungen in Property-Dateien
Da die Einstellungen auf verschiedene Property-Dateien verteilt werden, ist es notwendig, diese in einem Verzeichnis zusammenzufassen. Dieses Verzeichnis trägt den
Namen der Maske und kann innerhalb eines beliebigen Verzeichnisbaums gespeichert werden. Neben der Angabe eines Maskennamens muß also noch ein Verzeichnis
gewählt werden, in welchem die Maskendaten in dem entsprechenden Unterverzeich3
4
Dies erfolgt durch Setzen des Fill-Parameters auf HORIZONTAL.
Dafür wird der Fill-Parameter auf BOTH gesetzt.
63
64
Die Implementierung eines Gerüsts“ für den Maskengenerator JForms
”
Abbildung 4.7: Einstellungen zum Layout
Abbildung 4.8: Eine generierte Maske
4.4 Der Ablauf der generierten Maske
nis abgelegt werden.
Aufgeteilt werden die Maskendaten auf folgende Property-Dateien, deren Namen
mit .properties enden:
Connect: speichert den Namen des JDBC-Treibers und die zugehörige URL.
View: speichert den Sichtnamen, der gleich dem Maskennamen ist, den Schemanamen, die Sichtbedingung und die Alias-Namen der Relationen und Attribute.
ViewTables: speichert für alle Sicht-Relationen den Sichtnamen, den vollständigen
Namen der zugehörigen Relation und den Typ (Master/Child/Partner).
ViewColumns: speichert für alle Sicht-Attribute den Sichtnamen, den Namen des
zugehörigen Attributs, den Alias-Namen der Sicht-Relation, den Klassennamen des darstellenden FormFields und ob das Attribut für die verschiedenen
Operationen spezifiziert werden kann.
FormFields: speichert für alle Sicht-Attribute die Angaben des darstellenden FormFields, also die GridBagConstraints sowie von den verschiedenen FormFieldImplementationen abhängige Einstellungen.
Da die implementierten FormFields ihre Attribute in Objekten vom Typ Property
speichern, erfolgt das Schreiben der Property-Dateien in der View über die Möglichkeit, daß ein Property Objekt seine Angaben direkt in einen OutputStream schreiben
kann. Das Einlesen der Werte erfolgt auf umgekehrte Weise. Dazu werden in der
Klasse View in einer Schleife alle Sicht-Elemente durchlaufen und die zugehörigen
Properties gelesen oder geschrieben.
4.4
Der Ablauf der generierten Maske
Das Einlesen der Masken-Einstellungen erfolgt durch Angabe des Maskenverzeichnisses mit den Property-Dateien in der entsprechenden Methode der Klasse MetaScheme (siehe Abbildung 4.1). Dies kann z. B. in einer Unterklasse von FormApplication
erfolgen. Nach dem Einlesen kann die Maske in einem Fenster angezeigt und bedient
werden. Die Klasse FormApplication wurde so implementiert, daß beim Aufruf der
Klasse mit dem Maskenverzeichnis als Parameter ein Fenster mit der entsprechenden
Maske geöffnet wird.
Eine Operation wird vom Benutzer über die Klasse FormControl ausgelöst, welche
eine entsprechende Methode von Form aufruft. Dafür wird zunächst der Zustand der
Maske gewechselt, indem der Zustand sowohl an die Klasse FormControl, als auch die
Klassen FormContainer und FormContainerElement delegiert wird. Anschließend wird
die gewünschte Operation durch Aufruf der entsprechenden Methode der Klasse
ViewOperation ausgeführt. In Abbildung 4.9 ist der Ablauf einer Such-Operation
dargestellt. Hierbei liefert die Klasse ViewOperation das Anfrageergebnis in Form
eines TupelSets zurück, in welchem navigiert werden kann. Das Einlesen der Werte
erfolgt in einer implementierenden Unterklasse von Value. An dieser Stelle wird das
zugehörige Maskenelement vom Typ FormField informiert, den neu eingelesenen Wert
darzustellen.
65
66
Die Implementierung eines Gerüsts“ für den Maskengenerator JForms
”
Abbildung 4.9: Ablauf einer Such-Operation
Umgesetzt wurden exemplarisch die Such-Operation und die Replace-Operation.
Bei der Delete-Operation ist zu beachten, daß vom Benutzer erfragt werden muß,
ob sich das Löschen auf die Master-Relation oder auf eine Child-Relation bezieht.
Dies kann entweder durch mehrere Delete-Buttons oder durch einen gesonderten
Dialog realisiert werden. Bei der Insert-Operation ist zu beachten, daß unspezifizierte Felder entweder durch Null-Werte aufgefüllt werden oder das Einfügen zurückgewiesen wird, falls ein NotNullable-Feld nicht spezifiziert wurde. Das Scrollen im
Anfrageergebnis ist in der Maske nur einmal in Vorwärtsrichtung möglich. Dies kann
geeignet in der Klasse TupelSet erweitert werden und ist vom verwendeten JDBCTreiber abhängig, der erst ab der Version 2.0 scrollbare ResultSets unterstützt. In der
JDBC-Version 2.0 wird auch das Ändern von ResultSets unterstützt, was in dieser
Implementierung nicht weiter berücksichtigt wurde, aber bei einer Erweiterung der
Funktionalität zu Hilfe genommen werden kann. So gibt es dort unter anderem die
Methoden refreshRow, updateRow, insertRow, deleteRow und cancelRowUpdates. Diese Methoden vereinfachen die Implementation von Änderungen auf dem ResultSet
sehr und können von der Klasse TupelSet genutzt werden. Da zum Zeitpunkt dieser
Arbeit kein entsprechender Treiber zur Verfügung stand, wurden einige Operationen
von TupelSet nicht realisiert.
Die Abbildungen B.3, B.4 und B.5 zeigen die Methoden zu einer Maske und ihren
Feldern. In Abbildung B.6 sind die Methoden der Klassen für den Datenbankzugriff
dargestellt.
Anhang A
Abkürzungen
Abkürzung
Beschreibung
ADT
Abstrakter Datentyp
API
Application Programmers Interface
BCNF
Boyce-Codd-Normalform
DB
Datenbank
DBS
Datenbanksystem
DBMS
Datenbankmanagementsystem
GUI
Graphical User Interface
JDBC
Java Database Connectivity
JDK
Java Developer Kit
JFC
Java Foundation Classes
RDBMS
Relationales DBMS
SQL
Structured Query Language
UML
Unified Modeling Language
68
Abkürzungen
Anhang B
Programmierung
B.1
Ausgewählte Klassendiagramme
Abbildung B.1: Methoden von JForms
70
Programmierung
Abbildung B.2: Methoden der Einstellfenster des Maskeneditors
B.1 Ausgewählte Klassendiagramme
Abbildung B.3: Methoden der Masken-Klassen
Abbildung B.4: Methoden von FormField
71
72
Programmierung
Abbildung B.5: Methoden von FieldAdjust
Abbildung B.6: Methoden der Klassen für den Zugriff eine Datenbankinstanz
B.1 Ausgewählte Klassendiagramme
Abbildung B.7: Allgemeine Methoden des Graphen
Abbildung B.8: Methoden des Abhängigkeits-Graphen und der spezialisierten Knoten
73
74
Programmierung
B.2 Sourcecode zur Pfadsuche in Abhängigkeits-Graphen
B.2
Sourcecode zur Pfadsuche in Abhängigkeits-Graphen
/**---------------------------------------------------------------------*/
/**
**/
public boolean existPath(MetaSchemeNode[] fromarray,
MetaSchemeNode[] toarray)
{
Enumeration iter;
Vector from, to, not_visited, visited_passable, visited_not_passable;
MetaSchemeNode n;
boolean found;
int size, fromsize;
from = new Vector(fromarray.length);
to = new Vector(toarray.length);
not_visited = new Vector(vertices.size());
visited_passable = new Vector(vertices.size());
visited_not_passable = new Vector(fdnodes.size());
// kopiere alle Knoten des Graphen in die Menge not_visited und
// setze sie als "nicht besucht"
iter = vertices.elements();
while (iter.hasMoreElements())
{
n = (MetaSchemeNode)iter.nextElement();
n.setVisited(false);
n.setPassable(false);
not_visited.addElement(n);
}
// kopiere die Knoten des from-Arrays in einen Vector und markiere sie
// als passierbar da sie Startknoten sind
for (int i = 0; i < fromarray.length; i++)
{
from.addElement(fromarray[i]);
fromarray[i].setPassable(true);
}
// kopiere die Knoten des to-Arrays in einen Vector
for (int i = 0; i < toarray.length; i++)
to.addElement(toarray[i]);
size = not_visited.size() + 1;
fromsize = from.size() + 1;
found = false;
while (!found && (size > not_visited.size() || fromsize > from.size()) &&
!from.isEmpty())
{
size = not_visited.size();
fromsize = from.size();
// untersuche alle Nachfolger der Knoten aus from
iter = from.elements();
while (iter.hasMoreElements())
visitSuccessors((MetaSchemeNode)iter.nextElement(), not_visited,
visited_passable, visited_not_passable);
from.removeAllElements();
// Pfad wurde gefunden, da to Teilmenge der Menge der passierbaren
75
76
Programmierung
// Knoten ist
if (isSubset(to, visited_passable))
found = true;
else
{
iter = visited_not_passable.elements();
while (iter.hasMoreElements())
from.addElement(iter.nextElement());
}
}
return found;
}
/**---------------------------------------------------------------------*/
/**
**/
private void visitSuccessors(MetaSchemeNode node, Vector not_visited,
Vector visited_passable,
Vector visited_not_passable)
{
Enumeration iter;
Vector queue;
queue = new Vector();
queue.addElement(node);
// Anfangsknoten wurde besucht
node.setVisited(true);
while (!queue.isEmpty())
{
node = (MetaSchemeNode)queue.firstElement();
queue.removeElement(node);
// entferne Knoten aus der entsprechenden Menge
if (node.isVisited())
visited_not_passable.removeElement(node);
else
not_visited.removeElement(node);
node.setVisited(true);
// pruefe ob der Knoten passierbare Vorgaenger hat
if (!(node instanceof FDNode))
node.testPassable();
// teile Knoten der entsprechenden Menge zu
if (node.isPassable())
{
visited_passable.addElement(node);
// uebernimm die Nachfolger in die Queue und untersuche sie
// anschliessend
iter = node.sucs.elements();
while (iter.hasMoreElements())
{
node = (MetaSchemeNode)iter.nextElement();
if (!node.isVisited())
queue.addElement(node);
}
B.2 Sourcecode zur Pfadsuche in Abhängigkeits-Graphen
}
else
visited_not_passable.addElement(node);
}
}
/**---------------------------------------------------------------------*/
/**
**/
private boolean isSubset(Vector subset, Vector superset)
{
Enumeration iter;
boolean is;
is = true;
iter = subset.elements();
while (is && iter.hasMoreElements())
if (!superset.contains(iter.nextElement()))
is = false;
return is;
}
}
77
78
Programmierung
Abbildungsverzeichnis
2.1
Der Spur-Graph für die Sicht V5 aus Abschnitt 2.1.4 . . . . . . . . .
17
2.2
Ein FD-Knoten zur funktionalen Abhängigkeit {B1 , . . . , Bk } →R A .
18
2.3
Der Abhängigkeits-Graph für die Sicht V5 aus Abschnitt 2.1.4 . . . .
18
2.4
Der gleiche Graph wie in Abbildung 2.3, jedoch hat die Sicht die
zusätzliche Selektionsbedingung DEP=’Sales’ . . . . . . . . . . . . .
19
Der Abhängigkeits-Graph für die Sicht V = πY (R o
nR.E=S.E S) mit
Y = {R.A, R.B, R.C, R.D, R.E, S.F } über den Relationenschemata
R[A, B, C, D, E] und S[E, F ] mit den funktionalen Abhängigkeiten
{A, B, C} →R E und E →S F . . . . . . . . . . . . . . . . . . . . . .
20
2.6
Der Abhängigkeits-Graph für die Sicht V9 aus Abschnitt 2.1.4 . . . .
22
2.7
Der Abhängigkeits-Graph für die Sicht V8 aus Abschnitt 2.1.4 . . . .
23
2.8
Abhängigkeits-Graph zur Sicht V = πY (R o
nNR=RECHNUNG P ) . . . .
29
2.9
Abhängigkeits-Graph zu einer Sicht V über der Master-Relation M
mit dem Schlüsselkandidaten X 0 = {P1 , . . . , Pk } und den ChildRelationen Ci . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30
2.10 Abhängigkeits-Graph zur Sicht V = πY ((R o
n A) o
nNR=RECHNUNG P )
34
2.5
3.1
Anwendungsfälle des Maskengenerators und der Ausführungsumgebung der Maske . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
3.2
Pakete des Maskengenerators und der Ausführungsumgebung . . . .
40
3.3
Übersicht der Klassen zu einem Datenbankschema . . . . . . . . . .
42
3.4
Übersicht der Klassen zum Aufbau der Sicht-Graphen . . . . . . . .
42
3.5
Klassenübersicht zum Paket db.form . . . . . . . . . . . . . . . . . .
44
3.6
Klassenübersicht zum Paket db.form.field . . . . . . . . . . . . . .
46
3.7
Klassenübersicht zum Paket db.instance . . . . . . . . . . . . . . .
50
3.8
Anbindung der Maske an eine Datenbankinstanz . . . . . . . . . . .
51
3.9
Zustandsdiagramm einer Maske vom Typ Form . . . . . . . . . . . .
53
3.10 Die Klassen des Maskengenerators JForms . . . . . . . . . . . . . . .
54
80
ABBILDUNGSVERZEICHNIS
4.1
Methodenübersicht zum Meta-Schema . . . . . . . . . . . . . . . . .
58
4.2
Methodenübersicht der Klasse View . . . . . . . . . . . . . . . . . . .
59
4.3
Methodenübersicht der Sicht-Elemente . . . . . . . . . . . . . . . . .
60
4.4
Auswahl der Sicht-Relationen . . . . . . . . . . . . . . . . . . . . . .
62
4.5
Auswahl der Sicht-Attribute und Anzeige der DB-Informationen der
entsprechenden Spalte . . . . . . . . . . . . . . . . . . . . . . . . . .
62
4.6
Einstellungen zu einem FormField . . . . . . . . . . . . . . . . . . . .
63
4.7
Einstellungen zum Layout . . . . . . . . . . . . . . . . . . . . . . . .
64
4.8
Eine generierte Maske . . . . . . . . . . . . . . . . . . . . . . . . . .
64
4.9
Ablauf einer Such-Operation . . . . . . . . . . . . . . . . . . . . . .
66
B.1 Methoden von JForms . . . . . . . . . . . . . . . . . . . . . . . . . .
69
B.2 Methoden der Einstellfenster des Maskeneditors . . . . . . . . . . . .
70
B.3 Methoden der Masken-Klassen . . . . . . . . . . . . . . . . . . . . .
71
B.4 Methoden von FormField . . . . . . . . . . . . . . . . . . . . . . . . .
71
B.5 Methoden von FieldAdjust . . . . . . . . . . . . . . . . . . . . . . . .
72
B.6 Methoden der Klassen für den Zugriff eine Datenbankinstanz . . . .
72
B.7 Allgemeine Methoden des Graphen . . . . . . . . . . . . . . . . . . .
73
B.8 Methoden des Abhängigkeits-Graphen und der spezialisierten Knoten
73
Literaturverzeichnis
[AHV95]
S. Abiteboul, R. Hull, V. Vianu: Foundations of Databases. AddisonWesley, Reading, MA, 1995.
[BRJ99]
G. Booch, J. Rumbaugh, I. Jacobson: The Unified Modeling Language
User Guide. Object Technology Series, Addison-Wesley, Reading,
MA, 1999.
[BS81]
F. Bancilhon, N. Spyratos: Update Semantics of Relational Views.
ACM Transactions on Database Systems 6:4 (1981), 557–575.
[CP84]
S. S. Cosmadakis, C. H. Papadimitriou: Updates of Relational Views.
Journal of the ACM 31:4 (1984), 142–160.
[DB78]
U. Dayal, P. A. Bernstein: On the updatability of relational views. In
J. Bubenko, S. Yao (eds.), Proceedings of the 4th International Conference on Very Large Data Bases - 1978, IEEE Computer Society
Press, 1978, 368–378.
[DB82]
U. Dayal, P. A. Bernstein: On the Correct Translation of Update
Operations on Relational Views. ACM Transactions on Database
Systems 7:3 (1982), 381–416.
[DD97]
C. Date, H. Darwen: A Guide to the SQL Standard (Fourth Edition),
4 edition. Addison-Wesley, Reading, MA, 1997.
[ELW98]
R. Eckstein, M. Loy, D. Wood: Java Swing. The Java Series, O’Reilly
& Associates, Cambridge, 1998.
[FC85]
A. L. Furtado, M. A. Casanova: Updating Relational Views. In
W. Kim, D. S. Reiner, D. S. Batory (eds.), Query Processing in Database Systems, Springer-Verlag, Berlin, 1985, 127–144.
[Fla97]
D. Flanagan: Java in a Nutshell: A Desktop Quick Reference for Java
Programmers, 2nd edition. O’Reilly, 1997.
[HCF97]
G. Hamilton, R. Cattell, M. Fisher: JDBC TM Database Access with
Java TM – A Tutorial and Annotated Reference. The Java TM Series,
Addison-Wesley, Reading, MA, 1997.
[JBR99]
I. Jacobson, G. Booch, J. Rumbaugh: The Unified Software Development Process. Addison-Wesley, Reading, MA, 1999.
[KE96]
A. Kemper, A. Eickler: Datenbanksysteme – Eine Einführung. Oldenbourg Verlag, München, 1996.
82
LITERATURVERZEICHNIS
[Kel82]
A. Keller: Updates to Relational Databases through Views Involving Joins. In P. Scheuermann (ed.), Improving Database Usability
and Responsiveness, Proceedings of the 2rd Intl. Conf. on Databases,
Academic Press, 1982, 363–384.
[Kel85a]
A. M. Keller: Algorithms for Translating View Updates to Database
Updates for Views Involving Selections, Projections, and Joins. In
ACM (ed.), 4th ACM Symposium on Principles of Database Systems,
ACM Press, New York, 1985, 154–163.
[Kel85b]
A. M. Keller: Updating relational databases through views. PhD
thesis, Stanford University, Stanford, 1985.
[KU84]
A. M. Keller, J. D. Ullman: On Complementary and Independent
Mappings on Databases. In B. Yormark (ed.), Proceedings of the
1984 ACM SIGMOD International Conference on Management of
Data, SIGMOD Record 2, ACM Press, New York, 1984.
[Lan90]
R. Langerak: View updates in relational databases with an independent scheme. ACM Transactions on Database Systems 15:1 (1990),
40–66.
[Oes97]
B. Oestereich: Objektorientierte Softwareentwicklung mit der Unified
Modeling Language (3. Aufl.). Oldenbourg Verlag, München, 1997.
[PDBGVG89] J. Paredaens, P. De Bra, M. Gyssens, D. Van Gucht: The Structure
of the Relational Database Model. Springer-Verlag, Berlin, 1989.
[RJB99]
J. Rumbaugh, I. Jacobson, G. Booch: The Unified Modeling Language – Reference Manual. Object Technology Series, Addison-Wesley,
Reading, MA, 1999.
[TFC83]
L. Tucherman, A. L. Furtado, M. A. Casanova: A Pragmatic Approach to Structured Database Design. In M. Schkolnick, C. Thanos (eds.), Proceedings of the 9th International Conference on Very
Large Data Bases - 1983, Morgan Kaufmann Publishers, 1983, 219–
231.
[vH98]
A. von Helmolt. Implementierung eines Datenbank-AdministrationsTools in Java. Studienarbeit, Institut für Informatik, Universität
Hannover, Hannover, 1998.
Erklärung
Hiermit erkläre ich, daß ich die vorliegende Arbeit und die zugehörige Implementierung selbständig verfaßt und dabei nur die angegebenen Quellen und Hilfsmittel
benutzt habe.
Hannover, den 2. November 1999
Herunterladen