Я использую Spring-Boot 2.1.3.RELEASE, включая spring-boot-starter-data-jpa. (Я не использую data-rest.) Моя база данных - Postgres.
У меня есть собственный запрос, к которому я применяю параметры подкачки и копирую результаты в проекцию. Простая версия запроса работает как шарм: магия Spring автоматически добавляет параметры сортировки / подкачки при вызове. Но когда я пытаюсь сделать запрос немного сложнее, добавив левое внешнее соединение, Spring начинает добавлять запятую перед параметрами сортировки / подкачки, что делает запрос недействительным.
Это простой запрос, который работает:
@Query( nativeQuery = true,
value = "SELECT order.date, order.volume, customer.name " +
FROM example.order " +
INNER JOIN example.customer ON order.customer_id = customer.id " +
WHERE customer.state = :state ",
countQuery = "SELECT count(order.id) " +
FROM example.order " +
INNER JOIN example.customer ON order.customer_id = customer.id " +
WHERE customer.state = :state "
)
<T> Page<T> findOrdersByCustomerState(String state, Pageable pageable, Class<T> projection);
Hibernates сообщает, что генерирует SQL, и это хорошо, и параметры подкачки применены, как и ожидалось:
SELECT order.date, order.volume, customer.name FROM example.order INNER JOIN example.customer ON order.customer_id = customer.id
WHERE customer.state = ? order by order.date desc limit ?
(Где date
был передан в Pageable.)
Теперь я пытаюсь расширить этот запрос, добавив левое внешнее соединение, чтобы получить дополнительные данные:
SELECT order.date, order.volume, customer.name, historic_orders.order_date
FROM example.order
INNER JOIN example.customer ON order.customer_id = customer.id
LEFT JOIN example.historic_orders ON historic_orders.id IN
(SELECT historic_orders.id FROM example.historic_orders WHERE
historic_orders.customer_id = customer.id ORDER BY historic_orders.order_date
LIMIT 1)
WHERE customer.state = :state
В основном я присоединяюсь к таблице historic_orders
, в которой может не быть записей об этом клиенте, поэтому я могу получить дату последнего заказа.
В любом случае, Hibernate теперь генерируется так:
SELECT order.date, order.volume, customer.name, historic_orders.order_date
FROM example.order
INNER JOIN example.customer ON order.customer_id = customer.id
LEFT JOIN example.historic_orders ON historic_orders.id IN
(SELECT historic_orders.id FROM example.historic_orders WHERE historic_orders.customer_id = customer.id ORDER BY historic_orders.order_date
LIMIT 1)
WHERE customer.state = ?, INNER.date desc limit ?
Это, конечно, недопустимый SQL. Перед параметром sort / paging стоит случайная запятая, и по какой-то причине было решено, что она должна быть отсортирована по таблице INNER ... которая не существует.
Единственное исключение из самой базы данных:
PSQLException: ОШИБКА: синтаксическая ошибка в или около ","
Как применить разбиение на страницы / сортировку к запросу с левым соединением? Добавление параметра Pageable достаточно для простых запросов с внутренними объединениями, но при левом соединении генерируется недопустимый SQL. Нужно ли применять ручную подкачку? Я делаю это неправильно, или это ошибка, о которой я должен сообщать пользователям данных Spring?
В качестве примечания я попытался обходной путь до версии 2.0.4 с использованием -- #pageable
. При этом все еще генерировался тот же недействительный SQL, но он был закомментирован, поэтому база данных не жаловалась… мои данные оказались не такими, как я ожидал.
Далее, если я уберу параметры сортировки, предел будет применен без посторонней запятой. То есть, если я передаю ему Pageable, который имеет параметры подкачки, но не сортирует параметры, он правильно возвращает запрос с примененным пределом / смещением.