Java:使用JPQL日期函数将时间段添加到另一个日期

30
SELECT x FROM SomeClass
WHERE x.dateAtt BETWEEN CURRENT_DATE AND (CURRENT_DATE + 1 MONTH)
在上述JPQL语句中,SomeClass有一个成员dateAttr,它是一个java.util.Date类型,并带有一个@Temporal(javax.persistence.TemporalType.DATE)注释。
我需要一种方法来做(CURRENT_DATE + 1 MONTH),当前状态下它显然是错误的,但是我找不到关于JPQL日期函数的文档。
有人能向我指出一个文档,其中记录了JPQL的日期函数(以及如何执行此特定查询)吗?

这是您想要在某个方法中查询吗?还是需要在实体 bean 本身的触发器中进行操作?例如:@PrePersist@PreUpdate - Shervin Asgari
@Shervin:不需要在 @PrePersist 或者 @PreUpdate 中执行查询。查询是 JPA 实体类(SomeClass)上的命名查询。 - bguiz
@Shervin:此外,我知道可以使用Java计算“Date”操作,然后使用“:parameter”将其传递到查询中,但是我更愿意在JPQL本身中完成它并避免不必要的代码。 - bguiz
我明白了,因为这是我建议的解决方法。 我不确定这些函数是否属于JPA标准。你使用的是哪个数据库? - Shervin Asgari
4个回答

22

标准JPQL不支持对日期进行这样的操作。您需要使用本地查询或在Java端进行计算。


19
这还是否属实? - span

20
如果您有一个已经加了1个月的日期对象,您可以像这样做:
public List findEmployees(Date endDate) {
  return entityManager.createQuery(
    "SELECT e from Employee e WHERE e.startDate BETWEEN ?1 AND ?2")
    .setParameter(1,new Date(), TemporalType.DATE)
    .setParameter(2,endDate, TemporalType.DATE).getResultList();
}

这需要在使用之前确保日期是有效的。

更新

如果您总是想要下一个月,可以使用 JodaTime,它具有出色且易于使用的 API。 然后,您可以像这样修改查询:

//Get next month
DateTime dt = new DateTime();
entityManager.createQuery(
"SELECT e from Employee e WHERE e.startDate BETWEEN ?1 AND ?2")
.setParameter(1,new Date(), TemporalType.DATE)
.setParameter(2,dt.plusMonths(1).toDate(), TemporalType.DATE).getResultList();

3
你试过 JodaTime 部分了吗?JPA 能处理 DateTime 类型吗? - Pascal Thivent
@Pascal:好点子。我忘了toDate()方法。它将返回一个“java.util.Date”。 - Shervin Asgari
1
轻微改进:.setParameter(1, dt.toDate(), TemporalType.DATE)(少了一个导入,与下一行保持一致) - Sean Patrick Floyd
1
这并没有真正回答“JPQL日期函数”的问题,因为JPQL本身就是一个查询规范,而这里的答案是基于Java/JPA的解决方案。无疑有获取解决方案的方法,但是...我认为下面的答案“标准JPQL不支持对日期进行此类操作”更正确。 - Darrell Teague

5

或者使用commons-lang代替jodatime:

entityManager.createQuery(
    "SELECT e from Employee e WHERE e.startDate BETWEEN ?1 AND ?2"
)
.setParameter(1,new Date(), TemporalType.DATE)
.setParameter(2,DateUtils.addMonths(new Date(), 1), TemporalType.DATE)
.getResultList();

但我知道这不是你问的问题,而且我非常确定它不能仅通过JPQL完成,你需要传递参数或使用本地命名查询。


DateUtils?那是标准 JDK 的一部分还是像 Joda 时间那样的库? - bguiz
它位于Apache Commons / Lang中,这是一个开源库,由许多框架内部使用:http://commons.apache.org/lang/ - Sean Patrick Floyd
2
最好使用Joda-Time,因为它是JSR-310(https://jsr-310.dev.java.net/)的参考实现。 - Shervin Asgari
2
是的,但在我参与的大多数项目中,commons / lang 已经在 classpath 中了。而且我认为,如果没有其他用途,就像上面所看到的简单用法并不能证明使用 joda 的必要性。 - Sean Patrick Floyd

-1
亲爱的,
我正在使用Spring Data,实体将创建日期保存为datetime,在存储库中是这样的:
@Query(value="SELECT t FROM MyEntity t WHERE t.createdDate Between ?1 and ?2")
public List<MyEntity> findAllBetweenDates(Calendar from, Calendar to);

所以我不能使用:

setParameter(1,new Date(), TemporalType.DATE

在后端的bean中,我使用以下代码:
    //to set zero of hours,minutes,seconds and milliseconds
    fromCalendar.set(java.util.Calendar.HOUR, 0);
    fromCalendar.set(java.util.Calendar.MINUTE, 0);
    fromCalendar.set(java.util.Calendar.SECOND, 0);
    fromCalendar.set(java.util.Calendar.MILLISECOND, 0);

    toCalendar.set(java.util.Calendar.HOUR, 0);
    toCalendar.set(java.util.Calendar.MINUTE, 0);
    toCalendar.set(java.util.Calendar.SECOND, 0);
    toCalendar.set(java.util.Calendar.MILLISECOND, 0);
    // add 1 days and decrease 1 millisecond
    toCalendar.add(java.util.Calendar.DAY_OF_MONTH, 1);
    toCalendar.add(java.util.Calendar.MILLISECOND, -1);

    allEntities = myEntityRepository.findAllBetweenDates(fromCalendar, toCalendar);
}

它正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接