SQL oder NoSQL (Teil 2)
Kommentare

Dokumentenorientiert modellieren
Wie aber soll man seine Daten gestalten, wenn nicht durch Tabellen und Relationen? Und was ist ein Dokument? Aus Sicht eines Programmierers ist die Antwort auf beide

Dokumentenorientiert modellieren

Wie aber soll man seine Daten gestalten, wenn nicht durch Tabellen und Relationen? Und was ist ein Dokument? Aus Sicht eines Programmierers ist die Antwort auf beide Fragen gleich: durch Objekte. Und damit steht das Objektmodell im Zentrum der Überlegungen und nicht ein Tabellenmodell.

Wie ein solches Datenmodell aussieht, soll am klassischen Auftragsbeispiel verdeutlicht werden. Natürlich braucht man ein Kundenobjekt, den Customer. Wie alle anderen Klassen im Beispiel handelt es sich hier um ein stark abgespecktes Modell. Dann gibt es das Order-Objekt, das die Bestellung eines Kunden aufnimmt. Dieser Auftrag hat natürlich eine Referenz zum Kunden. Wie bildet man diese Referenz dokumentenorientiert ab? Die erste Idee ist, die ID des Kunden zu verwenden. Aber dann braucht man, um alle relevanten Informationen zu einem Auftrag zu laden, entweder einen Join oder zwei Anfragen an den Server. Beides ist nicht erwünscht: Alle relevanten Daten sollen auf einen Schlag geladen werden. Also packt man das komplette Kundenobjekt in den Auftrag. Stellt man sich nun aber ein „echtes“ Kundenobjekt vor, so stellt man fest, dass es auch zahlreiche Informationen besitzen könnte, die für die Auftragsbearbeitung uninteressant sind. Durch eine Überfrachtung des Auftrags mit unnötigen Informationen steigt die zu übertragende Datenmenge, und die Übersichtlichkeit des Modells leidet.

Der Ausweg aus dem Dilemma ist nach relationaler Denkweise befremdlich: Man definiert ein neues Objekt namens OrderCustomer. Das beinhaltet alle Kundeninformationen, die im Kontext der Auftragsbearbeitung benötigt werden. Beim Anlegen eines Auftrags werden die benötigten Daten aus dem ursprünglichen Kunden kopiert. Dabei speichert man die ID des Originalkunden mit ab, so kann man später die Verbindung zu ihm wieder knüpfen, wenn es nötig ist. Man spricht dabei von einer denormalisierten Referenz (Listing 1). Auf diese Weise hat man Kundendaten mehrfach im System. Wenn sich der Originalkunde ändert, verändert das die bestehenden Bestellungen nicht. Will man die Änderung überall dort durchsetzen, wo der Kunde verwendet wird, was nur selten vorkommen dürfte, hat man mehr Arbeit. Dafür kann man in den häufigeren Fällen, in denen die Daten gelesen werden sollen, jetzt alles auf einen Streich laden. Das spart gegenüber der relationalen Speicherung eine Menge Joins.

Das Datenmodell in Listing 1 führt die oben beschriebene Idee noch ein bisschen weiter. Der Auftrag enthält eine Liste von OrderLineObjekten, jede Position beinhaltet einen bestellten Artikel. Für diese Referenz gilt die gleiche Überlegung wie für den Kunden im Auftrag: Die ID des Artikels zu speichern ist relationales Design, den gesamten Artikel zu speichern, kann zu einer Überladung führen. Also erzeugt man ein spezifisches Objekt OrderLineArticle, das nur die relevanten Informationen enthält.

Listing 1: Ein vereinfachtes Kunde/Artikel/Auftrag-Modell

public class Customer 
{ 
public String Id { get; set; } 
public String FirstName { get; set; } 
public String LastName { get; set; } 
public String Email { get; set; } 
} 
public class Article 
{ 
public String Id { get; set; } 
public String Name { get; set; } 
public bool IsBiological { get; set; } 
public bool IsGoodForYou { get; set; } 
} 
public class Order 
{ 
public String Id { get; set; } 
public OrderCustomer Customer { get; set; } 
public String OrderDate { get; set; } 
public List Positions { get; set; } 
} 
public class OrderCustomer 
{ 
public String Id { get; set; } 
public String FirstName { get; set; } 
public String LastName { get; set; } 
} 
public class OrderLine 
{ 
public OrderLineArticle Article { get; set; } 
public Double Price { get; set; } 
public Double Quantity { get; set; } 
} 
public class OrderLineArticle 
{ 
public String Id { get; set; } 
public String Name { get; set; } 
}   

Datenpersistenz in 60 Sekunden

Diese Daten sollen nun in RavenDB gespeichert werden. Dazu ist zunächst die Software unter ravendb.net zu beziehen. Im Folgenden ist die zip-Datei zu entpacken und aus dem Ordner Server die Datei Raven.Server.exe zu startet, und schon läuft die Datenbank. Natürlich gibt es noch andere Deployment-Möglichkeiten, diese werden hier jedoch nicht behandelt. Im nächsten Schritt fügt man der Solution mit dem Datenmodell die benötigten Referenzen für Raven aus dem Ordner Client hinzu, der Code befindet sich auf der Heft-DVD. Um Daten in Raven zu speichern benötigt man eine Instanz der Klasse DocumentStore. Dieser übergibt man den URL des Servers, per Default ist das http://localhost:8080. Der Store muss über die Initialize-Methode initialisiert werden. Über den Store kann nun eine Session abgerufen werden, innerhalb derer die eigentlichen Operationen abgesetzt werden: 

Store = new DocumentStore() { Url = "http://localhost:8080"}; 
Store.Initialize(); 
using (var Session = Store.OpenSession()) 
{ 
// Datenzugriffe hier... 
}   
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -