Hausarbeit FOM – Fachhochschule für Oekonomie & Management Frankfurt am Main Datenbankmanagement 3. Semester Hausarbeit zum Thema Zugriff auf Datenbanken unter .NET mit dem Entity Framework Betreuer: Professor Dr. rer. pol. Dieter Litzinger, Erik Reischl Autor: Max Jäger Frankfurt, den 06. Januar 2013 Inhalt Inhalt Abkürzungen II Abbildungen III Quelltexte IV 1 Einleitung 1 2 Überblick 1 2.1 Objektrelationale Mapper . . . . . . . . . . . . . . . . . . . . . 1 2.2 Architektur des ADO.NET Entity Framework . . . . . . . . . . 2 3 Das Entitätenmodell 3 3.1 Entitäten und deren Beziehungen . . . . . . . . . . . . . . . . . 3 3.2 Objektkontext . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 3.3 Metadaten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 3.3.1 Logische Schicht . . . . . . . . . . . . . . . . . . . . . . . 5 3.3.2 Konzeptionelle Schicht . . . . . . . . . . . . . . . . . . . 5 3.3.3 Mapping . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Entwurf des Entitätenmodells . . . . . . . . . . . . . . . . . . . 6 3.4 4 Arbeiten mit Entitätsdaten 7 4.1 Abfragen eines konzeptionellen Modells mit LINQ to Entities . . 7 4.2 Hinzufügen, Ändern und Löschen von Objekten . . . . . . . . . 8 4.2.1 Hinzufügen von Objekten . . . . . . . . . . . . . . . . . 8 4.2.2 Ändern von Objekten . . . . . . . . . . . . . . . . . . . . 9 4.2.3 Löschen von Objekten . . . . . . . . . . . . . . . . . . . 9 5 Fazit 10 6 Literatur 11 I Abkürzungen Abkürzungen CSDL . . . . . . . . . . . Conceptual Schema Definition Language EDM . . . . . . . . . . . . Entity Data Model LINQ . . . . . . . . . . . Language Integrated Query MSL . . . . . . . . . . . . . Mapping Schema Language O/R-Mapper . . . Objektrelationaler Mapper SSDL . . . . . . . . . . . . Storage Schema Definition Language II Abbildungen Abbildungen 1 Entity Framework-Architektur . . . . . . . . . . . . . . . . . . . III 2 Quelltexte Quelltexte 1 SSDL-Abschnitt des EDM . . . . . . . . . . . . . . . . . . . . . 5 2 CSDL-Abschnitt des EDM . . . . . . . . . . . . . . . . . . . . . 5 3 MSL-Abschnitt des EDM . . . . . . . . . . . . . . . . . . . . . . 6 4 Abfragen von Objekten . . . . . . . . . . . . . . . . . . . . . . . 7 5 Hinzufügen eines Objektes . . . . . . . . . . . . . . . . . . . . . 8 6 Ändern eines Objektes . . . . . . . . . . . . . . . . . . . . . . . 9 7 Löschen eines Objektes . . . . . . . . . . . . . . . . . . . . . . . 9 IV Überblick 1 Einleitung Bei vielen Anwendungen muss eine große Menge an Informationen gespeichert werden. Für die Speicherung dieser Daten werden häufig relationale Datenbanken verwendet. Bei der Programmierung mit objektorientierten Programmiersprachen stehen Entwickler vor der Aufgabe, sowohl Klassenmodelle zu entwerfen und Objekte und deren Beziehungen zu verwalten, als auch die Daten in der Datenbank zu speichern.1 Der Zugriff auf Datenbanken lässt sich aus Sicht der Programmierung auf mehrere Arten realisieren, von denen eine die Verwendung eines objektrelationalen Mappers (O/R-Mapper) ist. Diese Hausarbeit bietet nach einer kurzen Erläuterung der Funktionsweise eines O/R-Mappers eine Einführung in das ADO.NET Entity Framework, dem O/R-Mapper für die Programmiersprache C#. 2 Überblick 2.1 Objektrelationale Mapper Ein O/R-Mapper ist eine Zwischenschicht zwischen einer relationalen Datenbank und einer Anwendung. In einer relationalen Datenbank gibt es Tabellen, die über Relationen miteinander verknüpft werden können, und auf Anwendungsseite gibt es in objektorientierten Programmiersprachen Klassen und Objekte. Der O/R-Mapper übernimmt die Verbindung (Mapping) zwischen den Tabellen der Datenbank und den Klassen der Anwendung. Ein O/R-Mapper erzeugt aus Objekten SQL-Abfragen bzw. aus Ergebnissen von SQL-Abfragen wieder Objekte. Hierbei werden einzelne Datensätze in der Datenbanktabelle in einzelne Objekte umgesetzt, die Spalten der Datenbanktabelle werden in die entsprechenden Eigenschaften der Objekte umgesetzt.2 Für das Verständnis sind Kenntnisse in Bezug auf die Datenbank-Struktur und SQL-Abfragen hilfreich, z. B. im Hinblick auf Geschwindigkeitsoptimierungen von Abfragen.3 1 2 3 Vgl. Microsoft, (2012a), o.S. Vgl. Kansy, (2011), S. 20. Vgl. Mostarda, Sanctis und Bochicchio, (2011), S. 25. 1 Überblick 2.2 Architektur des ADO.NET Entity Framework Das ADO.NET Entity Framework ist in mehrere Ebenen unterteilt. Zentrale Stelle ist der EntityClient Data Provider. Dieser stellt die Verbindung zwischen den Klassen und Objekten in .NET und der Datenbank her.4 Hinterlegt sind die dafür notwendigen Informationen im Entitätenmodell (EDM). Dieses ist in drei Schichten aufgeteilt:5 • die logische Schicht, die die Datenbankstruktur darstellt (Storage Model) • die konzeptionelle Schicht, die das Datenmodell darstellt (Conceptual Model) • die Zuordnungsschicht, die die logische und die konzeptionelle Schicht miteinander verbindet (Mapping) Quelle: Entnommen aus: http://msdn.microsoft.com/de-de/library/vstudio/bb399567, Zugriffsdatum: 2012-10-03 Abbildung 1: 4 5 Entity Framework-Architektur Vgl. Lerman, (2010), S. 14. Vgl. Mertins, Neumann und Kühnel, (2012), S. 1151. 2 Das Entitätenmodell Mit den Informationen des EDM ist der EntityClient Data Provider in der Lage, datenbankspezifische ADO.NET Data Provider anzusprechen und Zugriffe auf unterschiedlichen Datenbanksystemen auszuführen.6 Innerhalb der .NET-Programmiersprachen bietet das Entity Framework dem Entwickler zwei Möglichkeiten, um Daten abzufragen: LINQ to Entities und Entity SQL. LINQ ist eine SQL-ähnliche Abfragesprache direkt auf Objektebene. Entity SQL ist eine datenbankunabhängige SQL-Syntax. LINQ to Entities hat sich mittlerweile als Standard-Abfragesprache etabliert, jedoch gibt es Anwendungsfälle, in denen LINQ to Entities nicht möglich ist. Die Abfragen bei LINQ to Entities müssen zur Kompilierzeit feststehen, wohingegen sich eine Entity SQL-Abfrage dynamisch zur Laufzeit erzeugen und ausführen lässt.7 Bei beiden Verfahren übersetzt der EntityClient Data Provider die erzeugten Abfragen in die entsprechenden SQL-Abfragen und liefert einen Datenleser zurück. Die Object Services übersetzen die gelesenen Daten in die entsprechenden Objekte.8 3 Das Entitätenmodell Nachdem die Architektur des Entity Frameworks erläutert wurde, werden nun die einzelnen Bestandteile des Entitätenmodells erläutert. Hierzu zählen die Klassen, mit denen der Entwickler programmiert, der Objektkontext, der die Verbindung zur Datenbank herstellt, und die Metadaten, mit denen die Klassenund die Datenbankstrukturen abgebildet und verknüpft werden.9 3.1 Entitäten und deren Beziehungen Entitäten sind Klassen, die Datenbanktabellen repräsentieren, deren Tabellenspalten als Eigenschaften der Klassen abgebildet werden. Neben skalaren Werten können Klassen über Navigationseigenschaften verfügen, die die Beziehungen, die in der Datenbankbank als Relationen hinterlegt sind, abbilden. 6 7 8 9 Vgl. Vgl. Vgl. Vgl. Lerman, (2010), S. 49f. Mertins, Neumann und Kühnel, (2012), S. 1200. Microsoft, (2012a), o.S. Microsoft, (2012a), o.S. 3 Das Entitätenmodell Hierüber kann von einer zu einer anderen Klasse navigiert werden, die mit dieser über eine Zuordnung verbunden ist. Zudem verfügt jede Klasse über einen Primärschlüssel, der eine Ausprägung dieser Klasse eindeutig identifizert.10 3.2 Objektkontext Der Objektkontext verwaltet die Verbindung zwischen den Entitäten und der Datenbank. Er überwacht die Änderungen an den Objekten, die Einhaltung der definierten Beziehungen der Objekte untereinander und stellt über eine SaveChanges-Methode die zentrale Funktion bereit, die Einfügungen, Änderungen und Löschungen in die Datenquelle schreibt.11 Hierzu werden datenbankspezifische Befehle generiert und ausgeführt, die die entsprechenden Änderungen in der Datenbank vornehmen.12 3.3 Metadaten Wie bereits in der Architektur dargestellt, besteht das Entitätenmodell intern aus drei Schichten. Diese drei Schichten werden in einer gemeinsamen Datei mit der Dateiendung .edmx gespeichert, die einen XML-Aufbau besitzt.13 Innerhalb dieser Datei gibt es für jede einzelne Schicht einen eigenen Abschnitt.14 Durch diese Trennung ist es möglich, das gleiche Klassenmodell mit unterschiedlichen Datenprovidern zu verwenden, indem lediglich das Datenbankmodell und die Zuordnungen ausgetauscht werden. Über diese drei Schichten kann das Entity Framework aus den Vorgängen, die auf die Entitäten angewendet werden, die entsprechenden Vorgänge für die Datenbank ableiten.15 10 11 12 13 14 15 Vgl. Vgl. Vgl. Vgl. Vgl. Vgl. Kansy, (2011), S. 81. Microsoft, (2012a), o.S. Microsoft, (2012b), o.S. Kansy, (2011), S. 27. Mertins, Neumann und Kühnel, (2012), S. 1162. Microsoft, (2012a), o.S. 4 Das Entitätenmodell 3.3.1 Logische Schicht Die logische Schicht beschreibt das physische Datenbankmodell. Darunter fallen die Datenbanktabellen mit ihren Spalten, Datentypen, Primärschlüsseln und Beziehungen untereinander. Die Beschreibung erfolgt mit der Storage Schema Definition Language (SSDL).16 Für die Verdeutlichung der Zuordnung wird die Datenbanktabelle mit englischen Bezeichnungen angegeben und die .NET-Klasse mit deutschen Bezeichnern. Eine Tabelle wird über ein EntityType-Element definiert. Der Primärschlüssel wird im Unterelement Key, die einzelnen Spalten in Property-Elementen definiert. Jedes Property-Element hat mehrere Attribute, die z. B. den Namen, den Datentyp oder die maximale Länge festlegen. Der Datentyp bezieht sich hierbei auf den Datentyp des Datenbanksystems.17 Quelltext 1: 1 2 3 4 5 6 7 8 9 SSDL-Abschnitt des EDM < EntityType Name = " Address " > <Key > < PropertyRef Name = " AddressID " / > </ Key > < Property Name = " AddressID " Type = " int " Nullable = " false " / > < Property Name = " Street " Type = " nvarchar " MaxLength = " 100 " / > < Property Name = " Postcode " Type = " nvarchar " MaxLength = " 5 " / > < Property Name = " City " Type = " nvarchar " MaxLength = " 100 " / > </ EntityType > 3.3.2 Konzeptionelle Schicht Die Beschreibung der .NET-Klassen erfolgt in der konzeptionellen Schicht mit der Conceptual Schema Definition Language (CSDL). Dieser Abschnitt hat große Ähnlichkeit mit der Definition der logischen Schicht, jedoch gibt es erwähnenswerte Unterschiede. Beispielsweise beziehen sich die Datentypen hier auf die .NET-Datentypen und nicht mehr auf die datenbankspezifischen Datentypen.18 16 17 18 Vgl. Mertins, Neumann und Kühnel, (2012), S. 1163. Vgl. Mertins, Neumann und Kühnel, (2012), S. 1163. Vgl. Doberenz und Gewinnus, (2010), S. 1174. 5 Das Entitätenmodell Quelltext 2: 1 2 3 4 5 6 7 8 9 CSDL-Abschnitt des EDM < EntityType Name = " Adresse " > <Key > < PropertyRef Name = " AdressNr " / > </ Key > < Property Name = " AdressNr " Type = " Int32 " Nullable = " false " / > < Property Name = " Strasse " Type = " String " MaxLength = " 100 " / > < Property Name = " PLZ " Type = " String " MaxLength = " 5 " / > < Property Name = " Ort " Type = " String " MaxLength = " 100 " / > </ EntityType > 3.3.3 Mapping Die Verbindung zwischen der logischen und der konzeptionellen Schicht wird mit der Mapping Schema Language (MSL) beschrieben. Die Tabellen werden auf die .NET-Klassen und die einzelnen Spalten auf die Eigenschaften der Klassen abgebildet.19 Quelltext 3: 1 2 3 4 5 6 7 8 9 10 MSL-Abschnitt des EDM < E n t i t y S e t M a p p i n g Name = " Adresse " > < E n t i t y T y p e M a p p i n g TypeName = " Adresse " > < M ap pi ng F ra gm en t StoreEntity Set = " Address " > < ScalarPr operty Name = " AdressNr " ColumnName = " AddressID " / > < ScalarPr operty Name = " Strasse " ColumnName = " Street " / > < ScalarPr operty Name = " PLZ " ColumnName = " Postcode " / > < ScalarPr operty Name = " Ort " ColumnName = " City " / > </ MappingFragment > </ EntityTypeMapping > </ EntitySetMapping > 3.4 Entwurf des Entitätenmodells Dem Entwickler stehen zwei Ansätze zur Erzeugung des Entitätenmodells zur Verfügung: Database-First oder Model-First. Beim Database-First-Ansatz wird zunächst die Datenbank mit allen Tabellen, Spalten, Primär- und Fremdschlüsseln erzeugt. Danach kann das Entitätenmodell aus dieser Datenbank generiert werden. Der Model-First-Ansatz geht den umgekehrten Weg, bei dem zunächst das Klassenmodell erstellt und daraus die Datenbank erzeugt wird.20 19 20 Vgl. Mertins, Neumann und Kühnel, (2012), S. 1165. Vgl. Doberenz und Gewinnus, (2010), S. 1178f. 6 Arbeiten mit Entitätsdaten 4 Arbeiten mit Entitätsdaten Als meistgenutzte Abfragesprache des Entity Frameworks hat sich LINQ to Entities etabliert. Dieses Kapitel bietet einen Überblick über die Möglichkeiten, mit dieser Abfragesprache sowohl Daten aus der Datenbank auszulesen als auch dort anzulegen, zu ändern oder zu löschen. Um Daten aus der Datenbank auszulesen oder dort zu speichern, muss zunächst eine Instanz des Objektkontextes erstellt werden. Darüber ist der Zugriff auf alle Entitäten des Entitätenmodells möglich.21 4.1 Abfragen eines konzeptionellen Modells mit LINQ to Entities Als Beispiel für eine Abfrage von Objekten dient die Klasse Adresse, die bereits bei der Beschreibung der Schichten des Entitätenmodells verwendet wurde. Es wird zunächst ein Objekt der Klasse DbContext erzeugt, das den Objektkontext repräsentiert. Danach wird aus dem soeben erzeugten Kontext eine Liste von Adressen ausgelesen, bei denen Testingen als Ort hinterlegt ist. Hierdurch findet also gleichzeitig eine Filterung statt. Diese Liste wird der Variablen adressen zugewiesen. Danach werden alle Adressen auf der Kommandozeile ausgegeben. Quelltext 4: Abfragen von Objekten 1 2 3 4 5 6 7 8 // D a t e n b a n k k o n t e x t erstellen using ( DbContext context = new DbContext () ) { // alle Adressen aus " Testingen " auslesen var adressen = context . Adresse . Where ( a = > a . Ort == " Testingen " ) ; // gefundene Adressen auf der Kommandozeile ausgeben adressen . ForEach ( a = > Console . WriteLine ( a ) ) ; } 21 Vgl. Mostarda, Sanctis und Bochicchio, (2011), S. 55f. 7 Arbeiten mit Entitätsdaten 4.2 Hinzufügen, Ändern und Löschen von Objekten Das Entity Framework protokolliert alle Änderungen an den Objekten. Wird ein neues Objekt angelegt, so wird der Status auf added gesetzt. Werden Objekte aus der Datenbank gelesen, bekommen diese den Status unchanged. Wird eine Eigenschaft gesetzt, so wird der Status auf modified gesetzt. Durch diesen Mechanismus weiß das Entity Framework, welche Art von Befehl es für die Datenbank erzeugen muss. Innerhalb der SaveChanges-Methode wird der Status des Objektes wieder auf unchanged gesetzt.22 4.2.1 Hinzufügen von Objekten Um der Datenquelle Daten hinzuzufügen, wird eine neue Instanz der entsprechenden Entitätsklasse erstellt, mit den entsprechenden Werten befüllt und dem Objektkontext hinzugefügt. Es muss darauf geachtet werden, dass alle Eigenschaften, die keine Null-Werte zulassen, auch gesetzt sind. Nachdem die Instanz dem Objektkontext hinzugefügt wurde, kann auf diesem die SaveChanges-Methode aufgerufen werden, die die Daten der erzeugten Instanz in der Datenbank abspeichert.23 Quelltext 5: 1 2 3 4 5 6 7 8 9 10 11 12 13 22 23 Hinzufügen eines Objektes // D a t e n b a n k k o n t e x t erstellen using ( DbContext context = new DbContext () ) { // Adress - Objekt erstellen und Eigenschaften festlegen Adresse adresse = new Adresse () ; adresse . Strasse = " Musterstraße 1 " ; adresse . PLZ = " 12345 " ; adresse . Ort = " Testingen " ; // die Adresse dem Objektkontext hinzufügen context . AddObject ( adresse ) ; // Speichern context . SaveChanges () ; } Vgl. Microsoft, (2012b), o.S. Vgl. Microsoft, (2012b), o.S. 8 Arbeiten mit Entitätsdaten 4.2.2 Ändern von Objekten Um einen Datensatz zu ändern, muss zunächst ein Datensatz aus der Datenquelle ausgelesen werden. Nachdem dies geschehen ist, können die gewünschten Änderungen durchgeführt werden, indem die Eigenschaften gesetzt werden. Zu beachten ist, dass beim Setzen von Eigenschaften der Status des Objektes auch auf modified gesetzt wird, wenn der gleiche Eigenschaftswert gesetzt wird. Durch den Aufruf der SaveChanges-Methode wird der Datensatz in der Datenbank geändert.24 Quelltext 6: 1 2 3 4 5 6 7 8 9 10 11 12 Ändern eines Objektes // D a t e n b a n k k o n t e x t erstellen using ( DbContext context = new DbContext () ) { // die erste Adresse aus " Testingen " auslesen var adresse = context . Adresse . Where ( a = > a . Ort == " Testingen " ) . First () ; // die Straße der gefundenen Adresse ändern adresse . Strasse = " Am Test 1 " ; // Speichern context . SaveChanges () ; } 4.2.3 Löschen von Objekten Für das Löschen von Objekten stellt der Objektkontext die Methode DeleteObject zur Verfügung. Beim Aufruf dieser Methode mit einem Objekt wird dieses in der Datenbank als zu löschen gekennzeichnet. Erst durch den Aufruf der SaveChanges-Methode wird der Datensatz auch wirklich aus der Datenbank gelöscht.25 Quelltext 7: Löschen eines Objektes 1 2 3 4 // D a t e n b a n k k o n t e x t erstellen using ( DbContext context = new DbContext () ) { // die erste Adresse aus " Testingen " auslesen 24 Vgl. Microsoft, (2012b), o.S. Vgl. Microsoft, (2012b), o.S. 25 9 Fazit 5 6 7 8 9 10 11 12 5 var adresse = context . Adresse . Where ( a = > a . Ort == " Testingen " ) . First () ; // die gefundene Adresse löschen context . DeleteObject ( adresse ) ; // Speichern context . SaveChanges () ; } Fazit Das Entity Framework bietet eine gute Möglichkeit, auf eine Datenbank zuzugreifen, und dabei in dem für den Programmierer gewohnten Kontext von .NET zu bleiben und mit Klassen und Objekten zu arbeiten. Dadurch kann eine schnelle Entwicklung erfolgen, und durch die Unterstützung einer Entwicklungsumgebung, wie z. B. Visual Studio, lassen sich Fehler vermeiden. Der Entwickler muss sich nicht mehr mit dem Verwaltungsaufwand zum Herstellen einer Verbindung zur Datenbank, zum Auslesen der Daten und Übertragen in die Entitäten beschäftigen.26 Es gibt zudem diverse Datenbanksysteme, mit denen sich der Entwickler auskennen müsste. Das Entity Framework stellt die Erzeugung korrekter SQL-Abfragen unter Berücksichtigung der datenbankspezifischen Besonderheiten sicher. Dadurch nimmt es ihm die Arbeit ab, datenbankspezifische Abfragen erzeugen zu müssen.27 Jedoch sollte immer der spezifische Anwendungsfall betrachtet werden, ob der Einsatz des Entity Frameworks sinnvoll ist. Bei Massenaktualisieren zum Beispiel ist das Entity Framework nicht das beste Verfahren, da hierbei der gesamte Verwaltungsmechanismus viel Performance kostet.28 26 27 28 Vgl. Lerman, (2010), S. 1f. Vgl. Mostarda, Sanctis und Bochicchio, (2011), S. 25. Vgl. Mostarda, Sanctis und Bochicchio, (2011), S. 26. 10 Literatur 6 Literatur 1. Doberenz, Walter und Thomas Gewinnus (2010): DatenbankProgrammierung mit Visual C# 2010: Grundlagen, Rezepte, Anwendungsbeispiele. Microsoft Press Deutschland. isbn: 978-3866454460. 2. Kansy, Thorsten (2011): Programmieren mit dem ADO.NET Entity Framework. Microsoft Press Deutschland. isbn: 978-3866454613. 3. Lerman, Julia (2010): Programming Entity Framework. O’Reilly Media. isbn: 978-0596807269. 4. Mertins, Dirk, Jörg Neumann und Andreas Kühnel (2012): SQL Server 2012: Das Programmierhandbuch. Inkl. ADO.NET 4.0 Entity Framework. Galileo Computing. isbn: 978-3836219440. 5. Microsoft (2012a): Entity Framework-Architektur. url: http://msdn. microsoft . com / de - de / library / vstudio / bb399567 (besucht am 03. 10. 2012). 6. — (2012b): Hinzufügen, Ändern und Löschen von Objekten (Entity Framework). url: http : / / msdn . microsoft . com / de - de / library / bb738695 (besucht am 10. 10. 2012). 7. Mostarda, Stefano, Marco De Sanctis und Daniele Bochicchio (2011): Microsoft Entity Framework in Action. Manning. isbn: 978-1935182184. 11 Ehrenwörtliche Erklärung Hiermit versichere ich, dass die vorliegende Hausarbeit von mir selbstständig und ohne unerlaubte Hilfe angefertigt worden ist, insbesondere, dass ich alle Stellen, die wörtlich oder annähernd wörtlich aus Veröffentlichungen entnommen sind, durch Zitate als solche gekennzeichnet habe. Ich versichere auch, dass die von mir eingereichte schriftliche Version mit der digitalen Version übereinstimmt. Weiterhin erkläre ich, dass die Hausarbeit in gleicher oder ähnlicher Form noch keiner anderen Prüfungsbehörde vorgelegen hat. Frankfurt am Main, den 6. Januar 2013 Max Jäger