JPQL无法使用日期

时间:2017-07-25 10:01:39

标签: java rest spring-boot spring-data-jpa jpql

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

我正在使用Spring Data JPA和Oracle Database的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;

我还为case创建了新的界面,与以往一样:

@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 Developer中,查询工作正常。

我在某处看过,在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

编辑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')

**编辑[回应Brian]:**

实体中的类型也应该是日历,对吧?我还为这两个字段添加了两个不同的时间注释。一个指向TemporalType.TIMESTAMP,另一个指向TemporalType.DATE。但是传递日历值作为http参数的问题是。我尝试了四个版本的网址:

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

但这一切都没有用......

4 个答案:

答案 0 :(得分:2)

如果不进一步深入细节,我认为你只需要改变

@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")

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

  

...绑定参数[8]为[TIMESTAMP] ...

答案 1 :(得分:1)

我犯了大错...问题不在于日期,而在于查询和实体......在我的实际应用程序中,我有@EmbeddedId的实体,我确信没有过滤器的查询在日期工作正常...所以我没有提到它。不幸的是,问题是@EmbeddedId ...我认为我可以使用c.customerId, c的查询来返回所有内容但不起作用而没有c.customerId只返回没有{{1}的实体}}

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

  

该ID应该是JSON响应中自我URL的一部分。在JSON对象中包含ID将是多余的。尽管如此,您可以通过config公开它。有关详细信息,请参阅this question and answer

总而言之,查询无需使用EmbeddedId函数,TO_DATE注释用于Calendar参数,@DateTimeFormat注释用于包含实体中日期的字段。

感谢您的帮助,对不起这个错误。

答案 2 :(得分:0)

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

@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);

答案 3 :(得分:0)

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

我认为它应该是FUNCTION(TO_DATE('2000-01-01', 'YYYY-MON-DD'))