Limitar Resultados de Consultas con JPA y Spring Data JPA

1. Introducción

En este tutorial, vamos a aprender sobre cómo limitar los resultados de las consultas utilizando la JPA y Spring Data JPA. Primero, examinaremos la tabla que queremos consultar, así como la consulta SQL que queremos reproducir. Luego, nos adentraremos en cómo lograr esto con JPA y Spring Data JPA. ¡Vamos a empezar!

2. Los Datos de Prueba

A continuación, tenemos la tabla que estaremos consultando a lo largo de este artículo. La pregunta que queremos responder es: “¿Cuál es el primer asiento ocupado y quién lo ocupa?”

First NameLast NameSeat Number
JillSmith50
EveJackson94
FredBloggs22
RickiBobbie36
SiyaKolisi85

3. La Consulta SQL

Con SQL, podríamos escribir una consulta que se vea algo así:


SELECT firstName, lastName, seatNumber FROM passengers ORDER BY seatNumber LIMIT 1;

Esta consulta selecciona el primer asiento disponible ordenado por el número de asiento, limitando el resultado a solo uno.

4. Configuración de JPA

Con JPA, primero necesitamos una entidad para mapear nuestra tabla:


@Entity
class Passenger {

    @Id
    @GeneratedValue
    @Column(nullable = false)
    private Long id;

    @Basic(optional = false)
    @Column(nullable = false)
    private String firstName;

    @Basic(optional = false)
    @Column(nullable = false)
    private String lastName;

    @Basic(optional = false)
    @Column(nullable = false)
    private int seatNumber;

    // constructor, getters, etc.
}

A continuación, necesitamos un método que encapsule nuestro código de consulta, implementado aquí como PassengerRepositoryImpl#findOrderedBySeatNumberLimitedTo(int limit):


@Repository
class PassengerRepositoryImpl {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public List findOrderedBySeatNumberLimitedTo(int limit) {
        return entityManager.createQuery("SELECT p FROM Passenger p ORDER BY p.seatNumber", Passenger.class)
                             .setMaxResults(limit)
                             .getResultList();
    }
}

En nuestro método de repositorio, utilizamos el EntityManager para crear una Query en la que llamamos al método setMaxResults().

Esta llamada a Query#setMaxResults resultará en la sentencia limit añadida a la SQL generada:


select
  passenger0_.id as id1_15_,
  passenger0_.first_name as first_nam2_15_,
  passenger0_.last_name as last_nam3_15_,
  passenger0_.seat_number as seat_num4_15_
from passenger passenger0_ order by passenger0_.seat_number limit ?;

5. Con Spring Data JPA

También podemos generar nuestra SQL utilizando Spring Data JPA.

5.1. first o top

Una forma de abordar esto es utilizando la derivación del nombre del método con las palabras clave first o top. Podemos, opcionalmente, especificar un número como el tamaño máximo de resultado que será devuelto. Si lo omitimos, Spring Data JPA asume un tamaño de resultado de 1.

Dado que queremos saber cuál fue el primer asiento ocupado y quién lo ocupa, podemos obtenerlo dejando el número en blanco de estas dos maneras:


Passenger findFirstByOrderBySeatNumberAsc();
Passenger findTopByOrderBySeatNumberAsc();

Si limitamos a una instancia de resultado, como se muestra arriba, también podemos envolver el resultado usando Optional:


Optional findFirstByOrderBySeatNumberAsc();
Optional findTopByOrderBySeatNumberAsc();

5.2. Pageable

Alternativamente, podemos usar un Pageable:


Page page = repository.findAll(PageRequest.of(0, 1, Sort.by(Sort.Direction.ASC, "seatNumber")));

Si observamos la implementación predeterminada de JpaRepository, SimpleJpaRepository, podemos ver que también llama a Query#setMaxResults.

5.3. Usando Limit

Spring Data JPA versión 3.2 proporciona un nuevo tipo llamado Limit para limitar el número de resultados devueltos de una consulta. Tiene dos métodos estáticos: of() y unlimited(). El método of() acepta un entero como argumento. Limita los resultados de la consulta al tamaño máximo indicado, lo que permite obtener solo el número especificado de resultados.

A continuación, usaremos el método of() de Limit para limitar el resultado de la consulta a 1:


List passenger = repository.findByOrderBySeatNumberAsc(Limit.of(1));

Aquí, invocamos el método estático of() en Limit para volver 1 resultado basado en nuestra especificación.

5.4. Comparación

Estas alternativas producen la SQL que estamos buscando, siendo first y top favorables a la convención, Pageable a la configuración, y Limit proporcionando una llamada simple al método:


select
  passenger0_.id as id1_15_,
  passenger0_.first_name as first_nam2_15_,
  passenger0_.last_name as last_nam3_15_,
  passenger0_.seat_number as seat_num4_15_
from passenger passenger0_ order by passenger0_.seat_number asc limit ?;

6. Conclusión

Limitar los resultados de consultas en JPA es ligeramente diferente de SQL; no incluimos la palabra clave limit directamente en nuestro JPQL. En su lugar, simplemente hacemos una única llamada al método Query#maxResults, o incluimos la palabra clave first o top en el nombre de nuestro método de Spring Data JPA.

Además, con Spring Data JPA versión 3.2 y superiores, podemos usar la interfaz Limit para limitar los resultados de la consulta llamando a su método estático of() para especificar el tamaño máximo.

Consejos Prácticos para Programadores Java

  • Familiarízate con la configuración básica de JPA y Spring Data JPA antes de implementar consultas complejas.
  • Utiliza Optional para manejar resultados nulos de manera más segura.
  • Considera usar Limit de manera eficiente si estás trabajando con una gran cantidad de datos, para mejorar el rendimiento.
  • No dudes en experimentar con derivación de métodos en Spring Data JPA para obtener consultas más limpias y legibles.

Con estos enfoques, podrás manejar tus consultas en JPA y Spring Data JPA de manera eficiente y efectiva, limitando los resultados según tus necesidades.