Saltar a contenido

Repository

Un Repository es un componente de la capa de persistencia que se encarga de gestionar el acceso a los datos de la aplicación. Su función principal es actuar como intermediario entre la lógica de negocio y la base de datos, permitiendo realizar operaciones sobre las entidades sin necesidad de escribir consultas SQL manualmente.

En Spring Data JPA, un repository representa el punto central para interactuar con una entidad almacenada en la base de datos.

¿Para qué sirve?

El repository sirve para abstraer la forma en que se almacenan y recuperan los datos. Gracias a esto, la aplicación puede:

  • Guardar información en la base de datos.
  • Consultar registros de forma sencilla.
  • Actualizar entidades existentes.
  • Eliminar datos (o marcarlos como eliminados, en caso de soft delete).
  • Todo esto se realiza sin que la capa de negocio tenga que conocer detalles sobre la base de datos o el motor utilizado.

Como se implementa

UserRepository es el repository de la entidad User.

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserRepository extends JpaRepository<User, Long> {
}
  • JpaRepository indica:
  • User → entidad que se va a persistir.
  • Long → tipo de la llave primaria.

Funciones

Método ¿Para qué sirve?
save(entity) Guarda una nueva entidad o actualiza una existente en la base de datos.
saveAll(entities) Guarda o actualiza una colección de entidades en una sola operación.
findById(id) Busca una entidad por su llave primaria y retorna un Optional.
existsById(id) Verifica si existe un registro con el identificador indicado.
findAll() Retorna todos los registros de la tabla asociada a la entidad.
findAllById(ids) Retorna todos los registros cuyos identificadores coinciden con la lista enviada.
count() Retorna la cantidad total de registros almacenados.
deleteById(id) Elimina un registro usando su llave primaria (o ejecuta soft delete si está configurado).
delete(entity) Elimina una entidad específica.
deleteAll() Elimina todos los registros de la tabla asociada.
deleteAll(entities) Elimina un conjunto específico de entidades.
flush() Fuerza la sincronización inmediata de los cambios con la base de datos.
saveAndFlush(entity) Guarda una entidad y ejecuta flush inmediatamente.
findAll(Sort sort) Retorna los registros ordenados según el criterio indicado.
findAll(Pageable pageable) Retorna los registros de forma paginada.

Consultas personalizadas: JPQL y SQL nativo

En Spring Data JPA es común definir consultas personalizadas cuando los métodos automáticos no cubren un caso. Hay dos enfoques principales:

  • JPQL (Java Persistence Query Language): consulta orientada a objetos que usa nombres de entidad y atributos Java.
  • SQL nativo: consulta SQL del motor de base de datos, opera sobre tablas y columnas reales.

Ambos pueden usarse en repositorios mediante la anotación @Query.

JPQL

Características:

  • Portabilidad entre bases de datos.
  • Usa nombres de entidad y propiedades (no nombres de tabla/columna).
  • Permite retornar entidades, ad-hoc DTOs (constructor expression) o valores escalares.

Ejemplo en un UserRepository:

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.transaction.annotation.Transactional;

public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT u FROM User u WHERE u.email = :email")
    Optional<User> findByEmailJPQL(@Param("email") String email);

    // Retorno a DTO usando constructor expression
    @Query("SELECT new com.example.dto.UserSummary(u.id, u.names, u.email) FROM User u WHERE u.company.code = :code")
    List<UserSummary> findSummariesByCompanyCode(@Param("code") String companyCode);

    @Modifying
    @Transactional
    @Query("UPDATE User u SET u.status = :status WHERE u.id = :id")
    int updateStatus(@Param("id") Long id, @Param("status") Status status);

}

Notas: - Para UPDATE/DELETE con @Query se debe usar @Modifying y una transacción (@Transactional). - Las consultas JPQL devuelven objetos gestionados por el EntityManager cuando retornan entidades.

SQL nativo

Características:

  • Permite usar funciones y sintaxis específicas del motor (optimización o consultas complejas).
  • Opera sobre tablas y columnas reales; menos portable.

Ejemplo equivalente con SQL nativo:

public interface UserRepository extends JpaRepository<User, Long> {

    @Query(value = "SELECT * FROM app_user u WHERE u.email = :email", nativeQuery = true)
    Optional<User> findByEmailNative(@Param("email") String email);

    @Modifying
    @Transactional
    @Query(value = "UPDATE app_user SET status = :status WHERE id = :id", nativeQuery = true)
    int updateStatusNative(@Param("id") Long id, @Param("status") int status);

}

Notas: - Cuando la consulta nativa devuelve columnas que no coinciden exactamente con la entidad, puede requerirse un @SqlResultSetMapping o mapear manualmente los resultados a DTOs (por ejemplo, List<Object[]>) y transformarlos.

Usando EntityManager para consultas dinámicas

Para consultas complejas o dinámicas también se puede usar EntityManager:

@Repository
public class PostCustomRepository {

    @PersistenceContext
    private EntityManager em;

    public List<Post> searchByTitle(String term) {
        return em.createQuery("SELECT p FROM Post p WHERE p.title LIKE :t", Post.class)
                 .setParameter("t", "%" + term + "%")
                 .getResultList();
    }

    public List<Object[]> nativeSearch(String sql) {
        return em.createNativeQuery(sql).getResultList();
    }

}

¿Cuándo usar cada una?

  • Usa JPQL cuando la consulta puede expresarse en términos de entidades y quieres portabilidad y claridad orientada a objetos.
  • Usa SQL nativo cuando necesites funcionalidades específicas del motor, optimizaciones complejas, o acceder a vistas/materialized views.
  • Usa EntityManager cuando necesites construir consultas dinámicas o usar la API Criteria.

Con esto tendrás ejemplos y reglas prácticas para elegir entre JPQL y SQL nativo en tus Repository.