JPA 条件 API:数据库中两个日期之间的差异?
JPA Criteria API: Difference between two dates in database?
简单问题:我有一个 (MySQL) table,其中包含两个日期列(从,到),并用
询问它
select * from mytable where until > from + interval 4 week;
这在MySQL中真的很简单。
你怎么能像
这样在 JPA 查询中做到这一点
cq.where(cb.and(mytable_.get(until),...)
编辑:两个日期都来自数据库行,我比较了数据库的两个字段,而不是应用程序中的一个字段与数据库中的一个字段。
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)
供参考,导致死胡同的版本:
没有办法让它像这样工作,你不能发送"hour" 没有包围""作为数据库的参数。
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
)
这里是
的等效 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);
它工作正常。
**使用条件 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();
}
简单问题:我有一个 (MySQL) table,其中包含两个日期列(从,到),并用
询问它select * from mytable where until > from + interval 4 week;
这在MySQL中真的很简单。
你怎么能像
这样在 JPA 查询中做到这一点cq.where(cb.and(mytable_.get(until),...)
编辑:两个日期都来自数据库行,我比较了数据库的两个字段,而不是应用程序中的一个字段与数据库中的一个字段。
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)
供参考,导致死胡同的版本:
没有办法让它像这样工作,你不能发送"hour" 没有包围""作为数据库的参数。
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
)
这里是
的等效 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);
它工作正常。
**使用条件 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();
}