Persistenz
Datenbanken werden in Schleupen.CS 3.0 einfach über Cmdlets verwaltet. Hier wird - wie bereits beschrieben - Microsofts Sql Server verwendet. Datenbanken für Länder werden in der Systemstruktur verwaltet, d.h. in Schleupen.CS 3.0 bekannt gemacht. Datenbanken mit Infrastruktur-Charakter hängen unter dem System-Knoten in der Systemstruktur. Insbesondere Datenbanken für Länder bilden quasi den Datenkontext für Serviceaufrufe. Welche Datenbank dabei konkret verwendet wird, ergibt sich durch die ServiceImplementierungsgruppe, die einem Systemstrukturelementknoten zugeordnet ist, auf welchem Knoten und Verwendungszweck man verbunden ist, welche Datenbanken unter einem Systemstrukturelementknoten definiert sind und welcher dieser Datenbanken das Schema des Landes zugeordnet ist.
Die nachfolgende Abbildung zeigt eine minimale Systemstruktur, die man mithilfe des Cmdlets Select-SystemStructureView
anzeigen kann.
Wie man sehen kann, besteht die Systemstruktur lediglich aus den Knoten System und 9999. Dem Knoten 9999 ist die Serviceimplementierungsgruppe Bibliotheksverwaltung zugeordnet. Hierdurch besteht die Verknüpfung zum Datenbank-Schema MT_BIB. Diese Verbindung wird durch das Land definiert.
Repositories - Baustein zur DB
Wie in Taktisches Domain-Driven Design beschrieben, werden Entities mithilfe eines Repository in die Datenbank geschrieben. Die Implementierung verwendet intern im Standard den OR-Mapper NHibernate.
Die Implementierung zeigt folgender Code-Ausschnitt
public sealed class BuchRepository : Repository<Buch, BuchId> { public BuchRepository(INHibernateSessionFactory nhibernateSessionFactory, IBuchRepositoryConfigurator configurator) : base(nhibernateSessionFactory, configurator) { } public async Task QueryByIdAsync(IEnumerable<BuchId> buchIds) { … } … }
Da wir in diesem Kapitel mehr die technischen Aspekte der Persistenz beleuchten, betrachten wir nun den Zugriff auf den Datenbank genauer.
Connection-Handling
Der folgende Abschnitt beschreibt, wie ein Land für die Verarbeitung beginnend beim Login zu einer Datenbankverbindung kommt. Hierzu betrachten wir das folgende Bild. Hier werden ganz einfach Daten gelesen und dem Benutzer präsentiert.
- Durch das Einloggen wird ein sogenanntes SessionToken anhand der Anmeldung an einem Konten des Systemstrukturbaums erzeugt.
- Dieses SessionToken wird im SOAP-Header des Serviceaufrufs an den Service gegeben und durch die Infrastruktur ausgelesen. Mithilfe eines sogenannten SessionToken-Providers wird ein Repository per Dependency-Injection erzeugt.
- Das Repository liest den Connection-String und erstellt eine Connection mit spezifischen SQL-Benutzer gegen die Datenbank. Es wird also nicht Integrated-Security verwendet.
- Das Ergebnis wird durch die Schalen transportiert und dem Benutzer angezeigt.
Richtlinien und Konventionen
In Schleupen.CS kommen auch im Datenbank-Kontext einige Design-Richtlinien und Konventionen zur Anwendung. Am wichtigsten ist, dass Tabellennamen und Spaltennamen möglichst sprechend sind. Die Konvention lautet: Die Tabelle wird wie die zugehörige Entität benannt. D.h. die Tabelle der Entität Buch wird somit Buch genannt. Genauso werden Spalten 1:1 auf Attribute / Eigenschaften abgebildet.
Des Weiteren gilt:
- Standard in CS 3.0 sind GUIDs für den Primärschlüssel der Entitys. Diese GUIDs werden in die Entitäten übernommen, was mehrere Vorteile bietet. So könnten beispielsweise Daten einfach portiert und zurückgespielt werden, was insbesondere für Testsysteme interessant ist. Zudem können in der Logik Entitäten sehr "früh" in Verarbeitungsketten IDs kollisionsfrei erhalten und diese müssen nicht durch die Datenbank oder einer anderen Infrastrukturkomponente wie ein OR-Mapper erzeugt werden. Auch die etwaigen Performance-Nachteile von GUIDs zu anderen Typen sind nicht signifikant.
- Tabellen sollten möglichst schmal sein, denn Tabellen mit geringer Spaltenbreitensumme sind performanter als Tabellen mit vielen und breiten Spalten. Das ist konform zur Domänen, in denen keine großen Aggregate erstellt werden sollten und die Kohäsion schnell nicht mehr gegeben ist.
- Breite Spalten beispielsweise für Kommentare, Notizen, Bemerkungen und Blob-Spalten sollten in eigene Tabellen (Weak Entities) ausgelagert werden.
Beispiel: Person -> PersonNotiz - Das Datenbank-Schema eines Landes / einer Geschäftsprozesskomponente leitet sich direkt aus dessen Kürzel ab. Heißt beispielsweise ein Land MT.BIB (-> Mediathek / Bibliotheksverwaltung), so wird das Schema MT_BIB verwendet. Hinweis: Aufgrund von Pfadlängenproblemen werden leider Kürzel zur Produktbezeichnung verwendet.
Jedes Land / jede Geschäftsprozesskomponente mit Persistenz verwendet ein Tool für das Patchen der Datenbank. Dies ist durch ein Installationspaket abgebildet, das die Patches auf definierte Art einspielt.
Konventionen NHibernate
Bei der Definition von ClassMap<T>
mittels FluentNhibernate kommen folgende Konventionen zur Anwendung:
- Tabellenname: Es wird der Name der Entität als Name der Tabelle verwendet.
- Spaltenname: Der Name der gemappten Property wird als Spaltennamen verwendet.
- Fremdschlüssel: 1:n-Beziehungen werden für den Zieltyp mit Namen verkettet mit '_' und Id verknüpft. Beispiel: Die Tabelle Ausleihe referenziert ein Buch. Der Fremdschlüssel hat dann den Namen Buch_Id.
Das folgende Codebeispiel zeigt dies:
public sealed class BuchMap : ClassMap<Buch> { public BuchMap() { Schema(DatabaseInfo.DatabaseSchema); ... Id(x => x.Id).CustomType<EntityIdUserType<BuchId>>(); // per Konvention angeschlossen Map(x => ((IBuchData)x).Autor); Map(x => ((IBuchData)x).Titel).Not.Nullable(); ... Component( x => ((IBuchData)x).Isbn, p => p.Map(x => ((IIsbnData)x).Nummer).Column("Isbn").Not.Nullable()); ... References(x => ((IBuchData)x).Inhaltsangabe) .Cascade.All(); HasMany(x => ((IBuchData)x).PreiseData) .Not.KeyUpdate() .Not.KeyNullable() .Cascade.AllDeleteOrphan(); } }
Auch hier gilt das Prinzip Convention Over Configuration, d.h. bei Abweichung von der Konvention kann beispielsweise ein abweichender Tabellenname einfach angegeben werden.
Elastic und Co.
Für Monitoring, Protokollierungen, Reporting kommen auch andere Persistenzmechanismen zum Einsatz, z.B. der Elastic Stack: Elasticsearch, Kibana, Beats und Logstash | Elastic.