Montag, 2. September 2013

Generische Datenspeicherung mit XML - Teil 5 (SQL Server als Generic Entity Data Storage)

Bisherige Teile dieser Lecture

Falls Sie die bisherigen Teile dieser Lecture noch nicht kennen:

Kurze Rekapitulation was wir machen wollen

Wir wollen also einen dritten Generic Entity Data Storage implementieren, in welchem Generic Entities gespeichert werden sollen. Als Speicherort des Data Storage wählen wir für diesen Teil der Lecture eine SQL Server Datenbank

Übersicht zur geplanten Implementierung

Für die Implementierung des Data Storage benötigen wir genau eine Klasse: den GenericEntitySqlServerDataStorage.
Diese muss dann das Interface IGenericEntityDataStorage implementieren. Die einzige Information, welche Sie benötigt, ist welche Datenbank zu verwenden ist und wie auf diese zugegriffen werden kann. Da diese Angaben wesentlich sind für ihr ordnungsgemäßes Funktionieren, werden wir sie in Form eines Connection-Strings bereits im Konstruktor als Argument vorsehen

Der eigentliche Umgang mit den Daten in der Datenbank - sprich das Speichern, Finden und Löschen - werden wir mit der LINQ to SQL Technologie von .Net implementieren - im Folgenden mehr dazu. Hier jetzt erst einmal die Definition der Klasse GenericEntitySqlServerDataStorage:

Wichtige Frage im Zusammenhang mit der Datenbank - wie soll diese aufgebaut sein? Hier zunächst einmal zusammengefasst, welche Daten wir speichern wollen: Generic Entities mit den String-Eigenschaften "ApplicationKey", "FullClassName", "EntityId" sowie einem XElement "XmlSerialisierung". Basierend hierauf werden wir eine Datenbank mit genau einer Tabelle erstellen. Diese wird dann die entsprechenden Eigenschaften der Generic Entities als Spalten enthalten. Der Tabelle werden wir den Namen "tGenericEntities" geben. Hier das genaue Tabellen-Design:

Eigentlich ist jeder Eintrag durch die Kombination der 3 String-Eigenschaften eindeutig identifiziert. Um uns das Leben einfacher zu machen und das ganze etwas performanter zu gestalten legen wir als Key in der Datenbank aber eine künstliche Id an, welche wir dann als Primary Key verwenden. Diese wird auf "Auto-Inkrement" gesetzt und zählt selbständig hoch. Irgendwo extern verwendet wird sie allerdings nicht

Datenbank-Zugriff mit LINQ to SQL

Um auf die Datenbank mittels LINQ to SQL zuzugreifen benötigen wir zuerst ein DataContext-Objekt für unsere Datenbank, welches wir dann für die zu implementierenden CRUD-Operationen verwenden (CRUD = "Create, Read, Update, Delete"). Das geht mit Visual Studio sehr einfach. Wir fügen dem Projekt ein neues Element vom Typ "LINQ to SQL Klassen" hinzu, welches wir "GenericEntities.dbml" nennen. Im Server-Explorer öffnen wir dann die Datenbank und ziehen die Tabelle "tGenericEntities" aus dem Server-Explorer in die Design-Ansicht der neu erzeugten Datei "GenericEntities.dbml". Visual Studio erzeugt uns dabei zwei neue Klassen: tGenericEntity und GenericEntitiesDataContext

Da der Name und die Property-Namen der erzeugten Klasse tGenericEntity nicht ganz zu unseren Code-Konventionen passt benennen wir sie im Designer um, so dass wir anschließend folgende beiden neuen Klassen haben:

Die Klasse GenericEntitiesDataContext bekommt im Konstruktor einen Connection-String für die Datenbank-Verbindung übergeben und stellt uns dann über die Property GenericDatabaseEntities Methoden zur Verfügung um mit Objekten des Typs GenericDatabaseEntity umgehen zu können. Da diese den von uns eigentlich zu speichernden Objekten des Typs GenericEntity genau entsprechen lassen sie sich einfach ineinander umwandeln und wir können mit der eigentlichen Implementierung beginnen:

Implementierung mit LINQ to SQL

Kommen wir nun zur Implementierung der Klasse GenericEntitySqlServerDataStorage:

Konstruktor

Als erstes betrachten wir den Konstruktor. In diesem instanziieren wir ein Objekt der gerade automatisch neu erzeugten Klasse GenericObjectsDataContext mittels des übergebenen Connection-Strings

Hier die wesentlichen Code-Segmente des Konstruktors:

DataContext = new GenericEntitiesDataContext(connectionString);

Hilfsmethoden

Im nächsten Schritt implementieren wir dann eine Hilfsmethode um ein Generic Entity mithilfe seiner ID-Eigenschaften in der Datenbank zu finden

Hier die wesentlichen Code-Segmente um ein Generic Entity XElement zu finden:

return DataContext.GenericDatabaseEntities.SingleOrDefault<GenericDatabaseEntity>( c => c.ApplicationKey == applicationKey && c.FullClassName == fullClassName && c.EntityId == entityId );

Speichern, Finden und Löschen

Beim den eigentlichen Hauptoperationen des Data Storage - dem Speichern, Finden und Löschen - greifen wir hauptsächlich auf die gerade vorgestellte Hilfsmethode zu. Außerdem benutzen wir die Methoden des DataContext-Objektes um die Operationen durchzuführen. Anschließend machen wir die Änderungen mittels der SubmitChanges-Methode des DataContext-Objektes persistent

Hier die wesentlichen Code-Segmente zum Speichern einer Generic Entity:

GenericDatabaseEntity existingItem = findExisting(...); if (existingItem == null) { // -> insert GenericDatabaseEntity newItem = new GenericDatabaseEntity(); newItem.ApplicationKey = genericEntity.ApplicationKey; newItem.FullClassName = genericEntity.FullClassName; newItem.EntityId = genericEntity.EntityId; newItem.XmlSerialization = genericEntity.XmlSerialization; DataContext.GenericDatabaseEntities.InsertOnSubmit(newItem); } else { // -> update existingItem.XmlSerialization = genericEntity.XmlSerialization; } DataContext.SubmitChanges();

... zum Finden einer Generic Entity:

GenericDatabaseEntity existingItem = findExisting(...); if (existingItem != null) { GenericEntity genericEntity = new GenericEntity(); genericEntity.ApplicationKey = existingItem.ApplicationKey; genericEntity.FullClassName = existingItem.FullClassName; genericEntity.EntityId = existingItem.EntityId; genericEntity.XmlSerialization = existingItem.XmlSerialization; return genericEntity; } return null;

... und zum Löschen einer Generic Entity:

GenericDatabaseEntity existingItem = findExisting(...); if (existingItem != null) { DataContext.GenericDatabaseEntities.DeleteOnSubmit(existingItem); DataContext.SubmitChanges(); }

Damit wären wir fertig mit der Implementierung des Generic Entity Sql Server Data Storage. Was noch fehlt ist eine Fehlerbehandlung sowie die Implementierung der restlichen Methoden. Diese erfolgt dann analog den gerade beschriebenen Methoden

Nächster Schritt

Im nächsten Teil der Lecture werden wir uns genauer überlegen, wie wir die nun implementierte Funktionalität einem Verwender der Komponente am einfachsten zur Verfügung stellen können. Mit der rein technischen Implementierung der Datenspeicherung sind wir an dieser Stelle erst mal fertig

... to be continued

Autor: Thomas Gysser | www.advadev.de

Keine Kommentare:

Kommentar veröffentlichen