Persistenzframeworks Präsentation im Rahmen des Software Engineering-Seminars Zaferna-Hütte, 5. Januar 2009 Georg Senft Inhalt Grundbegriffe Objektrelationales Mapping LINQ Hibernate und JPA Einordnung Heraus Herausforderungen Architektur Exkurs: Spracherweiterungen Lösungen objektrelationales Mapping Abfragen LINQ to SQL • ORM • Abfragen 2 NHibernate Fazit Grundbegriffe Framework konzeptspezifische Lösung für generisches Problem OO: insb. Vererbung, →White-Box-Wiederverwendung Problem-Abdeckung ~ Standardisierbarkeit Persistenz Fähigkeit einer Anwendung, Daten in einem nicht-flüchtigen Speicher zu sichern und später wiederherzustellen. Persistenzframework allgemein: Lösung für weit verbreitete Persistenz-Anforderung dabei: Kapselung → Entkoppelung + speziell DBMS): Objektrelationales i ll (OO & relationales l ti l DBMS) Obj kt l ti l Mapping M i 3 Objektrelationales Mapping (1/5) Abbild Abbildung: objektorientierte bj kt i ti t ↔ relationale l ti l Strukturen St kt Problem: Verschiedenheit der Paradigmen objektorientiertes Paradigma Pendant relationales Paradigma Kl Klasse T b ll (R Tabelle (Relation) l ti ) Attribut Attribut Objekt Datensatz (Tupel) Assoziation Assoziation Liste Primärschlüssel Vererbung Methoden „Impedanz-Unterschied“ 4 Objektrelationales Mapping (2/5) Mapping: Klasse ↔ Tabelle einfache e ac e Attribute bu e ↔ Attribute bu e Objektinstanzen ↔ Datensätze objektorientiert j relational Klasse Tabelle (Relation) Attribut Attribut Objekt Datensatz (Tupel) Herausforderung: Primitive Typen ↔ SQL-Datentypen SQL Datentypen Java, C#, VB.NET byte short float char int double übliche SQL-Typen long decimal String/string real smallint double char(n) int bigint decimal(n,m) varchar(n) boolean/bool bit (GregorianCalendar/DateTime) date time timestamp datetime Längenangaben herstellerindividuelle Datentypen zusätzlich: NULL-Wert 5 tinyint blob(n) ( ) clob(n) ( ) Objektrelationales Mapping (3/5) objektorientiert j relational Assoziation Assoziation 1:1-Beziehung und n:1-Beziehung: Automobil 1 * Person Halter► 1 Automobil ID … Halter Strategien zur Primärschlüssel-Vergabe: g g Generierung durch DBMS V Verwendung d von P Pseudo-Zufallszahlen d Z f ll hl etc. 6 Primärschlüssel Person ID … Objektrelationales Mapping (4/5) 1:n-Beziehung: Automobil Fahrer: Person[] * relational Assoziation Assoziation Liste Person 0 1 0..1 objektorientiert j * Automobil ID … Person ID … Auto m:n-Beziehung: m:n Beziehung: Automobil Automobil Person Fahrer: Person[] Autos:Automobil[] * 7 * ID … AutoPersZuo ID AID PID Person ID … Objektrelationales Mapping (4/5) 1:n-Beziehung: Automobil Fahrer: Person[] * relational Assoziation Assoziation Liste Person 0 1 0..1 objektorientiert j * Automobil ID … Person ID … Auto OO: keine Unterscheidung Automobil Automobil Fahrer: Person[] 8 Person * * ID … AutoPersZuo ID AID PID Person ID … Vererbung: 3 Strategien Kfz Leistung Pkw Türen Objektrelationales Mapping (5/5) relational Klasse Tabelle Lkw Achsen Tabelle je Klasse vollständige Tabelle je Klasse Kfz ID Diskriminator Leistg Leistg. Kfz ID Diskriminator Pkw ID Türen Pkw ID Leistungg Türen Lkw ID Achsen Lkw ID Leistung Achsen Vorteil: effiziente Speichernutzung 9 objektorientiert j Vererbung gemeinsame Tabelle Kfz ID Diskr Diskr. Leistung Türen Achsen bei großer Klassenvielfalt LINQ für .NET L Language Integrated I t t d Query Q für fü Microsoft Mi ft .NET NET 3.5 35 vereinheitlichte Syntax für Arbeit mit Datenmengen und Elemente erweiterbarer Umfang an LINQ-Providern it b U f LINQ P id Sprachintegration, neuartige Sprachelemente Programmiersprachen C# LINQ‐Bausteine Expression‐Bäume LINQ‐Provider LINQ to Objects Visual Basic Abfrage‐Ausdrücke Abfrage‐Operationen LINQ to SQL LINQ to XML SQL Server XML LINQ to Entities KlasseA KlasseB int : Zahl KlasseB : myB Datenquellen foo() bar() int : ZahlB bool : fertig flexnet() indapta() Objekte 10 Entity Framework Exkurs: Spracherweiterungen in C# 3.0 (1/1) Objekt-Initialisierer Kurzschreibweise für Initialisierung + Setzen öffentlicher Attribute Cl o = new Cl(4) { Attr1 = 1, Attr2 = 2 }; Erweiterungsmethoden Bestehende Klassen ohne Vererbung g um Methoden erweitern internal static void add(this int a,int b){ a+=b; } Implizit typisierte Variablen lokales var innerhalb einer Methode, Initialisierung erforderlich Anonyme Typen var mit Objektinitialisierer für implizite implizite, neue Klasse Lambda-Ausdrücke vergleichbar mit anonymen Methoden, Typen Methoden Delegat Delegat-Typen Array.FindAll<int>(Zahlen, i => (i<42) ); vom Compiler in Expression-Baum übertragen 11 LINQ to SQL (1/5) ORM für bestehende SQL Server Datenquellen grafisches ORM-Werkzeug in Visual Studio liefert gemappte Klassen Verwendung von Annotationen, Annotationen sog. sog „Attributen Attributen“ an gemappte Klasse[Table(Name="dbo.Automobil")] [Column(DbType="DateTime NOT NULL",CanBeNull=false)] [Column(DbType="DateTime")] System.Nullable<System.DateTime> Erstzulassung Primärschlüssel: IsPrimaryKey=true und IsDbGenerated=… Assoziation: [Association(ThisKey="Halter", OtherKey="PersonID", IsForeignKey=true)] Person PersonHalter; Gegenseite: EntitySet<Automobil> AutosGehalten; neben den gemappten Klassen: DataContext für DB-Interaktion getTable(), submitChanges() typisierte Table als Grundlage für Abfragen 12 13 LINQ to SQL (2/5) Abfrage: anonym typisiert t i i t als l vergleichbar: l i hb H k ft M Herkunfts-Menge IQueryable<Auto> foreach Table<Auto> Operation O ti (Auswahl) var Autos = from auto in tabAutos select auto; mit Kriterium und implizitem JOIN: var Autos = from auto in tabAutos where auto.PersonHalter.Vorname=="Georg" select auto; wird zum SQL-Ausdruck: 0 0 SELECT [t0].[Kennzeichen], [t0].[Typ], [t0].[Erstzulassung], [t0].[Halter] FROM [dbo].[Automobil] AS [t0] LEFT OUTER JOIN [dbo].[Person] [t1].[PersonID]=[t0].[Halter] [db ] [P ] AS [t1] ON [t1] [P ID] [t0] [H lt ] WHERE [t1].[Vorname] = 'Georg' 14 LINQ to SQL (3/5) Einfügen: tabAutos.InsertOnSubmit(neuesAuto); ausgeführter SQL-Ausdruck: INSERT INTO [dbo].[Automobil] ([Kennzeichen], [Typ], [Erstzulassung], [Halter]) VALUES (@p0, @p1, @p2, @p3) SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value] Löschen: tabAutos.DeleteOnSubmit(altesAuto); Aktualisierungen implizit, danach DataContext.submitChanges(); 15 LINQ to SQL (4/5) Prinzip des IQueryable für Abfragen: Übersetzung des LINQ-Ausdrucks zu Expression-Baum durch CIL-Compiler Auswertung durch LINQ-Provider Generierung und Ausführung adäquater SQL SQL-Ausdrücke Ausdrücke C# Expression‐Bäume Abfrage‐Ausdrücke LINQ to SQL SQL Server 16 Abfrage‐Operationen LINQ to SQL (5/5) Transaktionen: explizit über DataContext.Connection.BeginTransaction(..) und anschließender Zuweisung an Kontext Connection Pooling: implizit über ADO.NET-Verbindung g bedarfsweises Laden der Tabellen (Lazy Fetching) Normalfall, über DataLoadOptions regulierbar Zwischenfazit LINQ Q to SQL Q und LINQ: Q vollständige Kapselung vorhandener MS SQL Sever-Datenquellen Sprachintegration: Typsicherheit, Überprüfung, Vervollständigung LINQ Ausdrücke prägnant, LINQ-Ausdrücke prägnant zumindest bei geringer Komplexität keine Zerlegung eines LINQ-Ausdrucks beim Debugging 17 Hibernate und Java Persistence API (1/4) Java Persistence API (JPA) Schnittstellenspezifikation für Persistenzframeworks (JSR 220) Bestandteil von EJB 3.0, Bestandteil von Java EE 5.0 Einsatz in Java EE-Container oder Java SE 5.0-Anwendung Hibernate Open Source Persistenzframework, implementiert JPA, derzeit: 3.3.1 für JDBC-kompatible, relationale Datenquellen Hibernate Funktionsumfang übersteigt JPA-Anforderungen B t dt il Bestandteile: Entity Manager: JPA-kompatible Schnittstelle pp g p g g Core: zentrale OR-Mapping-Komponente und Abfragegenerator Annotations: ORM-Spezifikation per Annotationen in Java-Klassen (alternativ: ORM-Spezifikation per XML-Datei) 18 Hibernate und Java Persistence API (2/4) A Annotationen t ti zur ORM-Spezifikation: ORM S ifik ti Klassen erhalten @Entity Primärschlüssel-Attribut Primärschlüssel Attribut erhält @Id ggf.: @GeneratedValue(Strategy=GenerationType…) IDENTITY TABLE SEQUENCE uuid Generierung g durch Datenbank aktuelle Werte liegen in Sondertabelle Generierung durch Sequenz in Datenbank (z. B. Oracle) Pseudo-Zufallswert Pseudo Zufallswert weitere Attribute erhalten @Column ggf. mit nullable, length Assoziationen: @OneToOne mit @JoinColumn(name="…") @OneToMany(mappedBy="…") an Set-Kollektion z. B. HashSet und bei der Gegenseite @ManyToOne @JoinColumn(…) @JoinColumn( ) @ManyToMany(…) mit Aktualisierungs-Operation zusätzlich fetch=… und cascade=… möglich 19 Hibernate und Java Persistence API (3/4) weitere Annotationen zur ORM-Spezifikation: ORM Spezifikation: Vererbung: @Entity zu @InheritanceStrategy(strategy=…) TABLE_PER_CLASS JOINED SINGLE_TABLE vollständige Tabelle je Klasse Tabelle je Klasse (mit individuellen Attributen) gemeinsame Tabelle, @DiscriminatorColumn Verwendung des EntityManager Erzeugung aus Session y j p für Entity-Objekte persist()und remove() Transaktionssteuerung Suche anhand Primärschlüssel: find() weiterführende Abfragen EM.createNativeQuery()direkter SQL-Befehl an das DBMS EM createQuery() EM.createQuery() JPA Query Language Criteria typsichere Parameter-Struktur Example Beispielobjekt als Kriterium 20 Hibernate und Java Persistence API (4/4) weitere it Aspekte: A kt Connection Pooling nur über Zusatz-Lösungen (z. B. C3PO) E t ll Erstellung gemappter t Tabellen T b ll iin DBMS möglich, ö li h über: hb2ddl.SchemaExport.create() diverse Werkzeuge g für automatisierten Schema-Import p und -Export p Zwischenfazit Hibernate / JPA: vollständige Kapselung der Persistenz-Mechanismen typsichere Verfahren zur Abfrage wie Criteria oder Example automatisierte Tabellen-Generierung möglich 21 NHibernate für .NET Portierung Hibernate → .NET ausgehend von Version 2.1, seitdem eigenständig weiterentwickelt Funktionsumfang NHibernate 2 vergleichbar mit Hibernate 3 kompatibel mit .NET ab 1.1 Datenzugriff per ADO.NET somit auch OLE DB und ODBC ORM-Spezifikation nur mit XML-Mapping-Dateien Q to NHibernate-Provier Version 3: LINQ IQueryable wird über Criteria realisiert 22 Fazit Grad der Problemabdeckung: Objektrelationales Mapping gleichwertig umgesetzt Kapselung der Datenzugriffsschicht gleichwertig umgesetzt aber: LINQ to SQL nur für vorhandene Datenbanken Abfragemechanismen: JPA sehr allgemein ausgereifte Mechanismen in Hibernate Mechanismen in LINQ durch Sprachintegration prägnanter Architekturvergleich: JPA ↔ LINQ g der Sprache p g → LINQ durch Einbezug umfasender und überlegen 23 Literatur [MEW08] Fabrice F b i Marguerie, M i Steve St Eichert, Ei h t Jim Ji Wooley: W l LINQ im i Einsatz, Ei t Carl C l Hanser H Verlag, V l 2008. 2008 [Me08] Vijay P. Mehta: Pro LINQ Object Relational Mapping with C# 2008, Apress, 2008. [PR07] Paolo Pialorsi, Marco Russo: Introducing Microsoft LINQ, Microsoft Press, 2007. [Ra07] Joseph C. Rattz: Pro LINQ: Language Integrated Query in C# 2008, Apress, 2007. [BHRS07] Robert F. Beeger, Arno Haase, Stefan Roock, Sebastian Sanitz: Hibernate – Persistenz in Java-Systemen mit Hibernate und der Java Persistence API, 2. Aufl., dpunkt.verlag, 2007. [He07] Sebastian Hennebrüder: Hibernate – Das Praxisbuch für Entwickler, Galileo Press, 2007. [MW08] Bernd Müller, Harald Wehr: Java-Persistence-API mit Hibernate, Standardisierte Persistenz, Addison-Wesley, 2008. 24