Как наложить LIMIT на подзапрос запроса JPA? - PullRequest
9 голосов
/ 19 декабря 2011

Можно ли наложить ограничение на подзапрос в запросе JPA?

У меня следующий запрос в чистом SQL

select * from ipinfo 
where RangeEnd < (select RangeStart from ipinfo where RangeStart >= 1537022421 order by RangeStart asc limit 1) and (1537022421 <= RangeEnd)
ORDER BY RangeEnd desc
limit 1

Преобразование его непосредственно в JPQL У меня будет что-то вроде

select obj from IpInfo obj
where obj.rangeEnd < (select obj2.rangeStart from IpInfo obj2 where obj2.rangeStart >= ?1 order by obj2.rangeStart asc limit 1) and (?1 <= obj.rangeEnd)
ORDER BY obj.rangeEnd desc
limit 1

Поскольку я не могу использовать LIMIT в JPQL, мне нужно будет использовать setMaxResults(1) для него.Но как насчет подзапроса?

Обновление:

Я решил пока использовать @NamedNativeQuery, но это специфичный для БД код.Если вы, ребята, можете предложить чистое решение JPA, я буду очень признателен.

Ответы [ 3 ]

2 голосов
/ 19 декабря 2011

Я не знаю, как это сделать с JPQL, но вы, вероятно, можете справиться с этим с помощью API Criteria, по крайней мере, я уверен, что мы можем сделать это с помощью подзапросов критериев Hibernate, так что я думаю, что это возможно и с JPA, даже если API-критерии JPA меня немного смущают.

Проверьте это: JPA 2.0, API критериев, подзапросы, в выражениях

В любом случае вам даже не нужно ограничение на ваш подзапрос.

Ваш оригинальный запрос: выберите RangeStart из ipinfo, где RangeStart> = 1537022421, порядок по пределу RangeStart asc 1 Кажется, вы хотите минимальный RangeStart вашего списка ipinfo, который чуть выше заданного значения. Для этого была создана функция min.

Вы можете просто использовать подзапрос, подобный этому:

select min(RangeStart) from ipinfo where RangeStart >= 1537022421

Даже если вам нужен другой ipinfo, возвращенный в вашем подзапросе, это можно сделать с помощью чего-то подобного:

select RangeEnd, anything,blabla from ipinfo where RangeStart = (
    select min(RangeStart) from ipinfo where RangeStart >= 1537022421
)
0 голосов
/ 04 августа 2018

Для этого не существует чистого решения JPA. Вы можете использовать пользовательскую функцию SQL , которая выполняется во время генерации SQL-запроса. Все провайдеры JPA так или иначе поддерживают что-то подобное.

Если вы не хотите реализовывать это самостоятельно или даже хотите использовать надлежащий API для создания таких запросов, я могу только порекомендовать вам реализованную мной библиотеку под названием Blaze-Persistence .

Вот документация, демонстрирующая вариант использования лимита / смещения с подзапросами: https://persistence.blazebit.com/documentation/1.2/core/manual/en_US/index.html#pagination

Ваш запрос может выглядеть так с API построителя запросов:

criteriaBuilderFactory.create(entityManager, IpInfo.class)
  .where("rangeEnd").lt()
    .from(IpInfo.class, "subInfo")
    .select("subInfo.rangeStart")
    .where("subInfo.rangeStart").geExpression("1537022421")
    .orderByAsc("subInfo.rangeStart")
    .setMaxResults(1)
  .end()
  .where("1537022421").leExpression("rangeEnd")
  .orderByDesc("rangeEnd")
  .setMaxResults(1)

По сути, это сводится к использованию LIMIT функции SQL , зарегистрированной в Blaze-Persistence. Поэтому, когда вы загружаете Blaze-Persistence с помощью EntityManagerFactory, вы даже можете использовать его следующим образом

entityManager.createQuery(
    "select * from ipinfo where RangeEnd < LIMIT((" +
    "  select RangeStart " +
    "  from ipinfo " +
    "  where RangeStart >= 1537022421 " +
    "  order by RangeStart asc" +
    "),1) " +
    "and (1537022421 <= RangeEnd)" +
    "ORDER BY RangeEnd desc"
).setMaxResults(1)

Если вы используете EclipseLink, соглашение о вызове таких функций выглядит как OPERATOR('LIMIT', ...).

0 голосов
/ 01 августа 2018

В настоящее время невозможно добавить LIMIT (maxResults) или OFFSET (startIndex) через JPQL, и это невозможно сделать в подзапросе JPA.Существует открытый билет JPA для добавления этой функциональности:

https://github.com/eclipse-ee4j/jpa-api/issues/88

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...