Red Hat Training

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

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

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

18.1. 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>
このデフォルトの条件は、条件を指定せずに何かに紐付けされる場合いつでも使われます。これは、特定のケースにおいてデフォルトの条件をオーバーライドするフィルターのアタッチメントの一部として、特定の条件を与えることができることを意味します。