Object Relational Mapping Stefan Lieser Email: stefan@lieser-online.destefan@lieser-online.de Web: .

Post on 05-Apr-2015

118 views 1 download

Transcript of Object Relational Mapping Stefan Lieser Email: stefan@lieser-online.destefan@lieser-online.de Web: .

Object Relational Mapping

Stefan Lieser

Email: stefan@lieser-online.deWeb: www.lieser-online.de

Agenda

Domain Driven DesignBegriffsklä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 getrenntDatenbank 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")]

    2     public class Address2 {

    3         private int m_Id;

    4         private string m_Name;

    5         private string m_Street;

    6 

    7         [Id(0, TypeType = typeof(int), Column = "RecId")]

    8         [Generator(1, Class = "native")]

    9         public int Id {

   10             get { return m_Id; }

   11             set { m_Id = value; }

   12         }

   13 

   14         [Property()]

   15         public string Name {

   16             get { return m_Name; }

   17             set { m_Name = value; }

   18         }

   19     }

Datei basiertes Mapping

    1 <?xml version="1.0" encoding="utf-8"?>

    2 <hibernate-mapping xmlns:xsd="http://www.w3.org/2001/XMLSchema"

    3                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    4                   xmlns="urn:nhibernate-mapping-2.0">

    5   <class name="ORM.Address, ORM" table="Addresses" dynamic-update="true" >

    6     <id name="Id" column="RecID" type="System.Int32" access="field">

    7       <generator class="native" />

    8     </id>

    9     <property name="Name" column="Name" type="System.String" access="field" />

   10     <property name="Street" column="Street" type="System.String" access="field" />

   11     <property name="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

Zahlung

+Kunde+Betrag

Kreditkarte

+Nummer+Gültigkeit

Abbuchung

+Kontonummer+BLZ+Inhaber

Kreditkarte<<table>>

RecIdKundeBetragNummerGültigkeit

Abbuchung<<table>>

RecIdKundeBetragKontonummerBLZInhaber

„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'

Zahlung

+Kunde+Betrag

Kreditkarte

+Nummer+Gültigkeit

Abbuchung

+Kontonummer+BLZ+Inhaber

Zahlung<<table>>

RecIdKundeBetragZahlartNummerGültigkeitBLZInhaber

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

Zahlung

+Kunde+Betrag

Kreditkarte

+Nummer+Gültigkeit

Abbuchung

+Kontonummer+BLZ+Inhaber

ZahlungDetail<<table>>

RecIdKundeBetrag

KreditkarteDetail<<table>>

RecIdZahlungIdNummerGültigkeit

AbbuchungDetail<<table>>

RecIdZahlungIdKontonummerBLZInhaber

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 werdenUnit 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

Unit Of Workclient unit of work databaseanzeige erscheinung

1 : new()2 : BeginTransaction()

3 : new()

4 : AddNew(anzeige)

5 : new()

6 : AddNew(erscheinung)

7 : Execute()

8 : Insert(erscheinung)

9 : Insert(anzeige)

10 : CommitTransaction()

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 DateiAbfrage 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.Customerswhere c.City ==

"London"select c;

var custs = (from c in db.Customerswhere c.City ==

"London"select c)

.Including(r => r.Orders);

Und Tschüss...

Die PowerPoint Datei sowie die Beispiele finden Sie unter

http://www.lieser-online.de