最新的 Spring Data/Hibernate 在本机查询中不支持 java.time.LocalDate?
Posted
技术标签:
【中文标题】最新的 Spring Data/Hibernate 在本机查询中不支持 java.time.LocalDate?【英文标题】:java.time.LocalDate not supported in native queries by latest Spring Data/Hibernate? 【发布时间】:2018-04-05 19:33:00 【问题描述】:问题:带有 Spring Data 返回日期的本机查询返回 java.sql.Date 而不是 java.time.LocalDate,尽管进行了设置。
上下文:一个带有 Spring Boot 2.0.0.M5(最新)、Hibernate 5.2.11、Hibernate-Java8 5.2.12(只要它在类路径上就支持 JSR310 类)的新项目。
下面的匿名示例(该应用与生日无关):
public interface BirthdayRepository<T, ID extends Serializable> extends Repository<T, ID>
@Query(value = "select day from birthdays", nativeQuery = true)
Iterable<java.sql.Date> getBirthdays(); //the return type should ideally be java.time.LocalDate
在数据库(SQL Server)中,day 字段为 DATE,值类似于 2017-10-24。
问题是在运行时,Spring Data 存储库(我无法控制其实现,或者有办法吗?)返回 java.sql.Date
而不是 java.time.LocalDate
(澄清:返回类型似乎是由 Spring Data 决定的,即使我将返回类型更改为 java.time.LocalDate
,也仍然是 java.sql.Date
,这是我开始的方式。
没有办法直接得到LocalDate
吗?我可以稍后转换它,但是(1)效率低下,(2)存储库方法必须返回旧的日期/时间类,这是我想避免的。我阅读了 Spring Data documentation,但没有任何内容。
编辑:对于任何有同样问题的人,下面是解决方案,Jens 建议的转换器。
public class LocalDateTypeConverter
@Converter(autoApply = true)
public static class LocalDateConverter implements AttributeConverter<LocalDate, Date>
@Nullable
@Override
public Date convertToDatabaseColumn(LocalDate date)
return date == null ? null : new Date(LocalDateToDateConverter.INSTANCE.convert(date).getTime());
@Nullable
@Override
public LocalDate convertToEntityAttribute(Date date)
return date == null ? null : DateToLocalDateConverter.INSTANCE.convert(date);
【问题讨论】:
我很困惑。你在你的界面中指定了你想要的Iterable<java.sql.Date>
为什么你还期待别的?为什么“存储库方法必须返回旧的日期/时间类?”
这就是 Spring Data 返回的内容。如果我输入 LocalDate (我最初这样做),当我从迭代器中检索项目时,它会在运行时失败并出现 ClassCastException。这就是为什么我发表评论的原因,类型应该是。我将补充说明。
【参考方案1】:
我知道这是一个较老的问题,但我对这个问题的解决方案不需要自定义转换器。
public interface BirthdayRepository<T, ID extends Serializable> extends Repository<T, ID>
@Query(value = "select cast(day as date) from birthdays", nativeQuery = true)
Iterable<java.time.LocalDate> getBirthdays();
CAST
告诉 JPQL 使用可用的 java date\time 类型而不是 java.sql.Date
【讨论】:
酷!效果很好!【参考方案2】:您似乎在转换器中发现了一个缺口。 Spring Data 在java.util.Date
和java.time.LocalDate
之间进行开箱即用的转换,但不在java.time.LocalDate
和java.sql.Date
以及java.sql
包中的其他日期和时间相关类型之间进行转换。
您可以创建自己的转换器来做到这一点。您可以使用Jsr310JpaConverters 作为模板。
此外,您可能想要创建一个功能请求,如果您构建一个转换器供您使用,您甚至可以提交一个拉取请求。
【讨论】:
谢谢,珍。如果知道的话,您能否澄清一下为什么 Spring Data(或者它是驱动程序)选择java.sql.Date
而不是java.util.Date
或java.time.Date
?数据库中的字段类型是日期(对于 SQL Server,就是它所说的,只是 YYYY-MM-DD)。在 3 种可能性中,如何选择特定的一种?另外,鉴于查询是本机的,如何告诉 Spring Data 使用它作为返回类型?没有什么要注释的,就像 JPA 实体和列的情况一样。谢谢。
无需查看代码的任何细节:Spring Data 可能只是将驱动程序提供的任何内容作为默认值,然后尝试使用其转换器将其转换为所需的类型。但在这种情况下,没有合适的转换器。
我怀疑转换器匹配逻辑着眼于完全相同的类,而不是子类。 java.sql.Date
是 java.util.Date
的子类(一个有用的讨论 here 所以后者的转换器应该/可以激活,但它没有。然后我会处理转换器。
转换器工作正常,所以我会完全接受答案。以上是关于最新的 Spring Data/Hibernate 在本机查询中不支持 java.time.LocalDate?的主要内容,如果未能解决你的问题,请参考以下文章
JPA---Spring-data-JPA---Hibernate
Java SE + Spring Data + Hibernate
优化 Spring-data / Hibernate ManyToMany 插入