jpa queries

Click here to load reader

Download Jpa queries

Post on 07-Aug-2015

82 views

Category:

Documents

0 download

Embed Size (px)

TRANSCRIPT

  1. 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. 2. Dirk Weil GEDOPLAN GmbH, Bielefeld Java EE seit 1998 Konzeption und Realisierung Seminare Vortrge Verffentlichungen Java Persistence Queries 2
  3. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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

View more