Hibernate 5.4-java.time.LocalDate参数被错误地处理为java.util.Date

我正在尝试将java.time.LocalDate参数传递给命名查询,但是Hibernate错误地期望java.util.Date类型的参数。我在Spring Boot 2.2.5(与Hibernate 5.4.12和JPA 2.2.5)上使用Java 8。

Exception:

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:

@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...
}

我认为问题(错误?)出在命名查询中,其中从时间戳到日期的强制转换生成java.util.Data类型。实际上,如果我在相同类型的属性上使用LocalDate类型参数查询另一个实体,它将按预期工作。

但是我决定将java.sql.Date.valueOf(date)作为参数传递,但是我想知道为什么Hibernate没有按我的预期解析LocalDate。

谢谢。

0
投票

您在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 ) );
   }
}

然后使用该方言。之后,您的初始查询将起作用。