2017-01-07 13 views
2

JPA基準APIを使用して、日付ベースからレコードをフェッチします。 私はエンティティレコードフィールドdateTimeを持つことができます。私はコード:JPA criteria API order by NULL last

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のレコードが最初に表示されます。 私はPostrgresデータベースを使用しています。 私は解決策を見つけたので、私はこの質問に答えます。 似たような投稿です。 JPA Criteria Query API and order by null last

答えて

7

ここで私はこの作業に答えました。

まず、デフォルトでPostgresはnullを最初に返します。

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

ノート、休止状態-JPA-2.1からCriteriaBuilderを変更しなければなりませんでした。

/** 
* 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

これを試して、「エラー:タイムゾーンのないタイムスタンプとバイトアが一致しません」というエラーが表示されました。 'cb.coalesce(root.get( 'joinedModel')。get( 'someDate')、MIN_DATE)' –

+0

本当に?それは私のコードで働いた。休止状態のバージョンMIN_DATEを確認してください。また、エンティティのリレーションをナビゲートする代わりにjoinメソッドを使用しましたrecordRoot = externalRoot.jolin( "recordRelation"); 次に、recordRoot.get( "field") –

+1

発見された根本原因。私は日付とは対照的に 'LocalDateTime'を使用しました。 Postgres DBでは、これは動作しません。答えに指定されているように 'Date'に切り替えました。 –

2

NULLSが処理されます(そして、すべてのRDBMSがデフォルトのために自分の好みを持っている)方法を制御するためのJPA仕様では何もありません。これは、JPQL(文字列ベースのクエリ)またはCriteria APIでは使用できません。 JPQLでは、主要JPAプロバイダのすべてが、注文句に

NULLS [FIRST|LAST] 

の使用を許可しています。 Criteriaでは、Criteria APIに制約されるため、何もできません。私はDataNucleusのJPAは

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

を指定できますが、明らかにそれはそのJPAプロバイダに固有であるJPAクライテリアAPIのカスタムバージョンを提供することを知っています。

+0

私はあなたに同意する、私は別の解決策を示します。 –