Исключение SQLSyntaxErrorException: ORA-00932: несогласованные типы данных: ожидаемая ДАТА получена ДВОИЧНОЙ

#java #oracle #hibernate #jpa

#java #Oracle #переход в спящий режим #jpa

Вопрос:

Я был бы признателен за некоторую помощь в этом исключении.

Я провел некоторое исследование этой ошибки, но не смог найти решение. Я использую JPA с гибернацией и получаю эту ошибку при выполнении запроса.

Очевидно, есть что-то, чего я не понимаю в Java LocalDate и oracle Date. 🙁

Это объект:

 @Entity
@Table(name = "MY_TABLE")
public class MyObject implements Serializable {

    private static final long serialVersionUID = 1731972128723930612L;

    @Id
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "OTHER_ID", nullable = false)
    private OtherObject otherObject;

    @Column(name = "MY_DATE", columnDefinition="DATE", nullable = false)
   // @Convert(converter = LocalDateSQLDateConverter.class)
   // @Convert(converter = LocalDateConverter.class)
    private LocalDate date;
  

Как вы можете видеть, я пытался использовать конвертеры, которые преобразуют LocalDate в java.util.Date или java.sql.Date и наоборот — оба, к сожалению, не помогли.

Это запрос:

 public class MyDao extends BaseDao {

    public void save(MyObject object) {
        entityManager.persist(object);
    }

    public MyObject findByDate(LocalDate date) {
        TypedQuery<MyObject> query = entityManager.createQuery("SELECT w from MyObject w"
                  " where w.date = :date", MyOBject.class)
                .setParameter("date", date);
        return query.getResultList().stream().findFirst().orElse(null);
    }
  

Это исключение:

java.sql.SQLSyntaxErrorException: ORA-00932: несогласованные типы данных: ожидаемая ДАТА получена ДВОИЧНОЙ

oracle.jdbc.driver.Ошибка T4CTTIoer.Processor(T4CTTIoer.java:445) oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396) oracle.jdbc.driver.Ошибка T4C8Oall.Processor(T4C8Oall.java:879) oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:450) oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:192) oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531) oracle.jdbc.driver.T4CPreparedStatement.doOall8(t4cpreparredstatement.java:207) oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:884) oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1167) oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1289) oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3584) oracle.jdbc.driver.OraclePreparedStatement.ExecuteQuery(OraclePreparedStatement.java:3628) oracle.jdbc.driver.OraclePreparedStatementWrapper.ExecuteQuery(OraclePreparedStatementWrapper.java:1493) org.jboss.jca.adapters.jdbc.WrappedPreparedStatement.ExecuteQuery(WrappedPreparedStatement.java:462) org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.extract(ResultSetReturnImpl.java:79) org.hibernate.loader.Loader.getResultSet(Loader.java:2090) org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1887) org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1866) org.hibernate.loader.Loader.doQuery(Loader.java:905) org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:347) org.hibernate.loader.Загрузчик.Список(Loader.java:2578) org.hibernate.loader.Загрузчик.Список(Loader.java:2564) org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2394) org.hibernate.loader.Loader.list(Loader.java:2389) org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:495) org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:357) org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:198) org.hibernate.internal.SessionImpl.list(SessionImpl.java:1230) org.hibernate.internal.Запрос IMPL.list(запрос IMPL.java:101) org.hibernate.ejb.Запрос IMPL.getResultList(запрос IMPL.java:268) my.company.path.MyDao.findByDate(MyDaoDao.java:21)

Заранее большое спасибо за любые подсказки!

Комментарии:

1. Какая версия вашего драйвера Oracle JDBC? попробуйте более свежую!

2. К сожалению, я не смогу изменить ее, как указано в изображении jboss docker.

3. Я обнаружил, что не использовал новейшую версию JPA и изменил ее. К сожалению, проблема осталась. Я заменил LocalDate amp; LocalDateTime в своем приложении на java.util. Дата, и это работает. Но я бы действительно предпочел использовать LocalDate amp; LocalDateTime.

4. Попробуйте что-то вроде этого: thoughts-on-java.org/persist-localdate-localdatetime-jpa

5. Я тоже это обнаружил и попробовал, к сожалению, безуспешно.

Ответ №1:

Хотя это кажется нелогичным, вы должны передать строковое представление, например, так:

 SELECT * FROM xxx where date_of_birth = '1990-08-21';
  

где date_of_birth имеет тип DATE ( MySQL , не Oracle , но не должно иметь значения) и сопоставляется с LocalDate в Spring / Hibernate

Комментарии:

1. В Oracle вы можете захотеть использовать TO_CHAR() / TO_DATE() , поскольку он плохо сочетается со стандартами…

Ответ №2:

Hibernate 4 вышел до java.time.LocalDate был добавлен, и он этого не понимает. Поэтому он отправляет данные в виде двоичного файла в Oracle.

Лучшее решение — перейти на спящий режим 5.

Комментарии:

1. Ммм, на самом деле я использую hibernate-core-5.4.1.Final.jar .

2. Ваш ответ заставил меня узнать, что я не использовал JPA 2.2, который теоретически поддерживает LocalDate amp; LocalDateTime. К сожалению, проблема не была решена этим изменением.

Ответ №3:

Я узнал, что наш образ docker использует JBoss 6.4, который, согласно https://access.redhat.com/articles/112673 — использует гибернацию JPA 2.0.

Итак, это не может сработать. Нам нужен JPA 2.2 для поддержки LocalDate amp; LocalDateTime.

Я изменил все вхождения LocalDate и LocalDateTime в DAOS на Date, в то время как остальная часть моего приложения продолжает использовать LocalDate и LocalDateTime — с помощью небольшого конвертера:

 public class LocalDateConverter {

    public static Date convertToDate(LocalDate date) {
        return date != null ? Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()) : null;
    }

    public static LocalDate convertToLocalDate(Date date) {
        return date != null ? LocalDate.from(date.toInstant().atZone(ZoneId.systemDefault())) : null;
    }

    public static Date convertToDate(LocalDateTime dateTime) {
        return dateTime != null ? Date.from(dateTime.atZone(ZoneId.systemDefault()).toInstant()) : null;
    }
}
  

Теоретически, отсутствует один метод, который преобразует дату в LocalDateTime, но в моем случае мне это не нужно, потому что я использую LocalDateTime только для creationDates, которые никогда не читаются.

Ответ №4:

Проблема заключается не в отображении выходных данных, а в отображении параметра.

В то время как hibernate управляет компонентами, он знает, что должен преобразовать LocalDate в Date.

Я не знаю почему, но EntityManager не делает то же самое для ввода параметров. Я предполагаю, что EntityManager имеет более короткий список известных классов с преобразователями, а другие преобразуются с помощью toString().

Вы должны преобразовать свой входной параметр в Date:

 TypedQuery<MyObject> query = entityManager.createQuery("SELECT w from MyObject w"
              " where w.date = :date", MyOBject.class)
            .setParameter("date",Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()));
  

Если вы используете Spring, вы также можете org.springframework.data.jpa.repository.Запрос

  @Query("SELECT w from MyObject w where w.date = :date")
 public MyObject findByDate(LocalDate date);
  

Он автоматически преобразует ваш входной параметр.