Projection

adriencaubel.fr

Introduction

  • Nous avons étudié les concepts suivants
    • La notion @Entity
    • Les associations @OneToMany ... et mappedBy (bidirectionnelle)
    • L'héritage @Inheritance
    • L'optimisation des lectures (Fetch.LAZY / Fetch.EAGER)
    • L'API Criteria

Regardons comment "optimiser" les informations de retour

C'est quoi ?

Les projections sont des techniques qui permettent de sélectionner et de récupérer uniquement les données nécessaires d’une base de données.

Elles permettent ainsi de

  • réduire la quantité de données transférées
  • améliorer donc la performance du système

Exemple

Ainsi au lieu de tout récupérer (SELECT *), nous sélectionnons les colonnes qui nous intéressent

em.createQuery("SELECT b.title, b.publisher, b.author.name FROM Book b");

Types de Projections

JPA supportent principalement trois types de projections :

  • Projections d’entités : Récupération complète des entités.
  • Projections de valeurs scalaires : Sélection de colonne spécifique
  • Projections DTO: Utilisation d’objets personnalisés pour transporter des données spécifiques.

Projection d’entité

C’est la plus commune, on récupère toute l’entité soit via un find() soit avec JPQL

TypedQuery<Book> query = entityManager.createQuery("SELECT b FROM Book b", Book.class);
List<Book> books = query.getResultList();

Projections de Valeurs Scalaires

Les projections de valeurs scalaires permettent de sélectionner des colonnes spécifiques ou des résultats de fonctions agrégées, sans charger des entités complètes.

// Récupère un tableau d'Object
TypedQuery<Object[]> query = entityManager.createQuery(
  "SELECT b.title, b.publisher FROM Book b", Object[].class);
 
List<Object[]> results = query.getResultList();
for (Object[] result : results) {
    String title = (String) result[0];
    String publisher = (String) result[1];
}

Projections de Valeurs Scalaires : lisibilité

Très pratique, mais pas très lisible, il serait intéressant d’utiliser un type précis au lieux de Object ⇒ DTO

=> Les projections DTO impliquent l’utilisation de classes personnalisées pour encapsuler les données nécessaires, offrant une structure claire.

Projections DTO (Data Transfer Object)

public class BookDTO {
    private String title;
    private String authorName;
    private String publisher;
}
// Pas Object[] mais typé avec le DTO
TypedQuery<BookDTO> query = entityManager.createQuery(
  "SELECT new com.example.BookDTO(b.title, b.author.name, b.publisher) FROM Book b", 
  BookDTO.class);
 
List<BookDTO> bookDTOs = query.getResultList();

ATTENTION : Note ultra importante

Contrairement au projection d’entité, les projections scalaire et DTO ne font plus partie du contexte de persistance et ne suivent plus le cycle de vie.

  • Ainsi si vous mettez à jour le DTO, la nouvelle donnée ne sera pas persister en base de donnée
  • Par conséquent les projections scalaire et DTO ne peuvent être utilisé que pour de la lecture

"Choisir sa projection"

Le choix du type de projection dépend du cas d’utilisation :

  • Opérations d’écriture : Les projections d’entités sont obligatoire en raison de la gestion automatique du cycle de vie des entités par le contexte de persistance.

  • Opérations en lecture seule : Les projections de valeurs scalaires ou DTO sont préférables pour réduire le surcoût et améliorer les performances.