Richtlinie: Relationale Datenbanken rückentwickeln
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.
Beziehungen
Zugehörige Elemente
Hauptbeschreibung

Einführung

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.

RDBMS-Datenbank oder DDL-Script zum Generieren eines Datenmodells rückentwickeln

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.

Datenmodell in Designmodell umsetzen

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.

Tabellen in Klassen umsetzen

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:

Definition der Klasse Kunde

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.

Eingebettete oder implizite Klassen identifizieren

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:

Im Begleittext beschriebenes Diagramm

Ü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.

Fremdschlüsselbeziehungen behandeln

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:

Im Folgenden beschriebenes UML-Diagramm

Darstellung für Fremdschlüsselbeziehungen im Designmodell

Der Fremdschlüssel wird als Assoziation zwischen den Klassen Auftrag und Position dargestellt.

N:M-Beziehungen behandeln

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.

In der Überschrift genanntes UML-Diagramm

Darstellung der Klassen Produkt und Lieferant

Generalisierung einführen

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:

Im Begleittext beschriebenes Diagramm

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).

Im Begleittext beschriebenes komplexes UML-Diagramm

Konsolidiertes Klassendiagramm für das Auftragserfassungssystem

RDBMS-Verhalten im Designmodell nachbilden

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:

  1. 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.
  2. 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.
  3. 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)).
  4. 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.
  5. 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.

Elemente im Designmodell organisieren

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.