Hibernateによるソート

Hibernateでのソート

1. 概要

この記事では、Hibernate Query Language(HQL)とCriteria APIの両方を使用したhow to Sort with Hibernateについて説明します。

参考文献:

Hibernate:保存、永続化、更新、マージ、saveOrUpdate

Hibernate書き込みメソッドの迅速かつ実用的なガイド:保存、永続化、更新、マージ、saveOrUpdate。

Hibernateを使用したオブジェクトの削除

Hibernateでエンティティを削除するためのクイックガイド。

休止状態のインターセプター

Hibernateインターセプターを作成するための迅速かつ実用的なガイド。

2. HQLによる並べ替え

HibernateのHQLを使用した並べ替えは、HQLクエリ文字列にOrder By句を追加するのと同じくらい簡単です。

String hql = "FROM Foo f ORDER BY f.name";
Query query = sess.createQuery(hql);

このコードが実行されると、Hibernateは次のSQLクエリを生成します。

Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_ from
    FOO foo0_ order by foo0_.NAME

デフォルトのソート順は昇順です。 これが、生成されたSQLクエリに注文条件ascが含まれていない理由です。

2.1. 明示的な並べ替え順序の使用

並べ替え順序を手動で指定するには、HQLクエリ文字列に順序の方向を含める必要があります。

String hql = "FROM Foo f ORDER BY f.name ASC";
Query query = sess.createQuery(hql);

この例では、HQLでasc句を設定することが、生成されたSQLクエリに含まれていました。

Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_
    from FOO foo0_ order by foo0_.NAME ASC

2.2. 複数の属性による並べ替え

オプションの並べ替え順序とともに、複数の属性をHQLクエリ文字列のOrder By句に追加できます。

String hql = "FROM Foo f ORDER BY f.name DESC, f.id ASC";
Query query = sess.createQuery(hql);

生成されたSQLクエリはそれに応じて変更されます。

Hibernate: select foo0_.ID as ID1_0_, foo0_.NAME as NAME2_0_
    from FOO foo0_ order by foo0_.NAME DESC, foo0_.ID ASC

2.3. ヌル値のソート優先順位の設定

デフォルトでは、ソートする属性にnullの値がある場合、優先順位を決定するのはRDMS次第です。 このデフォルトの処理は、a NULLS FIRST or NULLS LAST clause in the HQL query stringを配置することでオーバーライドできます。

この単純な例では、結果リストの最後にヌルを配置しています。

String hql = "FROM Foo f ORDER BY f.name NULLS LAST";
Query query = sess.createQuery(hql);

generated SQL queryis null then 1 else 0句を見てみましょう。

Hibernate: select foo0_.ID as ID1_1_, foo0_.NAME as NAME2_1_,
foo0_.BAR_ID as BAR_ID3_1_, foo0_.idx as idx4_1_ from FOO foo0_
order by case when foo0_.NAME is null then 1 else 0 end, foo0_.NAME

2.4. 1対多の関係の並べ替え

複雑な並べ替えのケースを分析してみましょう:sorting entities in a one to many relationFooエンティティのコレクションを含むBar

これを行うには、コレクションにthe Hibernate @OrderBy annotationの注釈を付けます。順序付けを行うフィールドと方向を指定します。

@OrderBy(clause = "NAME DESC")
Set fooList = new HashSet();

注釈に対するclause引数に注意してください。 これは、同様の@OrderBy JPAアノテーションと比較して、Hibernateの@OrderByに固有です。 このアプローチを同等のJPAと区別する別の特徴は、clause引数が、nameではなくFOOテーブルのNAME列に基づいてソートが行われることを示していることです。 Fooのs属性。

次に、BarsFoosの実際の並べ替えを見てみましょう。

String hql = "FROM Bar b ORDER BY b.id";
Query query = sess.createQuery(hql);

resulting SQL statementは、ソートされたFoo’sfooList:に配置されていることを示しています

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_ID3_0_0_,
    foolist0_.ID as ID1_1_0_, foolist0_.ID as ID1_1_1_, foolist0_.NAME as
    NAME2_1_1_, foolist0_.BAR_ID as BAR_ID3_1_1_, foolist0_.idx as idx4_1_1_
    from FOO foolist0_ where foolist0_.BAR_ID=? order by foolist0_.NAME desc

