Преобразование сложного запроса postgres в JPQL для репозитория Spring Hibernate - PullRequest
0 голосов
/ 22 ноября 2018

У меня есть следующий запрос Postgres SQL, чтобы получить alerts с самой последней date:

SELECT latest_alerts.subject_id,
       latest_alerts.alertconfiguration_id_id,
       latest_alerts.alert_level,
       latest_alerts.maxdate
FROM   (SELECT subject_id,
               alertconfiguration_id_id,
               alert_level,
               Max(date) AS maxdate
        FROM   alert
        WHERE  subject_id IN ( 'da157532-8de5-4c0c-8608-d924e670d5db', '63b99886-77c8-4784-b8f0-7ff5310f1272' )
               AND alertconfiguration_id_id IN (
                   '6feb6b8b-6b96-4d5d-ac58-713b3cd637a0'
                                               )
        GROUP  BY subject_id,
                  alertconfiguration_id_id,
                  alert_level) AS latest_alerts
       INNER JOIN alert
               ON alert.date = latest_alerts.maxdate
                  AND alert.subject_id = latest_alerts.subject_id
                  AND alert.alertconfiguration_id_id =
                      latest_alerts.alertconfiguration_id_id
                  AND alert.alert_level IN ( 'WARNING' )
ORDER  BY latest_alerts.maxdate DESC;

Это хорошо работает в базе данных postgres, созданной Hibernate.Обратите внимание, что странная конструкция id_id вызвана встроенным ключом.

Но я изо всех сил пытаюсь преобразовать это в JPA / JPQL-запрос, который я могу использовать в приложении Spring Boot.Пока у меня есть это:

@Query("SELECT" +
        " latest_alerts.subject," +
        " latest_alerts.alertConfiguration," +
        " latest_alerts.alertLevel," +
        " latest_alerts.max_date" +
        "FROM" +
        " (SELECT" +
        " subject," +
        " alertConfiguration," +
        " alertLevel," +
        " MAX(date) AS max_date" +
        " FROM" +
        " alert" +
        " WHERE" +
        " subject.id IN (:subjectIds) AND alertConfiguration.id.id IN (:alertConfigurationIds)" +
        " GROUP BY" +
        " subject, alertConfiguration, alertLevel) AS latest_alerts" +
        " INNER JOIN" +
        " alert" +
        " ON" +
        " alert.date = latest_alerts.max_date" +
        " AND alert.subject = latest_alerts.subject" +
        " AND alert.alertConfiguration = latest_alerts.alertConfiguration" +
        " AND alert.alertlevel IN (:alertLevels)" +
        " ORDER BY latest_alerts.date DESC")
Page<Alert> findLatest(@Param("subjectIds") List<UUID> subjectIds,
                       @Param("alertConfigurationIds") List<UUID> alertConfigurationIds,
                       @Param("alertLevels") List<AlertLevel> alertLevels,
                       Pageable pageable);

Но Hibernate не понимает, что с этим делать, до того момента, когда он фактически выбрасывает нулевой указатель при анализе этого запроса.

Caused by: java.lang.IllegalArgumentException: Validation failed for query for method public abstract org.springframework.data.domain.Page ournamespace.sense.repository.AlertRepository.findLatest(java.util.List,java.util.List,java.util.List,org.springframework.data.domain.Pageable)!
    at org.springframework.data.jpa.repository.query.SimpleJpaQuery.validateQuery(SimpleJpaQuery.java:93)
    at org.springframework.data.jpa.repository.query.SimpleJpaQuery.<init>(SimpleJpaQuery.java:63)
    ... many more
Caused by: java.lang.NullPointerException
    at org.hibernate.hql.internal.antlr.HqlBaseParser.identPrimary(HqlBaseParser.java:4355)
    at org.hibernate.hql.internal.antlr.HqlBaseParser.primaryExpression(HqlBaseParser.java:993)
    at org.hibernate.hql.internal.antlr.HqlBaseParser.atom(HqlBaseParser.java:3549)

ЛюбойИдея, если такой запрос вообще возможен?С помощью nullpointer, генерируемого Hibernate, немного трудно понять, какая часть запроса является проблемой.

1 Ответ

0 голосов
/ 22 ноября 2018

Не могу сделать это с Hibernate.Из документации :

Обратите внимание, что подзапросы HQL могут появляться только в предложениях select или where.

Но вы можете использовать собственный запрос:

@Query(
  value = "SELECT latest_alerts.subject_id,
       latest_alerts.alertconfiguration_id_id,
       latest_alerts.alert_level,
       latest_alerts.maxdate ...
FROM ...", 
  nativeQuery = true)
Page<Alert> findLatest(@Param("subjectIds") List<UUID> subjectIds,
                       @Param("alertConfigurationIds") List<UUID> alertConfigurationIds,
                       @Param("alertLevels") List<AlertLevel> alertLevels,
                       Pageable pageable);
...