Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA criteria API order by NULL last

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

like image 975
Yan Khonski Avatar asked Jan 07 '17 11:01

Yan Khonski


People also ask

How does JPA handle null values?

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.

What is coalesce in JPA?

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.

What is JPA Criteria API?

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.

How do you use coalesce in hibernate criteria?

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.


1 Answers

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);
like image 170
Yan Khonski Avatar answered Sep 18 '22 05:09

Yan Khonski