Hibernate.orgCommunity Documentation

Chapitre 19. Filtrer les données

19.1. Filtres Hibernate

Hibernate3 fournit une nouvelle approche innovatrice pour manipuler des données avec des règles de "visibilité". Un filtre Hibernate est un filtre global, nommé, paramétré qui peut être activé ou désactivé pour une session Hibernate particulière.

Hibernate3 ajoute la capacité de prédéfinir des critères de filtre et d'attacher ces filtres à une classe ou à une collection. Un critère de filtre est la faculté de définir une clause de restriction très similaire à l'attribut "where" existant disponible sur une classe et divers éléments d'une collection. Par ailleurs ces conditions de filtre peuvent être paramétrées. L'application peut alors prendre la décision à l'exécution si des filtres donnés doivent être activés et quels doivent être leurs paramètres. Des filtres peuvent être utilisés comme des vues de base de données, mais paramétrées dans l'application.

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.


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.


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:


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


Les méthodes sur Session sont : enableFilter(String filterName), getEnabledFilter(String filterName), et disableFilter(String filterName). Par défaut, les filtres ne sont pas activés pour une session donnée ; ils doivent être explicitement activés en appelant la méthode Session.enabledFilter(), laquelle retourne une instance de l'interface Filter. Utiliser le simple filtre défini ci-dessus ressemblerait à :

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

Notez que des méthodes sur l'interface org.hibernate.Filter autorisent le chaînage de beaucoup de méthodes communes à Hibernate.

Un exemple complet, utilisant des données temporelles avec une structure de date d'enregistrement effectif :


<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>

Puis, afin de s'assurer que vous pouvez toujours récupérer les enregistrements actuellement effectifs, activez simplement le filtre sur la session avant de récupérer des données des employés :

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

Dans le HQL ci-dessus, bien que nous ayons seulement mentionné une contrainte de salaire sur les résultats, à cause du filtre activé, la requête retournera seulement les employés actuellement actifs qui ont un salaire supérieur à un million de dollars.

A noter : si vous prévoyez d'utiliser des filtres avec des jointures externes (soit à travers HQL, soit par le chargement), faites attention à la direction de l'expression de condition. Il est plus sûr de la positionner pour les jointures externes à gauche ; en général, placez le paramètre d'abord, suivi du(des) nom(s) de colonne après l'opérateur.

Après avoir été défini, un filtre peut être attaché à de nombreuses entités et/ou des collections, chacune avec sa propre condition. Cela peut être fastidieux quand les conditions sont les mêmes à chaque fois. Ainsi <filter-def/> permet de définir une condition par défaut, soit en tant qu'attribut, soit comme CDATA.


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

Cette condition par défaut sera alors utilisée à chaque fois que le filtre est attaché à quelque chose sans spécifier la condition. Notez que cela signifie que vous pouvez fournir une condition spécifique en tant que faisant partie de la pièce attachée du filtre qui surcharge la condition par défaut dans ce cas particulier.