Repositoris a Spring Boot
Els repositoris permeten interactuar amb la base de dades de manera senzilla, evitant escriure SQL manualment i proporcionant una interfície clara per realitzar operacions comunes com consultar, guardar o eliminar dades.
Un repositori és una interfície que encapsula la lògica necessària per accedir a una base de dades. En el context de Spring Data JPA, els repositoris faciliten la gestió de les operacions CRUD (Create, Read, Update, Delete) sobre les entitats mitjançant un conjunt de mètodes predefinits.
Característiques dels repositoris:
- Relació amb l’entitat: Cada repositori està associat a una entitat que representa una taula a la base de dades.
- Generació automàtica: Spring Boot genera automàticament la implementació dels repositoris en temps d’execució.
- Simplificació: Evita haver d’escriure manualment consultes SQL per a operacions bàsiques.
- Convenció de noms: Permet definir mètodes personalitzats basant-se en noms específics que segueixen regles establertes.
Funcions dels repositoris
- Accedir a les dades: Permet obtenir, guardar, modificar i eliminar registres de la base de dades.
- Gestió d’operacions CRUD: Faciliten operacions com
findById
,save
,delete
, etc. - Consultes personalitzades: Permeten definir mètodes per a consultes específiques utilitzant convencions de noms o anotacions.
- Abstracció: Ofereixen una capa que separa la lògica de negoci de l’accés a les dades.
1. Creació de Repositoris
Abans de crear un repositori, ens hem d’assegurar que tenim una entitat JPA definida. Una entitat és una classe que representa una taula a la base de dades:
- Tenim una entitat definida amb l’anotació
@Entity
. - La classe d’entitat té una clau primària definida amb l’anotació
@Id
.
Exemple d’una entitat Ciutat
:
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@Entity
public class Ciutat {
@Id
private Long id;
private String nom;
private int poblacio;
private String pais;
// Constructors, Getters i setters
}
Per crear un repositori, hem de definir una interfície que herete d’una de les interfícies de Spring Data JPA, com ara JpaRepository
, CrudRepository
o PagingAndSortingRepository
.
Exemple de repositori per a l’entitat Ciutat
:
import org.springframework.data.jpa.repository.JpaRepository;
public interface CiutatRepository extends JpaRepository<Ciutat, Long> {
// Mètodes personalitzats es poden afegir ací
}
JpaRepository<Ciutat, Long>
:Ciutat
: És l’entitat associada al repositori.Long
: És el tipus de la clau primària de l’entitat.
2. Mètodes predefinits
Quan heretem de JpaRepository
, obtenim una sèrie de mètodes predefinits per gestionar dades:
Operacions bàsiques (CRUD):
save(T entity)
: Guarda o actualitza una entitat.findById(ID id)
: Busca una entitat per la seva clau primària.findAll()
: Retorna totes les entitats.deleteById(ID id)
: Elimina una entitat per la seva clau primària.delete(T entity)
: Elimina una entitat específica.
Exemple d’ús en un servei:
@Service
public class CiutatService {
@Autowired
private CiutatRepository ciutatRepository;
public List<Ciutat> obtenirTotesLesCiutats() {
return ciutatRepository.findAll();
}
public Optional<Ciutat> obtenirCiutatPerId(Long id) {
return ciutatRepository.findById(id);
}
public Ciutat guardarCiutat(Ciutat ciutat) {
return ciutatRepository.save(ciutat);
}
public void eliminarCiutat(Long id) {
ciutatRepository.deleteById(id);
}
}
3. Consultes personalitzades mitjançant convencions de noms
La convenció de noms en Spring Data JPA permet que els mètodes dels repositoris es generen automàticament basant-se en els seus noms. Això elimina la necessitat d’escriure consultes SQL o JPQL manuals.
Funcionament:
- Anàlisi del nom del mètode: Spring Data JPA interpreta el nom del mètode com una expressió lògica que indica quina consulta ha de generar.
- Prefixos reconeguts:
findBy
,getBy
,readBy
: Per cercar entitats.countBy
: Per comptar entitats.deleteBy
,removeBy
: Per eliminar entitats.existsBy
: Per comprovar si existeixen entitats.
Exemples de mètodes basats en convencions de noms:
- Cerca per una propietat:
List<Ciutat> findByNom(String nom);
Genera la consulta:
SELECT * FROM ciutat WHERE nom = ?;
- Cerca per una propietat amb condició:
List<Ciutat> findByPoblacioGreaterThan(int poblacio);
Genera la consulta:
SELECT * FROM ciutat WHERE poblacio > ?;
- Combinació de condicions:
List<Ciutat> findByNomAndPais(String nom, String pais);
Genera la consulta:
SELECT * FROM ciutat WHERE nom = ? AND pais = ?;
- Comprovació d’existència:
boolean existsByNom(String nom);
Genera la consulta:
SELECT EXISTS (SELECT 1 FROM ciutat WHERE nom = ?);
- Comptar entitats:
long countByPais(String pais);
Genera la consulta:
SELECT COUNT(*) FROM ciutat WHERE pais = ?;
- Cerca amb ordre:
List<Ciutat> findByPaisOrderByPoblacioDesc(String pais);
Genera la consulta:
SELECT * FROM ciutat WHERE pais = ? ORDER BY poblacio DESC;
- Cerca per text parcial (
LIKE
en SQL):
List<Ciutat> findByNomContaining(String fragment);
Genera la consulta:
SELECT c.* FROM ciutat c WHERE c.nom LIKE %?%;
4. Consultes personalitzades amb @Query
- Quan la convenció de noms no és suficient, pots definir consultes personalitzades amb l’anotació
@Query
. @Query
ens permet escriure consultes en JPQL (Java Persistence Query Language) o, si ho especifiquem, en SQL natiu.
Exemple:
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
public interface CiutatRepository extends JpaRepository<Ciutat, Long> {
@Query("SELECT c FROM Ciutat c WHERE c.poblacio > :poblacioMinima")
List<Ciutat> trobarCiutatsAmbPoblacioMinima(@Param("poblacioMinima") int poblacioMinima);
}
:poblacioMinima
éss un paràmetre de consulta que es representa amb : i un nom (poblacioMinima). El valor serà proporcionat com a argument quan cridem el mètode en el codi.@Param("poblacioMinima")
indica que el paràmetre de la funciótrobarCiutatsAmbPoblacioMinima(int poblacioMinima)
està associat amb:poblacioMinima
en la consulta JPQL, el que ens permet passar valors dinàmics a la consulta.
5. Tipus de repositoris
Spring Data ofereix diversos tipus de repositoris segons les necessitats:
CrudRepository
:- Ofereix operacions bàsiques de CRUD.
- Exemple:
CrudRepository<T, ID>
.
JpaRepository
:- Estén
CrudRepository
i afegeix funcionalitats avançades com paginació i ordenació. - Exemple:
JpaRepository<T, ID>
.
- Estén
PagingAndSortingRepository
:- Ofereix suport per a paginació i ordenació.
- Exemple:
PagingAndSortingRepository<T, ID>
.
- Mètodes principals dels repositoris
Mètode | Descripció | Tipus de repositori |
---|---|---|
save(T entity) | Guarda o actualitza una entitat. | CrudRepository, JpaRepository |
findById(ID id) | Busca una entitat per la seva clau primària (ID). | CrudRepository, JpaRepository |
existsById(ID id) | Comprova si existeix una entitat amb un ID específic. | CrudRepository, JpaRepository |
findAll() | Retorna totes les entitats de la taula. | CrudRepository, JpaRepository |
findAllById(Iterable<ID> ids) | Retorna totes les entitats que coincideixen amb els IDs especificats. | CrudRepository, JpaRepository |
deleteById(ID id) | Elimina una entitat pel seu ID. | CrudRepository, JpaRepository |
delete(T entity) | Elimina una entitat específica. | CrudRepository, JpaRepository |
deleteAll() | Elimina totes les entitats. | CrudRepository, JpaRepository |
count() | Retorna el nombre total d’entitats de la taula. | CrudRepository, JpaRepository |
findAll(Sort sort) | Retorna totes les entitats ordenades segons els criteris especificats. | PagingAndSortingRepository, JpaRepository |
findAll(Pageable pageable) | Retorna totes les entitats amb suport de paginació. | PagingAndSortingRepository, JpaRepository |
flush() | Força l’execució immediata de les operacions pendents a la base de dades. | JpaRepository |
saveAndFlush(T entity) | Guarda l’entitat i immediatament executa l’operació de base de dades. | JpaRepository |
deleteInBatch(Iterable<T> entities) | Elimina un lot d’entitats en una sola operació. | JpaRepository |