JPA Criteria API:数据库中两个日期之间的差异?

时间:2015-11-03 12:47:43

标签: java jpa query-builder

简单问题:我有一个(MySQL)表,有两个日期列(从,直到),并用

询问
select * from mytable where until > from + interval 4 week;

这在MySQL中非常简单。

如何在JPA Query中执行此操作,如

cq.where(cb.and(mytable_.get(until),...)

编辑:两个日期都来自数据库行,我比较数据库的两个字段,而不是应用程序中的一个字段和数据库中的一个字段。

3 个答案:

答案 0 :(得分:4)

以下是

的等效JPA标准查询的说明
  

从mytable中选择*,直到>从+间​​隔4周开始;

首先,您必须创建单元表达式并从BasicFunctionExpression对其进行扩展,对于BasicFunctionExpression,它将“ WEEK”参数作为单元并仅覆盖其rendor(RenderingContext renderingContext)方法。

import java.io.Serializable;
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
import org.hibernate.query.criteria.internal.compile.RenderingContext;
import org.hibernate.query.criteria.internal.expression.function.BasicFunctionExpression;

public class UnitExpression extends BasicFunctionExpression<String> implements Serializable {

  public UnitExpression(CriteriaBuilderImpl criteriaBuilder, Class<String> javaType,
      String functionName) {
    super(criteriaBuilder, javaType, functionName);
  }

  @Override
  public String render(RenderingContext renderingContext) {
    return getFunctionName();
  }
}

然后在JPA条件查询中使用此单位表达式。

 CriteriaBuilder cb = session.getCriteriaBuilder();
    CriteriaQuery<MyTable> cq = cb.createQuery(MyTable.class);
    Root<MyTable> root = cq.from(MyTable.class);

    Expression<String> week= new UnitExpression(null, String.class, "WEEK");
    Expression<Integer> timeDiff = cb.function(
        "TIMESTAMPDIFF",
        Integer.class,
        week,
        root.<Timestamp>get(MyTable_.until),
        root.<Timestamp>get(MyTable_.from));
    List<Predicate> conditions = new ArrayList<>();
    conditions.add(cb.greaterThan(timeDiff, 4));
    cq.where(conditions.toArray(new Predicate[]{}));
    return session.createQuery(cq);

一切正常。

答案 1 :(得分:2)

EDIT2:找到解决方法

因为我们只需要处理不需要内置参数的函数(比如WEEK),所以我最终得到了

cb.greaterThan(
  cb.diff(
    cb.function("unix_timestamp", Long.class, root.get(Table_.until)),
    cb.function("unix_timestamp", Long.class, root.get(Table_.from))
  )
, 3600L*longerThanHours)

供参考导致死胡同的版本:

没有办法让它像这样工作,你不能发送“小时”而不将“”作为参数包含在数据库中。

CriteriaBuilder cb = ...;
CriteriaQuery<MyTable> cq = cb.createQuery(MyTable.class);
Root<MyTable> mytable = cq.from(MyTable.class);

cb.greaterThan(
   cb.function(
      "timestampdiff"
      , Integer.class
      , WEEK // <-- this is where JPA gets unable to create SQL
      , mytable.get(MyTable_.from)
      , mytable.get(MyTable_.until)
   )
   , 4
)

答案 2 :(得分:0)

**使用标准 api 在两个日期之间获取实体的示例示例 ** 其中日期范围介于 startDate 和 endDate 之间:-

public EntityClass getResultEntities(Date startDate, Date endDate){
          CriteriaBuilder builder = em.getCriteriaBuilder();
          CriteriaQuery<EntityClass> criteria = builder.createQuery(EntityClass.class);
          Root<OrderImpl> entityClass = criteria.from(EntityClassImpl.class);
          criteria.select(entityClass);
          criteria.where(builder.between(entityClass.<Date>get("submitDate"), startDate, endDate));
          criteria.orderBy(builder.desc(entityClass.get("submitDate")));
          TypedQuery<EntityClass> query = em.createQuery(criteria);
          return query.getResultList();
    }