2017-01-07 10 views
2

Я использую API критериев JPA для извлечения записей из базы дат. У меня есть объект Запись с полем dateTime который может быть пустым. Я бы назвал код:Порядок API API JPA по NULL последний

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*/); 
} 

Оказалось, сначала отображаются записи с NULL dateTimeField. Я использую базу данных Postggres. Я отвечу на этот вопрос, потому что нашел решение. Вот аналогичный пост. JPA Criteria Query API and order by null last

ответ

7

Здесь я поставил ответ на эту задачу.

Во-первых, Postgres по умолчанию возвращает nulls в первую очередь.

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; 

Во-вторых, я должен был изменить applyOrderBy метод

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); 
} 

Обратите внимание, CriteriaBuilder из спящем-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); 
+0

Я пробовал это и получил «ERROR: COALESCE» временную метку без часового пояса, а bytea нельзя сопоставить ». Может иметь какое-то отношение к конкретному способу построения cb: 'cb.coalesce (root.get ('joinModel'). Get ('someDate'), MIN_DATE)' –

+0

Действительно? Он работал в моем коде. Проверьте версию спящего режима, MIN_DATE. Также я использовал метод соединения вместо того, чтобы перемещаться по отношениям сущностей recordRoot = externalRoot.jolin ("recordRelation"); Тогда recordRoot.get ("field") –

+1

Обнаружена первопричина. Я использовал «LocalDateTime» в отличие от даты. В DB Postgres это не работает. Переключился на 'Date', как указано в ответе. –

2

Там нет ничего в спецификации JPA, чтобы контролировать, как NULLS обрабатываются (и все СУБД имеют свои предпочтения по умолчанию). Это не доступно ни в JPQL (запрос на основе строк), ни в Criteria API. В JPQL все основные поставщики JPA разрешают использовать

NULLS [FIRST|LAST] 

в заказе. Для критериев вы ограничены API критериев, поэтому ничего невозможного. Я знаю, что DataNucleus JPA обеспечить пользовательскую версию Criteria API JPA, что позволяет спецификации

Order order = criteriaBuilder.asc(myExpression).nullsFirst(); 

, но ясно, что является специфическим для этого провайдера JPA.

+0

Я согласен с вами, я покажу другое решение. –

 Смежные вопросы

  • Нет связанных вопросов^_^