Ressource
Définition
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. Cependant l’objet projeté ne font plus partie du contexte de persistance (voir plus bas)
Elles permettent ainsi de
- réduire la quantité de données transférées
- améliorer donc la performance du système
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");Note :
b.author.nameest autorisé car dans la classeBooknous avons une relation@ManyToOne private Author author;
Types de Projections
JPA supporte principalement trois types de projections :
- Projections d’entités : Récupération complète des entités.
- Projections de valeurs scalaires : Sélection de colonnes spécifiques
- 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];
}Très pratique, mais pas très lisible, il serait intéressant d’utiliser un type précis au lieu de Object => DTO
Projections DTO (Data Transfer Object)
Les projections DTO impliquent l’utilisation de classes personnalisées pour encapsuler les données nécessaires, offrant une structure claire.
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();Note importante
Contrairement aux projections d’entités, les projections scalaires 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 persistée en base de données
- Par conséquent les projections scalaires et DTO ne peuvent être utilisées que pour de la lecture
Comparons les deux comportements sur la même modification.
// Projection d'entité : Book est géré par le contexte de persistance
Book book = entityManager.createQuery("SELECT b FROM Book b WHERE b.id = 1", Book.class)
.getSingleResult();
book.setTitle("Nouveau titre"); // ✅ le dirty checking détecte la modification
// => UPDATE book SET title = 'Nouveau titre' WHERE id = 1; au flush// Projection DTO : BookDTO est un simple objet Java
BookDTO dto = entityManager.createQuery(
"SELECT new com.example.BookDTO(b.title, b.publisher) FROM Book b WHERE b.id = 1",
BookDTO.class)
.getSingleResult();
dto.setTitle("Nouveau titre"); // ❌ ne modifie que l'objet en mémoire
// => aucune requête émise, la base n'est pas modifiéeDans le second cas, BookDTO n’est pas une entité : le contexte de persistance ne le connaît pas, ne conserve aucun état initial pour lui, et n’a donc aucun moyen de détecter le changement (voir Dirty checking). L’objet est un simple conteneur de données, détaché de toute logique de persistance.
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 obligatoires 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.