O/R-Mapping in .NET Das ADO.NET Entity Framework

leathermumpsimusSoftware and s/w Development

Dec 13, 2013 (3 years and 10 months ago)

467 views







Fachhochschul-Bachelorstudiengang
SOFTWARE ENGINEERING
A-4232 Hagenberg, Austria







O/R-Mapping in .NET
Das ADO.NET Entity Framework


Bachelorarbeit
Teil 1

zur Erlangung des akademischen Grades
Bachelor of Science in Engineering


Eingereicht von

Günter Zöchbauer










Begutachter: Dipl.-Ing. Johann Heinzelreiter


Hagenberg, Dezember 2008
© Copyright 2008 Günter Zöchbauer
http://www.entityframework.de
Alle Rechte vorbehalten
Inhaltsverzeichnis
Kurzfassung iv
Abstract v
1 Einleitung und Motivation 1
1.1 Aufgabenstellung.........................1
1.2 Motivation............................1
1.3 Zielsetzung............................2
2 Grundlagen 4
2.1 O/R-Mapping-Framework....................4
2.1.1 Wozu objektrelationale Abbildung?...........4
2.1.2 Data Mapper.......................5
2.1.3 Metadaten-Abbildung bzw.O/R-Mapping-Framework 5
2.2 Abbildungsszenarien.......................7
2.2.1 Objektidentität......................7
2.2.2 Beziehungen.......................8
2.2.3 Eingebetteter Wert (Embedded Value).........9
2.2.4 Vererbung.........................9
2.2.5 Arbeitseinheit (Unit of Work)..............12
2.2.6 Nebenläufigkeit (Concurrency).............13
2.2.7 Laden bei Bedarf (Lazy Loading)............13
2.2.8 Unabhängigkeit der Entitätsklassen von der Persis-
tenzschicht (Persistence Ignorance)...........14
2.2.9 Konfiguration.......................14
2.2.10 Weitere Aufgaben einer O/R-Mapping-Lösung....15
3 Evaluierung 17
3.1 Verglichene Produkte.......................17
3.1.1 ADO.NET Entity Framework..............17
3.1.2 Genome..........................19
3.1.3 NHibernate........................20
3.2 Funktionalität...........................21
3.2.1 Metadaten........................21
ii
Inhaltsverzeichnis iii
3.2.2 Objektidentität......................26
3.2.3 Beziehungen.......................28
3.2.4 Eingebetteter Wert....................30
3.2.5 Vererbung.........................30
3.2.6 Nebenläufigkeit......................30
3.2.7 Abfragen.........................31
3.3 Softwarearchitektur........................32
3.3.1 Unabhängigkeit der Entitätsklassen von der Persis-
tenzschicht (Persistence Ignorance)...........32
3.3.2 Unterstützte Datenbanksysteme............34
3.4 Produktivität...........................34
3.4.1 Codegenerierung.....................34
3.4.2 Designer-Werkzeug....................36
3.4.3 Visual Studio Integration................38
4 Implementierung 39
4.1 Anforderungen..........................39
4.2 Realisierung............................40
4.2.1 Visual Studio Projektorganisation...........40
4.2.2 Vererbung.........................40
4.2.3 ID-Generierung......................42
4.2.4 Beziehungen.......................44
4.2.5 Feingranulares Objektmodell..............44
4.2.6 Nebenläufigkeit......................44
5 Resumee und Ausblick 46
5.1 Resumee..............................46
5.2 Ausblick..............................47
Literaturverzeichnis 49
Kurzfassung
Objektrelationale Abbildung (O/R-Mapping) ist das Überwinden der kon-
zeptionellen und technischen Unterschiede zwischen dem Objektmodell in
objektorientierten Programmiersprachen und dem relationalem Modell in
Datenbankmanagementsystemen (RDBMS).So wird beispielsweise das Kon-
zept der Vererbung im relationalen Modell nicht unterstützt.Auch die Iden-
tität von Entitäten sowie die Beziehungen zwischen Entitäten wird in diesen
Modellen unterschiedlich dargestellt.Das Überwinden dieser Unterschiede
stellt eine erhebliche Herausforderung für Softwareentwickler dar.
Für die Microsoft-.NET-Plattform wird eine Reihe fertiger Produkte an-
geboten,die diese Abbildung übernehmen.Seit der Version 3.5 Service Pack
1 ist das O/R-Mapping-Framework ADO.NET Entity Framework integraler
Bestandteil der Microsoft.NET-Plattform.
Diese Arbeit untersucht,ob das ADO.NET Entity Framework bereits
für den produktiven Einsatz geeignet ist und vergleicht den Funktionsum-
fang mit etablierten Produkten.Für diesen Vergleich wurde das kommerzi-
elle O/R-Mapping-Framework Genome von TechTalk sowie das quelloffene
NHibernate herangezogen.Im Rahmen dieser Arbeit werden die grundle-
gende Anforderungen an ein O/R-Mapping-Framework,die Visual Studio-
Integration,der Beitrag zu höherer Produktivität sowie der Einfluss auf die
Softwarearchitektur untersucht.
Mit einer Beispielapplikation wird veranschaulicht,welche objektorien-
tierten Konstrukte auf das relationale Modell abbildbar sind und welche
Einschränkungen gegebenenfalls bei den untersuchten Produkten zu berück-
sichtigen sind.
iv
Abstract
Object-relational-mapping (O/R-mapping) is a technique to overcome the
complexities when mapping objects of object oriented languages to the re-
lational model of database management systems (RDBMS).For example,
inheritance is not supported in the relational model.Even the identity of
entities or the relations between entities are represented differently.A con-
siderable effort is necessary by software engineers to overcome this mismatch.
Several solutions are available for the Microsoft-.NET plattform which
provide this functionality.With the release of.NET 3.5 Service Pack 1,the
O/R mapping framework ADO.NET Entity Framework became an integral
part of the Microsoft.NET plattform.
This thesis verifies if the ADO.NET Entity Framework is applicable for a
productive environment and compares its features with establied solutions.
The commericial O/R-mapping framework Genome by TechTalk and the
open source solution NHibernate are consulted for this comparsion.
This paper examines and compares the basic features usually provided
by O/R mapping frameworks,the integration into Visual Studio as well as
the benefit for productivity and its influence in software architectures.
A sample application demonstrates object-relational constructs and how
they are mappable via the O/R mapping frameworks.A special focus is set
on the restrictions given by the examined technologies.
v
Kapitel 1
Einleitung und Motivation
1.1 Aufgabenstellung
Diese Arbeit vergleicht ADO.NET Entity Framework [26,27],Microsofts
neue O/R-Mapping-Technologie,mit zwei etablierten Produkten,NHiber-
nate [40] sowie TechTalk Genome [59].
Untersucht und gegenübergestellt werden die grundlegende Anforderun-
gen an ein Persitenzframework,die Visual Studio-Integration,der Beitrag
zu höherer Produktivität sowie Auswirkungen auf die Softwarearchitektur
(z.B.in Bezug auf „Separation of concerns“).Des Weiteren wird untersucht,
inwieweit die aktuelle Version des Microsoft ADO.NET Entity Framework
bereits für den produktiven Einsatz geeignet ist.
1.2 Motivation
Ein Großteil moderner Geschäftsapplikationen wird mittlerweile in objekt-
orientierten Programmiersprachen wie Java und C#erstellt und die Objekte
üblicherweise in einer relationalen Datenbank persistiert.Zwischen Objekt-
modell und relationalemModell der Datenbank gibt es einige technische und
konzeptionelle Unterschiede.Das Überwinden dieser Unterschiede stellt eine
erhebliche Herausforderung für Softwareentwickler dar.Schon in den frühen
90er-Jahren wurden z.B.für Smalltalk Standardlösungen angeboten
1
,die
dem Entwickler diese Aufgabe abnehmen oder zumindest erleichtern soll-
ten.
Die Popularität der Java-Plattform hat in diesem Bereich die Entwick-
lung vorangetrieben.Für Java gibt es seit einigen Jahren leistungsfähig O/R-
Mapping-Lösungen,die großteils quelloffen sind und eine weite Verbreitung
gefunden haben.Mit JPA
2
hat Sun eine einheitliche API für die Nutzung
1
z.B.Enterprise Objects Framework,das in Apples WebObjects [2] aufging oder Top-
Link [37,52],das von Oracle in einer Java-Version angeboten wird.
2
Java Persistance API [55]
1
1.Einleitung und Motivation 2
verschiedener Persistenzframeworks in Java integriert.
Im.NET-Umfeld besteht diesbezüglich noch Aufholbedarf.Es werden
einige leistungsfähige O/R-Mapping-Lösungen für.NET angeboten,doch
Microsofts Ankündigung ein eigenes Produkt anzubieten,verunsicherte An-
wender wie Mitbewerber.Verschärft wurde diese Situation dadurch,dass
Microsoft das im Jahr 2001 erstmals angekündigte Produkt ObjectSpaces
[8],[Esp04] aufgegeben hat um im Jahr 2005 dafür die neue Technologie
LINQ
3
sowie Entity Framework anzukündigen [1,5,31].
Eine O/R-Mapping-Lösung für ein Projekt einzusetzen,hat weitreichen-
de Auswirkungen auf die Softwarearchitektur.Die angebotenen Lösungen
verfolgen teilweise unterschiedliche Ansätze mit unterschiedlichen APIs,wo-
durch es schwierig und kostspielig werden kann,die Entscheidung für ein
konkretes Produkt später zu revidieren.
Laut aktuellemInformationsstand wird Microsoft ADO.NET Entity Fra-
mework als Teil des.NET-Frameworks ausgeliefert werden,somit kostenlos
Verfügbar sein und nicht zuletzt deshalb eine interessante Option für viele
Entwickler darstellen.Diese Lösung wird daher schon vor der endgültigen
Fertigstellung untersucht,um frühzeitig eine Entscheidungsgrundlage ver-
fügbar zu haben.
1.3 Zielsetzung
Die Arbeit zeigt,inwieweit das Microsoft ADO.NET Entity Framework in
der vorliegenden Version
4
ein ausgereiftes Produkt darstellt,das für den Ein-
satz in komplexeren Projekten geeignet ist.Es untersucht,ob ADO.NET
Entity Framework bereits den Funktionsumfang etablierter Produkte an-
derer Hersteller bietet bzw.in welchen Bereichen es diesen überlegen ist.
Unterschiedliche Lösungsansätze werden gegenübergestellt,ohne diese not-
wendigerweise zu bewerten.
Dutzende kommerzielle und frei verfügbare Persistenzframeworks wer-
den für Microsoft.NET angeboten.Da alle diese Produkte in den Vergleich
einzubeziehen,den Rahmen dieser Arbeit bei Weitem überschreiten würde,
wurde die Auswahl auf zwei Produkte eingeschränkt,die mit demADO.NET
Entity Framework verglichen werden.Aus den verfügbaren quellofenen Lö-
sungen wurde NHibernate,aus den kommerziellen Angeboten TechTalk Ge-
nome für den Vergleich ausgewählt.Alle drei Produkte verfolgen einen ähn-
lichen Lösungsansatz,Abbildung per Metadaten,wobei NHibernate und
Entity Framework für Objekterzeugung und Zugriff auf die Entity-Objekte
hauptsächlich auf Reflection setzen,Genome hingegen zur Übersetzungszeit
den Quelltext für die Abbildung generieren.
3
Language INtegrated Query
4
Microsoft Visual Studio 2008 Service Pack 1 und.NET Framework 3.5 Service Pack
1 [26,28]
1.Einleitung und Motivation 3
Neben den grundlegenden Funktionalitäten eines O/R-Mapping-Frame-
works wird untersucht,welche Unterstützung dem Softwareentwickler bei
der Arbeit mit dem Framework geboten wird bzw.wie komfortabel der Ent-
wickler damit arbeiten kann (z.B.welche Assistenten und grafische Werk-
zeuge für die Erstellung der Abbildungs-Metadaten und Enitätsklassen be-
reit gestellt werden),wie die Integration in Visual Studio realisiert wurde
und wie weit es notwendig ist,die Softwarearchitektur einer Anwendung auf
das eingesetzte Persistenzframework abzustimmen.
Die einzelnen Aspekte werden herausgearbeitet,indem eine Beispielan-
wendung realisiert wird,anhand derer die Umsetzung bestimmter Funktio-
nalität mit den einzelnen Testkandidaten untersucht und dargestellt wird.
Nicht näher eingegangen wird auf die von den Produkten angebotenen
Abfragesprachen,Caching,Abbildung von Stored Procedures oder zusam-
mengesetzte Primärschlüssel.Weitgehend unberücksichtigt bleiben Daten-
bindung sowie generell die Anbindung an die Benutzeroberfläche oder an-
dere Clients.Ein weiterer Aspekt der hier nicht untersucht wird,ist die
Unterstützung von 3-Tier-Architektur,bei der persistente oder transiente
Objekte bzw.Objektgraphen serialisiert über Prozess- und Rechnergrenzen
hinweg übertragen werden.
Außerdem wird davon ausgegangen,dass Microsoft Visual Studio 2008
mit der.NET-Implementierung von Microsoft verwendet wird.Alternative
.NET-Implementierungen (z.B.Mono [33]) oder IDEs (z.B.SharpDevelop
[9]) bleiben unberücksichtigt.
Kapitel 2
Grundlagen
Die theoretischen Grundlagen für die Persistierung von Objekten in relatio-
nalen Datenbankmanagementsystemen (RDBMS) werden in der Literatur
ausgiebig diskutiert (z.B.[Fus97,Amb06a,FRF02,Nil06]).Dieser Abschnitt
stützt sich weitgehende auf die Ausführungen in [FRF02] und fasst die für
die weitere Diskussion relevanten Themen zusammen.
2.1 O/R-Mapping-Framework
O/R-Mapping-Lösungen sind,nicht zuletzt seit Microsofts Ankündigung
ein entsprechendes Produkt liefern zu wollen,ein viel diskutiertes Thema.
Warum es sinnvoll sein kann,einen O/R-Mapping-Framework einzusetzen,
welche Aufgaben er erfüllen kann und welche Problematiken dabei auftreten,
wird nachfolgend analysiert.
2.1.1 Wozu objektrelationale Abbildung?
Vor einigen Jahren war es noch üblich,Geschäftslogik in der Datenbank
(z.B.Oracle PL-SQL) oder in anderen prozeduralen Sprachen wie C,Pas-
cal oder VisualBasic zu implementieren und ist auch noch heute in vielen
Projekten gängige Praxis.Diese Vorgangsweise entspricht dabei meist dem
unter [FRF02,S.111] beschriebenen „Transaction Script“.
“Organizes business logic by procedures where each procedure
handles a single request from the presentation.”
Die Einfachheit ist der große Vorteil dieses Ansatzes und hat daher nach
wie vor seine Berechtigung.Bei einfacher Geschäftslogik ist es naheliegend,
diesen Lösungsansatz zu wählen,da er leicht zu verstehen ist und der geringe
Overhead sich positiv auf die Geschwindigkeit auswirkt.
Steigende Komplexität der Geschäftslogik macht es zunehmend schwie-
riger,eine übersichtliche Struktur beizubehalten.Jedes Transaktionsskript
4
2.Grundlagen 5
ist darauf ausgelegt,genau eine Transaktion abzubilden.Dabei ist darauf
zu achten,dass allgemeiner Code nicht mehrfach implementiert wird.Die
Vorzüge der objektorientierten Programmierung (OOP),Komplexität durch
Kapselung der Daten und Kombination mit zugehöriger Programmlogik in
Objekten sowie differenziertere Abbildung von Beziehungen mithilfe der Ver-
erbung handhabbar zu machen,bleiben ungenutzt.Der in [FRF02,116] als
„Domain Model“ beschriebene Ansatz (vgl.auch DDD (Domain-Driven De-
sign) [Eva03,Nil06]) rückt gerade diese Möglichkeiten in den Vordergrund.
Bei einem Domänenmodell kann zwischen einfachem und komplexem
Domänenmodell unterschieden werden,wobei das einfache Domänenmodell
weit gehend mit dem Datenbankschema übereinstimmt,das komplexe da-
gegen beträchtlich davon abweichen kann.Entsprechend aufwändig ist es,
ein komplexes Domänenmodell in ein RDBMS zu persistieren,bzw.einen
Objektgraphen daraus wiederherzustellen.Für das einfache Domänenmo-
dell kann z.B.„Active Record“ [FRF02,S.160] verwendet werden,für das
komplexe ist dagegen ein „Data Mapper“ [FRF02,S.165] erforderlich.
2.1.2 Data Mapper
Ein Data Mapper ist eine Vermittlungsschicht,die Daten zwischen Objek-
ten im Speicher und Datenbank transferiert und dabei die technischen und
konzeptionellen Unterschiede zwischen Objektmodell und relationalem Mo-
dell [Cod90],in der Literatur teilweise als „Object relationinal impedance
mismatch“ [Amb06b] oder nur „Impedance Mismatch“ bezeichnet,über-
windet.Objekte und Datenbank sollen möglichst unabhängig voneinander
bleiben und die Objekte keine Kenntnis über die Existenz der Datenbank,
in die sie persistiert werden,benötigen (siehe Unterabschnitt 2.2.8).
Vollständige Unabhängigkeit von der Persistenzschicht wird zwar ange-
strebt,ist aber kaum ohne schwerwiegende Nachteile,vor allem bzgl.Lauf-
zeitoverhead,realisierbar [Nil06,S.182].Daher werden meist gewisse Kom-
promisse eingegangen.
Die Trennung zwischen Domänen- und relationalem Modell stellt sicher,
dass beide Modelle unabhängig weiterentwickelt werden können und hat zu-
sätzliche Vorteile wie z.B.die Möglichkeit,das Domänenmodell unabhängig
von der Datenbank zu testen oder durch Austausch des Abbildungsframe-
works in ein anderes RDBMS zu persistieren.
2.1.3 Metadaten-Abbildung bzw.O/R-Mapping-Framework
Eine spezielle Ausprägung des Data Mapper-Entwurfsmusters ist „Metada-
ta Mapping“ [FRF02,S.306],die allgemein als O/R-Mapping-Framework
bezeichnet wird (vgl.[Nil06,S.289]).
Für das Abbilden wird entweder ein universelles Data Mapper Frame-
work per Metadaten konfiguriert oder aus den Metadaten zur Kompilierzeit
2.Grundlagen 6
Code für die konfigurierte Abbildung generiert.Mischformen sind möglich
und auch üblich.
Per Metadaten wird definiert,wie bestimmte Objekte und Objektgra-
phen in das relationale Modell transformiert bzw.wie aus diesen persis-
tierten Daten Objekte rekonstruiert werden sollen.Die Metadaten liegen
üblicherweise als XML-Datei vor oder sind als Attribute in die Klassendefi-
nitionen eingebettet.
Eine O/R-Mapping-Lösung abstrahiert das eingesetzte RDBMS weitge-
hend und bietet eine Schnittstelle mit Methoden,um z.B.neue Objekte
für die Persistierung zu registrieren oder Abfragen auszuführen und die ent-
sprechenden Objekte zurückzuliefern.Die Kommunikation mit demRDBMS
sowie die Umsetzung der Methodenaufrufe in SQL-DML
1
-Statements erfolgt
transparent.Durch das Zusammenfassen des Datenbankzugriffes in einer ei-
genen Schicht (Layer [FRF02,S.17]),wird die Komplexität der Applikation
reduziert.
ImDetail führt das zu einer Reihe von Aufgaben,die zu lösen sind.Nicht
jeder O/R-Mapping-Lösung unterstützt alle möglichen Szenarien.[Fus97]
unterscheidet z.B.fünf Ausbaustufen.
Einfache O/R-Mapping-Lösungen bilden nur Objekte ab,deren Struktu-
ren dem Datenbankschema direkt entsprechen (einfaches Domänenmodell).
Leistungsfähigere O/R-Mapping-Lösungen können auch Objektmodelle per-
sistieren,die weitere Ausdrucksmöglichkeiten der OOP nutzen,für die keine
direkte Entsprechung imrelationalen Modell existiert,z.B.Vererbung (kom-
plexes Domänenmodell).
Für eine Geschäftstransaktion wird ein Teil der Daten aus der Datenbank
angefordert und als Objekte rekonstruiert.Diese Objekte werden während
der Transaktion geändert,gelöscht bzw.neue Objekte erstellt.Das Zusam-
menführen dieser Änderungen mit dem Datenbestand im RDBMS am Ende
der Transaktion gehört zu den Aufgaben des O/R-Mapping-Frameworks.
Dabei darf der bei RDBMS übliche gleichzeitige Zugriff mehrerer Clients
nicht zu inkonsistenten Daten führen.
Üblicherweise wird ein O/R-Mapping-Framework mit einem Satz von
Werkzeugen wie grafische Designer und Assistenten geliefert,die dem Ent-
wickler das Entwerfen der Entitätsklassen und der Konfiguration der Abbil-
dung erleichtern.Je nach Lösungsansatz wird automatisch Code für Enti-
tätsklassen und das Abbilden generiert.
Optimierungen sind notwendig,damit der gewonnene Komfort möglichst
nicht durch Einbußen bei der Geschwindigkeit erkauft wird.
1
Data Manipulation Language
2.Grundlagen 7
2.2 Abbildungsszenarien
Eine O/R-Mapping-Lösung benötigt Strategien für verschiedenste Konstruk-
te und Szenarien,auf die nachfolgend näher eingegangen wird.
Je nach Konfiguration und Unterstützung durch das verwendete O/R-
Mapping-Framework werden Properties oder private oder öffentliche Daten-
komponenten persistiert.In weiterer Folge wird in diesem Zusammenhang
nur der Begriff Properties verwendet.
2.2.1 Objektidentität
Entitäten (vgl.Entities [Eva03,S.89] und [Nil06,S.462]) im Arbeitsspei-
cher müssen den zugehörigen Datensätzen in der Datenbank eindeutig zu-
ordenbar sein.Die Identität von Objekten ist anders definiert (z.B.über
die Adresse im Arbeitsspeicher) als die von Datensätzen in einem RDBMS,
die über den Primärschlüssel,ein oder mehrere Attribute des Datensatzes,
identifiziert werden.
Der Primärschlüssel (Primary key,PK) kann auf unterschiedlich Wei-
se gebildet werden,z.B.als natürlicher Schlüssel (Meaningful key,Natu-
ral key),wobei bestehende Attribute als Primärschlüssel verwendet wer-
den.Eine bessere Alternative,vor allem für den Einsatz mit O/R-Mapping-
Lösungen,sind künstliche Schlüssel (Meaningless key,Surrogate key,Sur-
rogat).Dabei wird eine zusätzliches Attribut eingefügt,dessen Bedeutung
ausschließlich darin besteht,den Datensatz eindeutig zu identifizieren.Wer-
den natürliche Schlüssel verwendet,führt das,z.B.bei m:n-Beziehungen,zu
kombinierten Schlüsseln,bei denen mehrere Attribute den Primärschlüssel
bilden.Kombinierte Schlüssel verkomplizieren das Abbilden.
Die Werte für künstliche Schlüssel können aus unterschiedlichen Werte-
bereichen gebildet werden,z.B.64-Bit-Ganzzahl,wobei Eindeutigkeit pro
Tabelle oder für die gesamte Datenbank gewählt werden kann.Ist Eindeutig-
keit über mehrere Datenbanken gefordert,weil diese synchronisiert werden,
bietet sich der GUID
2
-Datentyp an,der aber mehr Speicher benötigt (128
Bit) und somit die Indizes vergrößert (vgl.[Nil02]).
Weiters ist zu unterscheiden,wo und zu welchemZeitpunkt die Schlüssel-
werte generiert werden.Einige RDBMS bieten dafür spezielle Mechanismen
wie Sequence (z.B.ORACLE) oder Identity Field (z.B.Microsoft SQL-
Server).Das Identity-Field des Microsoft SQL-Server hat bei Verwendung
mit einem O/R-Mapping-Framework den Nachteil,dass die neue ID erst
beim Einfügen in die Datenbank generiert wird.Soll z.B.ein neuer Auftrag
gespeichert werden,muss zuerst der Order-Datensatz gespeichert werden,
danach muss die vom RDBMS generierte ID mit einer zusätzlichen Daten-
bankoperation ausgelesen werden,damit diese für den nächsten Schritt,das
Speichern der Auftragspositionen als Fremdschlüssel (Foreign key,FK) zur
2
Global Unique Identifier
2.Grundlagen 8
Verfügung steht.Dadurch werden zusätzliche zeitaufwändige Datenbankzu-
griffe notwendig.
Wesentlich effizienter ist die in ORACLE verfügbare Sequence.Es kann
vorab eine beliebige Anzahl von IDs angefordert werden,die vom ORMsuk-
zessiv für neue Objekte vergeben werden bis sie aufgebraucht sind.Je mehr
Werte auf einmal angefordert werden,umso weniger Datenbankzugriffe sind
insgesamt dafür notwendig,aber umso mehr IDs werden im Durchschnitt
verschwendet.Einmal angeforderte IDs,sollten sie nicht aufgebraucht wer-
den,weil die Applikation vorher beendet wurde,können nicht zurückgege-
ben werden und sind damit endgültig verloren.Bei einemausreichend großen
Wertebereich,z.B.64-Bit-Ganzzahl,stellt das in der Praxis üblicherweise
kein Problem dar.
Wird der Sequence-Mechanismus vom verwendeten RDBMS nicht zur
Verfügung gestellt,kann diese Funktion leicht nachgebildet werden.Eine ei-
gene Tabelle enthält eine Spalte und einen Datensatz mit der bisher höchsten
vergebenen ID.Soll die ID pro Tabelle eindeutig sein,wird eine weiteres At-
tribut mit dem Tabellennamen und für jede Tabelle ein Datensatz benötigt.
Der Wert erhöht sich jeweils um die Anzahl angeforderter IDs.Das Anfor-
dern der IDs muss in einer eigenen Transaktion durchgeführt werden,da
ansonsten Optimistic Offline Lock (siehe Unterabschnitt 2.2.6) nicht funk-
tionieren würde.
GUIDs können direkt vom O/R-Mapping-Framework generiert werden
und benötigen daher keine zusätzlichen Datenbankzugriffe.
Für die Verwendung mit einem O/R-Mapping-Lösung sind deshalb ein-
fache künstliche Schlüssel,die per Sequence-Mechanismus generiert werden
sowie GUID oft die beste Lösung.
2.2.2 Beziehungen
Beziehungen zwischen Objekten sind unidirektional und werden mit Daten-
komponenten,die ein weiteres Objekt referenzieren,dargestellt (1:1).Mehre-
re Objekte gleichen Typs werden referenziert,indem eine Behälterklasse als
Datenkomponente verwendet wird (1:n).Bidirektionale Beziehungen werden
als zwei unidirektionale Beziehungen abgebildet.Mit zwei 1:n-Beziehungen
kann eine m:n-Beziehung erstellt werden.Eine Objektreferenz kann Objekte
jener Typen referenzieren,die dem Typ der Datenkomponente oder einem
davon abgeleiteten Typ entsprechen und sind damit polymorph.
Beziehungen im Relationenmodell werden durch Attribute abgebildet.
Der Primärschlüssel einer Tabelle wird als Fremdschlüssel in der referen-
zierten Tabelle verwendet.Die Datensätze beider Tabellen sind referen-
ziert,wenn Primärschlüssel und Fremdschlüssel die gleichen Werte enthal-
ten.Grundsätzlich bietet das Relationenmodell nur bidirektionale 1:n-Bezie-
hungen,die mit Hilfe von Einschränkungen (Constraints) auf 1:1 beschränkt
werden können.Mit einer zusätzlichen Beziehungstabelle,zu denen zwei Ta-
2.Grundlagen 9
bellen eine 1:n-Beziehung definieren,wird eine m:n-Beziehung abgebildet.
Dieses Behelfskonstrukt ist bei m:n-Beziehungen zwischen Objekten nicht
notwendig.Für Polymorphismus werden im Relationenmodell keine spezi-
ellen Konstrukte angeboten,die Funktionalität kann aber auf verschiede-
ne Weise nachgebildet werden und erfordert in erster Linie entsprechend
gestaltete Abfragen.Weiterführende Informationen dazu finden sich unter
„Foreign Key Mapping“ in [FRF02,S.136] für 1:n-Beziehungen sowie unter
„Association Table Mapping“ [FRF02,248] für m:n-Beziehungen.
2.2.3 Eingebetteter Wert (Embedded Value)
Objekte sind oft feingranularer als Datenbanktabellen (Fine-grained object
model [KBK08]) umDaten und zugehöriges Verhalten sauber zu kapseln.So
kann es sinnvoll sein,beispielsweise bei einemCustomer-Objekt die Address-
Properties in ein eigenes Address-Objekt auszulagern,das vom Customer-
Objekt nur referenziert wird.Im relationalen Modell bietet diese Aufteilung
keinen Vorteil.Dort gibt es nur Daten ohne Verhalten,und daher keine Not-
wendigkeit für Kapselung.Würden die Objekte in unterschiedlichen Tabel-
len abgebildet,müssten bei Abfragen die Datensätze aus unterschiedlichen
Tabellen wieder zusammengeführt werden.Das ist zeitintensiv und deshalb
nach Möglichkeit zu vermeiden.Die Properties des Address-Objektes sollen
daher in die Customer-Tabelle eingebettet werden.
Unter [FRF02,S.268] wird auf diese Funktionalität ausführlich einge-
gangen.
2.2.4 Vererbung
Das Relationenmodell in RDBMS sieht keine Vererbung vor,daher werden
Strategien benötigt,um Vererbungshierarchien in Datenbanken abzubilden.
Es stehen drei Möglichkeiten zur Auswahl,bei denen es unterschiedliche
Vor- und Nachteile abzuwägen gilt.Die Abbildung einer Klassenhierarchie
muss nicht auf eine dieser Strategien beschränkt bleiben.Für Teilhierarchien
können unterschiedliche Varianten verwendet werden.
Vererbungshierarchie in einer Tabelle (Single Table Inheritance)
Bei Vererbungshierarchie in einer Tabelle (Single Table Inheritance) wird die
gesamte Hierarchie in einer Tabelle abgelegt (siehe Abbildung 2.1).Jedes
Objekt wird durch einen Datensatz repräsentiert,wobei nur die Attribute
befüllt werden,die in der konkreten Klasse vorkommen.Die restlichen At-
tribute bekommen den Wert null.Das heißt,dass alle zu persistierenden
Properties der Klassen der Hierarchie als Attribut in der Tabelle vorkom-
men.Zusätzlich wird ein Diskriminator benötigt,der die konkrete Klasse
identifiziert,die beim Laden aus einem Datensatz erzeugt werden soll.
2.Grundlagen 10
name
Player
club
Footballer
batting average
Cricketer
bowling average
Bowler
name
club
batting average
bowling average
type
«table»
Players
Abbildung 2.1:Single Table Inheritance [FRF02,S.278].
Der Vorteil ist,dass für die gesamte Hierarchie nur eine Tabelle benötigt
wird.Beim Laden entfällt das zusammenführen (Join) mehrerer Tabellen,
Abfragen sind entsprechend effizient.Polymorphe Relationen können damit
abgebildet werden.
Nachteilig wirkt sich aus,dass in der Tabelle die Zahl der Attribute
schnell anwachsen kann.Definieren die abgeleiteten Klassen eigene Pro-
perties,werden in der Tabelle entsprechend viele Spalten benötigt,obwohl
bei jedem einzelnen Datensatz nur ein Teil davon belegt wird.Außer bei
den Attributen der Basisklasse ist es daher nicht möglich,„NOT NULL“-
Einschränkungen zu definieren.Werden in verschiedenen Subklassen gleich-
namige Properties eingeführt,entstehen Konflikte die aufgelöst werden müs-
sen,z.B.durch voranstellen eines spezifischen Präfixes für jede Subklasse.
Vererbung mit einer Tabelle pro Klasse (Class Table Inheritance)
Bei Vererbung mit einer Tabelle pro Klasse wird für jede Klasse der Hier-
archie eine Tabelle erstellt,wobei für die in einer Subklasse zusätzlich defi-
nierten Properties eine eigene Tabelle verwendet wird (siehe Abbildung 2.2).
Ein Vorteil gegenüber Vererbungshierarchie in einer Tabelle ist,dass keine
Spalten ungenützt bleiben.Nachteilig wirkt sich aus,dass beim Laden die
Tabellen wieder zusammengeführt werden müssen.Wobei pro Datensatz,ab-
hängig vom konkreten Typ,unterschiedliche Tabellen zu kombinieren sind.
Vor allem bei Klassenhierarchien mit mehr als drei Tabellen beeinträchtigt
das die Geschwindigkeit,da RDBMS üblicherweise nur für Joins mit bis zu
drei Tabellen optimiert sind.
2.Grundlagen 11
name
Player
club
Footballer
batting average
Cricketer
bowling average
Bowler
club
«table»
Footballers
batting average
«table»
Cricketers
bowling average
«table»
Bowlers
name
«table»
Players
Abbildung 2.2:Class Table Inheritance [FRF02,S.285].
name
Player
club
Footballer
batting average
Cricketer
bowling average
Bowler
name
club
«table»
Footballers
name
batting average
«table»
Cricketers
name
batting average
bowling average
«table»
Bowlers
Abbildung 2.3:Concrete Table Inheritance [FRF02,S.293].
Vererbung mit einer Tabelle pro konkreter Klasse (Concrete Table
Inheritance)
Bei Vererbung mit einer Tabelle pro konkreter Klasse (Concrete Table Inhe-
ritance) wird für jede konkrete Klasse der Hierarchie eine Tabelle angelegt
(siehe Abbildung 2.3).Alle Properties der konkreten Klasse sowie die al-
ler direkten und indirekten Superklassen werden in dieser Tabelle abgelegt.
2.Grundlagen 12
Die Properties der Superklassen kommen daher in allen Tabellen vor,deren
Klassen von dieser Superklasse ableiten.
Wie bei Vererbung mit einer Tabelle pro Klasse werden bei jedemDaten-
satz alle Attribute belegt,weiters werden beim Laden keine Joins benötigt.
Wesentliche Nachteile sind,dass bei Abfragen auf eine Basisklasse Uni-
ons notwendig sind,sowie bei Änderungen an Attributen einer Basisklasse,
die Änderungen in allen Tabellen abgeleiteter Klassen durchgeführt werden
müssen.
2.2.5 Arbeitseinheit (Unit of Work)
Wird jede einzelne Datenänderung an einem Objekt im Speicher einzeln
in die Datenbank geschrieben,resultiert das in einer Unmenge von Daten-
bankzugriffen.Dadurch wird die Skalierbarkeit drastisch eingeschränkt,auch
deshalb,weil eine Datenbanktransaktion vom ersten bis zum letzten Zugriff
offen gehalten werden muss.Dieses Problem kann umgangen werden,indem
die Änderungen im Arbeitsspeicher mitprotokolliert und dann gebündelt an
die Datenbank abgesetzt werden („Unit of Work“ [FRF02,S.184]).
Eine Arbeitseinheit muss von den Datenänderungen erfahren,um sie
protokollieren zu können.Entweder wird die Arbeitseinheit explizit von jeder
Änderung benachrichtigt oder es werden Mechanismen implementiert,mit
denen die Arbeitseinheit Änderungen selbständig eruieren kann.
Explizite Benachrichtigungen haben den Nachteil,dass sie leicht verges-
sen werden.Sollen die Objekte selbständig Änderungen melden,müssen die-
se Kenntnis vom Abbildungs-Framework haben,womit die Unabhängigkeit
von der Persistenzschicht (siehe Unterabschnitt 2.2.8) aufgeweicht wird.
Werden lesende Zugriffe auf die Datenbank mit der Arbeitseinheit kom-
biniert,können Kopien der zurückgelieferten Objekte zum späteren Ver-
gleich behalten werden,um damit Änderungen automatisch festzustellen
(in [FRF02,S.187] als „Unit of Work Controller“ bezeichnet).Der Nachteil
hierbei ist,dass alle Objekte doppelt im Speicher angelegt werden.
Eine alternative Möglichkeit ist,dass die Zugriffsoperationen von den
Entitätsklassen abgeleitete Klassen liefern (Proxy [GHJV04,S.254]),die
die Properties überschreiben und so erweitern,dass die Arbeitseinheit von
Änderungen benachrichtigt wird.
Durch das Zusammenfassen aller Änderungen einer Geschäftstransaktion
geht die Reihenfolge der Änderungen verloren.Wird nicht eine bestimmte
Reihenfolge eingehalten besteht die Gefahr,dass die referentielle Integrität
verletzt wird,oder es zu Deadlocks kommt.Aufgabe der Arbeitseinheit ist
es daher,vor dem Absetzen der DMS-Statements an die Datenbank die
Reihenfolge so zu sortieren,dass alle Abhängigkeiten aufgelöst sind.
2.Grundlagen 13
2.2.6 Nebenläufigkeit (Concurrency)
Optimistische verbindungslose Sperre (Optimistic Offline Lock) [FRF02,S.
416] ist eine Methode,die Dateninkonsistenzen bei konkurrierenden Daten-
änderungen gleichzeitig ablaufender Transaktionen verhindert.
Realisiert wird diese Konflikterkennung durch ein zusätzliches Attribut
in jeder Tabelle,das bei jeder Datenänderung inkrementiert wird und somit
die Version eines Datensatzes definiert.Vor dem Schreiben der Änderung
wird geprüft,ob die Version in der Datenbank noch mit der des Lesezeit-
punktes übereinstimmt.Ist sie unverändert,wird die Änderung durchge-
führt.Wurde der Datensatz in der Zwischenzeit von einer anderen Transak-
tion geändert oder gelöscht,besteht ein Konflikt und die laufende Transak-
tion muss mit einem Rollback abgebrochen werden.
Optimistische Verbindungslose Sperre lässt mehr gleichzeitige Datenzu-
griffe zu als Datenbanktransaktionen und verbessert damit den Durchsatz.
Nachteilig wirkt sich aus,dass erst am Ende der Geschäftstransakti-
on geprüft wird,ob ein Konflikt besteht.Dadurch kann es passieren,dass
zeitaufwändig erfasste Eingaben verworfen und von Neuem erstellt werden
müssen.Das kann zu Akzeptanzproblemen bei den Anwendern führen.
2.2.7 Laden bei Bedarf (Lazy Loading)
Für jedes Transaktionsskript (siehe Unterabschnitt 2.1.1) kann eine ange-
passte SQL-Abfrage erstellt werden,die genau jene Daten liefert,die für
die Transaktion benötigt werden,mit Hilfe von entsprechenden Joins und
Projektionen.Ein Data Mapper ist allerdings vollkommen unabhängig von
der Geschäftslogik.Unter dieser Voraussetzung lautet ein einfacher Ansatz,
jedes angeforderte Objekt einzeln aus der Datenbank zu laden.
Wird beispielsweise auf eine Auftragsposition zugegriffen,werden oft
auch die zugehörigen Auftragspositionen benötigt.Bei einem darauf folgen-
den Zugriff auf jede Auftragsposition würde dadurch ein neuerlichen Daten-
bankzugriff verursacht,obwohl es wesentlich effizienter wäre,den Auftrag
mit allen Auftragspositionen mit einem Zugriff (z.B.Join) zu laden.
Würden bei einem Zugriff auf einen Datensatz alle Detaildatensätze au-
tomatisch mit geladen,müssten mit einem Zugriff auf einen Kunden alle
erteilten Aufträge dieses Kunden und alle zugehörigen Positionsdaten und
die darin referenzierten Artikeldaten usw.geladen werden.Das würde dazu
führen,dass der Zugriff auf einen Kunden beinahe die gesamte Datenbank
in den Arbeitsspeicher lädt.Also muss der Automatismus irgendwo unter-
brochen werden.Dieses Problem kann mittels „Lazy Loading“ [FRF02,S.
200] gelöst werden.
2.Grundlagen 14
2.2.8 Unabhängigkeit der Entitätsklassen von der Persistenz-
schicht (Persistence Ignorance)
Um den „Domain-Layer“ [Eva03,S.75] von Infrastrukturcode freizuhal-
ten,also eine saubere Trennung zwischen den Schichten beizubehalten,ist
es wichtig,die Entitätsklassen weitgehend unabhängig vom O/R-Mapping-
Framework zu halten.Diese Trennung wird angestrebt,um das Designprin-
zip „Separation of concerns“ [Dij82] möglichst sauber umsetzen zu können.
Entitätsklassen sollen nach Möglichkeit keine Kenntnis davon haben,
dass sie überhaupt persistiert werden.Diese Anforderung wird üblicherwei-
se als „Persitence Ignorance“ [Nil06,S.182] bezeichnet.Klassen,die frei
von Persistierungscode sind,werden als POCO (Plain old CLR Object oder
unter Java als POJO) bezeichnet.Verschiedene Anforderungen an den O/R-
Mapping-Framework,z.B.Setzen von privaten Properties beim Wiederher-
stellen von persistenten Objekten oder automatische Änderungsverfolgung,
widersprechen dieser Anforderung.
Es gibt verschiedene Ansätze,Unabhängigkeit von der Persistenzschicht
zu realisieren,Kompromisse sind aber unumgänglich.Teilweise wird Reflec-
tion verwendet,um auf private Properties zuzugreifen oder ein Konstruktor
wird gefordert,der für alle Properties entsprechende Parameter vorsieht.
Müssen Entitätsklassen ein bestimmtes Interfaces implementieren,um
den Zugriff auf Internas der Objekte zu ermöglichen,wird das auch als IPO-
CO (Interface-POCO) bezeichnet [34,50].
Unumgänglich ist weiters die Implementierung einer Property für den
Primärschlüssel.Vollständige Unabhängigkeit von der Persistenzschicht ist
daher kaum realisierbar.
2.2.9 Konfiguration
Die in dieser Arbeit untersuchten Produkte sind Meta Data Mapper (siehe
Unterabschnitt 2.1.3).Das bedeutet,die Abbildung der Klassen und Objekte
auf die Datenbank wird per Metadaten definiert.
Metadaten können als XML-Dateien vorliegen oder als Attribute in den
Entitätsklassen eingebettet sein.Je nach Implementierung werden diese Me-
tadaten zur Laufzeit ausgewertet und die Abbildung entsprechend durch-
geführt oder es wird zur Kompilierzeit expliziter Code für die Abbildung
generiert.Die erste Variante verwendet üblicherweise Reflection für die Ob-
jekterzeugung und den Zugriff auf die Properties.
Reflection gilt,im Verhältnis zu direkten Aufrufen,als sehr langsam,
wobei dieser Overhead durch Optimierungen weitgehend eliminiert werden
kann.In ausgelagerten oder anderen sicherheitskritischen Umgebungen kann
Reflection eingeschränkt sein,wodurch darauf basierende Produkte nicht
eingesetzt werden können.
2.Grundlagen 15
2.2.10 Weitere Aufgaben einer O/R-Mapping-Lösung
Zu einer leistungsfähigen O/R-Mapping-Lösung gehören weitere grundle-
gende Funktionen.Einige davon betreffen den Entwickler direkt,andere ar-
beiten unbemerkt im Hintergrund.Aus Platzgründen kann in dieser Arbeit
nicht näher darauf eingegangen werden.Der Vollständigkeit halber sollen
einige trotzdem kurz angesprochen werden.
Abfragen (Query)
O/R-Mapping-Lösungen bieten zumindest eine,oft auch mehrere Möglich-
keiten,Abfragen abzusetzen.Zur Anwendung kommen u.a.Abfragespra-
chen,die an die für Objektdatenbanken entworfene Object Query Language
(OQL) [35] angelehnt sind.Solche Abfragen werden wie in SQL als Zeichen-
kette übergeben.
Typsichere Varianten wie das unter [FRF02,S.316] beschriebene „Query
Object“,ermöglichen Abfragekriterien als Objektgraph zu konstruieren.
Seit der.NET-Version 3.5 ist die objektorientierte und typsichere Ab-
fragesprache LINQ [31] in die.NET-Sprachen (C#,VisualBasic.NET) inte-
griert.Der Trend geht dahin,dass LINQ- auch von O/R-Mapping-Lösungen
als Abfragesprache unterstützt wird.
Caching
Um das aufwändige Laden der Daten aus der Datenbank sowie das Erzeu-
gen der Objekte zu minimieren,werden üblicherweise verschiedene Caching-
Strategien unterstützt.Die Palette reicht von einemfixen integrierten Cache
bis zu per Konfiguration einbindbaren Zusatzmodulen (auch von Dritther-
stellern) mit speziellen Cachingstrategien,wie Unterstützung für verteilte
Cache-Lösungen für Umgebungen mit mehreren Applikationsservern.
Stored Procedures
Der Zugriff auf die Datenbank über Stored Procedures kann u.U.durch
Einsparen von Roundtrips oder Nützen RDBMS-interner Optimierungen,
Geschwindigkeitsvorteile bringen.Es wird aber auch die Wartbarkeit von
Programmen erschwert,da der Programmcode auf unterschiedliche Entwick-
lungsumgebungen und Programmiersprachen verteilt wird.Designentschei-
dungen,firmeninterne Richtlinien oder der gemeinsame Zugriff auf Legacy-
Datenbanken mit anderen Applikationen,die auf Stored Procedures aufset-
zen,können das Zugreifen auf Stored Procedures erforderlich machen.Des-
halb bieten O/R-Mapping-Lösungen oft entsprechende Möglichkeiten an.
2.Grundlagen 16
Zusammengesetzte Schlüssel
Für den Einsatz mit einem O/R-Mapping-Framework ist es aus verschiede-
nen Gründen empfehlenswert,ein Surrogat als Primärschlüssel zu verwen-
den (siehe auch Unterabschnitt 2.2.1).Trotzdem kann es erforderlich sein,
mit zusammengesetzten Schlüsseln zu arbeiten,wenn bestehende Daten-
bankschemas verwendet werden müssen.Eine entsprechende Unterstützung
durch die O/R-Mapping-Lösung sollte daher bei entsprechenden Anforde-
rungen geprüft werden.
Datenbindung
Um die aus der Datenbank geladenen Daten per Datenbindung von Steue-
relementen der Benutzeroberfläche darstellen zu lassen,sind entsprechende
Vorkehrungen zu treffen.Die Entitätsklassen können meist nach Bedarf ge-
staltet werden.Die gegebenenfalls notwendige Implementierung der Anfor-
derungen des.NET-Frameworks
3
,liegt daher weitgehend in der Verantwor-
tung des Entwicklers.Die Behälterklassen werden oft vom O/R-Mapping-
Framework vorgegeben,da sie z.B.für Laden bei Bedarf spezielle Mecha-
nismen implementieren.Hier kann es schwierig werden,die Anforderungen
des.NET-Frameworks
4
zu implementieren.
3-Tier bzw.n-Tier-Architektur
Nicht jeder mögliche Mechanismus zum Verfolgen von Datenänderungen
(change tracking) funktioniert ohne weiteres,wenn die Objekte über Prozess-
grenzen hinaus übertragen werden (z.B.ASP.NET Viewstate,Client-Tier in
3-Tier-Applikationen).Eine Diskussion zu diesem Thema ist z.B.unter [6]
zu finden.
3
z.B.INotifyPropertyChanged oder PropertyDescriptor
4
z.B.ITypedList
Kapitel 3
Evaluierung
In diesem Abschnitt werden die für das Erstellen der Beispielapplikation
relevanten Anforderungen an O/R-Mapping-Frameworks und deren Umset-
zung in den einzelnen Produkten (ADO.NET Entity Framework,Genome
und NHibernate) untersucht und deren Verwendung beschrieben.
3.1 Verglichene Produkte
Alle untersuchten Produkte weisen bereits eine lange Entwicklungsgeschichte
auf,auch wenn das Microsoft ADO.NET Entity Framework erst vor kurzem
erschienen ist.Dieser Abschnitt soll einen Eindruck davon vermitteln,wie
sich die Produkte entwickelt haben und wie sie am Markt positioniert sind.
3.1.1 ADO.NET Entity Framework
Beim Erscheinen der.NET-Plattform von Microsoft im Jahr 2002 wurde
ADO.NET und Datasets als große Neuerung und Verbesserung gegenüber
ADO (Active Data Objects) angekündigt [MN02,S.47] [RNG
+
04,S.514].
Schon damals war bekannt,dass mit O/R-Mapping-Lösungen komfortablere
Möglichkeiten für die Peristierung von Objekten existieren,wobei aktuelle
O/R-Mapping-Lösungen für.NET durchwegs auf ADO.NET,aber nicht auf
Datasets aufbauen.
Im Jahr 2001 wurde von Microsoft erstmals ein entsprechendes Produkt,
unter der Bezeichnung ObjectSpaces,angekündigt [Esp04] [8].Es wurde von
Microsoft sogar eine Vorabversion für interessierte Entwickler bereitgestellt.
Während im Jahr 2005 die baldige Auslieferung erwartet wurde,kündig-
te Microsoft an,dass ObjectSpaces zugunsten der neuen Technologie,dem
ADO.NET Entity Framework,LINQ
1
sowie LINQ to SQL [1,5,13,31] aufge-
geben wurde.Es kamen allerdings einige Zweifel auf,ob Microsoft wirklich
1
Language INtegrated Query
17
3.Evaluierung 18
in der Lage und auch Willens war,eine eigene O/R-Mapping-Lösung zu
entwickeln [Sch07].
Gegen Ende des Jahres 2007 hat Microsoft als Teil des neuen.NET-
Frameworks Version 3.5,LINQ und LINQ to SQL ausgeliefert,wobei LINQ
to SQL eine minimalistische O/R-Mapping-Lösung darstellt [Sch08].Die
Auslieferung der angekündigten flexiblen,leistungsfähigen und datenbank-
unabhängigen O/R-Mapping-Lösung ADO.NET Entity Framework,wurde
ein weiteres Mal verschoben.Im August 2008 wurde mit dem Microsoft
Visual Studio 2008 Service Pack 1 und.NET Framework 3.5 Service Pack
1 endlich eine,von vielen seit Jahren erwartete,erste Version einer O/R-
Mapping-Lösung von Microsoft fertiggestellt und gemeinsam mit anderen
Neuerungen und Erweiterungen als Service Pack für Visual Studio und.NET
angeboten [26,28–30,56].
Seit Microsoft Vorabversionen des ADO.NET Entity Framework bereit-
stellt,gibt es Kritiker,die Schwächen in der Architektur und der gebotenen
Funktionalität bemängeln [64].Auch für einen Hersteller wie Microsoft ist
es unmöglich,alle Anwender vollkommen zufrieden zu stellen,doch gestehen
sogar Mitglieder des Entwicklerteams Unzulänglichkeiten ein [15,17].
Die Laufzeitkomponenten des ADO.NET Entity Framework sind Teil des
.NET-Framework Version 3.5 Service Pack 1,die zugehörige Entwicklungs-
werkzeuge sind Teil des Service Pack 1 für Visual Studio 2008.Mit der Sha-
red Source-Initiative [23] gewährt Microsoft für Teile des.NET-Frameworks
Einblick in den Quellcode.Das Entity Framework ist,zumindest derzeit,
noch davon ausgenommen.
Kompetente Unterstützung bei eventuellen Problemen erhält man im
MSDN-Produktforum zum ADO.NET Entity Framework [18].Im rege be-
nutzten Forum werden viele Probleme diskutiert und mögliche Lösungen
aufgezeigt.Die vorhandene Dokumentation ist leider nicht auf dem letzten
Stand.Sie enthält Dokumente,die nicht vorhandene Funktionen beschrei-
ben,oder sich auf Vorabversionen bezieht.Eine schnell größer werdende
Anzahl an Blogeinträgen und anderen Onlineressourcen zum Entity Frame-
work bieten oft die gesuchten Informationen.Weiterführende Unterstützung
bietet der von Microsoft angebotene kostenpflichtige Support.
Microsoft weist immer wieder darauf hin,dass die Einsatzmöglichkei-
ten des ADO.NET Entity Framework weiter reichen als die herkömmlicher
O/R-Mapping-Lösungen.Dem EntityDataReader kommt dabei laut Micro-
soft eine entscheidende Bedeutung zu.Während beim herkömmlichen Data-
Reader die Daten entsprechend demSpeichermodell strukturiert sind,bezie-
hen sich Anfragen an den EntityDataReader auf das konzeptionelle Modell.
Der ausschließlich sequentielle Zugriff umgeht die Objekterzeugung durch
die ObjectServices (siehe Abbildung 3.1).Die ObjectServices entsprechen
dabei weitgehend der in Unterabschnitt 2.2.5 beschriebenen Arbeitseinheit.
Wenn die Daten nicht als Objekte benötigt werden,wie das z.B.bei Aus-
wertungen und Berichten der Fall sein kann,entfällt somit ein beträchtli-
3.Evaluierung 19
Abbildung 3.1:Entity Framework Architektur [21].
cher Verwaltungsaufwand.Die unter dem Projektnamen Astoria entwickel-
ten ADO.NET DataServices [32,58],stellen eine erste Lösung dar,die das
konzeptionelle Modell des Entity Framework auf diese Weise nutzen.Die
ADO.NET DataServices ermöglichen den Datenbankzugriff über das HTTP
Protokoll und bauen auf das Entity Framework auf.Die Daten werden als
Datenstrom per HTTP übertragen.Es wäre dabei ineffizient aus den Daten
Objekte zu erzeugen nur um sie danach für die Übertragung zu serialisieren.
3.1.2 Genome
Genome [59] wurde von dem Wiener Softwarehaus TechTalk [60] entwickelt.
Seit 2003 wird Genome als eigenständiges Produkt vertrieben und ist seit
August 2008 in der Version 4.0 erhältlich.
Bei Genome handelt es sich um ein kommerzielles Produkt,das in ver-
schiedene Editionen zu verschiedenen Preisen angeboten wird.Die Professio-
3.Evaluierung 20
nal-Edition bietet den vollständigen Funktionsumfang.
Eine im Funktionsumfang etwas eingeschränkte Express Edition unter-
stützt grundsätzlich nur die verschiedenen Microsoft SQL-Server-Varianten,
kann aber laut TechTalkfür die Unterstützung von Oracle 9i,Oracle 10g und
IBMDB2 aufgerüstet werden.Eine kostenlose Community-Edition für nicht
kommerzielle Softwareentwicklung,sowie eine kostenlose Evaluation-Edition
runden das Angebot ab.Der Quellcode ist über eine entsprechende Lizenz
erhältlich.Die Express-Edition,die laut TechTalk für die meisten Projek-
te ausreichen müsste,wird für e 299,-
2
pro Entwickler angeboten.Für die
Professional-Edition liegen die Preise zwischen e 1.170,- und e 1.800,- pro
Entwickler,gestaffelt nach Anzahl der erworbenen Lizenzen.Zu beziehen ist
Genome entweder direkt von TechTalk oder über Vertriebspartner.
Für diese Arbeit wurde von TechTalk freundlicherweise eine Lizenz für
die Community-Edition mit der Laufzeit von einem Jahr zur Verfügung ge-
stellt.Die Community-Edition entspricht vom Funktionsumfang der Profes-
sional-Edition.Für die erstellte Beispielanwendung wird nur Funktionalität
genutzt,die auch von der Express-Edition geboten wird.
Für die aktuelle Version 4.0 wird.NET 3.5 und Visual Studio 2008 vor-
ausgesetzt,Vorgängerversionen arbeitet auch mit den früheren.NET- und
Visual Studio-Versionen zusammen.
Für Fragen wurde einige Male auf das kostenlose Support-Forum zu-
rückgegriffen,das über die Genome-Webseite erreichbar ist.Die Antworten
erfolgten durchwegs innerhalb weniger Stunden und waren kompetent und
ausführlich.Die Dokumentation ist umfangreich,wurde aber für diese Arbeit
zu wenig benötigt,um sie beurteilen zu können.
3.1.3 NHibernate
NHibernate [KBK08] [46] ist eine Portierung der für Java entwickelten und
sehr populären O/R-Mapping-Lösung Hibernate [KB04,Bau06] [41] auf die
.NET-Plattform.Hibernate wurde von Gavin King als quelloffenes Projekt
initiiert [62].Auf SourceForge.net reichen die Informationen bis zur Version
0.8 im Dezember 2001 zurück [61].Gavin King wurde später von der Firm
JBoss [44],das mittlerweile zu RedHat [45] gehört,angestellt,um Hiberna-
te weiterzuentwickeln [65].Tom Barret begann,ausgehend von der Version
2.1,Hibernate nach.NET zu portieren [3].Erste Einträge dazu finden sich
ebenfalls auf SourceForge.net,datiert mit März 2003.Später wurden auch
führende NHibernate-Entwickler von JBoss angestellt,um die weitere Ent-
wicklung hauptberuflich zu betreiben [3].
Im August 2008 wurde die NHibernate-Version 2.0 freigegeben,die vom
Funktionsumfang weitgehend Hibernate 3.2 entsprechen soll.LINQ-Support
für NHibernate ist schon längere Zeit in Arbeit und wird für die nächs-
2
Auf der Webseite ausgewiesene Listenpreise
3.Evaluierung 21
te Version erwartet [43].Für aktuelle NHibernate-Versionen ist.NET 2.0
Mindestvoraussetzung.Weiters soll NHibernate auch mit der quelloffenen
.NET-Implementierung Mono [33] zusammenarbeiten.
Dass NHibernate von vielen Entwicklern eingesetzt wird,ist an der An-
zahl an Einträgen in verschiedensten Foren und Blogs zu erkennen.Für die
meisten auftretenden Fragen und Probleme sind daher bereits Antworten
vorhanden.Die große Anzahl an Einträgen erschwert es oft,zu konkreten
Problemen die passenden Einträge auch zu finden.Die Dokumentation ist
für eine quelloffenes Produkt umfangreich und weitgehend leicht zu verste-
hen.Professioneller Support für NHibernate wird von RedHat angeboten.
3.2 Funktionalität
3.2.1 Metadaten
Bei allen drei Testkandidaten muss dem O/R-Mapping-Framwork mittels
Metadaten (siehe Unterabschnitt 2.1.3) vorgegeben werden,welche Klassen
für die Persistierung vorgesehen sind und wie diese Klassen und ihre Be-
ziehungen untereinander behandelt werden sollen.Beim ADO.NET Entity
Framework und bei NHibernate werden diese Informationen grundsätzlich
erst zu Laufzeit benötigt.Die Metadaten können zur Laufzeit,vor der Wei-
tergabe an das O/R-Mapping-Framework,generiert und auch manipuliert
werden.ADO.NET Entity Framework kann aus den Metadaten den Quell-
text für die Entitätsklassen automatisch generieren,auch dafür müssen die
Metadaten bereits zur Entwicklungszeit vorliegen.Genome generiert aus
den Metadaten Quelltext,der die Persistierung und Wiederherstellung der
Objekte vornimmt und benötigt die Metadaten daher zwingend zur Ent-
wicklungszeit.Genome und das Entity Framework validieren die Metadaten
schon zur Übersetzungszeit,bei NHibernate treten eventuelle Fehler erst zur
Laufzeit zu Tage.
Alle untersuchten Produkte erwarten die Metadaten im XML-Format.
NHibernate ermöglicht,die Einbettung der Metadaten als Attribute in die
Entitätsklassen,aus denen zur Laufzeit das geforderte XML-Format gene-
riert wird.NHibernate und Genome benötigen für jede zu persistierende
Entitätsklasse in den Metadaten ein Element,das definiert,wie diese Klas-
se und die Beziehungen abgebildet werden sollen.Die Metadaten können
auf mehrere Dateien aufgeteilt werden,wobei eine Datei einen oder mehrere
Elemente enthalten kann.Beim ADO.NET Entity Framework wurde hier
ein abweichender Ansatz gewählt.
Die Metadaten des ADO.NET Entity Framework bestehen aus drei Tei-
len,die gemeinsamdas Entity Data Model (EDM) bilden [Pap07] [20,25,27].
Ein Teil,das Konzeptionelle Modell (Conceptual Schema),beschreibt die
Struktur der Entitätsklassen und deren Beziehungen untereinander.Das
Speichermodell (Storage Schema),gibt die Struktur des Datenbankschemas
3.Evaluierung 22
wider.Die Abbildungsdefinition (Mapping Specification) ist der dritte Teil,
der beschreibt,wie das konzeptionelle Modell auf das Speichermodell ab-
gebildet wird.Das Entity Data Model wird zusammen mit Daten für das
grafische Designer-Werkzeug in einer Datei mit der Endung.edmx abgelegt.
Listing 3.1 bis Listing 3.5 zeigen die Teile einer minimalistischen edmx-Datei,
mit der eine einzelne Klasse „Country“ ohne Beziehungen abgebildet wird.
Listing 3.1 zeigt dabei das Gerüst,das die einzelnen Abschnitte umgibt.In
Listing 3.2 bis Listing 3.4 sind diese Abschnitte der Metadaten dargestellt.
Diese drei Abschnitte sind ähnlich strukturiert.Das konzeptionelle Modell
sowie das Speichermodell enthalten jweils eine Definition für einen Entity-
Container,der einer Arbeitseinheit (siehe Unterabschnitt 2.2.5 entspricht.
Der EntityContainer enthält EntitySet- und AssociationSet-Definitionen,
die imSpeichermodell den Tabellen und referentiellen Beziehungen zwischen
den Tabellen entsprechen,im konzeptionellen Modell jedoch den Entitäts-
klassen entsprechen.AssociationSet-Definitionen kommen in den angeführ-
ten Quelltexten nicht vor,da keine Beziehungen definiert wurden.In der Ab-
bildungsdefinition wwerden über EntityContainerMapping,EntitySetMap-
ping und AssociationSetMapping die Elemente aus demkonzeptionellen Mo-
dell den entsprechenden Elementen aus demSpeichermodell zugeordnet.Die
EntityType-Definitionen geben die Struktur der Tabellen und Entitätsklas-
sen wider,auf die sich die EntitySet-Definitionen im konzeptionellen sowie
im Speichermodelle beziehen.Die EntityTypeMapping-Elemente in der Ab-
bildungsdefinition legen wiederumfest welche EntityType-Elemente aus dem
konzeptionellen Modell auf welche EntityType-Elemente im Speichermodell
abgebildet werden.Für die Definition des EntityDataModel stehen noch ei-
nige weitere Elemente zur Verfügung,etwa um Vererbung festzulegen.Bei-
spielhafte Daten des Designer-Werkzeugs werden in Listing 3.5 gezeigt.
Listing 3.1:ADO.NET Entity Framework edmx-Datei.
1 <?xml version="1.0"encoding="utf-8"?>
2 <edmx:Edmx Version="1.0"xmlns:edmx="http://schemas.microsoft.
com/ado/2007/06/edmx">
3 <!−− EF Runtime content −−>
4 <edmx:Runtime>
5 <!−− SSDL content −−>
6 <!−− CSDL content −−>
7 <!−− C−S mapping content −−>
8 </edmx:Runtime>
9 <!−− EF Designer content (DO NOT EDIT MANUALLY BELOW HERE) −−
>
10 </edmx:Edmx>
Zur Laufzeit müssen die Metadaten als drei eigenständige XML-Dateien,mit
den Endungen.csdl
3
,.ssdl
4
und.msl
5
vorliegen.Beim Übersetzen werden
3
Conceptual Schema Definition Language
4
Storage Schema Definition Language
5
Mapping Specification Language
3.Evaluierung 23
diese Dateien aus der.edmx-Datei generiert [11].
Listing 3.2:Der „CSDL content“ aus Listing 3.1,Zeile 6.
1 <!−− CSDL content −−>
2 <edmx:ConceptualModels>
3 <Schema Namespace="ERPModel"Alias="Self"xmlns="http://
schemas.microsoft.com/ado/2006/04/edm">
4 <EntityContainer Name="ERPEntities">
5 <EntitySet Name="Country"EntityType="ERPModel.Country"
/>
6 </EntityContainer>
7 <EntityType Name="Country">
8 <Key>
9 <PropertyRef Name="Id"/>
10 </Key>
11 <Property Name="Id"Type="Int64"Nullable="false"/>
12 <Property Name="ISOCode"Type="String"Nullable="false"
MaxLength="3"Unicode="true"FixedLength="false"/>
13 <Property Name="Name"Type="String"Nullable="false"
MaxLength="100"Unicode="true"FixedLength="false"/
>
14 <Property Name="Version"Type="Int32"Nullable="false"
ConcurrencyMode="Fixed"/>
15 </EntityType>
16 </Schema>
17 </edmx:ConceptualModels>
Listing 3.3:Der „SSDL content“ aus Listing 3.1,Zeile 5.
1 <!−− SSDL content −−>
2 <edmx:StorageModels>
3 <Schema Namespace="ERPModel.Store"Alias="Self"Provider="
System.Data.SqlClient"ProviderManifestToken="2005"
xmlns:store="http://schemas.microsoft.com/ado/2007/12/
edm/EntityStoreSchemaGenerator"xmlns="http://schemas.
microsoft.com/ado/2006/04/edm/ssdl">
4 <EntityContainer Name="ERPModelStoreContainer">
5 <EntitySet Name="Country"EntityType="ERPModel.Store.
Country"store:Type="Tables"Schema="dbo"/>
6 </EntityContainer>
7 <EntityType Name="Country">
8 <Key>
9 <PropertyRef Name="Id"/>
10 </Key>
11 <Property Name="Id"Type="bigint"Nullable="false"/>
12 <Property Name="ISOCode"Type="nvarchar"Nullable="false
"MaxLength="3"/>
13 <Property Name="Name"Type="nvarchar"Nullable="false"
MaxLength="100"/>
14 <Property Name="Version"Type="int"Nullable="false"/>
15 </EntityType>
16 </Schema>
17 </edmx:StorageModels>
3.Evaluierung 24
Listing 3.4:Der „C-S mapping content“ aus Listing 3.1,Zeile 7.
1 <!−− C−S mapping content −−>
2 <edmx:Mappings>
3 <Mapping Space="C-S"xmlns="urn:schemas-microsoft-
com:windows:storage:mapping:CS">
4 <EntityContainerMapping StorageEntityContainer="
ERPModelStoreContainer"CdmEntityContainer="
ERPEntities">
5 <EntitySetMapping Name="Country">
6 <EntityTypeMapping TypeName="IsTypeOf(ERPModel.Country
)">
7 <MappingFragment StoreEntitySet="Country">
8 <ScalarProperty Name="Id"ColumnName="Id"/>
9 <ScalarProperty Name="ISOCode"ColumnName="ISOCode"
/>
10 <ScalarProperty Name="Name"ColumnName="Name"/>
11 <ScalarProperty Name="Version"ColumnName="Version"
/>
12 </MappingFragment>
13 </EntityTypeMapping>
14 </EntitySetMapping>
15 </EntityContainerMapping>
16 </Mapping>
17 </edmx:Mappings>
Listing 3.5:Ausschnitt „EF Designer content“ aus Listing 3.1,Zeile 9.
1 <!−− EF Designer content (DO NOT EDIT MANUALLY BELOW HERE) −−
>
2 <edmx:Designer xmlns="http://schemas.microsoft.com/ado
/2007/06/edmx">
3 <edmx:Connection>
4 <DesignerInfoPropertySet>
5 <DesignerProperty Name="MetadataArtifactProcessing"Value
="EmbedInOutputAssembly"/>
6 </DesignerInfoPropertySet>
7 </edmx:Connection>
8 <edmx:Options>
9 <DesignerInfoPropertySet>
10 <DesignerProperty Name="ValidateOnBuild"Value="true"/>
11 </DesignerInfoPropertySet>
12 </edmx:Options>
13 <!−− Diagram content (shape and connector positions) −−>
14 <edmx:Diagrams>
15 <Diagram Name="ERPModel">
16 <EntityTypeShape EntityType="ERPModel.Country"Width="1.5
"PointX="0.75"PointY="0.75"Height="
1.787985026041667"IsExpanded="true"/></Diagram></
edmx:Diagrams>
17 </edmx:Designer>
Bei Genome und NHibernate werden diese Metadaten wesentlich kom-
pakter dargestellt.So haben die Metadaten für das Entity Framework in der
erstellten Beispielanwendung in etwa den dreifachen Umfang im Vergleich
3.Evaluierung 25
zu den anderen beiden Produkten.Derselbe Anwendungsfall,den Listing 3.1
bis Listing 3.5 für das Entity Framework dargestellen,wird für NHibernate
mit Listing 3.6 bzw.für Genome mit Listing 3.7 umgesetzt.Für jede En-
titätsklasse die persitiert werden soll,wird ein class-Element erstellt.Mit
einem Attribut wird der Name der Tabelle festgelegt werden,in die die
Entitätsklasse persistiert werden soll.Sind Tabellenname und Klassenna-
me identisch wie im angeführten Beispiel,kann diese Angabe entfallen.Das
id-Element definiert das Id-Attribut bzw.den Primärschlüssel(siehe Unter-
abschnitt 2.2.1).Mit dem version-Element wird eine Property für optimis-
tische verbindungslose Sperre (siehe Unterabschnitt 2.2.6) festgelegt.Die
Abbildung einzelner Properties der Entitätsklassen auf Attribute der Tabel-
len erfolgt über property-Elemente,wobei die Namen der Tabellenattribute
nur anzugeben sind,wenn diese von den Propertynamen abweichen.
Listing 3.6:NHibernate Metadaten.
1 <?xml version="1.0"?>
2 <hibernate-mapping
3 xmlns="urn:nhibernate-mapping-2.2"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 namespace="DAL_NHibernate"
6 assembly="DAL_NHibernate">
7
8 <class
9 name="Country"
10 batch-size="100">
11 <id
12 name="Id"
13 column="Id"
14 access="field.camelcase">
15 <generator class="hilo">
16 <param name="table">RowId</param>
17 <param name="column">NextValue</param>
18 <param name="max_lo">10</param>
19 </generator>
20 </id>
21
22 <version
23 name="Version"
24 access="field.camelcase"/>
25
26 <property
27 name="ISOCode"
28 length="3"
29 not-null="true"/>
30
31 <property
32 name="Name"
33 length="100"
34 not-null="true"/>
35 </class>
36 </hibernate-mapping>
3.Evaluierung 26
Die Metadaten sind bei Genome ähnlich strukturiert wie bei NHibernate.
Die Elemente Type,PrimaryKey,OptimisticLock und Member in Genome
entsprechen in etwa den NHibernate-Elementen class,id,version und pro-
perty.Das Element CodeGeneratedProxy weist Genome an,zu den abstrak-
ten Entitätsklassen Quelltext für konkrete Implementierungen zu generieren.
Es ist bei allen Entitätsklassen anzugeben,außer es handelt sich umabstrak-
te Basisklassen von denen keine Objekte erzeugt werden sondern von denen
nur weiter abgeleitet wird,wie das z.B.bei den Klassen Item oder Contact
in der Beispielimplementierung der Fall ist (siehe Kapitel 4).
Listing 3.7:Genome Metadaten
1 <?xml version="1.0"?>
2 <Mapping xmlns="urn:TechTalk:TT.OODAL.XmlMapping">
3 <Using namespace="System"/>
4 <Using namespace="System.Data.SqlTypes"/>
5 <Using namespace="TechTalk.Genome"/>
6 <Using namespace="TechTalk.Genome.Mapping"/>
7 <Using namespace="TechTalk.Genome.Schema.Builder.Xml"/>
8 <Using namespace="TechTalk.Genome.Extensions.Linq"/>
9
10 <Using namespace="Client_Genome"/>
11
12 <Type name="Country">
13 <RootInheritance/>
14 <PrimaryKey>
15 <Key>Id</Key>
16 </PrimaryKey>
17 <Sealed/>
18 <CodeGeneratedProxy/>
19 <OptimisticLock fieldName="Version"/>
20
21 <Member name="Id">
22 <PersistentField Size="8"/>
23 </Member>
24 <Member name="ISOCode">
25 <PersistentField Unicode="true"VariableLength="true"
Length="3"/>
26 </Member>
27 <Member name="Name">
28 <PersistentField Unicode="true"VariableLength="true"
Length="100"/>
29 </Member>
30 </Type>
31 </Mapping>
3.2.2 Objektidentität
Wie im Unterabschnitt 2.2.1 beschrieben sind einfache künstliche Schlüssel,
die per Sequence-Mechanismus generiert werden,eine effiziente Lösung zum
Erzeugen von Ids für neue Objekte.Noch effizienter können GUID-Werte
3.Evaluierung 27
generiert werden,da das ohne jeden Datenbankzugriff erfolgen kann.Ids
vom Typ GUID haben aber den Nachteil,dass sie wesentlich mehr Spei-
cherplatz (16 Bytes) benötigen und dadurch die Indizes vergrößern (siehe
Unterabschnitt 2.2.1).Alle drei untersuchten Produkte können laut Doku-
mentation,GUID als Primärschlüssel ohne weiteres handhaben.Da in der
Beispielanwendung keine besonderen Anforderungen die Verwendung von
GUID rechtfertigen,ist die Wahl auf den Sequence-Mechanismus gefallen,
der nachfolgend näher untersucht wird.
NHibernate unterstützt,abhängig vom eingesetzten RDBMS,mehrere
Varianten.Bei Datenbanken wie z.B.Oracle,die selbst einen Sequence-
Mechanismus anbieten,kann NHibernate angewiesen werden,diesen zu ver-
wenden.Andernfalls genügt es,eine Tabelle mit einemAttribut in der Daten-
bank anzulegen,die NHibernate zur Verfügung gestellt wird,um den nächs-
ten verfügbaren Wert abzulegen.Letztere Variante wurde in der Beispielan-
wendung genutzt,da der Microsoft SQL-Server keinen Sequence-Mechanis-
mus anbietet.Diese Variante bietet höchstmögliche Portabilität,da sie auf
jedes RDBMS identisch abgebildet werden kann.Neben der Effizienz ist das
ein weiterer wesentliche Vorteil.
Listing 3.8:NHibernate Beispiel
1 <class
2 name="Country"
3 batch-size="100">
4 <id
5 name="Id"
6 column="Id"
7 access="field.camelcase">
8 <generator class="hilo">
9 <param name="table">RowId</param>
10 <param name="column">NextValue</param>
11 <param name="max_lo">10</param>
12 </generator>
13 </id>
14 </class>
15 </hibernate-mapping>
Listing 3.8 zeigt,wie die gewünschte Id-Generierungsvariante in NHi-
bernate festgelegt wird,die relevanten XML-Elemente sind durch Fettdruck
hervorgehoben.Die ID-Generierung ist für jede abzubildende Klasse ein-
zeln festzulegen.Der Generierungsalgorithmus heißt in NHibernate „hilo“.
RowId ist der Name der zu verwendenden Tabelle,NextValue der Name
des Attributes in der Tabelle.Die Anzahl der Werte,die bei jedem Zugriff
angefordert werden,wird mit Parameter max_lo festgelegt.Ohne explizite
Definition von table,column und max_lo werden von NHibernate bereit-
gestellte Vorgabewerte verwendet.Eine Schwäche dieser Implementierung
ist,dass für jede Klasse ein eigener Zähler im Speicher verwaltet wird.Die
Anzahl verlorener Werte wird dadurch unnötig erhöht.
3.Evaluierung 28
Per Konfiguration bietet ADO.NET Entity Framework die Auswahl zwi-
schen vier Varianten,umId-Werte zu generieren.Bei zwei der vier Varianten
wird erwartet,dass die Werte in der Datenbank erzeugt werden.Entweder
ist der Primärschlüssel als ein Attribut des Typs Identity definiert oder die
Werte des Primärschlüssels werden auf eine andere Art in der Datenbank
zugewiesen,z.B.durch Trigger.Wird für den Primärschlüssel der Datentyp
GUID gewählt,übernimmt das Entity Framework die automatische Zuwei-
sung neuer Werte.Als vierte Variante wird angeboten,dass sich das Entity
Framework nicht um die Generierung kümmert.Damit wird zumindest ei-
ne eigene Implementierung von Clientseitig zugewiesenen Id-Werten ermög-
licht.Für die Beispielanwendung wurde die letzte Variante gewählt,die den
Sequence-Mechanismus nachbildet,wie in Unterabschnitt 2.2.1 beschrieben.
Diese Lösung entspricht in etwa dem bei NHibernate verwendetem HiLo-
Algorithmus.Die konkrete Realisierung ist unter Unterabschnitt 4.2.3 de-
taillierter ausgeführt.
Trotz der bekannten Nachteile von GUID und datenbankgenerierten Pri-
märschlüsseln wird der Sequence-Mechanismus vomEntity Framework nicht
unmittelbar unterstützt.Die eigene,wiederverwendbare Implementierung,
besteht nur aus wenigen Zeilen Quellcode,aber gerade dieser Umstand ließe
erwarten,dass diese Variante als fixer Bestandteil eines Frameworks bereit-
gestellt wird.Auch wenn die eigene Implementierung nur aus wenigen Zeilen
besteht,waren doch fortgeschrittene Kenntnisse für die Implementierung er-
forderlich.Konkrete Hinweise dazu fanden sich in der Dokumentation nicht.
Die Situation bei Genome entspricht weitgehend der beimEntity Frame-
work.Wird Oracle als Datenbank verwendet,steht als zusätzliche Variante
Sequence zur Verfügung.Da die Beispielanwendung auch mit dem Micro-
soft SQL-Server zusammenarbeiten soll,wurde wie beim Entity Framework
eine eigene Lösung zum Nachbilden des Sequence-Mechanismus erstellt.Die
Umsetzung war mit noch etwas weniger Quellcode zu realisieren und mit
Grundkenntnissen in ca.fünf Stunden zu schaffen.Trotzdem wäre auch hier
eine integrierte Lösung wünschenswert.
3.2.3 Beziehungen
Grundsätzlich können mit allen drei Produkten alle in Unterabschnitt 2.2.2
beschriebenen Beziehungen definiert werden.Beim Entity Framework sind
alle Beziehungen automatisch bidirektional.Unidirektionale Beziehungen
werden nicht unterstützt.Genome und NHibernate bieten nur unidirektio-
nale Beziehungen,bidirektionale Beziehungen werden aus zwei unidirektio-
nalen Beziehungen aufgebaut.
Ob beim Löschen eines Datensatzes,der Detaildatensätze enthält,das
Löschen verhindert werden soll oder ob in diesem Fall auch die Detaildaten-
sätze automatisch gelöscht werden sollen,kann bei NHibernate und beim
Entity Framework in den Metadaten definiert werden.Bei Genome ist dafür
3.Evaluierung 29
eine Ereignismethode in der Entitätsklasse zu implementieren,die das Lö-
schen gegebenenfalls verhindert bzw.vorhandene Detaildatensätze explizit
löscht.Listing 3.9 zeigt eine entsprechende Implementierung aus der Klasse
PurchOrder.Die Klasse muss das Interface IDeleteCallback implementieren.
Listing 3.9:Genome:Bestellpositionen automatisch mit der Bestellung lö-
schen.
1#region IDeleteCallback Members
2
3 public void OnDelete()
4 {
5 foreach (PurchOrderLine ol in OrderLines)
6 Context.GetEffectiveContext(this).Delete(ol);
7 }
8
9#endregion
Für den Zugriff auf in Beziehung stehende Datensätze über entsprechen-
de Datenkomponenten der Enitätsklassen gibt es verschiedene Strategien.
Entweder müssen die Daten explizit vor dem ersten Zugriff aus der Da-
tenbank geladen werden,wie es beim Entity Framework der Fall ist,oder
sie werden beim ersten Zugriff automatisch nachgeladen (Laden bei Bedarf,
siehe Unterabschnitt 2.2.7).Die zweite Variante kommt bei Genome zum
Einsatz.Eine weitere mögliche Variante ist,referenzierte Daten sofort mit-
zuladen,entweder in einer Join-Abfrage oder in zwei aufeinander folgenden
Befehlen,auch gieriges Laden (Greedy Loading) genannt.Nur bei NHiber-
nate kann jede dieser Varianten,für jede Beziehung individuell,in den Me-
tadaten definiert werden.Alle drei Produkte bieten noch die Möglichkeit,
in einer Abfrage festzulegen,welche Beziehungen automatisch sofort mitge-
laden werden sollen.Die entsprechenden Anweisungen heißen bei Genome
PreCache,bei Entity Framework Include und bei NHibernate Fetch bzw.
SetFetchMode.Bei Genome können die in Beziehung stehenden Datensätze,
die nachgeladen werden sollen,über einfache oder komplexe Kriterien zu-
sätzlich eingeschränkt werden.Für Laden bei Bedarf müssen bei NHibernate
und Genome die mit den Produkten gelieferten Behälterklassen verwendet
werden.
Microsoft unterscheidet bei Laden bei Bedarf zwischen implizitem und
explizitem Laden bei Bedarf [16].Das Entity Framework unterstützt nur
explizites Laden bei Bedarf.Vor dem ersten Zugriff muss die Methode Load
aufgerufen werden.Beim impliziten Laden bei Bedarf,wie es NHiberna-
te und Genome unterstützen,wird dieser Aufruf bei Bedarf automatisch
ausgeführt.Das Entity Framework unterstützt implizites Laden bei Bedarf
nicht,was auch häufig kritisiert wird [64].Mitglieder des Entity Framework-
Entwicklungsteams stellen in Aussicht,implizites Laden bei Bedarf in einer
späteren Version zu implementieren [14,17].
3.Evaluierung 30
3.2.4 Eingebetteter Wert
Diese in Unterabschnitt 2.2.3 beschriebene Möglichkeit,Klassen auf Tabellen
abzubilden,wird nur von NHibernate ausreichend unterstützt.Bei Genome
sowie beim Entity Framework wird dieser Mechanismus grundsätzlich an-
geboten,jedoch mit der Einschränkung,dass diese eingebetteten Klassen
keine Beziehungen zu weiteren Entitäten beinhalten dürfen.Schon einfa-
che Beispiele,die in diesem Zusammenhang genannt werden,wie Geldbe-
träge [FRF02,S.268] oder Adressen,können damit nicht richtig abgebil-
det werden.Bei einem Geldbetrag wird eine Beziehung zur Währung,bei
Adresse zumindest eine Beziehung zu Land benötigt.Umgangen kann diese
Einschränkung bei Genome und dem Entity Framework werden,indem nur
die Abbildung der Fremdschlüssel-Attribute (z.B.CurrencyId bzw.Coun-
tryId) ohne die zugehörigen Beziehungen definiert werden.Definiert wird
eingebetteter Wert in NHibernate mit demXML-Element Component,beim
Entity Framework mit ComplexType.EmbeddedStruct ist das entsprechende
XML-Element bei Genome,obwohl damit auch Klassen eingebettet werden
können.
3.2.5 Vererbung
Von allen Testkandidaten werden alle drei möglichen Vererbungs-Varianten
(siehe Unterabschnitt 2.2.4) unterstützt.Genome benötigt,im Gegensatz
zum Entity Framework und zu NHibernate,auch bei Vererbung mit einer
Tabelle pro Klasse ein Diskriminator-Attribut.
Über das grafische Designer-Werkzeug des Entity Framework kann nur
die Variante „Vererbungshierarchie in einer Tabelle“ definiert werden.Die
beiden alternativen Varianten können,durch manuelles Anpassen des XML-
Quelltextes in der edmx-Datei,definiert werden,wobei das manuelle Bear-
beiten besonders erschwert wird,da die einzelnen XML-Elemente,die eine
Vererbung definieren,über das gesamte Entity Data Model verteilt sind und
Vererbung nicht explizit über entpsrechende Elemente ausgedrückt wird.Die
Vergleichsprodukte weisen zumindest „Vererbungshierarchie in einer Tabel-
le“ und „Vererbung mit einer Tabelle pro Klasse“ durch spezielle XML-
Elementen aus.Bei NHibernate sind dies subclass und joined-subclass,bei
Genome SharedInheritance und JoinedInheritance.
3.2.6 Nebenläufigkeit
Das ADO.NET Entity Framework unterstützt nur optimistische verbin-
dungslose Sperren (Optimistic Offline Lock) [24].NHibernate und Genome
bieten dagegen auch pessimistitsche Sperren (Pessimistic Lock),also Sper-
ren,die auf Datenbankebene gesetzt werden (siehe Unterabschnitt 2.2.6).
Alle drei Produkte können bei optimistischer verbindungsloser Sperre
eine beliebige Auswahl an Attributen einer Tabelle zur Konflikterkennung
3.Evaluierung 31
heranziehen.Die effizienteste Lösung besteht allerdings darin,nur ein At-
tribut als Datensatzversion zu verwenden.Der Microsoft SQL-Server bietet
speziell für diesen Zweck den Datentyp Timestamp.Um die Portabilität
nicht unnötig einzuschränken,wurde für die Beispielanwendung jedoch ein
Ganzzahliges Versionsattribut verwendet.
NHibernate bietet hier die einfachste Lösung.Es genügt,in der Konfi-
guratonsdatei eine Property der Klasse für die Konflikterkennung zu Kenn-
zeichnen.NHibernate erkennt am Datentyp automatisch,ob es den Wert
beim Speichern von Änderungen erhöhen muss,oder ob das Attribut von
der Datenbank aktualisiert wird.
Wird der Datentyp Timestamp für das Versionsattribut verwendet,ist
auch beim ADO.NET Entity Framework die Konfiguration ähnlich unkom-
pliziert.Soll der Datentyp Ganzzahl verwendet werden,ist der Entwickler
für das Erhöhen des Wertes beim Speichern zuständig.Die Implementie-
rung ist,wie beim Sequence-Mechanismus,mit wenigen Zeilen Quellcode zu
realisieren,aber für Einsteiger nicht unbendingt naheliegend (siehe Unter-
abschnitt 4.2.6).
Genome akzeptiert bei Verwendung des Microsoft SQL-Server nur den
Datentyp Timestamp für das Versionsattribut,obwohl in Zusammenarbeit
mit Oracle der Datentyp Ganzzahl dafür unterstützt wird.Die Portabilität
wird dadurch unnötig eingeschränkt.Im Supportforum wurde auf Anfrage
ein Lösungsansatz geschildert,wie auch mit dem SQL-Server der Ganzzahl-
Datentyp für das Versionsattribut verwendet werden kann,der aber zu kom-
plex erschien,um ihn im Zuge dieser Arbeit umzusetzen.Für die Genome-
Beispielapplikation wurde deshalb der Datentyp Timestamp verwendet,wo-
durch eine eigenes,entsprechend abweichendes Datenbankschema erstellt
werden musste.Weiters muss bei Genome jede Sperre für jedes Objekt ex-
plizit gesetzt werden.
3.2.7 Abfragen
OQL
Alle drei Testkandidaten bieten mehrere Möglichkeiten,Abfragen gegen das
konzeptionelle Modell abzusetzen.Eine an OQL angelehnte Abfragesprache,
die als Zeichenkette übergeben wird,wie in Unterabschnitt 2.2.10 beschrie-
ben,bieten alle untersuchten Produkten.Bei NHibernate wird sie HQL (Hi-
bernate Query Languag),bei Genome OQL (Object Query Language) und
beim Entity Framework eSQL bzw.Entity-SQL bezeichnet.
LINQ
Das ADO.NET Entity Framework bietet schon seit den ersten Testversio-
nen LINQ-Unterstützung.Für Genome ist diese Abfragevariante seit einigen
3.Evaluierung 32
Monaten verfügbar und dürfte bereits stabil sein.NHibernate hinkt den bei-
den anderen Testkandidaten diesbezüglich noch deutlich hinterher.Für die
im August veröffentlichte Version 2.0 wurde die LINQ-Unterstützung nicht
rechtzeitig fertig.Über einen möglichen Zeitpunkt der Fertigstellung wurde
noch nichts bekannt gegeben.
SQL
NHibernate und Genome bietet noch zusätzlich die Möglichkeit,SQL als
Abfragesprache zu nutzen.Da mit diesem Mechanismus die Abstraktion
der Datenbank aufgeweicht wird,sollte genau abgewogen werden,ob ein
konkreter Anwendungsfall diese Einschränkung rechtfertigt.
3.3 Softwarearchitektur
3.3.1 Unabhängigkeit der Entitätsklassen von der Persistenz-
schicht (Persistence Ignorance)
Jede O/R-Mapping-Lösungen schränkt die Freiheit beim Entwurf der Enti-
tätsklassen in gewissemMasse ein.So setzen alle Produkte eine ID-Property
in den Entitätsklassen voraus,um die Objekte im Speicher eindeutig den
persistierten Datensätzen zuordnen zu können.
Bei Genome müssen die Entitätsklassen abstrakte Klassen sein.Genome
generiert zur Übersetzungszeit automatisch Quelltext für die dazugehöri-
ge konkrete Implementierung.Die Objekterzeugung muss deshalb an das
Framework delegiert werden.Ein Vorteil dieser Vorgangsweise ist,dass Me-
thoden zum Hinzufügen und Entfernen von Detaildatensätzen automatisch
generiert werden.Ein Konstruktor,der alle in den Metadaten dieser En-
tität definierten Properties als Parameter akzeptiert,muss aber für jede
Klasse manuell implementiert werden.Es wird empfohlen,Entitätsklassen
von TechTalk.Genome.Persistent abzuleiten,da darin die Vergleichsopera-
toren überschrieben sind und einige weitere Methoden bereitgestellt wer-
den,die den Umgang mit den Entitätsklassen erleichtern.Zum Abbilden
von Beziehungen müssen die vom Framework bereitgestellten Behälterklas-
sen verwendet werden.Für alle Datenkomponenten,die persistiert werden
sollen,müssen Properties definiert werden,die abstrakt und entweder ge-
schützt oder öffentlich sind.Properties,die dem Entwickler nur lesenden
Zugriff ermöglichen oder die zusätzliche Programmlogik enthalten sollen,
müssen doppelt implementiert werden.Einmal als abstrakt und geschützt,
damit sie nur dem Persistierungsframework zugänglich sind,und ein zweites
Mal unter anderem Namen und öffentlich mit der gewünschten zusätzlichen
Programmlogik,die den Zugriff auf die erste Property weiterleitet.Das Im-
plementieren der Schnittstelle IDeleteCallback wird zusätzlich erforderlich,
3.Evaluierung 33
wenn beimLöschen eines Datensatzes die Detaildatensätze automatisch mit-
gelöscht werden sollen.
NHibernate benötigt neben der ID-Property noch einen parameterlosen
Konstruktor in den Entitätsklassen.Behälterklassen für Beziehungen dür-
fen nur mit Schnittstellen,nicht jedoch mit konkreten Implementierungen
definiert werden.Soll Laden bei Bedarf zum Einsatz kommen,müssen au-
ßerdem alle Methoden und Properties virtuell sein,damit NHibernate die
in diesem Fall benötigten Proxies erzeugen kann.Datenkomponenten kann
NHibernate entweder direkt oder über zugehörige Properties persistieren,
auch wenn der Lese- oder Schreibzugriff privat oder geschützt ist.
Beim ADO.NET Entity Framework werden die Entitätsklassen norma-
lerweise aus dem konzeptionellen Modell generiert.Die resultierenden Klas-
sen sind von System.Data.Objects.DataClasses.EntityObject abgeleitet,das
selbst von StrukturalObject ableitet und die Schnittstellen IEntityWithKey,
IEntityWithChangeTracker sowie IEntityWithRelationships implementiert.
StrukturalObject implementiert die Schnittstellen INotifyPropertyChanging
sowie INotifyPropertyChanged.Da das Entity Framework und somit alle ent-
haltenen Klassen und Schnittstellen Teil des.NET-Framework sind,wird
dadurch keine Abhängigkeit zu zusätzlichen Frameworks verursacht.Von
der Idealvorstellung eines POCO sind diese Entitätsklassen trotzdem weit
entfernt.
Der generierte Quelltext wird bei jeder Änderung der Metadaten neu ge-
neriert.Die Entitätsklassen sind deshalb als partielle Klassen definiert und
können somit manuell erweitert werden,ohne dass diese Änderungen von
der automatischen Quelltextgenerierung überschrieben werden.Bei diesen
manuellen Erweiterungen ist jedoch immer auf die vorhandene Programm-
logik Rücksicht zu nehmen [19].Die gebotenen Möglichkeiten sind dadurch
erheblich eingeschränkt.Das Entity Framework kann auch manuell erstellte
Entitätsklassen persistieren.Bei solchen Klassen wird vorausgesetzt,dass
sie die Schnittstellen IEntityWithKey,IEntityWithChangeTracker und IEn-
tityWithRelationships implementieren,wenn zugehörige Funktionalität wie
ein Id-Property,integrierte Änderungsüberwachung oder eine Beziehung be-
nötigt wird.Weitere Informationen dazu finden sich in [22].
Schon seit längerer Zeit stellen sich einzelne Mitglieder des Entwick-
lungsteams der Diskussion mit Anwendern,die eine weitere Annäherung an
vollständige Unabhängigkeit der Entitätsklassen von der Persistenzschicht
für die nächste Version des Entity Framework erwarten [49,51].
Wie schon in Unterabschnitt 3.2.3 ausgeführt wurde,unterstützt das
Entity Framework nur bidirektionale Beziehungen,wodurch die eventuell
gewünschte Kapselung aufgweicht wird,die die öffentliche Schnittstelle einer
Klasse unnötig erweitert wird.
3.Evaluierung 34
3.3.2 Unterstützte Datenbanksysteme
Beim ADO.NET Entity Framework wird über ein Providermodell die Un-
terstützung unterschiedlicher RDBMS ermöglicht.Microsoft liefert nur Pro-
vider für die eigenen Datenbankprodukte.An der Unterstützung weiterer
RDBMS wird von anderen Anbietern bereits gearbeitet [57].Die Firma De-
vart bietet Provider für die Unterstützung von Oracle,MySQL,PostgreSQL
und SQLite [7,36,38,53,54].Unter [47,63] wird ein SQLite-Provider zum
Download angeboten.Provider für eine Reihe weiterer RDBMS sind ange-
kündigt [57].Sybase iAnywhere stellt mittlerweile auch einen Provider für
das Entity Framework zur Verfügung [48].
Von den untersuchten Produkten unterstützt NHibernate zurzeit noch
die größte Anzahl an Datenbanksystemen,wobei das Entity Framework be-
reits aufholt.Neben Microsoft SQL-Server,Oracle 9i und Oracle 10g,arbei-
tet NHibernate mit einer Reihe weiterer kommerzieller und freier RDBMS
zusammen [40].
Genome unterstützt grundsätzlich nur den SQL-Server von Microsoft
sowie dessen CE-Variante,Oracle 9i und 10g sowie IBM DB2,wobei diese
Auswahl bei der Express-Edition weiter eingeschränkt ist.
3.4 Produktivität
3.4.1 Codegenerierung
Enitätsklassen aus Metadaten generieren
Das ADO.NET Entity Framework generiert die Entitätsklassen automatisch
entsprechend des konzeptionellen Schemas in den Metadaten.Änderungen
direkt in den Metadaten oder über das grafische Designer-Werkzeug initiie-
ren beim Speichern die erneute Generierung der Quelltextes.Mit NHiber-
nate wird seit der Version 1.2 das Kommandozeilenwerkzeug hbm2net mit-
geliefert,das auch aus den Metadaten den Quelltext für die Entitätsklassen
generieren kann.Genome wird ohne vergleichbare Funktionalität geliefert.
Datenbank-Schema aus Metadaten generieren (Forward Enginee-
ring)
Genome enthält einen in Visual Studio integrierten Assistenten,der das Da-
tenbankschema entsprechend den Metadaten aktualisiert.NHibernate bietet
in der Laufzeitumgebung eine entsprechende Funktionalität,die per Konfi-
gurationseinstellung oder über einen Aufruf der entsprechenden Funktion
das Datenbankschema aus den Metadaten neu erzeugt.Beim ADO.NET
Entity Framework fehlt eine enstprechende Funktionalität.
3.Evaluierung 35
Abbildung 3.2:Assistent von Genome zum Erstellen der Metadaten aus
einer Entitätsklasse.
Metadaten aus den Entitätsklassen generieren
Genome kann aus dem Quelltext der Entitätsklassen die Metadaten er-
zeugen.Dazu wird im Kontextmenü des Quelltexteditors ein zusätzliches
Untermenü „Genome Mapping“ eingeblendet,das eine Reihe verschiede-
ner Abbildungsmöglichkeiten zur Auswahl anbietet (siehe Abbildung 3.2).
NHibernate kann die Metadaten zwar nicht aus dem Quelltext der Enti-
tätsklassen generieren,bietet jedoch die Möglichkeit,die Metadaten als At-
tribute in den Quelltext zu integrieren.Die von NHibernate zur Laufzeit
benötigten Metadaten im XML-Format kann es automatisch aus diesen ge-
nerieren.Das Entity Framework bietet keine vergleichbare Funktionalität.
Entitätsklassen und Metdaten aus dem Datenbankschema gene-
rieren (Reverse Engineering)
Das Entity Framework sowie Genome bieten in Visual Studio integrierte
Assistenten,die aus einer Datenbank,die über die Verbindungsparameter