JPQL 不处理日期

JPQL not working with dates

我无法使用查询中的日期从数据库中获取数据...

我正在开发使用 Spring Data JPA 和 Oracle 数据库的 Web 应用程序。我在接口中使用了 @RepositoryRestResource 注释,我只是使用 声明了一些带有命名参数的查询方法@Param@Query 注释。今天我需要添加一个带有日期的新实体。在数据库中,两列都是 DATE 的类型,它在查询中使用。但是我还有另一个 TIMESTAMP 类型的,也许我将来需要使用。在 Java 仅表示这两列的下方,当然包含所有 setter 和 getter,但它有更多字段,因此只需添加:

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "INIT_DATE")
private Calendar initDate;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "AGG_DATE")
private Calendar aggDate;

我还为案例创建了新界面,与往常一样:

@RepositoryRestResource(collectionResourceRel = "customer", path = "customer")
public interface ICustomerRepository extends PagingAndSortingRepository<Customer, Long> {

    @Query("SELECT c FROM Customer c where c.initDate <= TO_DATE(:currentDate, 'yyyy-MM-dd') AND c.aggDate >= TO_DATE(:currentDate, 'yyyy-MM-dd')")
    public List<Customer> filterByDate(@Param("currentDate") @DateTimeFormat(pattern = "yyyy-MM-dd") Calendar currentDate);

}

我收到了这个错误:

org.springframework.dao.DataIntegrityViolationException: could not extract ResultSet; SQL [n/a]; nested exception is org.hibernate.exception.DataException: could not extract ResultSet
ORA-01858: a non-numeric character was found where a numeric was expected

我正在尝试使用此 http 请求从数据库中获取此数据:

http://localhost/webApp/customer/search/filterByDate?currentDate=2017-07-10

在 SQL 开发人员中查询工作正常。

我在某处读到 JPQL 中没有日期函数,但在日志中我可以看到如下所示的查询和参数:

select
    customer0_.customerId as col_0_0_,
    customer0_.customerName as col_0_1_,
    customer0_.aggDate as col_0_2_,
    customer0_.initDate as col_0_3_,
from
    customer customer0_ 
where       
    and customer0_.aggDate>=to_date(?, 'yyyy-MM-dd') 
    and customer0_.initDate<=to_date(?, 'yyyy-MM-dd')
