Параметр java .time.LocalDate обрабатывается как java .util.Date в запросе гибернации. - PullRequest
3 голосов
/ 30 марта 2020

Я пытаюсь передать параметр java.time.LocalDate в именованный запрос, но Hibernate ошибочно ожидал параметр типа java.util.Date. Я использую Java 8 в Spring Boot 2.2.5 (с Hibernate 5.4.12 и JPA 2.2.5).

Исключение:

    Exception - org.springframework.dao.InvalidDataAccessApiUsageException: Parameter value [2020-03-30] did not match expected type [java.util.Date (n/a)]; nested exception is java.lang.IllegalArgumentException: Parameter value [2020-03-30] did not match expected type [java.util.Date (n/a)]

Метод DAO:

java.time.LocalDate date = LocalDate.now(); // example date
result = entityManager.createNamedQuery("MyTableEntity.query", MyTableEntity.class)
        .setParameter("date", date)
        .setMaxResults(1)
        .getSingleResult();

Именованный запрос:

@NamedQuery(name = "MyTableEntity.query", query = "SELECT o FROM MyTableEntity o WHERE date(o.timestamp) = :date")

Сущность:

@Entity
@Table(name = "my_table")
public class MyTableEntity implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Long id;

    @Column(name = "time_control")
    private java.time.OffsetDateTime timestamp;

    private static final long serialVersionUID = 1L;

    // constructors...
    // getters and setters...
}

Я думаю, что проблема (ошибка?) Заключается в именованном запросе, где приведение от Timestamp к Date генерирует тип java.util.Data. Фактически, если я запрашиваю другую сущность с параметром типа LocalDate для атрибута того же типа, он работает как ожидалось.

Однако я решил эту проблему, передав java.sql.Date.valueOf(date) в качестве параметра, но я хочу знать, почему Hibernate не разрешил LocalDate, как я ожидал.

1 Ответ

1 голос
/ 30 марта 2020

Каждая функция, которую вы используете в запросе hql / jpql, должна быть объявлена ​​на используемом вами диалекте гибернации. В вашем случае объявление функции date выглядит примерно так:

import org.hibernate.type.StandardBasicTypes;

public YourDialect {

  // ...
  registerFunction( "date", new StandardSQLFunction( "date", StandardBasicTypes.DATE ) );

}

и ниже вы можете увидеть, как определяется StandardBasicTypes.DATE:

/**
 * The standard Hibernate type for mapping {@link java.util.Date} ({@link java.sql.Date}) to JDBC
 * {@link java.sql.Types#DATE DATE}.
 *
 * @see TimeType
 */
public static final DateType DATE = DateType.INSTANCE;

Вот почему вы получили упомянутое в вашем вопросе исключение. Вы можете изменить это, переопределив функцию date следующим образом:

import org.hibernate.dialect.function.StandardSQLFunction;
import org.hibernate.type.LocalDateType;

public class MyDialect extends SomeHibernateDialect
{
   public MyDialect()
   {
      super();
      registerFunction( "date", new StandardSQLFunction( "date", LocalDateType.INSTANCE ) );
   }
}

И затем используйте этот диалект. После этого ваш начальный запрос будет работать.

...