Diese Richtlinie beschreibt die Schritte, die beim Rückentwickeln einer Datenbank und bei der anschließenden Zuordnung
der Datenmodelltabellen zu Designklassen im Designmodell ausgeführt werden müssen. Dieser Prozess kann vom Datenbankdesigner verwendet werden, um die Entwicklung von
Datenbankänderungen im Rahmen eines evolutionären Entwicklungszyklus in Gang zu bringen. Der Datenbankdesigner muss den
Reverse-Engineering-Prozess während des gesamten Entwicklungszyklus des Projekts verwalten. In vielen Fällen wird der
Reverse-Engineering-Prozess bereits früh im Projektlebenszyklus durchgeführt. Änderungen am Datendesign werden
anschließend inkrementell verwaltet, ohne ein weiteres Rückentwickeln der Datenbank durchzuführen.
Die wichtigsten Schritte beim Rückentwickeln einer Datenbank und Umsetzen der sich ergebenden Datenmodellelemente in
Designmodellelemente sind im Folgenden beschrieben:
-
Erstellen Sie ein physisches Datenmodell, das Tabellen für die Darstellung des physischen Layouts persistenter
Daten in der Datenbank enthält. Dieser Schritt kann automatisch von Tools, die mit dem Managementsystem für
relationale Datenbanken (RDBMS, Relational Database Management System) bereitgestellt werden, oder mit den meisten
modernen Tools für visuelle Modellierung ausgeführt werden.
-
Setzen Sie die Tabellen im physischen Datenmodell in Designklassen im Designmodell um. Dieser Schritt kann durch
Kombination automatisierter Toolunterstützung für die erste Umsetzung und anschließender manueller Anpassungen
ausgeführt werden.
-
Definieren Sie Assoziationen zwischen den Klassen im Designmodell.
-
Definieren Sie basierend auf den in den Datenmodellelementen ausgeführten Aktionen entsprechende Operationen in den
Klassen im Designmodell.
-
Gruppieren Sie die Klassen im Designmodell bei Bedarf in Subsystemen und Paketen.
Das Rückentwickeln (Reverse-Engineering) der Datenbank bzw. des DDL-Scripts (Data Definition Language) liefert
gewöhnlich eine Gruppe von Modellelementen (Tabellen, Sichten, gespeicherte Prozeduren usw.). Je nach Komplexität der
Datenbank muss der Datenbankdesigner diese Modellelemente möglicherweise in Themenbereichspakete partitionieren, die
logisch zusammengehörige Gruppen von Tabellen enthalten.
Die folgende Prozedur beschreibt, wie Sie aus Modellelementen im Datenmodell Designklassen erzeugen können. Die
Nachbildung der Datenbankstruktur in einem Klassenmodell ist relativ unkompliziert. Der im Folgenden beschriebene
Prozess beschreibt die Algorithmen für die Umsetzung von Datenmodellelementen in Designmodellelemente.
Die folgende Tabelle zeigt eine Zusammenfassung der allgemeinen Zuordnung von Designmodellelementen zu
Datenmodellelementen.
Datenmodellelement
|
Entsprechendes Designmodellelement
|
Tabelle
|
Klasse
|
Spalte
|
Attribut
|
Nicht identifizierende Beziehung
|
Assoziation
|
Assoziationstabelle
|
Assoziationsklasse
N:N-Assoziation
Qualifizierte Assoziation
|
Identifizierende Beziehung
|
Aggregation
|
Kardinalität
|
Multiplizität
|
Prüfbedingung mit aufgelisteter Klausel
|
<<ENUM>> Klasse
|
Schema
|
Paket
|
Es gibt verschiedene Modellelemente im Datenmodell, die keine direkte Entsprechung im Designmodell haben. Zu diesen
Elementen gehören die Tabellenbereiche und die Datenbank selbst, die die physischen Speichermerkmale der Datenbank
modellieren und als Komponenten dargestellt werden. Weitere Elemente sind Datenbanksichten, die "virtuelle" Tabellen
sind und im Designmodell keine Bedeutung haben. Als letztes sind Indizes für Primärschlüssel von Tabellen und
Datenbankauslöserfunktionen zu nennen, die verwendet werden, um den Betrieb der Datenbank zu optimieren, und nur im
Kontext der Datenbank und des Datenmodells von Bedeutung sind.
Erstellen Sie für jede umzusetzende Tabelle eine Klasse, die die Tabelle darstellen soll. Erstellen Sie für jede Spalte
ein Attribut in der Klasse mit dem entsprechenden Datentyp. Versuchen Sie, den Datentyp des Attributs und den Datentyp
der zugeordneten Spalte so eng wie möglich aneinander anzupassen.
Beispiel
Schauen Sie sich die Datenbanktabelle Kunde mit der folgenden Struktur in der folgenden Abbildung an:
Spaltenname
|
Datentyp
|
Kunden_ID
|
number
|
Name
|
Varchar
|
Strasse
|
Varchar
|
Stadt
|
Varchar
|
Bundesland
|
Char(2)
|
Postleitzahl
|
Varchar
|
Land
|
Varchar
|
Tabellendefinition für die Tabelle Kunde
Hiervon ausgehend erstellen wir die Klasse Kunde mit der in der folgenden Abbildung gezeigten Struktur:
Anfangsklasse Kunde
In dieser Anfangsklasse Kunde gibt es ein Attribut für jede Spalte in der Tabelle Kunde. Jedes Attribut
hat die Sichtbarkeit public (öffentlich), da alle Spalten in der ursprünglichen Tabelle abgefragt werden können.
Das Pluszeichen ("+") links neben dem Attribut zeigt an, dass das Attribut die Sichtbarkeit 'public' hat. Standardmäßig
sollten alle Attribute, die aus RDBMS-Tabellen abgeleitet werden, den Typ 'public' haben, da RDBMS im Allgemeinen keine
Einschränkungen bezüglich der Abfrage von Spalten vorgibt.
Die Klasse, die sich aus der direkten Zuordnung der Tabelle zur Klasse ergibt, enthält häufig Attribute, die in eine
separate Klasse abgesondert werden können, insbesondere wenn die Attribute in mehreren übersetzten Klassen vorkommen.
Diese 'wiederholten Attribute' können von einer Denormalisierung stammen, die aus Leistungsgründen durchgeführt wurde,
oder das Ergebnis eines zu sehr vereinfachten Datenmodells sein. In diesen Fällen können Sie die entsprechende Klasse
in zwei oder mehr Klassen aufteilen, um eine normalisierte Sicht der Tabellen darzustellen.
Beispiel
Nachdem wir nun die Klasse Kunde definiert haben, können wir eine Klasse Adresse definieren, die alle
Adressinformationen enthält (vorausgesetzt, dass es weitere Dinge mit Adressen in unserem System gibt). Es ergeben sich
die folgenden Klassen:
Überarbeitete Klasse Kunde mit extrahierter Klasse Adresse
Die zwischen diesen beiden Klassen gezeichnete Assoziation ist eine Aggregation, da die Adresse des Kunden
praktisch Teil des Kunden ist.
Erstellen Sie für jede Fremdschlüsselbeziehung in der Tabelle eine Assoziation zwischen den zugeordneten Klassen und
entfernen Sie das Attribut aus der Klasse, die der Fremdschlüsselspalte zugeordnet ist. Wenn die Fremdschlüsselspalte
anfänglich als Attribut dargestellt wurde, entfernen Sie es aus der Klasse.
Beispiel
Schauen Sie sich im Folgenden die Struktur für die Tabelle Auftrag an:
Spaltenname
|
Datentyp
|
number
|
number
|
Kunden_ID
|
Varchar
|
Struktur der Tabelle Auftrag
In der oben gezeigten Tabelle Auftrag ist die Spalte Kunden_ID eine Fremdschlüsselreferenz. Diese
Spalte enthält den Primärschlüsselwert des Kunden, der dem Auftrag zugeordnet ist. Dies würde im Designmodell wie folgt
dargestellt:
Darstellung für Fremdschlüsselbeziehungen im Designmodell
Der Fremdschlüssel wird als Assoziation zwischen den Klassen Auftrag und Position dargestellt.
RDBMS-Datenmodell stellen N:M-Beziehungen mit einer verknüpften Tabelle bzw. einer Assoziationstabelle
dar. Mit diesen Tabellen können N:M-Beziehungen unter Verwendung einer Zwischentabelle dargestellt werden, die die
Primärschlüssel der beiden unterschiedlichen Tabellen enthält, die verknüpft werden können. Verknüpfte Tabellen werden
benötigt, weil eine Fremdschlüsselreferenz nur eine Referenz auf einen einzelnen Fremdschlüsselwert enthalten kann.
Wenn eine einzelne Zeile mit vielen anderen Zeilen in einer anderen Tabelle in Beziehung stehen kann, wird eine
verknüpfte Tabelle benötigt, um diese Zeilen einander zuzuordnen.
Beispiel
Schauen Sie sich den Fall von Produkten an. Produkte können von einer beliebigen Anzahl von Lieferanten
geliefert werden, und jeder Lieferant kann eine beliebige Anzahl von Produkten liefern. Die Tabellen
Produkt und Lieferant haben die folgende definierte Struktur:
Tabelle Produkt
Spaltenname
|
Datentyp
|
Produkt_ID
|
number
|
Name
|
Varchar
|
Beschreibung
|
Varchar
|
Preis
|
number
|
|
Tabelle Lieferant
Spaltenname
|
Datentyp
|
Lieferanten_ID
|
number
|
Name
|
Varchar
|
Strasse
|
Varchar
|
Stadt
|
Varchar
|
Bundesland
|
Char(2)
|
Postleitzahl
|
Varchar
|
Land
|
Varchar
|
|
Definitionen der Tabellen Produkt und Lieferant
Um diese beiden Tabellen zu verknüpfen, um die von einem bestimmten Lieferanten angebotenen Produkte zu finden,
benötigen wir eine Tabelle Produkt-Lieferant, die wie folgt definiert ist.
Tabelle Produkt-Lieferant
|
Spaltenname
|
Datentyp
|
Produkt_ID
|
number
|
Lieferanten_ID
|
number
|
Definition der Tabelle Produkt-Lieferant
Diese verknüpfte Tabelle enthält die Primärschlüssel von Produkten und Lieferanten und verbindet sie. Eine Zeile
in der Tabelle gibt an, dass ein bestimmter Lieferant ein bestimmtes Produkt anbietet. Alle Zeilen, deren Spalte
Lieferanten_ID einer bestimmten Lieferanten_ID entspricht, ergeben eine Liste aller Produkte, die von diesem
Lieferanten angeboten werden.
Im Designmodell ist diese Zwischentabelle redundant, da ein Objektmodell N:M-Assoziationen direkt darstellen kann. Die
Klassen Lieferant und Produkt und ihre Beziehungen sind in der folgenden Abbildung zusammen mit der
Klasse Adresse gezeigt, die aus der Klasse Lieferant extrahiert wurde, wie Sie der vorherigen
Beschreibung entnehmen können.
Darstellung der Klassen Produkt und Lieferant
Sie werden häufig Tabellen finden, die eine ähnliche Struktur haben. Im Datenmodell gibt es kein Konzept für Generalisierung, deshalb gibt es
auch keine Möglichkeit darzustellen, dass zwei oder mehr Tabellen eine gemeinsame Struktur haben. Gemeinsame Strukturen
entstehen manchmal, wenn aus Leistungsgründen eine Denormalisierung durchgeführt wird, wie beispielsweise im Fall mit
der 'impliziten' Tabelle Adresse, die wir in eine separate Klasse extrahiert haben. In anderen Fällen haben
Tabelle mehr grundlegende Merkmale gemeinsam, die wir in eine generalisierte übergeordnete Klasse mit zwei oder mehr
Unterklassen extrahieren können. Um Gelegenheiten für Generalisierung zu finden, müssen Sie nach Spalten suchen, die in
mehreren Tabellen vorkommen, die mehr Gemeinsamkeiten als Unterschiede aufweisen.
Beispiel
Schauen Sie sich die folgenden Tabellen Softwareprodukt und Hardwareprodukt an:
Tabelle Softwareprodukt
Spaltenname
|
Datentyp
|
Produkt_ID
|
number
|
Name
|
Varchar
|
Beschreibung
|
Varchar
|
Preis
|
number
|
Version
|
number
|
|
Tabelle Hardwareprodukt
Spaltenname
|
Datentyp
|
Produkt_ID
|
number
|
Name
|
Varchar
|
Beschreibung
|
Varchar
|
Preis
|
number
|
Version
|
number
|
|
Tabellen Softwareprodukt und Hardwareprodukt
Sie werden feststellen, dass die in Blau hervorgehobenen Spalten identisch sind. Die Definition dieser beiden Tabellen
ist nahezu identisch und weisen nur geringfügige Unterschiede auf. Wir können dies darstellen, indem wir eine
allgemeine Klasse Produkt mit den Unterklassen Softwareprodukt und Hardwareprodukt extrahieren:
Klassen Softwareprodukt und Hardwareprodukt mit einer Generalisierung zur Klasse Produkt
Wenn Sie alle Klassendefinitionen zusammenstellen, erhalten Sie, wie in der folgenden Abbildung gezeigt, ein
konsolidiertes Klassendiagramm für das Auftragserfassungssystem (nur Hauptklassen).
Konsolidiertes Klassendiagramm für das Auftragserfassungssystem
Das Nachbilden von Verhalten ist schwieriger, weil relationale Datenbanken in der Regel nicht objektorientiert sind und
keine Entsprechungen für Operationen in einer Klasse im Objektmodell zu haben scheinen. Die folgenden Schritte können
Ihnen dabei helfen, das Verhalten der zuvor identifizierten Klassen zu rekonstruieren:
-
Erstellen Sie Operationen, um jedes Attribut abzurufen und zu setzen. Es muss eine Möglichkeit geben, die
Werte der Attribute von Objekten zu setzen, zu ändern und abzufragen. Da der einzige Weg, auf die Attribute eines
Objekts zuzugreifen, die von der Klasse bereitgestellten Operationen sind, müssen solche Operationen in der Klasse
definiert werden. Wenn Sie die Operationen zum Setzen eines Attributs erstellen, müssen Sie alle
Validierungsbedingungen mit einfügen, die für die zugeordnete Spalte gelten. Wenn es keine Validierungsbedingungen
gibt, können Sie die Tatsache, dass die Attribute abgerufen (get) und gesetzt (set) werden können,
einfach so darstellen, dass Sie sie als öffentlich sichtbar kennzeichnen, wie es in den vorherigen Diagrammen (mit
dem Symbol links neben dem Attributnamen) getan wurde.
-
Erstellen Sie für jede gespeicherte Prozedur, die mit der zugeordneten Tabelle arbeitet, eine Operation in der
Klasse. Gespeicherte Prozeduren sind ausführbare Subroutinen, die im DBMS selbst ausgeführt werden. Diese Logik
muss in das Designmodell übersetzt werden. Wenn eine gespeicherte Prozedur nur mit einer Klasse arbeitet, erstellen
Sie eine Operation in der Klasse, die dieselben Parameter und denselben Rückgabetyp hat wie die gespeicherte
Prozedur. Dokumentieren Sie das Verhalten der gespeicherten Prozedur in der Operation und notieren Sie außerdem in
der Methodenbeschreibung, dass die Operation von der gespeicherten Prozedur implementiert wird.
-
Erstellen Sie Operationen, um Assoziationen zwischen Klassen zu verwalten. Wenn es eine Assoziation zwischen
zwei Klassen gibt, muss es immer eine Möglichkeit geben, Assoziationen zu erstellen, zu verwalten und zu entfernen.
Assoziationen zwischen Objekten werden über Objektreferenzen verwalten. Wenn Sie also eine Assoziation zwischen
einem Auftrag und einer Position erstellen möchten (d. h. um die Position dem Auftrag
hinzuzufügen), müssten Sie eine Operation in Auftrag aufrufen und die Position als Argument übergeben
(d. h. Auftrag.add(einePosition)). Außerdem muss es möglich sein, die Assoziation zu entfernen und zu
aktualisieren (d. h. Auftrag.remove(einePosition) und Auftrag.change(einePosition,eineNeuePosition)).
-
Behandeln Sie das Löschen von Objekten. Wenn die Zielsprache explizite Löschoperationen unterstützt, fügen
Sie dem Klassendestruktor Verhalten hinzu, das eine Überprüfung der referenziellen Integrität implementiert. Wenn
es referenzielle Integritätsbedingungen in der Datenbank gibt, z. B. kaskadierendes Löschen, muss das
Verhalten in den entsprechenden Klassen nachgebildet werden. Die Datenbank könnte beispielsweise eine Bedingung
definieren, die besagt, dass beim Löschen eines Auftrags alle zugeordneten Positionen ebenfalls
gelöscht werden müssen. Wenn die Zielsprache Garbage-Collection unterstützt, erstellen Sie einen Mechanismus, mit
dem Zeilen aus Tabellen gelöscht werden können, wenn das zugehörige Objekt von der Garbage-Collection erfasst wird.
Dies ist schwieriger, als es sich anhört (und es hört sich schon schwierig an), da Sie einen Mechanismus
implementieren müssen, der sicherstellt, dass kein Datenbankclient Referenzen auf das Objekt hält, das von der
Garbage-Collection erfasst werden soll. Es reicht nicht aus, sich auf die Garbage-Collection-Fähigkeiten der
Ausführungsumgebung/virtuellen Maschine zu verlassen, da dies nur eine Clientsicht in der Welt ist.
-
Behandeln Sie in Abfragen impliziertes Verhalten. Untersuchen Sie alle Select-Anweisungen, die auf die
Tabelle zugreifen, um festzustellen, wie Informationen abgerufen und bearbeitet werden. Setzen Sie für jede direkt
von einer Select-Anweisung zurückgegebene Spalte das Merkmal public des zugeordneten Attributs auf
true. Alle anderen Attribute müssen private sein. Erstellen Sie für jede berechnete Spalte in einer
Select-Anweisung eine Operation in der zugeordneten Klasse, um den Wert zu berechnen und zurückzugeben. Schließen
Sie bei der Betrachtung von Select-Anweisungen auch die in Sichtdefinitionen eingebetteten Select-Anweisungen ein.
Die Designklassen, die aus den Tabelle-Klasse-Umsetzungen erstellt werden, müssen je nach Struktur der
Gesamtarchitektur der Anwendung in entsprechenden Designpaketen und/oder Designsubsystemen im Designmodell organisiert werden. Eine Übersicht
über die Anwendungsarchitektur finden Sie in Konzept: Schichtung
und Konzept: Softwarearchitektur.
|