Hibernate.org Community Documentation

- 上一页
- 下一页

## 第 19 章 过滤数据

Hibernate3 提供了一种创新的方式来处理具有“显性（visibility）”规则的数据，那就是使用Hibernate 过滤器。Hibernate 过滤器是全局有效的、具有名字、可以带参数的过滤器，对于某个特定的 Hibernate session 您可以选择是否启用（或禁用）某个过滤器。

## 19.1. Hibernate 过滤器（filters）

Hibernate3 新增了对某个类或者集合使用预先定义的过滤器条件（filter criteria）的功能。过滤器条件相当于定义一个 非常类似于类和各种集合上的“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)`。Session 中默认是不启用过滤器的，必须通过 `Session.enabledFilter()` 方法显式的启用。该方法返回被启用的 `Filter` 的实例。以上文定义的过滤器为例：

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

注意，org.hibernate.Filter 的方法允许链式方法调用。（类似上面例子中启用 Filter 之后设定 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 中，虽然我们仅仅显式的使用了一个薪水条件，但因为启用了过滤器，查询将仅返回那些目前雇用关系处于生效期的，并且薪水高于一百万美元的雇员的数据。

注意：如果你打算在使用外连接（或者通过 HQL 或 load fetching）的同时使用过滤器，要注意条件表达式的方向（左还是右）。最安全的方式是使用左外连接（left outer joining）。并且通常来说，先写参数，然后是操作符，最后写数据库字段名。

在 Filter 定义之后,它可能被附加到多个实体和/或集合类,每个都有自己的条件。假若这些条件都是一样的，每次都要定义就显得很繁琐。因此，`<filter-def/>` 被用来定义一个默认条件，它可能作为属性或者 CDATA 出现：

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

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

当这个 filter 被附加到任何目的地，而又没有指明条件时，这个缺省条件就会被使用。注意，换句话说，你可以通过给 filter 附加特别的条件来重载默认条件。

版权 © 2004 Red Hat, Inc.

- 上一页第 18 章 Native SQL 查询
- 上一级
- 起始页
- 下一页第 20 章 XML 映射