Red Hat Training

A Red Hat training course is available for Red Hat JBoss Web Server

4.4. オブジェクトの問い合わせ

探しているオブジェクトの 識別子の値を知らない場合は、クエリが必要です。Hibernate EntityManager 実装は、使いやすく強力なオブジェクト指向クエリ言語 (EJB3-QL) をサポートします (EJB3-QL は HQL の影響を受けています。あるいは HQL は EJB3-QL の影響を受けています)。両方のクエリ言語はデータベース間で移植可能であり、(テーブル名とカラム名の代わりに) エンティティ名とプロパティ名を 識別子として使用します。また、クエリをデータベースのネイティブ SQL で記述することもできます (Java ビジネスオブジェクトへの結果セットの変換に対する JPA のオプションのサポートあり)。

4.4.1. クエリの実行

EJB3QL クエリと SQL クエリは javax.persistence.Query のインスタンスにより表されます。このインターフェースは、パラメータバインディング、結果セット処理、およびクエリの実行に関するメソッドを提供します。クエリは、常に現在のエンティティマネージャを使用して作成されます。
クエリは、通常 getResultList() を呼び出すことによって実行されます。このメソッドはクエリの結果となるインスタンスをメモリに完全にロードします。クエリにより取得されたエンティティインスタンスは、永続の状態になります。クエリが単一オブジェクトだけを返すことがわかっている場合は、getSingleResult() メソッドを使用することにより作業を短縮できます。

4.4.1.1. プロジェクション

プロジェクションが使用された場合、EJB3QL クエリはオブジェクトの組を返すことができます。各組はオブジェクトアレイとして返されます。
Iterator<Cat[]> kittensAndMothers = 
  em.createQuery("select kitten, mother from Cat kitten join kitten.mother mother").getResultList().iterator();
  while (kittensAndMothers.hasNext()) {
     Cat[] tuple = kittensAndMothers.next();
     Cat kitten = tuple[0];
     Cat mother = tuple[1];
  } 
    ....
}

4.4.1.2. スカラー結果

クエリは、select 句でエンティティエイリアスの代わりにエンティティの特定のプロパティを指定できます。SQL 集計関数も呼び出すことができます。返された非トランザクションオブジェクトまたは集計結果は、「スカラー」結果と見なされ、永続状態のエンティティではありません (つまり、「読み取り専用」と見なされます)。
Iterator<Object[]> results = em.createQuery(
        "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
        "group by cat.color")
        .getResultList()
        .iterator();

while ( results.hasNext() ) {
    Object[] row = results.next();
    Color type = (Color) row[0];
    Date oldest = (Date) row[1];
    Integer count = (Integer) row[2];
    .....
}

4.4.1.3. バインドパラメータ

名前付きおよび位置クエリパラメータの両方がサポートされます。Query API は引数をバインドするメソッドをいくつか提供します。JPA 仕様では、位置パラメータが 1 から数えられます。名前付きパラメータはクエリ文字列の :paramname という形式の ID です。(名前付きパラメータは堅牢であり、理解しやすいため)名前付きパラメータが推奨されます。
// Named parameter (preferred)
Query q = em.createQuery("select cat from DomesticCat cat where cat.name = :name");
q.setParameter("name", "Fritz");
List cats = q.getResultList();

// Positional parameter
Query q = em.createQuery("select cat from DomesticCat cat where cat.name = ?1");
q.setParameter(1, "Izi");
List cats = q.getResultList();

// Named parameter list
List names = new ArrayList();
names.add("Izi");
names.add("Fritz");
Query q = em.createQuery("select cat from DomesticCat cat where cat.name in (:namesList)");
q.setParameter("namesList", names);
List cats = q.getResultList();

4.4.1.4. Pagination

