4. N+1 SELECT PROBLEM
• Orders und OrderItems = FetchType.LAZY
@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval =
true)
private Set<Order> orders;
@OneToMany(mappedBy = "order", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> items;
• Ein Query für alle Customers
• Pro Customer 1 Query für die Orders
• Pro Order 1 Query für die OrderItems
5. LÖSUNGSANSÄTZE
• FetchType.EAGER oder EntityGraph (JPA 2.1)
– Nur ein Hinweis für JPA
– != SQL JOIN
– Hibernate erlaubt nur eine List mit
FetchType.EAGER pro Entity
org.hibernate.HibernateException: cannot simultaneously fetch
multiple bags
• JOIN FETCH
– Achtung vor kartesischen Produkten
6. DTO
Quelle: Martin Fowler, http://martinfowler.com/eaaCatalog/dataTransferObject.html
7. CustomerInfoDTO
public class CustomerInfoDTO {
private final Long id;
private final String lastname;
private final String firstname;
private final double revenue;
public CustomerInfoDTO(Long id, String lastname, String firstname,
double revenue) {
this.id = id;
this.lastname = lastname;
this.firstname = firstname;
this.revenue = revenue;
}
...
8. CONSTRUCTOR EXPRESSION
Query q = em.createQuery(
"SELECT " +
"NEW control.CustomerInfoDTO(c.id, c.lastname, c.firstname," +
"SUM(i.product.price)) " +
"FROM Customer c " +
"JOIN c.orders o " +
"JOIN o.items i " +
"GROUP BY c.lastnamem, c.firstname" +
"ORDER BY c.lastname, c.firstname");
List<CustomerInfoDTO> list = q.getResultList();
9. DAS DATENMODELL IM ZENTRUM
• Ein 1-1 Abbild der Datenbank in Entities oft
unnötig
X
10. WAS IST MIT JPQL OHNE DIE
BEZIEHUNG CUSTOMER->ORDER?
NEU IN JPA 2.1
Query q = em.createQuery(
"SELECT " +
"NEW control.CustomerInfoDTO(c.id, c.lastname, c.firstname, " +
"SUM(i.product.price)) " +
"FROM Customer c " +
"JOIN c.orders o ON o.customerId = c.id " +
"JOIN o.items i " +
"GROUP BY c.lastname, c.firstname" +
"ORDER BY c.lastname, c.firstname");
List<CustomerInfoDTO> list = q.getResultList();
11. ORM FÜR ALLES?
Just because you're using Hibernate, doesn't
mean you have to use it for everything.
A point I've been making for about ten years
now.
Gavin King, 10.12.2013
12. SQL?
• VORTEILE
– Testbar mit SQL Developer/TOAD/IDE
– Optimierbar (Execution Plan)
• ABER SQL VON HAND? NEIN!
– JPA 2.1 ConstructorResult
– QLRM
– jOOQ
13. JPA 2.1 CONSTRUCTOR RESULT
Query q = em.createNativeQuery(
"SELECT C.ID, C.LASTNAME, C.FIRSTNAME, SUM(P.PRICE) AS REVENUE" +
"FROM CUSTOMERS C " +
"JOIN ORDERS O ON O.CUSTOMER_ID = C.ID " +
"JOIN ORDERITEMS I ON I.ORDER_ID = O.ID " +
"JOIN PRODUCTS P ON P.ID = I.PRODUCT_ID " +
"GROUP BY C.ID, C.LASTNAME, C.FIRSTNAME " +
"ORDER BY C.LASTNAME, C.FIRSTNAME", "CustomerInfoDTO");
@SqlResultSetMapping(name="CustomerInfoDTO",
classes={
@ConstructorResult(targetClass=CustomerInfoDTO.class,
columns={@ColumnResult(name="ID"),
@ColumnResult(name="LASTNAME"),
@ColumnResult(name="FIRSTNAME"),
@ColumnResult(name="REVENUE", type=Double.class)})
})
14. QLRM
Query q = em.createNativeQuery(
"SELECT C.ID, C.LASTNAME, C.FIRSTNAME, SUM(P.PRICE) AS REVENUE" +
"FROM CUSTOMERS C " +
"JOIN ORDERS O ON O.CUSTOMER_ID = C.ID " +
"JOIN ORDERITEMS I ON I.ORDER_ID = O.ID " +
"JOIN PRODUCTS P ON P.ID = I.PRODUCT_ID " +
"GROUP BY C.ID, C.LASTNAME, C.FIRSTNAME " +
"ORDER BY C.LASTNAME, C.FIRSTNAME");
JpaResultMapper mapper = new JpaResultMapper();
List<CustomerInfoDTO> list =
jpaResultMapper.list(q, CustomerInfoDTO.class);
QLRM: https://github.com/simasch/qlrm