很明显,JPA 2.1 does not support the Java 8 Date/Time API.
作为解决方法,最常见的建议是使用AttributeConverter
.
在我现有的应用程序中,我将实体更改为使用LocalDate / LocalDateTime类型作为列映射字段,并将java.util.Date的旧的setter / getter添加到它们.
我创建了相应的AttributeConverter类.
当使用Query.setParameter()与java.util.Date实例(它在转换到新的API之前工作)时,我的应用程序现在失败.似乎JPA期望新的日期类型,并且不会即时转换它.
我预计如果将参数传递给已注册了AttributeConverter的类型的setParameter(),它将被转换器自动转换.
但是似乎并非如此,至少不要使用EclipseLink 2.6.2:
java.lang.IllegalArgumentException: You have attempted to set a value of type class java.util.Date for parameter closeDate with expected type of class java.time.LocalDate from query string SELECT obj FROM [...] at org.eclipse.persistence.internal.jpa.QueryImpl.setParameterInternal(QueryImpl.java:937) ~[eclipselink-2.6.2.jar:2.6.2.v20151217-774c696] at org.eclipse.persistence.internal.jpa.EJBQueryImpl.setParameter(EJBQueryImpl.java:593) ~[eclipselink-2.6.2.jar:2.6.2.v20151217-774c696] at org.eclipse.persistence.internal.jpa.EJBQueryImpl.setParameter(EJBQueryImpl.java:1) ~[eclipselink-2.6.2.jar:2.6.2.v20151217-774c696] [...]
问题:
这个行为是否预期?我错过了什么?
>有没有办法使用新的日期类型作为字段,而不会破坏现有的代码?
>您是如何处理在JPA中过渡到新的Date / Time API?
更新:
但是,似乎至少使用EclipseLink,存在AttributeConverter的自定义类型不完全支持:
在JPQL查询中,实际的字段类型和转换的数据库类型都不能用作参数.
使用转换的数据库类型时,会发生上述异常.
当使用实际的字段类型(例如LocalDate)时,它直接传递给不知道此类型的jdbc驱动程序:
Caused by: java.sql.sqlException: Invalid column type at oracle.jdbc.driver.OraclePreparedStatement.setObjectCritical(OraclePreparedStatement.java:10495) at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:9974) at oracle.jdbc.driver.OraclePreparedStatement.setObjectInternal(OraclePreparedStatement.java:10799) at oracle.jdbc.driver.OraclePreparedStatement.setObject(OraclePreparedStatement.java:10776) at oracle.jdbc.driver.OraclePreparedStatementWrapper.setObject(OraclePreparedStatementWrapper.java:241) at org.eclipse.persistence.internal.databaseaccess.DatabasePlatform.setParameterValueInDatabaseCall(DatabasePlatform.java:2506)
我希望EclipseLink使用AttributeConverter将字段类型转换为java.sql类型.
(另见这个bug报告:https://bugs.eclipse.org/bugs/show_bug.cgi?id=494999)
这导致我们最重要的问题#4:
>有没有解决方法/解决方案来支持使用EclipseLink的java 8日期字段,包括在这样一个字段上使用查询参数的可能性?
附加信息
> AttributeConverter used (for LocalDateTime conversion)
> Additional information to reproduce exception
解决方法
>是的,这个行为是预期的,因为AttributeConverter只能在用于实体字段的类型和数据库类型(即java.sql.Date等)之间进行转换;它不会在查询参数中使用的实体字段类型和java.util.Date之间进行转换.
>据我所知,不,在向JPA实体中引入java.time类型之后,没有办法继续在现有代码中继续使用java.util.Date.
>除了创建必要的AttributeConverter实现之外,我将java.util.Date的所有出现次数更改为适当的java.time类型,不仅在实体中,而且还在JPA-QL查询和业务方法中.
对于项目2,当然可以通过使用在java.util和java.time之间转换的实用程序方法和getter / setter来进行某种改变,但是不会一直发生.更重要的是,如果您不愿意转换剩余的使用这些代码的代码,我不太明白将java.time类型引入到JPA实体属性中属性.在Java EE应用程序进行转换后,没有使用任何java.util.Date(尽管我也必须为JSF创建转换器).