2017-07-25 11:55:22.550 TRACE 12252 --- [ (self-tuning)'] o.h.type.descriptor.sql.BasicBinder      : binding parameter [8] as [TIMESTAMP] - [java.util.GregorianCalendar[time=1499637600000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Berlin",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=143,lastRule=java.util.SimpleTimeZone[id=Europe/Berlin,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2017,MONTH=6,WEEK_OF_YEAR=28,WEEK_OF_MONTH=3,DAY_OF_MONTH=10,DAY_OF_YEAR=191,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=2,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=3600000,DST_OFFSET=3600000]]
2017-07-25 11:55:22.550 TRACE 12252 --- [ (self-tuning)'] o.h.type.descriptor.sql.BasicBinder      : binding parameter [9] as [TIMESTAMP] - [java.util.GregorianCalendar[time=1499637600000,areFieldsSet=true,areAllFieldsSet=true,lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Berlin",offset=3600000,dstSavings=3600000,useDaylight=true,transitions=143,lastRule=java.util.SimpleTimeZone[id=Europe/Berlin,offset=3600000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=2,startMonth=2,startDay=-1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2,endMonth=9,endDay=-1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]],firstDayOfWeek=1,minimalDaysInFirstWeek=1,ERA=1,YEAR=2017,MONTH=6,WEEK_OF_YEAR=28,WEEK_OF_MONTH=3,DAY_OF_MONTH=10,DAY_OF_YEAR=191,DAY_OF_WEEK=2,DAY_OF_WEEK_IN_MONTH=2,AM_PM=0,HOUR=0,HOUR_OF_DAY=0,MINUTE=0,SECOND=0,MILLISECOND=0,ZONE_OFFSET=3600000,DST_OFFSET=3600000]]

老实说,我不知道这里有什么问题...数据库中的格式日期是 yy/MM/DD,但它对我也不起作用...你能告诉我吗我错过了什么或做错了什么??

编辑 [对 Gusti Arya 的回答]:

我尝试了两件事。在您更新之前,我只是更改了类型并保留了@DateTimeFormat。然后我遇到了与 Calendar 类型相同的错误。 删除@DateTimeFormat 后,更新后使用相同的格式我收到此错误:

org.springframework.data.repository.support.QueryMethodParameterConversionException: Failed to convert 2017-07-10 into java.util.Date!
Caused by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [org.springframework.data.repository.query.Param java.util.Date] for value '2017-07-10'; nested exception is java.lang.IllegalArgumentException

更有趣的是,我有第二个几乎相同的查询,但没有 TO_DATE 函数,现在我有与上面相同的错误。以前我有:

Persistent Entity Must not be null

EDIT 2 [与日志中的查询相关]:

我刚刚注意到我在此处发布的查询与我在日志中看到的不一样...我的实体包含 EmbeddedId,其中包含 customerId 和 customerName。这两列出现了三次......所以这里是查询的有效日志:

select
    customer0_.customerId as col_0_0_,
    customer0_.customerName as col_0_1_,
    customer0_.customerId as col_1_0_,
    customer0_.customerName as col_1_1_,
    customer0_.customerId as customerId1_6_,
    customer0_.customerName as customerName2_6_,
    customer0_.aggDate as aggDate3_6_,
    customer0_.initDate as initDate4_6_,
from
    customer customer0_ 
where       
    and customer0_.aggDate>=to_date(?, 'yyyy-MM-dd') 
    and customer0_.initDate<=to_date(?, 'yyyy-MM-dd')

**编辑[对布赖恩的回应]:**

还有Entity里面的类型应该是Calendar吧?我还为这两个字段放置了两个不同的时间注释。一个指向 TemporalType.TIMESTAMP,另一个指向 TemporalType.DATE。但是接下来是将日历值作为 http 参数传递的问题。我试了四个版本 URL:

1. http://localhost/webApp/customer/search/filterByDate?currentDate=2017-07-10
2. http://localhost/webApp/customer/search/filterByDate?currentDate=2017-07-10 13:08:24.000+0000
3. http://localhost/webApp/customer/search/filterByDate?currentDate=2017-07-10T13:08:24.000+0000
4. http://localhost/webApp/customer/search/filterByDate?currentDate=1499692104

但是 none 这不起作用...

尝试将模型 class 中的代码更改为:

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "INIT_DATE")
private java.util.Date initDate;

@Temporal(TemporalType.TIMESTAMP)
@Column(name = "AGG_DATE")
private java.util.Date aggDate;

并且在 JPQL 中未定义 TO_DATE 函数,请尝试将您的 jqpl 更改为:

@Query("SELECT c FROM Customer c where c.initDate <= :currentDate AND c.aggDate >= :currentDate"
public List<Customer> filterByDate(@Param("currentDate") Date currentDate);

JPQL 中没有 TO_DATE 函数。您应该使用本机 sql 查询,或将本机数据库函数包装到 JPQL FUNCTION 函数中:)

我觉得应该是FUNCTION(TO_DATE('2000-01-01', 'YYYY-MON-DD'))

无需进一步深入细节,我认为您只需更改

@Query("SELECT c FROM Customer c where c.initDate <= TO_DATE(:currentDate, 'yyyy-MM-dd') AND c.aggDate >= TO_DATE(:currentDate, 'yyyy-MM-dd')")

@Query("SELECT c FROM Customer c where c.initDate <= :currentDate AND c.aggDate >= :currentDate")

为什么?因为字段 initDateaggDatejava.util.Calendar 类型,所以参数 currentDate 也是。一切都匹配并且 Spring 数据以及任何 JPA 提供程序将 java.util.Calendar 绑定到 SQL 时间戳,正如您在日志中看到的那样

...binding parameter [8] as [TIMESTAMP]...

我犯了一个大错误......问题不在于日期,而在于查询和实体......在我的实际应用程序中,我有 @EmbeddedId 的实体,我确信查询没有日期过滤器工作正常......所以我没有提到它。不幸的是,问题是这个 @EmbeddedId...我认为我可以使用带有 c.customerId, c 的查询,这将 return 一切,但是没有工作并且没有 c.customerId returns 只有实体没有 EmbeddedId.

正如@Brian 在他的评论中提到的那样:

The ID should be part of the self URL in your JSON response. Including the ID in the JSON object would be redundant. Nonetheless you can expose it via config. See for details.

总而言之,查询在没有 TO_DATE 函数的情况下工作,日历参数带有 @DateTimeFormat 注释,实体中带有日期的字段带有 @Temporal 注释。

感谢您的帮助,对于这个错误,我们深表歉意。