проблема с JPQL-запросом spring-data-jpa с дополнительным фильтром временных меток - PullRequest
2 голосов
/ 09 января 2020

мы столкнулись с одной проблемой. В нашем коде, который работает как минимум год, мы используем весенние репозитории с пользовательскими методами запросов, используя аннотацию @Query. В этих методах мы склонны применять фильтры к запросам на основе переданных в @Nullable параметров. До сих пор это работало хорошо, для запросов вроде этого:

@Query(value =
    "select p FROM PersonOfInterestEntity p "
        + "where (?1 is null or p.upperPoiIdentifier like ?1) "
        + "and p.status in ?2 "
        + "and (?3 is null or p.createdDtm >= ?3) "
        + "and (?4 is null or p.createdDtm <= ?4) "
        + "and p.ixTenant.id=?5 ")
Page<PersonOfInterestEntity> findAllByNamesAndDateRangeAndStatusesAndTenantId(
    @Nullable String identifier, List<StatusEnum> statuses, @Nullable Timestamp startDate, @Nullable Timestamp endDate, String tenantId, Pageable pageable);

Как указано в статьях по net, это удобный способ иметь метод с единым дао, который можно использовать для запроса с различными фильтрами, и пропустить условия для определенных столбцов в случае, если значения, переданные в NULL. Но проблема в том, что как только мы перешли на hibernate 5.4.10.Final (мы использовали hibernate 5.2.8.Final до сих пор), мы внезапно начали получать ошибку:

[ WARN] [  org.hibernate.engine.jdbc.spi.SqlExceptionHelper] - SQL Error: 932, SQLState: 42000
[ERROR] [  org.hibernate.engine.jdbc.spi.SqlExceptionHelper] - ORA-00932: inconsistent datatypes: expected TIMESTAMP got BINARY

Проблема в том, что это не только спящий режим что обновлено, но также и куча зависимостей, которые мы получаем от какой-то сторонней команды - поэтому мы не можем утверждать, что именно Hibernate является тем, что имеет значение здесь. Кроме того, мы не можем уменьшить версию Hibernate до версии 5.2.8 в обновленном коде, а также мы не можем увеличить версию Hibernate в старом коде, который прекрасно работает с этими запросами, поскольку в обоих случаях мы получаем некоторые проблемы с запуском -> которые затрудняют изоляцию что на самом деле вызывает это изменение поведения. Интересно, что тот же синтаксис все еще работает для параметров типа String (см.? 1 сразу после ключевого слова в запросе), проблема связана только с меткой времени.

Мой вопрос заключается в том, стоит ли нам смотреть на изменение в спящем режиме , spring-data-jpa или Oracle драйвер? Я не смог найти никаких документов, которые бы указывали на такую ​​обратную несоответствие. Мы действительно хотели бы пропустить необходимость обходного пути, чтобы разделить наши методы, чтобы разделить запросы для каждого нулевого / ненулевого параметра, поскольку это действительно увеличило бы беспорядок в коде, так как у нас есть много комбинаций этих необязательных параметров. А также хотел бы понять, как это работает до сих пор, и почему метка времени отличается от других типов.

update: Я только что понял, что у нас также есть некоторый специальный класс, который влияет на то, как метки времени в коде сериализуются в базу данных. Из-за запланированного порта на MySql было необходимо округлить время в дБ на 3/100 мс, поэтому у нас есть UserType, который должен быть ответственным за это. Это может как-то повлиять на привязку параметров запроса, не уверен ... Отладка кода гибернации (что довольно сложно, поскольку он не попадает в стек вызовов потоков в IDE), я заметил, что PreparedStatementParameter для части запроса выглядит следующим образом: p.createdDtm >= ?3, получает внутренний ожидаемый тип как CustomType с именем того специального класса, который был добавлен. часть запроса для параметра с тем же индексом: ?3 is null, разрешается без ожидаемого типа, что позже разрешается в привязке как (sqlTypeDescriptior = VarbinaryTypeDescriptor и javaTypeDescriptor = SerializableTypeDescriptor), а затем приводит к ошибке, которую я дал выше. Но также стоит сказать, что код, который корректирует значения меток времени, уже существовал в предыдущей версии кода, который нормально работал на hibernate 5.2.8 ... Может быть, этот пользовательский тип требует некоторых настроек для более новых версий hibernate?

1 Ответ

1 голос
/ 10 января 2020

Хорошо, это весело ... После некоторой отладки и попыток понять, почему он сломался, я понял, что тот же запрос работает, если мы используем именованные параметры!?

@Query(value =
    "select p FROM PersonOfInterestEntity p "
        + "where (:id is null or p.upperPoiIdentifier like :id) "
        + "and p.status in :statuses "
        + "and (:startDtm is null or p.createdDtm >= :startDtm) "
        + "and (:endDtm  is null or p.createdDtm <= :endDtm ) "
        + "and p.ixTenant.id=:tenantId ")
Page<PersonOfInterestEntity> findAllByNamesAndDateRangeAndStatusesAndTenantId(
    @Param("id") @Nullable String identifier,
    @Param("statuses") List<StatusEnum> statuses,
    @Param("startDtm") @Nullable Timestamp startDate,
    @Param("endDtm") @Nullable Timestamp endDate,
    @Param("tenantId") String tenantId,
    Pageable pageable);

Я думаю, что это доказывает, что это какая-то ошибка в hibernate, так как она должна работать одинаково для обоих запросов? По крайней мере, я достаточно доволен этим, надеюсь, что в будущем это также сэкономит кому-то еще время;)

Ура!

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