JPAによる並べ替え
1. 概要
この記事では、JPA can be used for sortingのさまざまな方法について説明します。
参考文献:
Spring Data JPA @Query
Spring Data JPAで@Queryアノテーションを使用して、JPQLとネイティブSQLを使用してカスタムクエリを定義する方法を学びます。
2. JPA / JQLAPIを使用した並べ替え
JQLを使用した並べ替えは、Order By句を使用して行われます。
String jql ="Select f from Foo as f order by f.id";
Query query = entityManager.createQuery (jql);
このクエリに基づいて、JPAは次の単純なSQL statementを生成します。
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_
from Foo foo0_ order by foo0_.id
JQL文字列のSQLキーワードでは大文字と小文字が区別されませんが、エンティティの名前とその属性は区別されることに注意してください。
2.1. 並べ替え順序の設定
デフォルトではthe sorting order is ascendingですが、JQL文字列で明示的に設定できます。 純粋なSQLの場合と同様に、順序付けオプションはascとdescです。
String jql = "Select f from Foo as f order by f.id desc";
Query sortQuery = entityManager.createQuery(jql);
generated SQL queryには、注文の方向が含まれます。
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_
from Foo foo0_ order by foo0_.id desc
2.2. 複数の属性による並べ替え
複数の属性で並べ替えるために、これらはJQL文字列のorder by句に追加されます。
String jql ="Select f from Foo as f order by f.name asc, f.id desc";
Query sortQuery = entityManager.createQuery(jql);
両方のソート条件がgenerated SQL queryステートメントに表示されます。
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_
from Foo foo0_ order by foo0_.name asc, foo0_.id desc
2.3. ヌル値のソート優先順位の設定
nullのデフォルトの優先順位はデータベース固有ですが、これはHQLクエリ文字列のNULLS FIRSTまたはNULLS LAST句を使用してカスタマイズできます。
簡単な例を次に示します。Fooのnameを降順で並べ、最後にNullsを配置します。
Query sortQuery = entityManager.createQuery
("Select f from Foo as f order by f.name desc NULLS LAST");
生成されるSQLクエリには、is null the 1 else 0 end clause(3行目)が含まれます。
Hibernate: select foo0_.id as id1_4_, foo0_.BAR_ID as BAR_ID2_4_,
foo0_.bar_Id as bar_Id2_4_, foo0_.name as name3_4_,from Foo foo0_ order
by case when foo0_.name is null then 1 else 0 end, foo0_.name desc
2.4. 1対多の関係の並べ替え
基本的な例を超えて、sorting entities in a one to many relation –Fooエンティティのコレクションを含むBarを含むユースケースを見てみましょう。
BarエンティティとそれらのFooエンティティのコレクションを並べ替えたい–JPAはこのタスクにとって特に簡単です。
-
コレクションの並べ替え:BarエンティティのFooコレクションの前にOrderBy注釈を追加します。
@OrderBy("name ASC") List
fooList; -
コレクションを含むエンティティの並べ替え:
String jql = "Select b from Bar as b order by b.id"; Query barQuery = entityManager.createQuery(jql); List
barList = barQuery.getResultList();
@OrderByアノテーションはオプションですが、各BarのFooコレクションをソートするため、この場合はこれを使用していることに注意してください。
RDMSに送信されたSQL queryを見てみましょう。
Hibernate: select bar0_.id as id1_0_, bar0_.name as name2_0_ from Bar bar0_ order by bar0_.id
Hibernate:
select foolist0_.BAR_ID as BAR_ID2_0_0_, foolist0_.id as id1_4_0_,
foolist0_.id as id1_4_1_, foolist0_.BAR_ID as BAR_ID2_4_1_,
foolist0_.bar_Id as bar_Id2_4_1_, foolist0_.name as name3_4_1_
from Foo foolist0_
where foolist0_.BAR_ID=? order by foolist0_.name asc
最初のクエリは、親のBarエンティティを並べ替えます。 2番目のクエリは、Barに属する子Fooエンティティのコレクションを並べ替えるために生成されます。
3. JPA Criteria Query ObjectAPIを使用した並べ替え
JPA基準の場合–orderByメソッドは、すべてのソートパラメーターを設定するための「ワンストップ」の代替手段です。order directionとattributes to sortbyの両方を設定できます。 メソッドのAPIは次のとおりです。
-
orderBy(CriteriaBuilder.asc):昇順で並べ替えます。
-
orderBy(CriteriaBuilder.desc):降順で並べ替えます。
各Orderインスタンスは、そのascまたはdescメソッドを介してCriteriaBuilderオブジェクトで作成されます。
簡単な例を次に示します–Foosをnameでソートします。
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root from = criteriaQuery.from(Foo.class);
CriteriaQuery select = criteriaQuery.select(from);
criteriaQuery.orderBy(criteriaBuilder.asc(from.get("name")));
getメソッドの引数は、属性の名前と一致する必要があるため、大文字と小文字が区別されます。
単純なJQLとは対照的に、クエリ内のJPA Criteria Query Object APIforces an explicit order direction。 このコードスニペットの最後の行で、criteriaBuilderオブジェクトが、そのascメソッドを呼び出すことによって昇順の並べ替え順序を指定していることに注意してください。
上記のコードが実行されると、JPAは以下に示すSQLクエリを生成します。 JPA Criteria Objectは、明示的なasc句を含むSQLステートメントを生成します。
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_
from Foo foo0_ order by foo0_.name asc
3.1. 複数の属性による並べ替え
複数の属性で並べ替えるには、並べ替える属性ごとにOrderインスタンスをorderByメソッドに渡すだけです。
簡単な例を次に示します。nameとidで、それぞれascとdescの順序で並べ替えます。
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Foo.class);
Root from = criteriaQuery.from(Foo.class);
CriteriaQuery select = criteriaQuery.select(from);
criteriaQuery.orderBy(criteriaBuilder.asc(from.get("name")),
criteriaBuilder.desc(from.get("id")));
対応するSQLクエリを以下に示します。
Hibernate: select foo0_.id as id1_4_, foo0_.name as name2_4_
from Foo foo0_ order by foo0_.name asc, foo0_.id desc
4. 結論
この記事では、単純なエンティティーと1対多の関係にあるエンティティーについて、Java Persistence APIでのソートの代替方法を検討します。 これらのアプローチは、ソート作業の負担をデータベース層に委任します。
このJPAソートチュートリアルの実装はthe GitHub projectにあります。これはMavenベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。