【问题标题】:JPA Criteria API: Difference between two dates in database?JPA Criteria API:数据库中两个日期之间的差异?
【发布时间】:2015-11-03 12:47:42
【问题描述】:

简单问题:我有一个 (MySQL) 表,其中包含两个日期列(从、直到)并询问它

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

这在 MySQL 中真的很简单。

你怎么能像这样在 JPA Query 中做到这一点

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

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

【问题讨论】:

  • @MarkS。在我看到的所有示例中,也在您的示例中,是从应用程序固定的一个日期(链接中的参数)。我的问题有两个来自数据库的日期。
  • 您是否有一个日期参数或来自字段的两个日期与问题无关...... Criteria API 有两种方法。在JPA Criteria中你不能简单地做的是“+间隔4周”。
  • 那么有没有办法找到超过某个时间间隔的预订?这似乎很奇怪。
  • 你可以使用CriteriaBuilder#function()docs.oracle.com/javaee/6/api/javax/persistence/criteria/…虽然这会破坏与不同数据库的兼容性,或者如果你可以改变表结构,你可以添加一个带有日期差异的列。

标签: java jpa query-builder


【解决方案1】:

这里是对等价JPA条件查询的解释

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

首先你必须创建单元表达式并从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);

一切正常。

【讨论】:

  • 酷,看起来很简单。如果这样的UnitExpression 将成为库的一部分,则可以使许多表达式变得更容易。
  • 正是这将非常有帮助。
  • 不是为它创建一个完整的类,你不能只使用Expression&lt;String&gt; week= cb.literal("WEEK");
【解决方案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
)

【讨论】:

  • 阅读我的回答。可以在函数中传递“WEEK”参数。
【解决方案3】:

**使用标准 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();
    }

【讨论】:

    猜你喜欢
    • 2014-08-31
    • 2011-10-29
    • 1970-01-01
    • 2018-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-19
    • 2013-10-02
    相关资源
    最近更新 更多