Hibernate.org Community Documentation

- 前のページ
- 次のページ

## 第17章 Criteria クエリ

Hibernate には、直感的で拡張可能な criteria クエリ API が用意されています。

## 17.1. `Criteria` インスタンスの作成

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

    Criteria crit = sess.createCriteria(Cat.class);

    crit.setMaxResults(50);

    List cats = crit.list();

## 17.2. リザルトセットの絞込み

`org.hibernate.criterion.Criterion` インターフェースのインスタンスは、個別のクエリクライテリオン（問い合わせの判定基準）を表します。 `org.hibernate.criterion.Restrictions` クラスは、ある組み込みの `Criterion` 型を取得するためのファクトリメソッドを持っています。

    List cats = sess.createCriteria(Cat.class)

        .add( Restrictions.like("name", "Fritz%") )

        .add( Restrictions.between("weight", minWeight, maxWeight) )

        .list();

Restriction （限定）は、論理的にグループ化できます。

    List cats = sess.createCriteria(Cat.class)

        .add( Restrictions.like("name", "Fritz%") )

        .add( Restrictions.or(

            Restrictions.eq( "age", new Integer(0) ),

            Restrictions.isNull("age")

        ) )

        .list();

    List cats = sess.createCriteria(Cat.class)

        .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )

        .add( Restrictions.disjunction()

            .add( Restrictions.isNull("age") )

            .add( Restrictions.eq("age", new Integer(0) ) )

            .add( Restrictions.eq("age", new Integer(1) ) )

            .add( Restrictions.eq("age", new Integer(2) ) )

        ) )

        .list();

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

    List cats = sess.createCriteria(Cat.class)

        .add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRING) )

        .list();

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

criterion を得る別の手段は、 `Property` インスタンスから取得することです。 `Property.forName()` を呼び出して、 `Property` インスタンスを作成できます。

    Property age = Property.forName("age");

    List cats = sess.createCriteria(Cat.class)

        .add( Restrictions.disjunction()

            .add( age.isNull() )

            .add( age.eq( new Integer(0) ) )

            .add( age.eq( new Integer(1) ) )

            .add( age.eq( new Integer(2) ) )

        ) )

        .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) )

        .list();

## 17.3. 結果の整列

`org.hibernate.criterion.Order` を使って結果を並び替えることができます。

    List cats = sess.createCriteria(Cat.class)

        .add( Restrictions.like("name", "F%")

        .addOrder( Order.asc("name") )

        .addOrder( Order.desc("age") )

        .setMaxResults(50)

        .list();

    List cats = sess.createCriteria(Cat.class)

        .add( Property.forName("name").like("F%") )

        .addOrder( Property.forName("name").asc() )

        .addOrder( Property.forName("age").desc() )

        .setMaxResults(50)

        .list();

## 17.4. 関連

By navigating associations using `createCriteria()` you can specify constraints upon related entities:

    List cats = sess.createCriteria(Cat.class)

        .add( Restrictions.like("name", "F%") )

        .createCriteria("kittens")

            .add( Restrictions.like("name", "F%") )

        .list();

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

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

    List cats = sess.createCriteria(Cat.class)

        .createAlias("kittens", "kt")

        .createAlias("mate", "mt")

        .add( Restrictions.eqProperty("kt.name", "mt.name") )

        .list();

（`createAlias()` は新しい `Criteria` インスタンスを作成しません。）

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

    List cats = sess.createCriteria(Cat.class)

        .createCriteria("kittens", "kt")

            .add( Restrictions.eq("name", "F%") )

        .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP)

        .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");

    }

Additionally you may manipulate the result set using a left outer join:

                    List cats = session.createCriteria( Cat.class )
                           .createAlias("mate", "mt", Criteria.LEFT_JOIN, Restrictions.like("mt.name", "good%") )
                           .addOrder(Order.asc("mt.age"))
                           .list();

This will return all of the `Cat`s with a mate whose name starts with "good" ordered by their mate's age, and all cats who do not have a mate. This is useful when there is a need to order or limit in the database prior to returning complex/large result sets, and removes many instances where multiple queries would have to be performed and the results unioned by java in memory.

Without this feature, first all of the cats without a mate would need to be loaded in one query.

A second query would need to retreive the cats with mates who's name started with "good" sorted by the mates age.

Thirdly, in memory; the lists would need to be joined manually.

## 17.5. 関連の動的フェッチ

`setFetchMode()` を使い、実行時に関連の復元方法を指定してもよいです。

    List cats = sess.createCriteria(Cat.class)

        .add( Restrictions.like("name", "Fritz%") )

        .setFetchMode("mate", FetchMode.EAGER)

        .setFetchMode("kittens", FetchMode.EAGER)

        .list();

This query will fetch both `mate` and `kittens` by outer join. See 「フェッチ戦略」 for more information.

## 17.6. クエリの例

