1. Введение
В этом руководстве мы узнаем об ограничении результатов запроса с помощью JPA и Spring Data JPA .
Во-первых, мы рассмотрим таблицу, которую мы хотим запросить, а также SQL-запрос, который мы хотим воспроизвести.
Затем мы углубимся в то, как этого добиться с помощью JPA и Spring Data JPA.
Давайте начнем!
2. Тестовые данные
Ниже у нас есть таблица, которую мы будем запрашивать в этой статье.
Вопрос, на который мы хотим ответить, звучит так: «Какое первое занятое место и кто его занимает?»
| Имя | Фамилия | Номер места |
| Джилл | Смит | 50 |
| Канун | Джексон | 94 |
| Фред | Блоги | 22 |
| Рики | Бобби | 36 |
| Сия | Колиси | 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<Passenger> findOrderedBySeatNumberLimitedTo(int limit) {
return entityManager.createQuery("SELECT p FROM Passenger p ORDER BY p.seatNumber",
Passenger.class).setMaxResults(limit).getResultList();
}
}
В нашем методе репозитория мы используем EntityManager
для создания запроса
, для которого мы вызываем метод 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 Data JPA
Мы также можем сгенерировать наш SQL, используя Spring Data JPA.
5.1. первый
или верхний
Один из способов приблизиться к этому — использовать производное имя метода с ключевыми словами first
или top.
При желании мы можем указать число в качестве максимального размера результата, который будет возвращен. Если мы его опустим, Spring Data JPA предполагает, что размер результата равен 1.
Поскольку мы хотим знать, какое место было занято первым и кто его занимает, мы можем получить его, опустив номер, двумя способами:
Passenger findFirstByOrderBySeatNumberAsc();
Passenger findTopByOrderBySeatNumberAsc();
Если мы ограничимся одним экземпляром результата, как указано выше, мы также можем обернуть результат, используя необязательный
:
Optional<Passenger> findFirstByOrderBySeatNumberAsc();
Optional<Passenger> findTopByOrderBySeatNumberAsc();
5.2. Постраничный
В качестве альтернативы мы можем использовать объект Pageable
:
Page<Passenger> page = repository.findAll(
PageRequest.of(0, 1, Sort.by(Sort.Direction.ASC, "seatNumber")));
Если мы посмотрим на реализацию JpaRepository
по умолчанию, SimpleJpaRepository ,
мы увидим, что она также вызывает Query#setMaxResults
:
protected <S extends T > 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, который нам нужен, с соглашением о первом
и наибольшем преимуществе и конфигурацией предпочтения
Pageable
: ``
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 ?
6. Заключение
Ограничение результатов запроса в JPA немного отличается от SQL; мы не включаем ключевое слово limit непосредственно в наш JPQL .
Вместо этого мы просто делаем один вызов метода Query#maxResults
или включаем ключевое слово first
или top
в имя нашего метода Spring Data JPA .
Как всегда, код доступен на GitHub .