JPA Criteria API: Difference between two dates in database?
Here is the Explanation of Equivalent JPA Criteria Query of
select * from mytable where until > from + interval 4 week;
First you have to create unit expression and extend it from BasicFunctionExpression for which take "WEEK" parameter as a unit and override its rendor(RenderingContext renderingContext) method only.
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();
}
}
then you use this unit expression in your JPA criteria Query.
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);
It is working fine.
EDIT2: workaround found
Since we have to work only with functions that don't need a built-in parameter (like WEEK), I ended up with
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)
For reference a version that leads to a dead end:
There is no way to make it work like this, you can not send "hour" without surrounding "" as a parameter to the database.
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
)