覚えておくべきことの1つは、JPAの場合と同様にnot possible to to sort Listsであるということです。 Hibernateドキュメントの状態:

「Hibernateは現在、たとえば、@ ElementCollectionの@OrderByを無視しています。 List 。 要素の順序は、データベースによって返されるとおりであり、未定義です。」

補足として、HibernateのレガシーXML構成を使用し、<List..>要素を<Bag…>要素に置き換えることで、この制限を回避することができます。

3. Hibernate基準での並べ替え

Criteria Object APIは、並べ替えを管理するためのメインAPIとしてOrderクラスを提供します。

3.1. 並べ替え順序の設定

Orderクラスには、ソート順を設定するための2つのメソッドがあります。

  • *asc*(String attribute):クエリをattributeで昇順で並べ替えます。

  • *desc*(String attribute):クエリをattributeで降順で並べ替えます。

簡単な例から始めましょう–単一のid属性でソートします。

Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.asc("id"));

ascメソッドの引数では大文字と小文字が区別され、並べ替える属性のnameと一致する必要があることに注意してください。

HibernateCriteriaのObjectAPIは、並べ替え順序の方向を明示的に設定します。これは、コードによって生成されるSQLステートメントに反映されます。

Hibernate: select this_.ID as ID1_0_0_, this_.NAME as NAME2_0_0_
    from FOO this_ order by this_.ID sac

3.2. 複数の属性による並べ替え

以下の例のように、複数の属性で並べ替えるには、OrderオブジェクトをCriteriaインスタンスに追加するだけで済みます。

Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.asc("name"));
criteria.addOrder(Order.asc("id"));

SQLで生成されるクエリは次のとおりです。

Hibernate: select this_.ID as ID1_0_0_, this_.NAME as NAME2_0_0_ from
    FOO this_ order by this_.NAME asc, this_.ID sac

3.3. ヌル値のソート優先順位の設定

デフォルトでは、ソートする属性にnullの値がある場合、優先順位を決定するのはRDMS次第です。 Hibernate Criteria Object APIを使用すると、昇順リストのデフォルトとplace nulls at the endを簡単に変更できます。

Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.asc("name").nulls(NullPrecedence.LAST));

基になるSQLクエリは次のとおりです–is null then 1 else 0句を使用します。

Hibernate: select this_.ID as ID1_1_1_, this_.NAME as NAME2_1_1_,
    this_.BAR_ID as BAR_ID3_1_1_, this_.idx as idx4_1_1_, bar2_.ID as
    ID1_0_0_, bar2_.NAME as NAME2_0_0_ from FOO order by case when
    this_.NAME is null then 1 else 0 end, this_.NAME asc

または、降順リストのplace the nulls at the beginningを指定することもできます。

Criteria criteria = sess.createCriteria(Foo.class, "FOO");
criteria.addOrder(Order.desc("name").nulls(NullPrecedence.FIRST));

対応するSQLクエリは次のとおりです–is null then 0 else 1句を使用します。

Hibernate: select this_.ID as ID1_1_1_, this_.NAME as NAME2_1_1_,
    this_.BAR_ID as BAR_ID3_1_1_, this_.idx as idx4_1_1_, bar2_.ID as
    ID1_0_0_, bar2_.NAME as NAME2_0_0_ from FOO order by case when
    this_.NAME is null then 0 else 1 end, this_.NAME desc

if the attribute to sort by is a primitive type like an int, a PresisitenceException will thrownであることに注意してください。

たとえば、f.anIntVariableの値がnullの場合、クエリの実行は次のようになります。

String jql = "Select f from Foo as f order by f.anIntVariable desc NULLS FIRST";
Query sortQuery = entityManager.createQuery(jql);

投げます:

javax.persistence.PersistenceException: org.hibernate.PropertyAccessException:
Null value was assigned to a property of primitive type setter of
com.cc.jpa.example.Foo.anIntVariable

4. 結論

この記事では、Hibernateを使用したソートについて説明します-単純なエンティティと1対多の関係にあるエンティティに使用可能なAPIを使用します。

このHibernateSorting Tutorialの実装は、the github projectにあります。これはEclipseベースのプロジェクトであるため、そのままインポートして実行するのは簡単です。