Hibernate.org Community Documentation

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

## 第19章 データのフィルタリング

Hibernate3 では「可視性」ルールに基づいてデータを扱うための画期的な方法を用意しています。 Hibernate filter はグローバルで、名前付きで、パラメータ化されたフィルタです。これは Hibernate セッションごとに有効無効を切り替えられます。

## 19.1. Hibernate のフィルタ

Hibernate3 はフィルタクライテリアをあらかじめ定義し、これらのフィルタをクラスやコレクションレベルに加える機能を加えました。フィルタクライテリアは制約節を定義する機能です。これらのフィルタ条件はパラメータ化できるということを除き、クラスやさまざまなコレクション要素で利用可能な ｢where｣ 句に非常によく似ています。アプリケーションは、与えられたフィルタを可能にすべきか、そしてそのパラメータ値を何にすべきかを実行時に決定することができます。フィルタはデータベースビューのように使用されますが、アプリケーション内ではパラメータ化されます。

Using annotatons filters are defined via `@org.hibernate.annotations.FilterDef` or `@org.hibernate.annotations.FilterDefs`. A filter definition has a `name()` and an array of parameters(). A parameter will allow you to adjust the behavior of the filter at runtime. Each parameter is defined by a `@ParamDef` which has a name and a type. You can also define a `defaultCondition()` parameter for a given `@FilterDef` to set the default condition to use when none are defined in each individual `@Filter`. `@FilterDef`(s) can be defined at the class or package level.

We now need to define the SQL filter clause applied to either the entity load or the collection load. `@Filter` is used and placed either on the entity or the collection element. The connection between `@FilterName` and `@Filter` is a matching name.

例19.1 @FilterDef and @Filter annotations

    @Entity

    @FilterDef(name="minLength", parameters=@ParamDef( name="minLength", type="integer" ) )

    @Filters( {

        @Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length"),

        @Filter(name="minLength", condition=":minLength <= length")

    } )

    public class Forest { ... }

When the collection use an association table as a relational representation, you might want to apply the filter condition to the association table itself or to the target entity table. To apply the constraint on the target entity, use the regular `@Filter` annotation. However, if you want to target the association table, use the `@FilterJoinTable` annotation.

例19.2 Using `@FilterJoinTable` for filterting on the association table

    @OneToMany

        @JoinTable

        //filter on the target entity table

        @Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length")

        //filter on the association table

        @FilterJoinTable(name="security", condition=":userlevel >= requredLevel")

        public Set<Forest> getForests() { ... }

Using Hibernate mapping files for defining filters the situtation is very similar. The filters must first be defined and then attached to the appropriate mapping elements. To define a filter, use the `<filter-def/>` element within a `<hibernate-mapping/>` element:

例19.3 Defining a filter definition via `<filter-def>`

    <filter-def name="myFilter">

        <filter-param name="myFilterParam" type="string"/>

    </filter-def>

This filter can then be attached to a class or collection (or, to both or multiples of each at the same time):

例19.4 Attaching a filter to a class or collection using `<filter>`

    <class name="myClass" ...>

        ...

        <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>

        <set ...>

            <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/>

        </set>

    </class>

`Session` 上のメソッドは `enableFilter(String filterName)`、 `getEnabledFilter(String filterName)`、 `disableFilter(String filterName)` です。デフォルトでは、フィルタは与えられたセッションに対して使用 できません 。 `Filter` インスタンスを返り値とする `Session.enabledFilter()` メソッドを使うことで、フィルタは明示的に使用可能となります。上で定義した単純なフィルタの使用は、このようになります：

    session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");

org.hibernate.Filter インターフェースのメソッドは、 Hibernate の多くに共通しているメソッド連鎖を許していることに注意してください。

有効なレコードデータパターンを持つ一時データを使った完全な例です：

    <filter-def name="effectiveDate">

        <filter-param name="asOfDate" type="date"/>

    </filter-def>

    <class name="Employee" ...>

    ...

        <many-to-one name="department" column="dept_id" class="Department"/>

        <property name="effectiveStartDate" type="date" column="eff_start_dt"/>

        <property name="effectiveEndDate" type="date" column="eff_end_dt"/>

    ...

        <!--

            Note that this assumes non-terminal records have an eff_end_dt set to

            a max db date for simplicity-sake

        -->

        <filter name="effectiveDate"

                condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>

    </class>

    <class name="Department" ...>

    ...

        <set name="employees" lazy="true">

            <key column="dept_id"/>

            <one-to-many class="Employee"/>

            <filter name="effectiveDate"

                    condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>

        </set>

    </class>

常に現在の有効レコードを返却することを保証するために、単純に、社員データの検索より前にセッション上のフィルタを有効にします:

    Session session = ...;

    session.enableFilter("effectiveDate").setParameter("asOfDate", new Date());

    List results = session.createQuery("from Employee as e where e.salary > :targetSalary")

             .setLong("targetSalary", new Long(1000000))

             .list();

上記の HQL では、結果の給料の制約について明示的に触れただけですが、有効になっているフィルタのおかげで、このクエリは給料が100万ドル以上の現役の社員だけを返します。

注記： (HQL かロードフェッチで）外部結合を持つフィルタを使うつもりなら、条件式の方向に注意してください。これは左外部結合のために設定するのが最も安全です。一般的に、演算子の後カラム名に続けて最初のパラメータを配置してください。

定義したあと、フィルタは、それぞれ独自のコンディションを持つ複数のエンティティやコレクションにアタッチされます。コンディションがいつも同じ場合、それは面倒かもしれません。従って、 `<filter-def/>` は、属性または CDATA としてデフォルトコンディションを定義することが可能になります：

    <filter-def name="myFilter" condition="abc > xyz">...</filter-def>

    <filter-def name="myOtherFilter">abc=xyz</filter-def>

このデフォルトのコンディションは、コンディションを指定せずに何かにアタッチされる場合いつでも使われます。これは、特定のケースにおいてデフォルトのコンディションをオーバーライドするフィルターのアタッチメントの一部として、特定のコンディションを与えることができることを意味します。

製作著作 © 2004 Red Hat, Inc.

- 前のページ第18章 ネイティブ SQL
- 上に戻る
- ホーム
- 次のページ第20章 XML マッピング