Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JPA2.1:引入Java8日期/时间API_Java_Hibernate_Jpa_Eclipselink_Jpa 2.1 - Fatal编程技术网

JPA2.1:引入Java8日期/时间API

JPA2.1:引入Java8日期/时间API,java,hibernate,jpa,eclipselink,jpa-2.1,Java,Hibernate,Jpa,Eclipselink,Jpa 2.1,我想在启用JPA的应用程序中为Java 8日期/时间API(JSR-310)添加支持。 很明显,JPA2.1 作为一种解决方法,最常见的建议是使用 在我现有的应用程序中,我将实体更改为对列映射字段使用LocalDate/LocalDateTime类型,并为它们添加了java.util.Date的旧setter/getter。 我创建了相应的AttributeConverter类 我的应用程序现在在使用Query.setParameter()和java.util.Date实例时失败了(它在转换到新

我想在启用JPA的应用程序中为Java 8日期/时间API(JSR-310)添加支持。

很明显,JPA2.1
作为一种解决方法,最常见的建议是使用

在我现有的应用程序中,我将实体更改为对列映射字段使用
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内部向新的日期/时间API的过渡的

  • 更新:

    但是,似乎至少在使用EclipseLink时,
    属性转换器
    存在的自定义类型并没有得到完全支持:

    在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类型。 (另请参见此错误报告:)

    这就引出了最重要的问题#4:

  • 是否有一种变通方法/解决方案支持使用
    EclipseLink
    的java 8日期字段,包括在此类字段上使用查询参数的可能性
  • 其他信息


    不久前,我将Java EE 7 web应用程序从Java 7转换为Java 8,并将实体中的
    Java.util.Date
    替换为
    LocalDate
    LocalDateTime

  • 是的,这种行为是预期的,因为
    AttributeConverter
    仅在用于实体字段的类型和数据库类型之间转换(即
    java.sql.Date
    等);它不会在实体字段类型和查询参数中使用的
    java.util.Date
    之间转换
  • 据我所知,不,在将
    java.time
    类型引入JPA实体之后,没有办法在现有代码中继续使用
    java.util.Date
  • 除了创建必要的
    AttributeConverter
    实现之外,我还将
    java.util.Date
    的所有出现更改为适当的
    java.time
    类型,不仅在实体中,而且在JPA-QL查询和业务方法中
  • 对于第2项,您当然可以通过使用实用程序方法和getter/setter在
    java.util
    java.time
    之间进行转换来实现,但它不会一直实现。更重要的是,如果您不愿意转换使用这些属性的剩余代码,我不太明白将
    java.time
    类型引入JPA实体属性的意义
    属性。在我在那个JavaEE应用程序中完成转换工作后,
    Java.util.Date
    的用途就没有了(尽管我还必须为JSF创建转换器)。

    AttributeConverter按设计工作,因为转换器是用来处理实体类型和数据库类型之间的来回转换。验证是验证参数的类型是否与实体中的类型不匹配-仅仅因为属性转换器可以处理它,并不意味着它符合属性转换器类型的约定。JPA只说它将在进入数据库之前通过转换器,在这种情况下它不会进入数据库

    如果你不喜欢罗盖里奥的建议,你可以 1) 修改EclipseLink代码以放松验证,使其能够通过转换器,或者
    2) 改为将属性类型更改为“Object”,以便您可能传入的所有参数类型都将进入转换器。

    由于提供程序本身存在许多错误,我认为您除了在映射级别使用
    java.util.Date
    和在API级别使用java 8日期之外别无选择

    假设您为名为
    DateUtils
    的实用程序编写了一个类,您可以按如下方式定义映射:

    @Entity
    public class MyEntity {
    
      @Column("DATE")
      private Date date; // java.util.Date
    
      public void setDate(LocalDateTime date) {
        this.date = DateUtils.convertToDate(date);
      }
    
      public LocalDateTime getDate() {
        return DateUtils.convertFromDate(date);
      }
    }
    
    然后在JPQL中按日期过滤:

    public List<MyEntity> readByDateGreaterThan(LocalDateTime date) {
      Query query = em.createQuery("select e from MyEntity e where e.date > :date");
      query.setParameter("date", DateTuils.convertToDate(date));
      return query.getResultList();
    }
    
    公共列表读取日期大于(LocalDateTime日期){
    Query Query=em.createQuery(“从MyEntity e中选择e,其中e.date>:date”);
    query.setParameter(“日期”,dateUils.convertToDate(日期));
    返回query.getResultList();
    }
    

    因此,
    java.util
    日期将在实体和DAO(存储库)内部使用,而实体和DAO公开的API将获取/返回java 8日期,从而使应用程序的其余部分只能使用java 8日期操作。

    我有以下设置:

    • EclipseLink v2.6.2
    • h2数据库v1.4.191
    • 爪哇8
    实体类类似于:

    @Entity
    public class MeasuringPoint extends BaseEntity {
    
        @Column(nullable = false)
        private LocalDateTime when;
    
        public void setWhen(LocalDateTime when) {
            this.when = when;
        }
    
        public LocalDateTime getWhen() {
            return when;
        }
    
    }
    
    JPA 2.1所需的转换器为:

    @Converter(autoApply = true)
    public class LocalDateTimeConverter implements AttributeConverter<LocalDateTime, Timestamp> {
    
        @Override
        public Timestamp convertToDatabaseColumn(LocalDateTime attribute) {
            return attribute == null ? null : Timestamp.valueOf(attribute);
        }
    
        @Override
        public LocalDateTime convertToEntityAttribute(Timestamp dbData) {
            return dbData == null ? null : dbData.toLocalDateTime();
        }
    
    }
    
    @转换器(autoApply=true)
    公共类LocalDateTimeConverter实现AttributeConverter{
    @凌驾
    公众的
    
    List<?> result = em.createQuery(
             "SELECT p FROM MeasuringPoint p WHERE p.when = :custDate")
             .setParameter("custDate", LocalDateTime.now())
             .getResultList();