Limitando resultados de consulta com JPA e JPA de dados de primavera

Limitando resultados de consulta com JPA e JPA de dados de primavera

1. Introdução

Neste tutorial, vamoslearn about limiting query results comJPAeSpring Data JPA.

Primeiro, vamos dar uma olhada na tabela que queremos consultar, bem como na consulta SQL que queremos reproduzir.

Então, vamos nos aprofundar em como conseguir isso com JPA e Spring Data JPA.

Vamos começar!

2. Os dados de teste

Abaixo, temos a tabela que consultaremos ao longo deste artigo.

A pergunta que queremos responder é: "Qual é o primeiro assento ocupado e quem o ocupa?".

Primeiro nome

Último nome

Número do assento

Jill

Smith

50

Eve

Jackson

94

Fred

Bloggs

22

Ricki

Bobbie

36

Siya

Kolisi

85

3. O SQL

Com o SQL, podemos escrever uma consulta parecida com esta:

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

4. Configuração da JPA

Com o JPA, precisamos primeiro de uma Entidade para mapear nossa tabela:

@Entity
class Passenger {

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

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

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

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

    // constructor, getters etc.
}

Em seguida, precisamos de um método que encapsula nosso código de consulta, implementado aqui comoPassengerRepositoryImpl#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();
    }
}

Em nosso método de repositório, usamosEntityManager para criar umQuery no qual chamamos o métodosetMaxResults().

Essa chamada paraQuery#setMaxResults acabará resultando na instrução de limite anexada ao SQL gerado:

select
  passenger0_.id as id1_15_,
  passenger0_.fist_name as fist_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. Com o Spring Data JPA

Também podemos gerar nosso SQL usando o Spring Data JPA.

5.1. first outop

Uma maneira de abordar isso é usando a derivação do nome do método com as palavras-chavefirst outop.

Opcionalmente, podemos especificar um número como o tamanho máximo do resultado que será retornado. Se o omitirmos, o Spring Data JPA assumirá o tamanho do resultado 1.

Lembrando que queremos saber qual é o primeiro assento ocupado e quem o ocupa, podemos fazê-lo omitindo o número das duas maneiras:

Passenger findFirstByOrderBySeatNumberAsc();
Passenger findTopByOrderBySeatNumberAsc();

Se limitarmos a um resultado de instância, como acima, também podemos agrupar o resultado usandoOptional:

Optional findFirstByOrderBySeatNumberAsc();
Optional findTopByOrderBySeatNumberAsc();

5.2. Pageable

Como alternativa, podemos usar um objetoPageable:

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

Se dermos uma olhada na implementação padrão deJpaRepository,, oSimpleJpaRepositorywe pode ver que ele também chamaQuery#setMaxResults:

protected  Page < S > readPage(TypedQuery < S > query,
  Class < S > domainClass, Pageable pageable,
  @Nullable Specification < S > spec) {
    if (pageable.isPaged()) {
        query.setFirstResult((int) pageable.getOffset());
        query.setMaxResults(pageable.getPageSize());
    }

    return PageableExecutionUtils.getPage(query.getResultList(), pageable, () -> {
        return executeCountQuery(this.getCountQuery(spec, domainClass));
    });
}

5.3. Comparação

Ambas as alternativas produzirão o SQL que buscamos:

select
  passenger0_.id as id1_15_,
  passenger0_.fist_name as fist_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 ?

Comfirst andtop favorecendo a convenção ePageable favorecendo a configuração.

6. Conclusão

Limitar os resultados da consulta emJPA é um pouco diferente do SQL - não incluímos a palavra-chave limit diretamente em nossoJPQL.

Em vez disso, apenas fazemos uma única chamada de método paraQuery#maxResults ou incluímos a palavra-chavefirst outop em nosso nome de métodoSpring Data JPA.

Como sempre, você pode encontrar o códigoover on GitHub.