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

sha*_*ves 5 java jpa

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

SELECT * from run where TIMESTAMPDIFF(SECOND, run.end_time, run.start_time) > 60;
Run Code Online (Sandbox Code Playgroud)

但是,JPA 2.0中似乎没有任何等效的东西。

我已经尝试了所有我能想到的一切,包括这里的建议:将TIMESTAMPDIFF与JPA条件查询一起使用,并休眠为提供者

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

根本不起作用,因为我专门尝试计算长时间(60/90天)。TIMEDIFF解决方案无济于事,因为可以返回的最大TIMEDIFF为35天。还有其他方法可以做到这一点吗?

Kha*_*hah 5

这是等效 JPA Criteria Query 的解释

SELECT * from run where 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();
  }
}
Run Code Online (Sandbox Code Playgroud)

然后您在 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);
Run Code Online (Sandbox Code Playgroud)

这是工作。