jpa queries
Post on 07-Aug-2015
82 views
Embed Size (px)
TRANSCRIPT
- 1. Java Persistence Queries Effektive DB-Abfragen mit Features aus dem Standard und darber hinaus Expertenkreis Java, 18.06.2015, GEDOPLAN Dirk Weil, GEDOPLAN GmbH
- 2. Dirk Weil GEDOPLAN GmbH, Bielefeld Java EE seit 1998 Konzeption und Realisierung Seminare Vortrge Verffentlichungen Java Persistence Queries 2
- 3. Java Persistence Mapping OO RDBMS POJOs Detachment macht DTOs verzichtbar API zum Speichern, Laden, Lschen, Finden von DB- Eintrgen Eclipselink, Hibernate, OpenJPA, Seit Java EE 5 im Standard Auch in SE nutzbar Aktuelle Version 2.1 3Java Persistence Queries
- 4. Demo-Entities 4Java Persistence Queries @Entity public class Publisher { @Id private Integer id; private String name; @ManyToOne private Country country; @OneToMany(mappedBy = "publisher") private List books; @Entity public class Book { @Id private Integer id; private String name; private String isbn; private int pages; @ManyToOne private Publisher publisher; 1 n @Entity public class Country { @Id @Column(name = "ISO_CODE") private String isoCode; private String name;n 1
- 5. JPQL Java Persistence Query Language SQL-hnlich, jedoch objektorientiert EntityManager.createQuery liefert TypedQuery Ausfhrung mit getSingleResult bzw. getResultList 5Java Persistence Queries Publisher publisher = entityManager .createQuery("select p from Publisher p where p.name=?1", Publisher.class) .setParameter(1, "O'Melly Publishing") .getSingleResult(); List books = entityManager .createQuery("select b from Book b where b.pages>=500", Book.class) .getResultList();
- 6. JPQL Navigation durch Relationen mit '.' und join 6Java Persistence Queries List books = entityManager .createQuery("select b from Book b where b.publisher.country=?1", Book.class) .setParameter(1, countryDE) .getResultList(); List publishers = entityManager .createQuery("select distinct p from Publisher p " + "join p.books b where b.pages>=500", Publisher.class) .getResultList();
- 7. JPQL JPQL SQL "leichtgewichtig" 7Java Persistence Queries List publishers = entityManager .createQuery("select distinct p from Publisher p " + "join p.books b where b.pages>=500", Publisher.class) .getResultList(); SELECT DISTINCT t1.ID, t1.NAME, t1.COUNTRY_ISO_CODE FROM JPA_BOOK t0, JPA_PUBLISHER t1 WHERE ((t0.PAGES >= ?) AND (t0.PUBLISHER_ID = t1.ID)) select distinct publisher0_.ID as ID1_35_, publisher0_.COUNTRY_ISO_CODE as COUNTRY_3_35_, publisher0_.name as name2_35_ from JPA_PUBLISHER publisher0_ inner join JPA_BOOK books1_ on publisher0_.ID=books1_.publisher_ID where books1_.pages>=500 Eclipselink Hibernate
- 8. Extended Queries Selektion von Einzelattributen etc. 8Java Persistence Queries List resultList = entityManager .createQuery("select p.name, p.country.name from Publisher p", Object[].class) .getResultList(); List resultList = entityManager .createQuery("select p, count(b) from Publisher p " + "left join p.books b " + "group by p", Object[].class) .getResultList();
- 9. Extended Queries Selektion von Einzelattributen etc. 9Java Persistence Queries List resultList = entityManager .createQuery("select new somepkg.NameAndCount(p.name, sum(b.pages)) " + "from Publisher p " + "join p.books b " + "where b.name like '%Java%' " + "group by p", NameAndCount.class) .getResultList(); public class NameAndCount { private String name; private Number count; public NameAndCount(String name, Number count) {
- 10. Native Queries bei schon vorhandenen SQL-Queries fr "besondere Flle" (proprietres SQL, spezielles Tuning, ) "Verlust" des O/R-Mappings auch Komplettobjekte als Ergebnis mglich 10Java Persistence Queries @SuppressWarnings("unchecked") List resultList = entityManager .createNativeQuery("SELECT DISTINCT p.ID, p.NAME, p.COUNTRY_ISO_CODE " + "FROM JPA_PUBLISHER p, JPA_BOOK b " + "WHERE b.PUBLISHER_ID = p.ID AND b.PAGES >= ?") .setParameter(1, 500) .getResultList();
- 11. Stored Procedure Queries fr "noch besonderere Flle" IN-, OUT- oder IN/OUT-Parameter 11Java Persistence Queries CREATE PROCEDURE GET_COCKTAIL_COUNT(IN ZUTAT_NAME VARCHAR(255)) BEGIN select count(*) from JPA_COCKTAIL C where exists (); END Number count = (Number) entityManager .createStoredProcedureQuery("GET_COCKTAIL_COUNT") .registerStoredProcedureParameter("ZUTAT_NAME", String.class, ParameterMode.IN) .setParameter("ZUTAT_NAME", "Sekt") .getSingleResult();
- 12. Criteria Query API Textbasierte Queries lassen sich zur Compile- oder Deploymentzeit nicht prfen Syntax Namen Typen 12Java Persistence Queries select p fron Publisher p select p from Publisher select p from Publisher p where p.nam=:name List books = entityManager .createQuery("select b from Book b where b.pages>=500", Publisher.class) .getResultList();
- 13. Criteria Query API Query wird mittels API kombiniert CriteriaQuery mittels CriteriaBuilder erstellen from, where, select Ausfhrung als "normale" TypedQuery 13Java Persistence Queries CriteriaBuilder cb = entityManager.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery(Book.class); List books = this.entityManager .createQuery(cq) .getResultList();
- 14. Criteria Query API 14Java Persistence Queries // select b from Book b where b.pages>=500 Root b = cq.from(Book.class); cq.select(b) .where(cb.greaterThanOrEqualTo(b.get(Book_.pages), 500)); // select b from Book b where b.publisher.country=:country Root b = cq.from(Book.class); cq.select(b) .where(cb.equal(b.get(Book_.publisher).get(Publisher_.country), cb.parameter(Country.class, "country"))); List books = this.entityManager .createQuery(cq) .setParameter("country", CountryTest.testCountryDE) .getResultList();
- 15. Criteria Query API nutzt statisches Metamodell E_ zu persistenter Klasse E 15Java Persistence Queries @StaticMetamodel(Publisher.class) public abstract class Publisher_ { public static volatile SingularAttribute id; public static volatile SingularAttribute name; public static volatile SingularAttribute country; public static volatile ListAttribute books; @Entity public class Publisher { @Id private Integer id; private String name; @ManyToOne private Country country; @OneToMany(mappedBy = "publisher") private List books;
- 16. Criteria Query API Metamodell wird durch Annotation Processor generiert muss im Compile Classpath liegen (z. B. als Maven Dependency) wird vom Compiler aufgerufen (Java 6+) 16Java Persistence Queries org.hibernatehibernate-jpamodelgen4.3.10.Finalprovidedtrue
- 17. Criteria Query API Annotation Processing in Eclipse kann in Luna entsprechend Maven konfiguriert werden sonst: Im Projekt Annotation Processing manuell konfigurieren Java Compiler Annotation Processing aktivieren, Zielordner whlen Factory Path Compile Classpath einstellen 17Java Persistence Queries
- 18. Root p = cq.from(Publisher.class); ListJoin b = p.join(Publisher_.books); cq.select(cb.construct(NameAndCount.class, p.get(Publisher_.name), cb.sum(b.get(Book_.pages)))) .where(cb.like(b.get(Book_.name), "%Java%")) .groupBy(p); Criteria Query API Problem: Lesbarkeit 18Java Persistence Queries // select new NameAndCount(p.name, sum(b.pages)) // from Publisher p // join p.books b // where b.name like '%Java%' // group by p
- 19. Root p = cq.from(Publisher.class); ListJoin b = p.join(Publisher_.books); cq.select(p.get(Publisher_.name)) .distinct(true) .where(cb.and(cb.equal(p.get(Publisher_.country), cb.parameter(Country.class, "country")), cb.like(b.get(Book_.name), "%Java%"))); Criteria Query API Problem: API durch CriteriaBuilder (u. a.) nicht "fluent" 19Java Persistence Queries p ~ Publisher; b ~ p.books; c ~ Parameter(Country); select(p.name) .distinct() .from(p) .where(p.country.equal(c).and(b.name.like("%Java%"))) Wunsch Ist
- 20. QueryDSL Open Source (http://www.querydsl.com) Sponsored by Mysema (http://www.mysema.com) Query wird mittels API kombiniert Query Roots und JPAQuery fr EntityManager erzeugen Methoden from, join, where, orderBy, distinct etc. Query ausfhren mittels singleResult, list 20Java Persistence Queries QPublisher p = QPublisher.publisher; JPAQuery jpaQuery = new JPAQuery(this.entityManager) List result = jpaQuery.list(p);
- 21. QueryDSL bentigt generierte Klassen hnlich JPA Metamodell 21Java Persistence Queries @Generated("com.mysema.query.codegen.EntitySerializer") public class QPublisher extends EntityPathBase { public static final QPublisher publisher = new QPublisher("publisher"); public final StringPath name = createString("name"); public final ListPath books = this.createList("books", public final de.gedoplan.seminar.jpa.demo.basics.entity.QCountry country; @Entity public class Publisher { @Id private Integer id; private String name; @ManyToOne private Country country; @OneToMany(mappedBy = "publisher") private List books;
- 22. QueryDSL Metamodell wird durch Annotation Processor generiert z. B. mit Maven Plugin 22Java Persistence Queries com.mysema.mavenapt-maven-plugin1.1.3processtarget/generated-sources/annotationscom.mysema.query.apt.jpa.JPAAnnotationProcessor
- 23. QueryDSL 23Java Persistence Queries QPublisher p = QPublisher.publisher; QBook b = QBook.book; Param countryParam = new Param(Country.class); List names = new JPAQuery(this.entityManager) .from(p) .innerJoin(p.books, b) .where(p.country.eq(countryParam).and(b.name.like("%Java%"))) .distinct() .set(countryParam, CountryTest.testCountryDE) .list(p.name); Root p = cq.from(Publisher.class); ListJoin b = p.join(Publisher_.books); cq.select(p.get(Publisher_.name)) .distinct(true) .where(cb.and(cb.equal(p.get(Publisher_.country), cb.parameter(Country.class, "country")), cb.like(b.get(Book_.name), "%Java%"))); QueryDSL Criteri a Query API
- 24. QueryDSL Bisherige Erfahrungen Intuitives API (meist ) gute Lesbarkeit API hat noch Schwchen z. B. Umwandlung von JPAQuery nur in Query mglich, nicht in TypedQuery Noch nicht gan