結果セットに境界 (取得したい行の最大数または取得したい最初の行) を指定する必要がある場合は、以下のメソッドを使用してください。
Query q = em.createQuery("select cat from DomesticCat cat");
q.setFirstResult(20);
q.setMaxResults(10);
List cats = q.getResultList(); //return cats from the 20th position to 29th
Hibernate は、この制限クエリを DBMS のネイティブ SQL に変換する方法を知っています。

4.4.1.5. 名前付きクエリの外部化

アノテーションを使用して名前付きクエリを定義することもできます。
@javax.persistence.NamedQuery(name="eg.DomesticCat.by.name.and.minimum.weight", 
  query="select cat from eg.DomesticCat as cat  where cat.name = ?1 and cat.weight > ?2")
パラメータは、実行される前に名前付きクエリにプログラムによりバインドされます。
Query q = em.createNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
q.setParameter(1, name);
q.setParameter(2, minWeight);
List cats = q.getResultList();
実際のプログラムコードは使用されるクエリ言語とは独立し、XML マッピングファイルに配置することによりメタデータのネイティブ SQL クエリを定義したり、Hibernate のネイティブ機能を使用したりできます。

4.4.1.6. ネイティブクエリ

createNativeQuery() を使用して SQL でクエリを表記できます。Hibernate では、JDBC 結果セットとビジネスオブジェクトのマッピングが考慮されます。@SqlResultSetMapping (SQL 結果セットマッピングのマップ方法については、Hibernate Annotations リファレンスドキュメンテーションを参照) またはエンティティマッピング (クエリ結果のカラム名がエンティティマッピングで宣言された名前と同じである場合。このメカニズムが動作するにはすべてのエンティティカラムが返される必要があります)。
@SqlResultSetMapping(name="getItem", entities = 
        @EntityResult(entityClass=org.hibernate.ejb.test.Item.class, fields= {
            @FieldResult(name="name", column="itemname"),
            @FieldResult(name="descr", column="itemdescription")
        })
)

Query q = em.createNativeQuery("select name as itemname, descr as itemdescription from Item", "getItem");
item = (Item) q.getSingleResult(); //from a resultset

Query q = em.createNativeQuery("select * from Item", Item.class);
item = (Item) q.getSingleResult(); //from a class columns names match the mapping

注記

名前付きクエリのスカラーサポートに関する詳細については、Hibernate Annotations ドキュメンテーションを参照してください。

4.4.1.7. クエリヒント

クエリヒント (通常はパフォーマンス最適化が目的) は実装固有です。ヒントは query.setHint(String name, Object value) メソッドまたは @Named(Native)Query(hints) アノテーションを使用して宣言されます。これらは SQL クエリヒントでないことに注意してください。Hibernate JPA 実装は以下のクエリヒントを提供します。

表4.1 Hibernate クエリヒント

ヒント定義
org.hibernate.timeout秒単位のクエリタイムアウト (new Integer(10) など)
org.hibernate.fetchSizeラウンドトリップごとに JDBC ドライバによりフェッチされる行数 (new Integer(50) など)
org.hibernate.commentSQL クエリにコメントを追加します。DBA の場合に役に立ちます (new String("fetch all orders in 1 statement") など)
org.hibernate.cacheableクエリがキャッシュ可能であるかどうか (new Boolean(true) など)。デフォルト値は false
org.hibernate.cacheModeこのクエリのキャッシュモードをオーバーライドします (CacheMode.REFRESH など)
org.hibernate.cacheRegionこのクエリのキャッシュリージョン (new String("regionName") など)
org.hibernate.readOnlyこのクエリにより取得されたエンティティは読み取り専用モードでロードされ、Hibernate によりエンティティがダーティチェックされないか、変更が永続化されません (new Boolean(true) など)。デフォルト値は false です
org.hibernate.flushModeこのクエリに使用されるフラッシュモード
org.hibernate.cacheModeこのクエリに使用されるキャッシュモード
値オブジェクトはネイティブタイプまたは文字列同等を受けいれます (CaheMode.REFRESH or REFRESH など)。詳細については、Hibernate リファレンスドキュメンテーションを参照してください。