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