Ограничение результатов запроса с помощью JPA и Spring Data JPA

Ограничение результатов запроса с помощью JPA и Spring Data JPA

1. Вступление

В этом руководстве мы перейдем кlearn about limiting query results сJPA иSpring Data JPA.

Сначала мы взглянем на таблицу, которую хотим запросить, а также на SQL-запрос, который мы хотим воспроизвести.

Затем мы сразу рассмотрим, как этого добиться с помощью JPA и Spring Data JPA.

Давайте начнем!

2. Тестовые данные

Ниже представлена ​​таблица, к которой мы будем обращаться в этой статье.

Вопрос, на который мы хотим ответить: «Какое первое место занято и кто его занимает?».

Имя

Фамилия

Номер места

Jill

кузнец

50

Eve

Джексон

94

Fred

Bloggs

22

Рики

Бобби

36

Siya

Колиси

85

3. SQL

С помощью SQL мы могли бы написать запрос, который выглядит примерно так:

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

4. Настройка JPA

В JPA нам сначала нужен Entity, чтобы отобразить нашу таблицу:

@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.
}

Затем нам нужен метод, который инкапсулирует наш код запроса, реализованный здесь как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();
    }
}

В нашем методе репозитория мы используемEntityManager для созданияQuery, для которого мы вызываем методsetMaxResults().

Этот вызовQuery#setMaxResults в конечном итоге приведет к добавлению оператора limit к сгенерированному SQL:

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. С данными Spring JPA

Мы также можем генерировать наш SQL, используя Spring Data JPA.

5.1. first илиtop

Один из способов приблизиться к этому - использовать вывод имени метода с ключевыми словамиfirst илиtop..

При желании мы можем указать число в качестве максимального размера результата, который будет возвращен. Если мы его опускаем, Spring Data JPA принимает размер результата 1.

Вспоминая, что мы хотим знать, какое первое место занято и кто его занимает, мы можем получить его, опуская число двумя способами:

Passenger findFirstByOrderBySeatNumberAsc();
Passenger findTopByOrderBySeatNumberAsc();

Если мы ограничимся одним результатом экземпляра, как указано выше, то мы также можем обернуть результат, используяOptional:

Optional findFirstByOrderBySeatNumberAsc();
Optional findTopByOrderBySeatNumberAsc();

5.2. Pageableс

В качестве альтернативы мы можем использовать объектPageable:

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

Если мы посмотрим на реализацию по умолчаниюJpaRepository,,SimpleJpaRepositorywe увидим, что он также вызываетQuery#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. сравнение

Обе эти альтернативы будут производить SQL, который мы ищем:

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 ?

Сfirst andtop в пользу соглашения иPageable в пользу конфигурации.

6. Заключение

Ограничение результатов запроса вJPA немного отличается от SQL - мы не включаем ключевое слово limit непосредственно в нашиJPQL.

Вместо этого мы просто вызываем один методQuery#maxResults или включаем ключевое словоfirst илиtop в имя нашего методаSpring Data JPA.

Как всегда, вы можете найти кодover on GitHub.