JAVA PERSISTENCE API CAS Enterprise Application Development Java EE Dieses Skript basiert auf: Pro JPA 2: Mastering the Java Persistence API, Keith and Schincariol, ISBN 978-1-4302-1956-9 Simon Martinelli, 03.2015 [email protected] | about.me/simas_ch 1 INHALT 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. INTRODUCTION GETTING STARTED ENTERPRISE APPLICATIONS (Æ EJB KURS) OBJECTION-RELATIONAL MAPPING COLLECTION MAPPING ENTITY MANAGER USING QUERIES QUERY LANGUAGE CRITERIA API ADVANCED OBJECT-RELATIONAL MAPPING ADVANCED TOPICS XML MAPPING FILES 2 1 INTRODUCTION 3 DAS PROBLEM 4 GRUNDSÄTZE DES O/R MAPPINGS • Objekte nicht Tabellen Applikationen arbeiten grundsätzlich nur mit dem Klassenmodell • Richtig nutzen, nicht ignorieren Um "gutes" O/R-Mapping zu betreiben, muss man sich der Probleme bewusst sein und die relationale Technologie kennen • Unauffällig, nicht transparent Persistenz ist nicht transparent. Die Applikation muss die Kontrolle über den Objekt-Lifecycle haben 5 GRUNDSÄTZE DES O/R MAPPINGS • Alte Daten, neue Objekte Es ist sehr häufig, dass eine Applikation bestehende Daten verwenden muss. Deshalb ist der Support für Legacy Daten zentral. • Ausreichend, aber nicht zuviel Applikationen dürfen nicht durch ein schwergewichtiges Persistenzmodell erdrückt werden • Lokal und mobil Entitäten müssen transportiert werden können 6 MODERNE PERSISTENZ APIS • Arbeiten mit gewöhnlichen Java-Klassen für Daten (POJOs) • Objekte können transient oder persistent sein • Innerhalb und ausserhalb von Applikationsservern verwendbar • Vererbung, Aggregation, Komposition abbildbar • Transitive Persistenz oder Persistence by Reachability • Lazy Loading • Automatic Dirty Checking • Datenbank-Roundtrips minimieren, Outer Join Fetching • SQL-Generierung zur Laufzeit 7 TECHNOLOGIE STACK 8 Geschichte 9 API Packages • javax.persistence • javax.persistence.spi Classes • Persistence Interfaces • EntityManagerFactory • EntityManager • EntityTransaction • Query Exceptions ( ~8 ) • RollbackException Annotations ( ~64 ) • Entity • Id • OneToOne • OneToMany Enumerations ( ~10 ) • InheritanceType • CascadeType • FetchType 10 2 GETTING STARTED 11 ENTITY ÜBERBLICK • Eine Entity ist persistierbar. Der Zustand kann in einer Datenbank abgespeichert und später wieder darauf zugegriffen werden • Wie jedes andere Java Objekt hat eine Entity eine Objektidentität. Zusätzlich besitzt sie eine Datenbankidentität (Primary Key) • In Zusammenhang mit der Datenbank werden die Entities transaktional verwendet. Die Erstellung, Änderung und das Löschen wird in einer Transaktion durchgeführt 12 ENTITY METADATA • • • • • Kennzeichnung mit Annotation @Entity oder Mapping mit XML Klasse kann Basisklasse oder abgeleitet sein Klasse kann abstrakt oder konkret sein Serialisierbarkeit ist bezüglich Persistenz nicht erforderlich Anforderungen: • Standardkonstrukutor muss vorhanden sein. • Klasse darf nicht final, kein Interface und keine Enumeration sein und keine final-Methoden enthalten • Felder müssen private oder protected sein. • Zugriff von Clients auf Felder nur über get/set- oder Business-Methoden erlaubt. • Jede Entity muss einen Primärschlüssel (@Id) haben CONVENTIONS OVER CONFIGURATION 13 ENTITY, BEISPIEL @Entity public class Employee { @Id protected int id; protected String name; protected long salary; public Employee() { } public Employee(int id) { this.id = id; } } 14 ENTITY MANAGER, ÜBERBLICK 15 ENTITY MANAGER, BEISPIEL // ENTITYMANAGER ERSTELLEN EntityManagerFactory emf = Persistence.createEntityManagerFactory("hr"); EntityManager em = emf.createEntityManager(); // ENTITY PERSISTIEREN em.getTransaction().begin(); Employee emp = new Employee(158); em.persist(emp); em.getTransaction().commit(); // ENTITY FINDEN Employee emp = em.find(Employee.class, 158); 16 ENTITY MANAGER, BEISPIEL // ENTITY VERÄNDERN em.getTransaction().begin(); emp.setSalary(emp.getSalary() + 1000); em.getTransaction().commit(); // ENTITY LÖSCHEN em.getTransaction().begin(); em.remove(emp); em.getTransaction().commit(); // QUERIES Query q = em.createQuery("SELECT e FROM Employee e"); Collection emps = q.getResultList(); 17 PERSISTENCE UNIT, BEISPIEL <!-- META-INF/persistence.xml --> <persistence version="2.0" ...> <persistence-unit name="hr" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>hr.Employee</class> <properties> <property name="javax.persistence.jdbc.url" value="jdbc:derby://localhost:1527/test"/> <property name="javax.persistence.jdbc.password" value="test"/> <property name="javax.persistence.jdbc.driver" value="org.apache.derby.jdbc.ClientDriver"/> <property name="javax.persistence.jdbc.user" value="test"/> <property name="eclipselink.ddl-generation“ value="create-tables"/> </properties> </persistence-unit> </persistence> 18 ÜBUNG: GETTING STARTED 1. Erstellen Sie eine neue Derby Datenbank 2. Erstellen Sie ein neues Projekt 3. Erstellen Sie eine Persistence Unit (METAINF/persistence.xml) 4. Erstellen Sie eine Klasse Employee 5. Machen Sie die Klasse zur Entity (@Entity, @Id) 6. Implementieren Sie den JUnit-Test um Employees 1. 2. 3. 4. einzufügen zu finden zu verändern zu löschen 19 20 4 OBJECT-RELATIONAL MAPPING 21 ACCESS TYP /* FUER DAS PERSISTENZ-FRAMEWORK EXISTIEREN ZWEI ZUGRIFFSPUNKTE AUF DIE DATEN EINER KLASSE */ //FIELD ACCESS @Entity public class Employee { @Id private int id; } //PROPERTY ACCESS @Entity public class Employee { protected int id; @Id public int getId() { return id; } } 22 ACCESS TYP OPTIONS (JPA 2.0) /* - VERSCHIEDENE ACCESS TYPES PRO KLASSE MÖGLICH - MISCHEN VON ACCES TYPES IN EINER VERERBUNGSHIERARCHIE */ @Entity @Access(FIELD) public class Vehicle { ... @Transient double fuelEfficiency; @Access(PROPERTY) protected double getDbFuelEfficiency() { return convertToImperial(fuelEfficiency); } ... } 23 MAPPING • Es wird immer vom Defaultverhalten ausgegangen • Das Defaultverhalten kann übersteuert werden @Entity @Table(name = "EMP") public class Employee { @Id @Column(name = "EMP_ID") private int id; } 24 PERSISTENTE DATENTYPEN • Erlaubt • Alle primitiven Typen, String • Alle Wrapperklassen (z.B. Integer, BigDecimal, Date, Calendar) • byte[], Byte[], char[], Character[] • Enumerations • Beliebige weitere Entity-Klassen • Collections von Entities und Wrapperklassen und String, welche als Collection<>, List<>, Set<> oder Map<> deklariert sind • Serialisierbare Klassen 25 JAVA / SQL TYPE MAPPING • Implizit durch JDBC “Data Type Conversion Table“ definiert • Explizit durch die @Column Annotation, z.B.@Column(name = "sender") protected String sender; • Produktespezifisch durch JPA-Implementation oder im JDBC-Driver für die jeweilige Datenbank 26 LARGE OBJECTS // Speichern von Daten in BLOB oder CLOB public class Employee { @Lob // BLOB private byte[] picture; @Lob // CLOB private char[] largeText; ... } 27 ENUMERATIONS /* Enumerations können persistiert werden. Entweder als - Ordinalwert (position) oder - Stringwert (Name der Konstante) */ // VARIANTE ORDINAL @Enumerated(EnumType.ORDINAL) private Color color; // VARIANTE STRING @Enumerated(EnumType.STRING) private Color color; /* VORSICHT BEI ÄNDERUNGEN AN DER ENUMERATION */ 28 TEMPORALE TYPEN • Erlaubte Zeittypen • java.sql.Date, java.sql.Time, java.sql.Timestamp, java.util.Date, java.util.Calendar • java.sql Typen brauchen keine weitere Definition • Bei java.util Typen muss der JDBC Typ angegeben werden • TemporalType.DATE, TemporalType.TIME, TemporalType.TIMESTAMP @Temporal(TemporalType.DATE) private Calendar dob; 29 TRANSIENTE ATTRIBUTE • Attribute können von der Persistierung ausgeschlossen werden • Entweder mittels dem Schlüsselwort transient transient private String translatedName; • oder wenn das Attribut serialisiert werden soll mittels Annotation @Transient private String translatedName; 30 ENTITY IDENTITY DER PRIMÄRSCHLÜSSEL • Jede Entity-Klasse muss einen mit @Id bezeichneten Primärschlüssel besitzen. • Eine Id kann von folgenden Typen sein Primitive Java Typen: byte, int, short, long, char Wrapper Klassen: Byte, Integer, Short, Long, Character Array von primitiven Typen oder Wrapper Klassen java.lang.String, java.math.BigInteger, java.util.Date, java.sql.Date • Floating Point Typen sind ebenfalls erlaubt, aber sind aufgrund der möglichen Rundungsfehler nicht zu empfehlen • • • • 31 PRIMÄRSCHLÜSSEL GENERIERUNG • Primärschlüssel können in Zusammenarbeit mit der Datenbank generiert werden. • Strategien sind Identity, Table, Sequence und Auto @Entity public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) public Integer id; } 32 5 COLLECTION MAPPING 33 BEZIEHUNGEN • Beziehungen zwischen Entities sind prinzipiell gegeben durch entsprechende Referenzen oder Collection-Member in den Entity-Klassen. • Sie müssen jedoch deklariert werden, und sehr oft sind Details zum O/R-Mapping und zum Verhalten notwendig. • Folgende Beziehungs-Charakteristiken spielen eine Rolle: • Unidirektional, bidirektional • many-to-one, one-to-one, one-to-many, many-to-many • Aggregation, Komposition DER KORREKTE UNTERHALT DER BEZIEHUNGEN IST SACHE DER APPLIKATION! 34 BEZIEHUNGEN - KONZEPTE • Richtung • Unidirektional • Bidirektional • Kardinalität • • • • one-to-one many-to-one one-to-many many-to-many 35 OWNING AND INVERSE SIDE • In JPA spricht man von owning und inverse Side • Die besitzende Seite ist verantwortlich für das führen der Beziehung in der Datenbank (Foreign Key) • Die inversen Seite wird durch das mappedBy Attribut gekennzeichnet • Bei unidirektonalen Beziehungen fehlt die inverse Seite 36 ONE-TO-ONE, UNIDIREKTIONAL // K Klasse lass la sse ss e Employee @ OneToOne @OneToOne private Address addr res ess; s; address; // entspricht: @OneToOne private Address address; 37 MANY-TO-ONE, UNIDIREKTIONAL // K // la l ass s e Em E ploy pl o ee ee Klasse Employee @One @O neTo ne ToOn To One On @OneToOne private Address address; // entspricht: @ManyToOne private Department department; 38 ONE-TO-MANY, BIDIREKTIONAL // Klasse Phone @ManyToOne(optional = false) private Employee employee; // Klasse Employee @OneToMany(mappedBy = "employee") private Set<Phone> phones; 39 MANY-TO-MANY, BIDIREKTIONAL // Klasse Employee @ManyToMany(mappedBy = "employees") private Set<Project> projects; // Klasse Project @ManyToMany private Set<Employee> employees; 40 COLLECTIONS OF NON-ENTITES AND EMBEDDABLES (JPA 2.0) @Entity public class Employee { @ElementCollection @Column(name="PHONE_NUMBER") private List<String> phoneNumbers; } 41 COLLECTIONS • java.util.Set • Eindeutig (Object.equals()) @OneToMany private Set<Phone> phones; • java.util.List • geordnet, kann sortiert werden @OneToMany @OrderBy("phonenumber ASC") private List<Phone> phones; • java.util.Map • Key/Value Paare @OneToMany @MapKey(name = "phonenumber") private Map<String, Phone> phones; 42 PERSISTENT ORDERING (JPA 2.0) /* DIE REIHENFOLGE EINER LISTE KANN PERSISTIERT WERDEN */ @Entity public class Employee { @OneToMany @OrderColumn(name="PHONE_POS") List<Phone> phones; } 43 ENHANCED MAP SUPPORT (JPA 2.0) /* VERWENDUNG VON OBJECTS, EMBEDABBLES UND ENTITIES ALS MAP KEY UND VALUE /* @Entity public class Vehicle { @OneToMany @MapKeyJoinColumn(name="PART_ID") Map<Part, Supplier> suppliers; } 44 LAZY LOADING • Default bei one-to-one und many-to-one • FetchType.EAGER • Default bei one-to-many und many-to-many • FetchType.LAZY • Defaultverhalten kann übersteuert werden. @OneToMany(fetch = FetchType.EAGER) private Set<Phone> phones; 45 ÜBUNG: BEZIEHUNGEN • Erweitern Sie Ihr Projekt gemäss nachfolgendem Klassenmodell • Wählen Sie die ID Generierungsstrategie • Definieren Sie die Beziehungstypen • Definieren Sie die Beziehungsmappings • Testen Sie Ihre Arbeit in dem Sie einen Employee mit sämtlichen Beziehungen erstellen 46 KLASSENMODELL 47 48 6 ENTITY MANAGER 49 PERSISTENCE CONTEXT Der Persistence Context definiert das physische Umfeld von Entities zur Laufzeit • die Menge aller Managed Entities in der Applikation • den Entity Manager für diese Entities • die laufende Transaktion • den Contexttyp 50 KONTEXT TYPEN • TRANSACTION • Standard im Java EE Umfeld • Lesender und schreibender Zugriff nur innerhalb der Transaktion • Gelesene Objekte sind nach der Transaktion im Zustand detached • Wiedereinkopplung in eine Transaktion mit merge() • EXTENDED • • • • • Standard im Java SE Umfeld Alle Objekte sind lesend und schreibend zugreifbar Modifikationen finden lokal statt Effekt von persist(), remove() usw. wird aufbewahrt Propagation von Efffekten und Änderungen in die DB aber nur, wenn nachträglich begin()/commit() ausgeführt wird 51 OBJEKTVERWALTUNG • Der Transfer von Objekten von und zur Datenbank erfolgt automatisch: so spät wie möglich --> Lazy Access • Der Transfer von Objekten von und zur Datenbank kann manuell erzwungen werden --> synchron zum Aufruf • Selbstverständlich gilt ein Transaktionsmodell: Der Zugriff auf Objekte erfolgt ab Beginn der Transaktion, die Synchronisation mit der Datenbank wird spätestens beim Commit abgeschlossen und unterliegt der ACIDRegel • Auf Objekte kann auch ausserhalb von Transaktionen zugegriffen werden, jedoch ohne Konsistenz- und Synchronisationsgarantie 52 ZUSTÄNDE UND ÜBERGÄNGE 53 Entity persistieren /* MIT PERSIST() WIRD EINE NEUE ENTITY VOM ENTITYMANAGER VERWALTET */ Department dept = em.find(Department.class, deptId); Employee emp = new Employee(); emp.setId(empId); emp.setName(empName); emp.setDepartment(dept); dept.getEmployees().add(emp); em.persist(emp); /* DIE METHODE CONTAINS() KANN GEPRÜFT WERDEN OB EINE ENTITY MANAGED IST */ if (em.contains(emp)) { } 54 KASKADIERTE PERSISTENZ (1) • Kaskadierte Persistenz heisst: Alle von einem persistenten Objekt aus erreichbaren Objekte sind ebenfalls persistent Employee employee = new Employee(); em.persist(emp); Address address = new Address(); employee.setAddress(address); • Die Kaskadierung muss deklariert werden: • PERSIST, MERGE, REMOVE, REFRESH • ALL 55 KASKADIERTE PERSISTENZ (2) /* DIE KASKADIERUNG KANN FÜR DAS ERSTELLEN UND DAS LÖSCHEN DER PERSISTENZ SEPARAT EINGESTELLT WERDEN */ public class Employee { @OneToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE}) private Address address; } 56 ORPHAN REMOVAL (JPA 2.0) /* SOLLEN ABHÄNGIGE KINDELEMENTE BEI TO-MANY BEZIEHUNGEN EBENFALLS GELÖSCHT WERDEN, KANN DIES SEIT JPA 2.0 EBENFALLS DEKLARIERT WERDEN (Orphan = Weisenkind) */ @OneToMany(cascade = CascadeType.ALL, mappedBy = "customer", orphanRemoval = true) private Set<Order> orders; 57 ENTITY SUCHEN • Mit find() kann eine Entity über ihren Primary Key gefunden werden • Die gefunden Entity kommt automatisch in den Zustand managed • Da find() über den Primary Key sucht, kann diese Methode vom Persistence Provider optimiert werden und unter Umständen einen Datenbankzugriff vermieden werden • Soll eine one-to-one oder many-to-one Reference auf eine bestehende Entity gebildet werden, kann getReference() verwendet werden um das vollständige Laden der Target-Entity zu verhindern 58 EINLESEN • Der Objektzustand wird beim ersten Zugriff auf das Objekt eingelesen. • Wenn FetchType.EAGER gesetzt ist, werden referenzierte Objekte ebenfalls mitgeladen. • Wenn FetchType.LAZY gesetzt ist, werden referenzierte Objekte beim ersten Gebrauch eingelesen. • Der Objektzustand wird nie automatisch aufgefrischt, nur via die EntityManager.refresh()-Methode. • Eine neue Transaktion führt nicht automatisch zum erneuten Einlesen bestehender Objekte. 59 OBJEKTZUSTAND NACH COMMIT • Persistence Context EXTENDED • Entity bleibt im Zustand managed • Änderungen nach dem Commit werden berücksichtig und im Rahmen der nächsten Transaktion in die Datenbank übernommen • Persistence Context TRANSACTION • Objekt ist nach Commit im Zustand detached • Änderungen müssen mit EntityManager.merge() innerhalb der nächsten Transaktion dem EntityManager übergeben werden 60 OBJEKTZUSTAND NACH ROLLBACK • Nach einem Rollback ist jedes noch vorhandene Objekt im Zustand detached • Die Belegung der Felder wird durch den Rollback nicht geändert, jedoch der Zustand in der Datenbank • Achtung! Inkonsistenzen! Objekte mit Entity Manager neu laden 61 PERSISTENCE CONTEXT AUFRÄUMEN • Ab und zu kann es vorkommen, dass der Persistence Context gelöscht werden soll • Dies kann mit der Methode clear() des EntityManager erreicht werden • Alle Entities kommen in den Zustand detached • Vorsicht! enthält der Persistence Context Änderungen welche noch nicht mit commit() gespeichert wurden, gehen diese verloren 62 ÜBUNG: ENTITY MANAGER • Definieren Sie die Kaskadierung auf den Beziehungen im Modell • Entfernen Sie die nicht mehr benötigten persist() Aufrufe • Definieren Sie das Ladverhalten (EAGER oder LAZY) bei Ihren Beziehungen • Schauen Sie sich im Debugger das Lazy Loading an • Wiederholen Sie die Tests und achten Sie auf die generierten SQL Statements in Bezug auf das Ladeverhalten 63 64 7 USING QUERIES 65 QUERIES IN JPA • JPA kennt drei Möglichkeiten um Abfragen zu formulieren • Java Persistence QL • Unabhängig von der darunterliegenden Datenbank • SQL Subset • Abfragen basieren auf dem Klassenmodell, nicht auf dem Datenmodell • SQL • Criteria API seit JPA 2.0 66 QUERIES DEFINIEREN /* DYNAMISCHE QUERIES */ em.createQuery("SELECT e FROM Employee e"); /* NAMED QUERIES */ // Deklaration @NamedQueries { @NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e") } public class Employee {...} // Verwendung Query q = em.createNamedQuery("Employee.findAll"); 67 QUERY API • Es stehen Query und TypedQuery<X> zu Verfügung • Methoden zum Ausführen sind • List getResultList() oder List<X> getResultList() • Object getSingleResult() oder X getSingleResult() • int executeUpdate() • Als Rückgabewert wird die Anzahl betroffener Datensätze zurückgeliefert 68 QUERIES AUSFÜHREN TypedQuery<Employee> q = em.createQuery("SELECT e FROM Employee e", Employee.class); List<Employee> emps = q.getResultList(); for(Employee e : emps) { ... } 69 EINFÜHRUNG (1) • Einfachstes Query SELECT e FROM Employee e • Pfadausdrücke, Navigation mit . SELECT e.name FROM Employee e SELECT e.department FROM Employee e • Resultate filtern SELECT e FROM Employee e WHERE e.department.name = 'NA42' AND e.address.state in ('NY','CA') • Projektion SELECT e.name, e.salary FROM Employee e 70 EINFÜHRUNG (2) • Join zwischen Entities SELECT p.number FROM Employee e, Phone p WHERE e = p.employee AND e.department.name = 'NA42' AND p.type = 'Cell' • Join mit JOIN Operator SELECT p.number FROM Employee e JOIN e.phones p WHERE e.department.name = 'NA42' AND p.type = 'Cell' 71 EINFÜHRUNG (3) • Aggregatfunktionen SELECT d, COUNT(e), MAX(e.salary), AVG(e.salary) FROM Department d JOIN d.employees e GROUP BY d HAVING COUNT(e) >= 5 • Query Parameter • Named SELECT e FROM Employee e WHERE e.department = :dept AND e.salary > :base • Positional SELECT e FROM Employee e WHERE e.department = ?1 AND e.salary > ?2 72 PARAMETERÜBERGABE // Uebergabe eines Named Parameter q.setParameter("dept", "NA42"); // Uebergabe eines Positional Parameter q.setParameter(1, "NA42"); 73 PFADAUSDRÜCKE • Ein Pfadausdruck ermöglicht die direkte Navigation von einem äusseren zu inneren, referenzierten Objekten: SELECT e.address FROM Employee e SELECT e.address.name FROM Employee e • Ein Pfadausdruck kann in einer Collection enden: SELECT e.projects FROM Employee e • Ein Pfadausdruck kann NICHT über eine Collection hinweg navigieren: SELECT e.projects.name FROM Employee e 74 QUERY RESULTATE VERARBEITEN • Mögliche Typen im Resultat: Primitive Typen und String, Entity Typen, Object[] und Benutzertypen durch Constructor Expression • Die List von getResultList() bzw. das Object aus getSingleResult() enhält direkt diese Resulttypen • Handelt es sich beim Resultat um eine Entity kommt diese in den Zustand managed wenn das Query: • innerhalb einer Transaktion ausgeführt wird • ausserhalb einer Transaktion ausgeführt wird und der Contexttyp EXTENDED ist. • Wird ein Query ausserhalb einer Transaktion im Context Type TRANSACTION ausgeführt, spricht man von einem Read-only Query 75 MEHRERE RESULTAT TYPEN /* BEI EINER PROJEKTION IN DER SELECT KLAUSEL WIRD EINE LISTE VON OBJECT[]-ARRAY ZURÜCKGEGEBEN */ List<Object[]> result = em.createQuery( "SELECT e.name, e.department.name " + "FROM Project p JOIN p.employees e " + "where p.name = "ZLD").getResultList(); for (Object[] values : result) { System.out.println(values[0] + "," + values[1]); } 76 CONSTRUCTOR EXPRESSION DEKLARATION /* MIT DER CONSTRUCTOR EXPRESSIONS EXISTIERT EINE EINFACHE MÖGLICHKEIT UM RESULTATE AUF KLASSEN ZU MAPPEN. */ // Beispiel TransferObject public class EmployeeTO { private String employeeName; private String deptName; public EmployeeTO(String employeeName, String deptName) { this.employeeName = employeeName; this.deptName = deptName; } } 77 CONSTRUCTOR EXPRESSION /* Query ausführen ACHTUNG: KLASSE MUSS VOLLQUALIFIZIERT ANGEGEBEN WERDEN! */ TypedQuery<EmployeeTO> q = em.createQuery( "SELECT NEW jpa.util.EmployeeTO(e.name, e.department.name) " + "FROM Project p JOIN p.employees e where p.name = "ZLD"); List<EmployeeTO> result = q.getResultList(); for (EmployeeTO emp : result) {ß System.out.println(emp.employeeName + "," + emp.deptName); } 78 PAGING UND SYNCHRONISATION • Paging wird in Applikationen definiert, um die Resultatmenge einzuschränken: Query.setFirstResult(int pos) Query.setMaxResults(int max) • Synchronisation Query.setFlushModeType(FlushModeType type) • FlushModeType.AUTO Ausstehende Änderungen werden ebenfalls in das Resultat einbezogen • FlushModeType.COMMIT Nur comittete Daten werden zurückgegeben 79 BULK UPDATE UND DELETE // BULK DELETE Query q = em.createQuery("DELETE from Employee e"); int count = q.executeUpdate(); // BULK UPDATE Query q = em.createQuery("UPDATE Employee e " + "SET e.name = 'Simon' WHERE e.name = 'Peter'); int count = q.executeUpdate(); /* VORSICHT damit wird der Entity Manager umgangen! Verwaltete Entities unbedingt aktualisieren! Versionen müssen selber hochgezählt werden */ 80 QUERY HINTS /* MÖGLICHKEIT FÜR DEN HERSTELLER FÜR OPTIMIERUNGEN */ // Beispiel direkt beim Query q.setHint("toplink.cache-usage", "DoNotCheckCache"); // Beispiel als Named Query @NamedQuery(name = "findAll", query = "SELECT e FROM Employee e", hints = {@QueryHint(name = "toplink-cache-usage", value = "DoNotCheckCache")}) public class Employee { ... } 81 EMPFEHLUNGEN • Verwenden Sie Named Queries • Constructor Expression • Werden die Daten nur zum Anzeigen z.B. für Statistiken verwendet, brauchen diese nicht als Entites gelesen werden • Verwenden Sie Query Hints zur Optimierung • Bulk Update und Delete in isolierter Transaktion verwenden und danach den Persistence Context "aufräumen" • Provider Unterschiede beachten • Studieren Sie die generierten SQLs um ein Gefühl für Ihre JPA Implementation zu erhalten 82 8 QUERY LANGUAGE 83 KLASSENMODELL 84 SELECT SELECT <select_expression> FROM <from_clause> [WHERE <conditional_expression>] [ORDER BY <order_by_clause>] // Beispiel SELECT e FROM Employee e WHERE e.name = 'John Doe' ORDER BY e.salary 85 FROM Identifikationsvariable FROM Employee e SQL Joins werden automatisch erzeugt, wenn - zwei oder mehr Range Variablen verwendet werden FROM Employee e, Department d - der JOIN Operator verwendet wird FROM Employee e JOIN e.department d - ein Pfad Ausdruck über eine Beziehung navigiert SELECT e.department ... 86 JOINS INNER JOINS JPQL: SELECT p FROM Employee e JOIN e.phones p SQL: SELECT p.* FROM emp e, phone p WHERE e.id = p.emp_id OUTER JOINS JPQL: SELECT e, d FROM Employee e LEFT JOIN e.department d SQL: SELECT * FROM emp e, dept d WHERE e.dept_id = d.id (+) FETCH JOINS SELECT e FROM Employee e JOIN FETCH e.address 87 WHERE INPUT PARAMETER Named = :name Positional = ?1 OPERATOREN PRÄZEDENZ Navigations Operator . Unäre Operatoren +/Multiplikation (*) und Division (/) Addition (+) und Subtraktion (-) Vergleichsoperatoren =, >, >=, <, <=, [NOT] BETWEEN, [NOT] LIKE, [NOT] IN, IS [NOT] NULL, IS [NOT] EMPTY, [NOT] MEMBER [OF] Logische Operatoren (AND, OR, NOT) 88 BETWEEN SELECT e FROM Employee e WHERE e.salary BETWEEN 40000 AND 45000 entspricht SELECT e FROM Employee e WHERE e.salary >= 40000 AND e.salary <= 45000 89 IN SELECT e FROM Employee e WHERE e.address.state IN ('NY', 'CA') SELECT e FROM Employee e WHERE e.department IN (SELECT DISTINCT d FROM Department d JOIN d.employees de JOIN de.projects p WHERE p.name LIKE 'QA%') 90 COLLECTIONS IS EMPTY /* IS EMPTY ist in Bezug auf Collections equivalent zu IS NULL bei Feldern */ SELECT e FROM Employee e WHERE e.directs IS NOT EMPTY entspricht SELECT m FROM Employee m WHERE (SELECT COUNT(e) from Employee e WHERE e.manager = m) > 0 91 COLLECTIONS MEMBER OF /* MEMBER OF prüft ob das Objekt ein Element einer Collection ist */ SELECT e FROM Employee e WHERE :project MEMEBER OF e.projects entspricht SELECT e FROM Employee e WHERE :project IN (SELECT p FROM e.projects p) 92 EXISTS SELECT e FROM Employee e WHERE NOT EXISTS (SELECT p FROM e.phones p WHERE p.type = 'Cell') 93 ANY, ALL und SOME SELECT e FROM Employee e WHERE e.directs IS NOT EMPTY AND e.salary > ALL (SELECT d.salary FROM e.directs d) 94 FUNKTIONEN ABS(number) CONCAT(string1, string2) CURRENT_DATE CURRENT_TIME CURRENT_TIMESTAMP LENGTH(string) LOCATE(string1, string2 [,start]) LOWER(string) MOD(number1, number2) SIZE(collection) SQRT(number) SUBSTRING(string, start, end) UPPER(STRING) TRIM 95 ORDER BY // Einfache Sortierung SELECT e FROM Employee e ORDER BY e.name DESC // Mehrfache Sortierung SELECT e FROM Employee e ORDER BY e.name, e.salary DESC /* Das beim ORDER BY verwendete Feld muss im SELECT enthalten sein! Folgendes Query ist NICHT erlaubt: */ SELECT e.name FROM Employee e ORDER BY e.salary DESC 96 AGGREGAT QUERIES SELECT <select_expression> FROM <from_clause> [WHERE <conditional_expression>] [GROUP BY <group_by_clause>] [HAVING <conditional_expression>] [ORDER BY <order_by_clause>] // Beispiel SELECT AVG(e.salary) FROM Employee e 97 AGGREGAT FUNKTIONEN AVG Durchschnitt der Gruppe COUNT Anzahl Werte in der Gruppe MAX Maximaler Wert in der Gruppe MIN Minimaler Wert in der Gruppe SUM Summe der Gruppe 98 GROUP BY /* Definiert eine Gruppierung für die Aggregation der Resultate /* SELECT d.name, COUNT(e) FROM Department d JOIN d.employee e GROUP by d.name /* Fehlt die GROUP BY Angabe, wird das ganze Query als Gruppe verwendet */ SELECT COUNT(e) FROM Department d JOIN d.employee e 99 HAVING /* Definiert einen Filter, welcher nach der Gruppierung der Resultate angewendet wird */ SELECT e, COUNT(p) FROM Employee e JOIN e.projects p GROUP BY e HAVING COUNT(p) >= 2 100 UPDATE UPDATE <entity_name> [[AS] <identification_variable>] SET <update_statement> {, <update_statement>}* [WHERE <conditional_expression>] // Beispiel UPDATE Employee e SET e.salary = 60000 WHERE e.salary = 55000 101 DELETE DELETE FROM <entity_name> [[AS] <identification_variable>] [WHERE <condition>] // Beispiel DELETE FROM Employee e WHERE e.department IS NULL 102 JPQL ERWEITERUNGEN IN JPA 2.0 // Timestamp SELECT t from BankTransaction t WHERE t.txTime > {ts ‘2008-06-01 10:00:01.0’} // Non-polymorphic Queries SELECT e FROM Employee e WHERE TYPE(e) = FullTimeEmployee OR e.wage = "SALARY" // Collection Parameters in IN Expression SELECT emp FROM Employee emp WHERE emp.project.id IN [:projectIds] 103 JPQL ERWEITERUNGEN IN JPA 2.0 // Ordered List Index SELECT t FROM CreditCard c JOIN c.transactionHistory t WHERE INDEX(t) BETWEEN 0 AND 9 CASE Statement UPDATE Employee e SET e.salary = CASE e.rating WHEN 1 THEN e.salary * 1.1 WHEN 2 THEN e.salary * 1.05 ELSE e.salary * 1.01 END 104 ÜBUNG: QUERY LANGUAGE • Erstellen Sie JUnit-Tests, um die Möglichkeiten der Query Language auszuprobieren • Abfragen von Objekten mit Bedingungen / Sortierung • Aggregatfunktionen • Gibt es Abfragen, die Schwierigkeiten bereiten, aber in SQL grundsätzlich möglich wären? • Verwenden Sie Named Queries 105 106 9 CRITERIA API http://www.ibm.com/developerworks/library/j-typesafejpa/ 107 MOTIVATION • Vor JPQL hatten die meisten OR-Mapper bereits eine objektorientierte Abfragesprache • Mit JPA 2.0 wurden diese APIs in der Criteria API standardisiert • Im Gegensatz zu JPQL können mit der Criteria API Abfragen mit Java programmiert werden, welche vom Compiler geprüft werden 108 EINFACHES QUERY SELECT e FROM Employee e WHERE e.name = 'John Smith'; CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Employee> cq = cb.createQuery(Employee.class); Root<Employee> employee = cq.from(Employee.class); cq.select(employee) .where(cb.equal(emp.getName("name"), "John Smith"; 109 PROJEKTION CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Object> cq = cb.createQuery(Object.class); Root<Employee> employee = cq.from(Employee.class); cq.multiselect(employee.get("id")); // entspricht JPQL SELECT e.id FROM Employee e 110 VORTEILE DER CRITERIA API • Gerade bei dynamischen Queries (z.B. bei Suchformularen) ist das Zusammensetzen eines JPQL Queries als String eine mühselige und fehleranfällige Tätigkeit • Dank des Java API der Criteria API ist dies mit der Criteria API einfacher 111 NACHTEILE DER CRITERIA API • Die Criteria API scheint etwas "over designed" • Dadurch ist der Einstieg schwieriger als bei JPQL • Und die Lesbarkeit der Abfragen leidet • Die Criteria API alleine reicht für eine vollständige Typsicherheit noch nicht aus 112 METAMODEL API • Aufgrund der Mappings kann JPA eine Metamodel generieren • Dieses Metamodel kann in den Abfragen verwendet werden und erhöht die Typsicherheit • Der Name der Metamodell Klassen wird aus dem Entity Namen und dem Suffix _ gebildet • Employee Æ Employee_ • Die Generierung übernimmt der Persistence Provider z.B. mit einem Annotation Processor 113 GENERIERTES METAMODEL @Generated(value="EclipseLink-2.5.0.v20130507-rNA", date="2013-11-05T10:51:00") @StaticMetamodel(Employee.class) public class Employee_ { public static volatile SingularAttribute<Employee, Long> id; } 114 METAMODEL VERWENDUNG CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Employee> cq = cb.createQuery(Employee.class); Root<Employee> employee = cq.from(Employee.class); cq.select(employee) .where(cb.equal(Employee_.name), "John Smith"; 115 116 10 ADVANCED OBJECT-RELATIONAL MAPPING 117 EMBEDDED OBJECTS • entspricht Komposition • Eingebettete Objekte haben keine eigene Identität • Mutterobjekt und eingebettetes Objekt sind in derselben Tabelle abgelegt 118 EMBEDDED OBJECTS, BEISPIEL @Embeddable public class Address { private String street; private String city; private String state; private String zip; } @Entity public class Employee { @Id private int id; private String name; private long salary; @Embedded private Address address; } 119 ENHANCED EMBEDDABLES (JPA 2.0) /* Verschachtelung von Embeddables und Embeddables mit Beziehungen */ @Embeddable public class Assembly { ... @Embedded ShippingDetail shipDetails; @ManyToOne Supplier supplier; ... } 120 ZUSAMMENGESETZTE PRIMÄRSCHLÜSSEL public class EmployeeId implements Serializable { protected String country; protected int id; } // Variante 1 @IdClass( EmployeeId.class ) @Entity public class Employee { @Id protected String country; @Id protected int id; } // Variante 2 @Entity public class Employee { @EmbeddedId public EmployeeId id; } 121 COMPOSITE PRIMARY KEY WITH RELATIONSHIPS (JPA 2.0) @Entity @IdClass(PartPK.class) public class Part { @Id int partNo; @Id @ManyToOne Supplier supplier; } public class PartPK { int partNo; int supplier; } 122 READ-ONLY MAPPINGS UND OPTIONAL /* Read-Only */ @Column(insertable = false, updateable = false) /* Es ist nicht möglich eine ganze Entity als read-only zu deklarieren */ /* Optional */ @ManyToOne(optional = true) // Default 123 MAPPING VON SQL-VIEWS /* Komplexe Abfragen werden in einer Datenbank gerne als (materialisierte) View vorgehalten. Um Performance-Vorteile zu nutzen, kann eine View wie eine Entity angesprochen werden. */ @Entity public class EmployeeStats { @Id protected long id; @Column(insertable=false, updatable=false) protected int numPhones; } CREATE VIEW employeestats (id, numPhones) AS SELECT e.id, COUNT(p.*) FROM employee e LEFT OUTER JOIN PHONES P on (…) group by e.id 124 VERERBUNG • Vererbungshierarchien können problemlos verwendet und abgebildet werden • Klassen können abstrakt oder konkret sein • Alle Klassen in der Vererbungshierarchie müssen den Primärschlüssel der Basisklasse verwenden (erben) • Es gibt vier Mappingstrategien auf die Datenbank: • • • • • Eine einzige Tabelle für die gesamte Verbungshierarchie Eine Tabelle für jede konkrete Klasse Eine Tabelle für jede Klasse Mapped Superclass 125 SINGLE_TABLE @Entity @Inheritance public abstract class Project @Entity public class DesignProject extends Project @Entity public class QualityProject extends Project 126 JOINED @Entity @Inheritance(strategy=InheritanceType.JOINED) public abstract class Project @Entity public class DesignProject extends Project @Entity public class QualityProject extends Project 127 TABLE_PER_CLASS (Optional) @Entity @Inheritance(strategy=TABLE_PER_CLASS) public abstract class Project @Entity public class DesignProject extends Project @Entity public class QualityProject extends Project 128 MAPPED_SUPERCLASS @MappedSuperclass public abstract class BaseEntity { @Id @GeneratedValue protected Integer id; protected Integer version; protected Timestamp createdAt; protected String createdFrom; protected Timestamp updatedAt; protected String updatedFrom; } @Entity public class Phone extends BaseEntity { } 129 ÜBUNG: ADVANCED ORM • Probieren Sie die verschiedenen Vererbungsmappings bei Project aus. • Achtung! Generierte Tabellen beim Wechsel löschen • Erstellen Sie ein Klasse BaseEntity für alle Entities und verwenden Sie für diese MAPPED_SUPERCLASS. • Probieren Sie die Java Persistence Query Language in Bezug auf die Vererbung aus 130 KLASSENMODELL 131 132 11 ADVANCED TOPICS 133 SQL QUERIES EntityManager.createNativeQuery(String sql) EntityManager.createNativeQuery(String sql, Class resultClass) // Kann auch als NamedQuery definiert werden @NamedNativeQuery( name = "employeeReporting", query = "SELECT * FROM emp WHERE id = ?", resultClass = Employee.class) // Ausführen des NamedQueries und Parameterübergabe Query q = em.createNamedQuery("employeeReporting"); q.setParameter(1, employeeId); List<Employee> list = q.getResultList(); 134 RESULT SET MAPPING // Definition @SqlResultSetMapping( name = "employeeResult", entities = @EntityResult(entityClass = Employee.class) // Verwendung Query q = em.createNativeQuery( "SELECT * FROM EMPLOYEE", "employeeResult"); /* Mapping Foreign Keys Wenn die Foreign Keys im Resultat der Abfrage enthalten sind, werden die einfachen Beziehungen ebenfalls mitgeführt */ 135 MULITPLE RESULT MAPPING SELECT e.*, a.* FROM emp e, address a WHERE e.adress_id = a.id @SqlResultSetMapping( name = "EmployeeWithAddress", entities = {@EntityResult(entityClass = Employee.class), @EntityResult(entityClass = Address.class)} 136 MAPPING INHERITANCE SELECT id, name, start_date, daily_rate, term, vacation, hourly_rate, salary, pension, type FROM employee_stage @SqlResultSetMapping( name="EmployeeStageMapping", entities= @EntityResult( entityClass=Employee.class, discriminatorColumn="TYPE", fields={ @FieldResult(name="startDate",column="START_DATE"), @FieldResult(name="dailyRate",column="DAILY_RATE"), @FieldResult(name="hourlyRate",column="HOURLY_RATE") })) 137 LIFECYCLE CALLBACKS • Callbacks sind eine gängige Methode, um Einfluss auf den Lade- oder Speichervorgang von Objekten zu nehmen. • Mögliche Events: PrePersist, PostPersist, PreRemove, PostRemove, PreUpdate, PostUpdate, PostLoad • • • • • • @Entity public class ImageMessage extends Message { @PrePersist @PreUpdate protected void compress(){ ... } @PostLoad @PostUpdate protected void uncompress() { ... } 138 Entity Listeners /* Wenn Sie dieselbe Funktionalität bei Callbacks von verschiedenen Entities verweden wollen, können Sie einen Entity Listener erstellen: /* public class BaseEntityDebugListener { @PrePersist public void debugPrePersist(BaseEntity e) { log.debug("PrePresist: " + e); } } // Entity Listener verwenden: @Entity @EntityListeners({BaseEntityDebugListener.class}) public class Employee extends BaseEntity 139 VERERBUNG UND LIFECYCLE EVENTS • Prüfen ob Default Listeners existieren • Höchste Ebene der Vererbung auf @EntityListeners Annotations prüfen • Wiederhole Schritt 2 für die nächst tiefere Ebene • Höchste Ebene der Vererbung auf Methoden mit zum Event passender Annotation prüfen • Wiederhole Schritt 4 für die nächst tiefere Ebene 140 ENTITY ZUSTAND REFRESH • Sind Sie nicht sicher, ob der Zustand Ihrer Entität mit dem Zustand in der Datenbank übereinstimmt, kann mit der Methode refresh() im EntityManager das Entity erneut geladen werden • Ist das zu aktualisierende Entity nicht im Zustand managed wird eine IllegalArgumentException geworfen 141 FRAGEN ZUM TRANSAKTIONSMANAGEMENT • Ist der Objektzustand nach dem Lesen durch die Applikation in der Datenbank eingefroren, während dem die Transaktion läuft (mit welchem Isolationsgrad wird gearbeitet)? • Ein Objekt wird geändert: Zu welchem Zeitpunkt wird es in der Datenbank gesperrt? • Kann entdeckt werden, ob Daten beim Commit in der Zwischenzeit von anderen Prozessen geändert wurden auf der DB? 142 LOST UPDATE PROBLEM 143 SPERRZEITPUNKT • Daten werden in der Datenbank im Rahmen von SQL-Befehlen gesperrt • Da Änderungen vorerst lokal durchgeführt und erst zum Commit-Zeitpunkt in die DB propagiert werden, findet das Sperren erst beim Commit statt. • Allfällige Wartesituationen, Deadlocks, Integritätsverletzungen treten effektiv erst zum Commit-Zeitpunkt auf 144 OPTIMISTIC LOCKING VERSIONIERUNG • Die Versionierung im Rahmen von JPA ist als optimistsches Locking zu verstehen. Mit der Versionierung kann ein Concurrency Control über Transaktionen hinweg realisiert werden. • Mit einer @Version können Lost Updates detektiert und vermieden werden: Das Feld kann vom Typ int, Integer, short, Short, long, Long oder java.sql.Timestamp sein @Entity public class Employee { @Version protected long version; } 145 WEITERE LOCKING STRATEGIEN • Soll REPEATABLE_READ zur Anwendung kommen, kann Read Locking verwendet werden:em.lock(LockModeType.READ) • Um eine Entität zum Schreiben zu sperren, wird Write Locking verwendetem.lock(LockModeType.WRITE) 146 ENHANCED LOCKING (JPA 2.0) • JPA 2.0 führt neue Lockingstrategien ein: • • • • • OPTIMISTIC ( = READ ) OPTIMISTIC_FORCE_INCREMENT ( = WRITE ) PESSIMISTIC_READ (Repeatable Read) PESSIMISTIC_WRITE (Serialized) PESSIMISTIC_FORCE_INCREMENT • Kombination Opitmistic/Pessimistic möglich! 147 ENHANCED LOCKING (JPA 2.0) // Beispiel mit EntityManager.refresh() public void applyCharges() { Account acct = em.find(Account.class, acctId); // calculate charges, etc. int charge = … ; if (charge > 0) { em.refresh(acct, PESSIMISTIC_WRITE); double balance = acct.getBalance(); acct.setBalance(balance - charge); } } 148 SCHEMA GENERATION • Die Erzeugung von DDL kann, aber muss nicht durch eine Implementation der JPA Spezifikation angeboten werden. • In der JPA Spezifikation sind verschiedene Angaben (Annotations und Attribute davon) vorgesehen, welche die Erzeugung von DDL-Befehlen ermöglichen public class Message { @Column(unique = false, nullable=false, columnDefinition="varchar", lenghth=64 ) public BigDecimal sender; 149 ÜBUNG: ADVANCED TOPICS • Verwenden Sie SQL • Erweiteren Sie die BaseEntity um die Attribute createdAt und updatedAt und verwenden Sie Lifecycle Callbacks, um diese Attribute vor dem Insert und Update entsprechend abzufüllen • Erweitern Sie Ihre BaseEntity mit Optimistic Locking und testen Sie das Verhalten • Erweitern Sie ihr Mapping an beliebiger Stelle mit Angaben zur Schema Generierung (@Column) 150 12 XML MAPPING 151 THE METADATA PUZZLE • Reihenfolge bei der Verarbeitung der Metadaten: • Annotations verarbeiten • Klassen aus XML Mapping hinzufügen • Attribute aus XML Mapping hinzufügen • Defaultwerte setzen 152 DAS MAPPING FILE <entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd" version="2.0"> ... </entity-mappings> 153 DEFAULTS IM MAPPING FILE Annotations ausschalten <xml-mapping-metadata-complete /> Persistence Unit Defaults schema, catalog, access, cascade-persist entity-listeners Diese können auch ausgeschaltet werden exclude-default-listeners @ExcludeDefaultListeners 154 QUERIES UND GENERATORS sequence-generator table-generator named-query named-native-query sql-result-set-mapping 155 ENTITY MAPPING MIT XML <entity class="examples.model.Employee"> <attributes> <id name="id"> <generated-value strategy="SEQUENCE" /> </id> <many-to-one name="department" /> <many-to-one name="manager" /> <one-to-many name="phones" mapped-by="employee" /> <one-to-many name="directs" mapped-by="manager" /> <one-to-one name="address" /> <many-to-many name="projects" mapped-by="employees" /> </attributes> </entity> 156 ÜBUNG: XML MAPPING • Verwenden Sie für einen Teil ihres Models XML für das Mapping • Lagern Sie ihre Named Queries in XML aus • Erstellen Sie eine globalen EntityListener um Veränderungen an den Daten zu loggen 157 158 13 PACKAGING AND DEPLOYMENT 159 CONFIGURING PERSISTENCE UNITS • Persistence Unit Name <persistence-unit name="EmployeeService" /> • Transaction Type RESOURCE_LOCAL oder JTA • Persistence Provider <provider>org.hibernate.ejb.HibernatePersistence</provider> • Data Source nur bei JTA • Mapping Files <mapping-file>META-INF/queries.xml</mapping-file> 160 MANAGED CLASSES • Lokale Klassen Alle annotierten Klassen im Deployment Unit in welcher das persistence.xml gepackt ist • Klassen in Mapping Files Mit XML gemappte Klassen • Explicitly Listed Classes Im persistence.xml eingetragene Klassen • Zusätzliche JARs mit Managed Classes Im persistence.xml unter jar-file eingetragene JARs 161 PROPERITES ZUR LAUFZEIT ÜBERGEBEN /* Die Properties im persistence.xml können ebenfalls zur Laufzeit beim Erstellen der EntityManagerFactory übergeben werden */ Map props = new HashMap(); props.put("javax.persistence.jdbc.user", "emp"); props.put("javax.persistence.jdbc.password", "emp"); EntityManagerFactory emf = Persistence.createEntityManagerFactory( "EmployeeService", props); 162 JPA 2.1 163 WHAT‘S NEW? • Converters - allowing custom code conversions between database and object types • Criteria Update/Delete - allows bulk updates and deletes through the Criteria API • Stored Procedures - allows queries to be defined for database stored procedures • ConstructorResult support for SQLResultSetMapping • Runtime creation of named queries • Injectable EntityListeners • Unsynchronized persistence contexts • DDL generation - automatic table, index and schema generation. • Entity Graphs - allow partial or specified fetching or merging of objects. • JPQL/Criteria enhancements - arithmetic sub-queries, generic database functions, join ON clause, TREAT option. 164 VARIOUS 165 JSR 303: BEAN VALIDATION • Validierung und gewisse Elemente der DDL Generierung werden mit JSR 303 ersetzt • @NotNull statt @Column(nullable=false) • @Size.max statt @Column.length • @Digits statt @Column.precision/.scale • @Min / @Max bei numerischen Columns • @Future / @Past bei Datumstypen • @Size für Collections und Arrays 166 VERSCHIEDENES • 2nd Level Cache Mechanismen • Standardisierung von häufig gebrauchen Properties im persistence.xml • • • • javax.persistence.jdbc.driver javax.persistence.jdbc.url javax.persistence.jdbc.user javax.persistence.jdbc.password • Bootstraping im Java SE Umfeld mittels ServiceLoader (ab Java 1.6) 167 REFERENZEN UND LINKS • Pro JPA 2: Mastering the Java Persistence API Mike Keith and Merrick Schincariol ISBN-13: 978-1-4302-1956-9 • JSR 317: Java Persistence 2.0 www.jcp.org/en/jsr/detail?id=317 • EclipseLink (Reference implementation) www.eclipse.org/eclipselink 168