250 likes | 395 Views
Object Relational Mapping. Stefan Lieser Email: stefan@lieser-online.de Web: www.lieser-online.de. Agenda. Domain Driven Design Begriffsklärung und Konzepte Mapping Metadaten Klassen Hierarchie auf Tabellen abbilden Locking, Transaktionen Beispiele „Zu Fuß“ mit ADO.NET NHibernate
E N D
Object Relational Mapping Stefan Lieser Email: stefan@lieser-online.de Web: www.lieser-online.de
Agenda • Domain Driven Design • Begriffsklärung und Konzepte • Mapping Metadaten • Klassen Hierarchie auf Tabellen abbilden • Locking, Transaktionen • Beispiele • „Zu Fuß“ mit ADO.NET • NHibernate • LINQ
Domain Driven Design • Relevanter Ausschnitt der Welt wird in Form von business objects modelliert. • Geschäftslogik und Regeln werden innerhalb der business objects als Methoden implementiert. • Datenbankzugriffe werden NICHT in den business objects selbst implementiert sondern in einem Repository.
Impedance mismatch • Relationale Datenbanken • Mengen und Relationen als mathematische Grundlage • Hoher Verbreitungsgrad (z.B. in „Legacy Anwendungen“) • Reine Datenhaltung • Objektorientierte Programmierung • Sehr ausdrucksstark • Daten und Operationen werden zusammengefasst • Keine Persistenz • Problembereiche • Unterschiedliche Datentypen • Klassenhierarchie auf Tabellen abbilden
Object Relational Mapper • Object Relational Mapper ermöglichen einen automatisierten Übergang zwischen Objekten und relationalen Datenbanken. • Mapping in Form von Metadaten • Generieren von SQL Statements für CRUD (Create, Retrieve, Update, Delete) • Kenntnisse in relationaler Datenbanktechnologie sind nach wie vor erforderlich.
Object Relational Mapper • Code für Persistenz und Business Logik bleibt getrennt • Datenbank Schema wird durch Mapping auf die Klassenstruktur abgebildet • Bei Änderungen am Schema oder der Klassenstruktur muss lediglich das Mapping angepasst werden. • Wechsel der Datenbankengine einfach möglich
Mapping • Wohin mit den Metadaten? • Attribute-based • Z.B. Java XDoclet, .NET Attribute • Vorteil: direkt im Code integriert • Nachteil: nicht sehr flexibel • Mapping file • XML • Vorteil: sehr flexibel • Nachteil: syntaktisch anspruchsvoll
Attribute-based Mapping 1 [Class(Table = "Addresses")] 2publicclassAddress2 { 3privateint m_Id; 4privatestring m_Name; 5privatestring m_Street; 6 7 [Id(0, TypeType = typeof(int), Column = "RecId")] 8 [Generator(1, Class = "native")] 9publicint Id { 10get { return m_Id; } 11set { m_Id = value; } 12 } 13 14 [Property()] 15publicstring Name { 16get { return m_Name; } 17set { m_Name = value; } 18 } 19 }
Datei basiertes Mapping 1<?xmlversion="1.0"encoding="utf-8"?> 2<hibernate-mappingxmlns:xsd="http://www.w3.org/2001/XMLSchema" 3xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4xmlns="urn:nhibernate-mapping-2.0"> 5 <classname="ORM.Address, ORM"table="Addresses"dynamic-update="true" > 6 <idname="Id"column="RecID"type="System.Int32"access="field"> 7 <generatorclass="native" /> 8 </id> 9 <propertyname="Name"column="Name"type="System.String"access="field" /> 10 <propertyname="Street"column="Street"type="System.String"access="field" /> 11 <propertyname="Town"column="Town"type="System.String"access="field" /> 12 </class> 13</hibernate-mapping>
Klassen Hierarchie Mapping • Table per concrete class • Jede konkrete Klasse in einer eigenen Tabelle • Table per class hierarchy • Eine Tabelle für eine Klassenhierarchie, Unterscheidung des konkreten Typs über eine Discriminator Spalte • Table per subclass • Normalisierte Tabellenstruktur
Table per concrete class „Alle Zahlungen eines Kunden“ benötigt zwei Select‘s: SELECT * FROM Kreditkarte WHERE Kunde = 'Lieser' SELECT * FROM Abbuchung WHERE Kunde = 'Lieser'
Table per class hierarchy „Alle Zahlungen eines Kunden“ benötigt nur ein Select:SELECT * FROM Zahlung WHERE Kunde = 'Lieser' Einschränkung auf eine Zahlart über den Discriminator:SELECT * FROM Zahlung WHERE Zahlart = 'K'
Table per subclass „Alle Zahlungen eines Kunden“ mittels outer join:SELECT * FROM ZahlungDetail ZD LEFT JOIN KreditkarteDetail KD ON KD.ZahlungId = ZD.RecId LEFT JOIN AbbuchungDetail AD ON AD.ZahlungId = ZD.RecId WHERE ZD.Kunde = 'Lieser‚ Einschränkung auf eine Zahlart über inner join
Polymorphie • Polymorphe Abfragen • class A { ... }class X : A { ... }class Y : A { ... } • select * from A • Mapping für X und Y muss berücksichtigt werden • Wenn X/Y jeweils in eigener Tabelle gespeichert sind, werden mehrere Tabellen abgefragt
Lazy vs. Eager Loading • Lazy Load • Eigenschaft eines Objektes wird erst aus der Datenbank geladen, wenn darauf zugegriffen wird. • Das Nachladen muss innerhalb der gleichen Session geschehen in der das Objekt geladen wurde. • Eager Loading • Daten werden mittels JOIN sofort geladen • Nur eine Collection kann per eager loading geladen werden, sonst würden (durch Kreuzproduktbildung) ggf. sehr große Datenmengen geliefert.
Traversing the object graph • class A { public B b; public IList C;} • A a;Save(a); • b und C werden automatisch in die Datenbank übertragen sofern sie geändert wurden. • Kann bei Bedarf abgeschaltet werden über ISession.FlushMode = FlushMode.Never;
Locking • Pessimistic • Datensätze werden während ihrer Bearbeitung in der Datenbank gesperrt • Nachteil: streng serieller Zugriff, dadurch evtl. schlechtes Antwortverhalten • Optimistic • Erst beim Aktualisieren der Datenbank wird geprüft ob die Daten von einem anderen Nutzer geändert wurden. • Sehr gute Skalierbarkeit
Optimistic Locking • Alle Spalten mit ihren vorherigen Werten vergleichen • UPDATE Adressen SET Strasse='My way'WHERE RecId=5 AND Name='Lieser' AND Strasse='Way' • Timestamp • UPDATE Adressen SET Strasse='My way', Timestamp='22.08.2006 14:06:05:87'WHERE RecId=5 AND Timestamp='20.08.2006 11:34:53:96' • Version • UPDATE Adressen SET Strasse='My way', Version=Version + 1WHERE RecId=5 AND Version=5
Unit of Work • Logisch zusammenhängende Änderungen müssen als Transaktion ausgeführt werden • Unit of Work als Pattern für Transaktionen • Constructor der UnitOfWork startet die Transaktion • Insert/Update/Delete Methoden ergänzen die Transaktion • Commit beendet die Transaktion • Im Fehlerfall wird ein Rollback ausgeführt
ORM „zu Fuß“ mit ADO.NET • Für jede Klasse werden CRUD Operationen geschrieben. • Vorgehensweise lässt sich mit Code Generatoren automatisieren.
NHibernate (LGPL) • Basiert auf Hibernate 2.1 (Java) • Mapping wahlweise über Attribute oder Datei • Abfrage • Criteria • Hybernate Query Language (HQL) • Query by Example
LINQ und ADO.NET • Language Integrated Query • Objektorientierte Abfragesprache • In die Sprache (C# und VB) integriert • Compile-time Prüfung (!) • Nicht auf Datenbanken beschränkt • ADO.NET Entity Framework • Client Views als Indirektionsebene • Migrationsweg für „alte“ ADO.NET Anwendungen
LINQ Beispiel • var custs = from c in db.Customers where c.City == "London" select c; • var custs = (from c in db.Customers where c.City == "London" select c) .Including(r => r.Orders);
Und Tschüss... Die PowerPoint Datei sowie die Beispiele finden Sie unterhttp://www.lieser-online.de