第12章 Criteriaクエリ

Hibernateは現在、直感的で拡張可能なcriteriaクエリAPIを用意しています。今ではこのAPIは、成熟したHQLクエリの機能に比べて力不足です。特にcriteriaクエリは射影や集約をサポートしていません。

12.1. Criteriaインスタンスの作成

net.sf.hibernate.Criteriaインタフェースは特定の永続性クラスに対するクエリを表現しています。SessionCriteriaインスタンスのファクトリです。

Criteria crit = sess.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();

12.2. リザルトセットの絞込み

個別のクエリ・クライテリオン(問い合わせの判定基準)はインターフェイスnet.sf.hibernate.expression.Criterionのインスタンスです。net.sf.hibernate.expression.Expressionクラスはある組み込みのCriterion型を取得するためのファクトリメソッドを定義します。

List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "Fritz%") )
    .add( Expression.between("weight", minWeight, maxWeight) )
    .list();

Expressionは論理的にグループ化されます。

List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "Fritz%") )
    .add( Expression.or(
        Expression.eq( "age", new Integer(0) ),
        Expression.isNull("age")
    ) )
    .list();
List cats = sess.createCriteria(Cat.class)
    .add( Expression.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
    .add( Expression.disjunction()
        .add( Expression.isNull("age") )
    	.add( Expression.eq("age", new Integer(0) ) )
    	.add( Expression.eq("age", new Integer(1) ) )
    	.add( Expression.eq("age", new Integer(2) ) )
    ) )
    .list();

元々あるcriterion型(Expressionのサブクラス)はかなりの範囲に及びますが、特に有用なのはSQLを直接指定できるものです。

List cats = sess.createCriteria(Cat.class)
    .add( Expression.sql("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )
    .list();

プレースホルダ{alias}は、問い合わせを受けたエンティティの行の別名によって置き換えられます。

12.3. 結果の整列

net.sf.hibernate.expression.Orderを使って結果を整列することができます。

List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "F%")
    .addOrder( Order.asc("name") )
    .addOrder( Order.desc("age") )
    .setMaxResults(50)
    .list();

12.4. 関連

createCriteria()を使い関連をナビゲートすることで、容易に関係するエンティティに制約を指定できます。

List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "F%")
    .createCriteria("kittens")
        .add( Expression.like("name", "F%")
    .list();

2番目のcreateCriteria()は、kittensコレクションの要素を参照する新しいCriteriaインスタンスを返すことに注意してください。

以下のような方法も、状況により有用です。

List cats = sess.createCriteria(Cat.class)
    .createAlias("kittens", "kt")
    .createAlias("mate", "mt")
    .add( Expression.eqProperty("kt.name", "mt.name") )
    .list();

(ここでcreateAlias())は新しいCriteriaインスタンスを作成しません。)

前の2つのクエリによって返されるCatインスタンスによって保持されるkittensコレクションは、criteriaによって事前にフィルタリングされないことに注意してください。もしcriteriaと対応するkittenを取得したいなら、returnMaps()を使わなければなりません。

List cats = sess.createCriteria(Cat.class)
    .createCriteria("kittens", "kt")
        .add( Expression.eq("name", "F%") )
    .returnMaps()
    .list();
Iterator iter = cats.iterator();
while ( iter.hasNext() ) {
    Map map = (Map) iter.next();
    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
    Cat kitten = (Cat) map.get("kt");
}

12.5. 動的関連のフェッチ

setFetchMode()を使い、実行時に関連の復元方法を指定することができます。

List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "Fritz%") )
    .setFetchMode("mate", FetchMode.EAGER)
    .setFetchMode("kittens", FetchMode.EAGER)
    .list();

このクエリはアウター・ジョインでmatekittensの両方をフェッチします。

12.6. クエリの例

net.sf.hibernate.expression.Exampleクラスを使って、与えられたインスタンスから クエリ・クライテリオンを構築することができます。

Cat cat = new Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List results = session.createCriteria(Cat.class)
    .add( Example.create(cat) )
    .list();

バージョン・プロパティ、識別子、関連は無視されます。デフォルトではnull値のプロパティは除外されます。

どのようにExampleを適用するか、状況に応じて調整することができます。

Example example = Example.create(cat)
    .excludeZeroes()           //ゼロ値プロパティを除外します
    .excludeProperty("color")  //"color"という名前のプロパティを除外します
    .ignoreCase()              //大文字・小文字の違いを無視して文字列の比較を行います
    .enableLike();             //文字列の比較にlikeを使用します
List results = session.createCriteria(Cat.class)
    .add(example)
    .list();

関連オブジェクトにcriteriaを指定するExampleを使うことも可能です。

List results = session.createCriteria(Cat.class)
    .add( Example.create(cat) )
    .createCriteria("mate")
        .add( Example.create( cat.getMate() ) )
    .list();