Hibernate.orgCommunity Documentation

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

18.1. Hibernate のフィルタ

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

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

フィルタを使うためにはまず、適切なマッピング要素に定義、追加しなくてはなりません。フィルタを定義するためには、 <hibernate-mapping/> 要素内で <filter-def/> 要素を使用します:


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

そうしてフィルタはクラスへと結び付けられます:


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

また、コレクションに対しては次のようになります:


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

どちらに対しても (また、それぞれを複数) 同時に設定することもできます。

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
>

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