I use JPA criteria API to fetch records from the datebase. I have entity Record with field dateTime which can be null. I would code:
public List<Record> find(RecordFilter recordFilter, int page, int pageSize) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Record> criteriaQuery = criteriaBuilder.createQuery(Record.class);
Root<Record> recordRoot = criteriaQuery.from(Record.class);
/*
* JOINS. Left Joins are used for optional fields, or fields inside of the optional fields.
*/
Join<Record, Agency> recordAgencyJoin = recordRoot.join(RecordTable.FIELD_AGENCY);
//Some other joins
//This is where I had the problem.
applyOrderBy(criteriaQuery, criteriaBuilder, recordRoot);
/*
* Specify which columns to select and their order.
* criteriaQuery.multiselect(....);
*/
applyMultiSelect(recordRoot, recordAgencyJoin, /*other joins*/ criteriaQuery);
/*
* criteriaQuery.where(somePredicate);
*/
applyFilter(recordFilter, criteriaQuery, criteriaBuilder,
recordRoot, recordAgencyJoin /*, other joins*/);
TypedQuery<Record> query = entityManager.<Record>createQuery(criteriaQuery);
RepositoryUtils.applyPagination(query, page, pageSize);
return query.getResultList();
}
private void applyOrderBy(CriteriaBuilder criteriaBuilder, Root<Record> recordRoot, CriteriaQuery<Record> criteriaQuery) {
//Other fields to be added to the final sort.
Order dateTimeDescOrder = criteriaBuilder.desc(recordRoot.get(RecordTable.FIELD_DATE_TIME));
criteriaQuery.orderBy(dateTimeDescOrder /*, other orders by*/);
}
It turns out, records with NULL dateTimeField are shown first. I use Postrgres database. I will answer this question because I found a solution. Here is a similar post. JPA Criteria Query API and order by null last
The JPA specification defines that during ordering, NULL values shall be handled in the same way as determined by the SQL standard. The standard specifies that all null values shall be returned before or after all non-null values. It's up to the database to pick one of the two options.
Coalesce is supported by JPA 2.0 API. The new construct is proprietary to Hibernate, not necessarily supported in all JPA implementations. First try the query without also trying to construct an object: select COALESCE(k.projectId,'N') as projectId, k.projectName from Emp o inner join o.projects k.
Advertisements. The Criteria API is a predefined API used to define queries for entities. It is the alternative way of defining a JPQL query. These queries are type-safe, and portable and easy to modify by changing the syntax.
Interface used to build coalesce expressions. A coalesce expression is equivalent to a case expression that returns null if all its arguments evaluate to null, and the value of its first non-null argument otherwise.
Here I put an answer to this task.
First, Postgres by default returns nulls first.
SELECT * FROM record ORDER BY date_time_field DESC;
https://stackoverflow.com/a/7621232/4587961
SELECT * FROM record ORDER BY date_time_field DESC NULLS LAST;
Second, I had to change applyOrderBy method
private void applyOrderBy(CriteriaBuilder criteriaBuilder, Root<Record> recordRoot, CriteriaQuery<Record> criteriaQuery) {
//In the class code
//private static final Date MIN_DATE = new Date(0L);
final Date MIN_DATE = new Date(0L);
//We treat records will NULL dateTimeField as if it was MIN_DATE.
Order dateTimeDescOrder = criteriaBuilder.desc(
//NULL values - last - WORKAROUND.
criteriaBuilder.coalesce(recordRoot.get(RecordTable.FIELD_DATE_TIME), MIN_DATE));
criteriaQuery.orderBy(dateTimeDescOrder);
}
Note, CriteriaBuilder from hibernate-jpa-2.1.
/**
* Create an expression that returns null if all its arguments
* evaluate to null, and the value of the first non-null argument
* otherwise.
*
* @param x expression
* @param y value
*
* @return coalesce expression
*/
<Y> Expression<Y> coalesce(Expression<? extends Y> x, Y y);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With