
Création d'interfaces Repository (`JpaRepository`, `CrudRepository`)
Apprenez à définir vos interfaces d'accès aux données en étendant CrudRepository et JpaRepository dans Spring Data JPA pour bénéficier des opérations CRUD et plus.
Définir le contrat d'accès aux données
Au coeur de Spring Data se trouve le concept de Repository, une interface qui définit les opérations d'accès aux données pour une entité spécifique. L'étape fondamentale pour utiliser Spring Data JPA est donc de créer ces interfaces pour vos entités. Vous n'avez pas besoin d'écrire l'implémentation ; Spring Data s'en charge pour vous.
Pour ce faire, vous créez une interface Java qui étend une des interfaces de base fournies par Spring Data. Les choix les plus courants pour JPA sont CrudRepository et JpaRepository, chacune offrant un niveau de fonctionnalité différent.
`CrudRepository` : Les bases du CRUD
L'interface org.springframework.data.repository.CrudRepository est l'une des interfaces fondamentales. Elle fournit un ensemble standard de méthodes pour les opérations CRUD (Create, Read, Update, Delete).
En étendant CrudRepository, votre interface personnalisée hérite automatiquement des méthodes suivantes :
: Sauvegarde (insère ou met à jour) une entité donnée.S save(S entity): Sauvegarde plusieurs entités.IterablesaveAll(Iterableentities)Optional: Récupère une entité par son identifiant. Retourne unfindById(ID id) Optionalpour gérer élégamment le cas où l'entité n'est pas trouvée.boolean existsById(ID id): Vérifie si une entité avec l'ID donné existe.Iterable: Récupère toutes les entités.findAll() Iterable: Récupère toutes les entités pour les IDs donnés.findAllById(Iterable ids) long count(): Compte le nombre total d'entités.void deleteById(ID id): Supprime l'entité avec l'ID donné.void delete(T entity): Supprime une entité donnée.void deleteAllById(Iterable extends ID> ids): Supprime les entités pour les IDs donnés.void deleteAll(Iterable extends T> entities): Supprime les entités données.void deleteAll(): Supprime toutes les entités du repository (à utiliser avec précaution!).
Exemple :
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
@Repository // Annotation recommandée pour la traduction d'exceptions
public interface BasicProductRepository extends CrudRepository {
// Pas besoin d'ajouter les méthodes CRUD ici, elles sont héritées.
// On peut ajouter des méthodes de requête dérivées si nécessaire.
List findByName(String name);
}
// Entité Product (simplifiée)
@Entity
class Product {
@Id @GeneratedValue
private Long id;
private String name;
// ...
}
CrudRepository est un bon choix si vous n'avez besoin que des opérations CRUD de base et éventuellement de quelques requêtes dérivées simples.
`JpaRepository` : Le choix complet pour JPA
L'interface org.springframework.data.jpa.repository.JpaRepository est l'interface la plus couramment utilisée et recommandée pour les projets basés sur JPA. Elle étend PagingAndSortingRepository (qui elle-même étend CrudRepository), ce qui signifie qu'elle hérite de toutes les méthodes CRUD ainsi que des méthodes de pagination et de tri.
En plus de cela, JpaRepository ajoute des méthodes spécifiques à JPA qui tirent parti des fonctionnalités de l'EntityManager sous-jacent :
List: Surcharge defindAll() CrudRepositorypour retourner uneListau lieu d'unIterable.List: Récupère toutes les entités, triées.findAll(Sort sort) List: Surcharge pour retourner unefindAllById(Iterable ids) List.: Surcharge pour retourner uneListsaveAll(Iterableentities)List.void flush(): Synchronise le contexte de persistance avec la base de données sous-jacente (force l'exécution des instructions SQL en attente).: Sauvegarde une entité et appelleS saveAndFlush(S entity)flush()immédiatement après.void deleteInBatch(Iterable(Déprécié, préférerentities) deleteAllInBatch): Supprime les entités données en utilisant une seule requête optimisée si possible (plus efficace que des suppressions individuelles).void deleteAllInBatch(Iterable: Remplaceentities) deleteInBatch.void deleteAllByIdInBatch(Iterable: Supprime par ID en utilisant une seule requête optimisée.ids) T getOne(ID id)(Déprécié): Retourne une référence proxy à l'entité sans nécessairement la charger depuis la base. Utile pour établir des relations. Peut leverEntityNotFoundExceptionsi l'entité n'existe pas lors de l'accès aux propriétés.T getById(ID id): RemplacegetOneavec un comportement similaire mais une sémantique potentiellement plus claire selon les versions de JPA/Hibernate.: Support pour les requêtes par l'exemple (Query by Example).ListfindAll(Exampleexample): Requêtes par l'exemple avec tri.ListfindAll(Exampleexample, Sort sort)
Exemple :
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface OrderRepository extends JpaRepository {
// Hérite CRUD, Pagination/Tri, et méthodes spécifiques JPA
// Exemple de requête dérivée
List findByCustomerNameOrderByOrderDateDesc(String customerName);
}
// Entité Order (simplifiée)
@Entity
@Table(name = "orders") // Bonne pratique de nommer la table
class Order {
@Id @GeneratedValue
private Long id;
private String customerName;
private java.time.LocalDateTime orderDate;
// ...
}
Etant donné qu'elle offre l'ensemble de fonctionnalités le plus complet (CRUD, pagination, tri, opérations spécifiques à JPA), JpaRepository est généralement le meilleur point de départ pour la plupart des applications utilisant Spring Data JPA.
Comment utiliser ces interfaces ?
Une fois que vous avez défini votre interface Repository (par exemple, OrderRepository), vous n'avez rien de plus à faire au niveau de l'implémentation. Spring Data détecte votre interface au démarrage et crée automatiquement un bean (un proxy) qui implémente cette interface.
Vous pouvez ensuite injecter cette interface directement dans vos composants (comme les services ou les contrôleurs) en utilisant l'injection de dépendances (@Autowired) et appeler ses méthodes comme si une implémentation concrète existait.
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@Service
public class OrderService {
private final OrderRepository orderRepository; // Injection de l'interface
@Autowired
public OrderService(OrderRepository orderRepository) {
this.orderRepository = orderRepository;
}
@Transactional(readOnly = true) // Bonne pratique pour les méthodes de lecture
public Optional getOrderById(Long id) {
return orderRepository.findById(id); // Appel direct d'une méthode héritée
}
@Transactional(readOnly = true)
public List findOrdersForCustomer(String customerName) {
// Appel direct d'une méthode de requête dérivée
return orderRepository.findByCustomerNameOrderByOrderDateDesc(customerName);
}
@Transactional // Pas readOnly car modifie des données
public Order createOrder(Order order) {
return orderRepository.save(order); // Appel direct d'une méthode héritée
}
// ... autres méthodes métier
}
Le rôle de l'annotation `@Repository`
Vous avez peut-être remarqué l'annotation @Repository sur les exemples d'interfaces. Quel est son rôle exact ?
- Détection par Component Scan : Elle marque l'interface comme un bean candidat à la détection par le scan des composants de Spring. Cependant, si votre interface étend
Repositoryou l'une de ses sous-interfaces, Spring Data la détectera même sans cette annotation, à condition qu'elle se trouve dans un package scanné. - Traduction d'exceptions : C'est la raison principale et la plus importante d'utiliser
@Repositoryavec Spring Data JPA. Cette annotation active un post-processeur de bean qui intercepte les exceptions spécifiques à la plateforme de persistance (commePersistenceExceptionde JPA ouSQLExceptionde JDBC) levées par le repository et les traduit en exceptions non-cochées standard de la hiérarchieDataAccessExceptionde Spring. Cela permet de découpler votre code métier des détails de la technologie de persistance et facilite une gestion cohérente des erreurs d'accès aux données.
Conclusion : Même si elle n'est pas strictement obligatoire pour la détection des interfaces Repository de Spring Data, il est fortement recommandé d'annoter vos interfaces Repository avec @Repository pour bénéficier de la traduction automatique des exceptions.