`org.hibernate.criterion.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()           //exclude zero valued properties

        .excludeProperty("color")  //exclude the property named "color"

        .ignoreCase()              //perform case insensitive string comparisons

        .enableLike();             //use like for string comparisons

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

## 17.7. 射影、集約、グループ化

`org.hibernate.criterion.Projections` クラスは `Projection` インスタンスのファクトリです。 `setProjection()` を呼び出すことで、クエリに射影を適用します。

    List results = session.createCriteria(Cat.class)

        .setProjection( Projections.rowCount() )

        .add( Restrictions.eq("color", Color.BLACK) )

        .list();

    List results = session.createCriteria(Cat.class)

        .setProjection( Projections.projectionList()

            .add( Projections.rowCount() )

            .add( Projections.avg("weight") )

            .add( Projections.max("weight") )

            .add( Projections.groupProperty("color") )

        )

        .list();

必要であっても、 criteria クエリに「group by」を明示する必要はありません。ある種の Projection 型は グループ化射影 として定義され、 SQL の `group by` 節にも現れます。

An alias can be assigned to a projection so that the projected value can be referred to in restrictions or orderings. Here are two different ways to do this:

    List results = session.createCriteria(Cat.class)

        .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) )

        .addOrder( Order.asc("colr") )

        .list();

    List results = session.createCriteria(Cat.class)

        .setProjection( Projections.groupProperty("color").as("colr") )

        .addOrder( Order.asc("colr") )

        .list();

`alias()` と `as()` メソッドは、 Projection インスタンスを別の名前の `Projection` インスタンスでラップするだけです。ショートカットとして、射影を射影リストに追加する際に、別名をつけられます:

    List results = session.createCriteria(Cat.class)

        .setProjection( Projections.projectionList()

            .add( Projections.rowCount(), "catCountByColor" )

            .add( Projections.avg("weight"), "avgWeight" )

            .add( Projections.max("weight"), "maxWeight" )

            .add( Projections.groupProperty("color"), "color" )

        )

        .addOrder( Order.desc("catCountByColor") )

        .addOrder( Order.desc("avgWeight") )

        .list();

    List results = session.createCriteria(Domestic.class, "cat")

        .createAlias("kittens", "kit")

        .setProjection( Projections.projectionList()

            .add( Projections.property("cat.name"), "catName" )

            .add( Projections.property("kit.name"), "kitName" )

        )

        .addOrder( Order.asc("catName") )

        .addOrder( Order.asc("kitName") )

        .list();

射影の式に `Property.forName()` も使用できます:

    List results = session.createCriteria(Cat.class)

        .setProjection( Property.forName("name") )

        .add( Property.forName("color").eq(Color.BLACK) )

        .list();

    List results = session.createCriteria(Cat.class)

        .setProjection( Projections.projectionList()

            .add( Projections.rowCount().as("catCountByColor") )

            .add( Property.forName("weight").avg().as("avgWeight") )

            .add( Property.forName("weight").max().as("maxWeight") )

            .add( Property.forName("color").group().as("color" )

        )

        .addOrder( Order.desc("catCountByColor") )

        .addOrder( Order.desc("avgWeight") )

        .list();

## 17.8. クエリおよびサブクエリの分離

`DetachedCriteria` クラスにより、セッションスコープ外にクエリを作成できます。後で、任意の `Session` を使って、実行できます。

    DetachedCriteria query = DetachedCriteria.forClass(Cat.class)

        .add( Property.forName("sex").eq('F') );

    Session session = ....;

    Transaction txn = session.beginTransaction();

    List results = query.getExecutableCriteria(session).setMaxResults(100).list();

    txn.commit();

    session.close();

`DetachedCriteria` は、サブクエリを表現するためにも使えます。サブクエリを伴う Criterion インスタンスは、 `Subqueries` もしくは `Property` から得られます。

    DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class)

        .setProjection( Property.forName("weight").avg() );

    session.createCriteria(Cat.class)

        .add( Property.forName("weight").gt(avgWeight) )

        .list();

    DetachedCriteria weights = DetachedCriteria.forClass(Cat.class)

        .setProjection( Property.forName("weight") );

    session.createCriteria(Cat.class)

        .add( Subqueries.geAll("weight", weights) )

        .list();

相互関係があるサブクエリでさえも可能です:

    DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2")

        .setProjection( Property.forName("weight").avg() )

        .add( Property.forName("cat2.sex").eqProperty("cat.sex") );

    session.createCriteria(Cat.class, "cat")

        .add( Property.forName("weight").gt(avgWeightForSex) )

        .list();

## 17.9. 自然識別子によるクエリ

criteria クエリを含むたいていのクエリにとって、クエリキャッシュはあまり効率がよくないです。なぜなら、クエリキャッシュが頻繁に無効になるためです。しかしながら、キャッシュを無効にするアルゴリズムを最適化できる特別なクエリの種類が１つあります。更新されない自然キーによる検索です。いくつかのアプリケーションでは、この種類のクエリが頻繁に現れます。このような使われ方のために、 criteria API は特別な対策を提供します。

最初に、 `<natural-id>` を使って、エンティティの自然キーをマップしてください。そして、二次キャッシュを有効にします。

    <class name="User">

        <cache usage="read-write"/>

        <id name="id">

            <generator class="increment"/>

        </id>

        <natural-id>

            <property name="name"/>

            <property name="org"/>

        </natural-id>

        <property name="password"/>

    </class

    >

注記： 変更される 自然キーを持つエンティティにこの機能を使うのは、意図されていない使い方です。

これで、 `Restrictions.naturalId()` により、より効率的なキャッシュアルゴリズムを使用できます。

    session.createCriteria(User.class)

        .add( Restrictions.naturalId()

            .set("name", "gavin")

            .set("org", "hb")

        ).setCacheable(true)

        .uniqueResult();

製作著作 © 2004 Red Hat, Inc.

- 前のページ第16章 HQL: Hibernate クエリ言語
- 上に戻る
- ホーム
- 次のページ第18章 ネイティブ SQL