【问题标题】:JPA CriteriaQuery calculating datetime difference for use in where predicateJPA CriteriaQuery 计算日期时间差以用于 where 谓词
【发布时间】:2015-12-16 01:43:39
【问题描述】:

我正在尝试从我的数据库中选择两个字段之间的时间差小于或大于某个值的实体。在标准 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 天。有没有其他方法可以做到这一点?

【问题讨论】:

    标签: java jpa


    【解决方案1】:

    这里是对等价的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();
      }
    }
    

    然后你在你的 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);
    

    它正在工作。

    【讨论】:

      【解决方案2】:
      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 并覆盖了渲染方法。

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

      【讨论】:

        【解决方案3】:

        抱歉,JPA 不支持 datediff 函数。如果您使用的是 eclipselink,您可以使用 FUNC 关键字,它调用 DB 的本机函数。否则,您将需要使用本机查询。

        【讨论】:

        • JPA 支持 datediff 函数。阅读我的答案。
        猜你喜欢
        • 2020-08-24
        • 2021-12-07
        • 2012-08-28
        • 1970-01-01
        • 2023-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多