Hibernate.orgCommunity Documentation

Chapitre 18. Filtrer les données

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

Afin d'utiliser des filtres, ils doivent d'abord être définis, puis attachés aux éléments de mapping appropriés. Pour définir un filtre, utilisez l'élément <filter-def/> dans un élément <hibernate-mapping/> :


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

Puis, ce filtre peut être attaché à une classe :


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

Ou bien, à une collection :


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

Ou même encore, aux deux (ou à plusieurs de chaque) en même temps.

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.