JPA CriteriaQuery计算用于谓词的日期时间差异

时间:2015-09-18 19:48:59

标签: java jpa

我正在尝试从我的数据库中选择两个字段之间的时间差小于或大于某个值的实体。在标准SQL中,只需使用TIMESTAMPDIFF函数即可完成:

SELECT * from run where TIMESTAMPDIFF(SECOND, run.end_time, run.start_time) > 60;

然而,在JPA 2.0中似乎没有任何等价物。

我已经尝试了我能想到的一切,包括这里的建议:Using TIMESTAMPDIFF with JPA criteria query and hibernate as the provider

predicate.getExpressions().add(criteriaBuilder.greaterThanOrEqualTo(criteriaBuilder.function("TIMESTAMPDIFF", Long.class, criteriaBuilder.literal("SECOND"), root.get(Run_.endTime), root.get(Run_.startTime)), minSeconds))

根本不起作用,因为我特意试图计算大的持续时间(60/90天)。 TIMEDIFF解决方案无效,因为可返回的最大TIMEDIFF为35天。还有其他方法可以实现这个目标吗?

3 个答案:

答案 0 :(得分:3)

以下是

的等效JPA标准查询的说明
  

SELECT *从运行中TIMESTAMPDIFF(SECOND,run.end_time,   run.start_time)> 60;

首先,您必须创建单位表达式并将其从BasicFunctionExpression扩展,对于该表达式,将“ SECOND”参数作为单位并仅覆盖其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<Run> cq = cb.createQuery(Run.class);
    Root<Run> root = cq.from(Run.class);

    Expression<String> second = new UnitExpression(null, String.class, "SECOND");
    Expression<Integer> timeDiff = cb.function(
        "TIMESTAMPDIFF",
        Integer.class,
        second,
        root.<Timestamp>get(Run_.endTime),
        root.<Timestamp>get(Run_.startTime));
    List<Predicate> conditions = new ArrayList<>();
    conditions.add(cb.greaterThan(timeDiff, 60));
    cq.where(conditions.toArray(new Predicate[]{}));
    return session.createQuery(cq);

正在工作。

答案 1 :(得分:1)

很抱歉这样说,但JPA不支持datediff功能。如果您正在使用eclipselink,则可以使用FUNC关键字,该关键字调用DB的本机功能。另外,您需要使用本机查询。

答案 2 :(得分:1)

Expression<String> month = new MyFunctionExpression(null, String.class, "MONTH");
Expression<Integer> diff = builder.function("timestampdiff", Integer.class, month, root.get(Run_.endTime), root.get(Run_.startTime));
predicates.add(builder.gt(diff, 60));

MyFunctionExpression扩展BasicFunctionExpression并覆盖render方法。

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