Hibernate.orgCommunity Documentation

Capítulo 19. Filtración de datos

19.1. Filtros de Hibernate

Hibernate3 proporciona un nuevo enfoque innovador para manejar datos con reglas de "visibilidad". Un filtro Hibernate es un filtro global, con nombre y parametrizado que puede ser habilitado o deshabilitado para una sesión de Hibernate especifica.

Hibernate3 tiene la habilidad de predefinir criterios de filtros y unir esos filtros tanto a nivel de clase como de colección. Un criterio de filtro le permite definir una cláusula de restricción muy similar al atributo existente "where" disponible en el elemento class y en varios elementos de colección. Sin embargo, las condiciones de estos filtros se pueden parametrizar. La aplicación puede tomar la decisión en tiempo de ejecución de si los filtros deben estar habilitados y cuáles deben ser sus parámetros. Los filtros se pueden utilizar como vistas de la base de datos, pero parametrizados dentro de la aplicación.

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


Los métodos en Session son: enableFilter(String filterName), getEnabledFilter(String filterName) y disableFilter(String filterName). Por defecto, los filtros no están habilitados para una sesión dada. Los filtros deben ser habilitados explícitamente por medio del uso del método Session.enableFilter(), el cual retorna una instancia de la interfaz Filter. Si se utiliza el filtro simple definido anteriormente, esto se vería así:

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

Los métodos en la interfaz org.hibernate.Filter permiten el encadenamiento de métodos, lo cual es bastante común en gran parte de Hibernate.

Este es un ejemplo completo, utilizando datos temporales con un patrón efectivo de fechas de registro:


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

Con el fin de asegurarse de que siempre recibirá los registros efectivos actualmente, habilite el filtro en la sesión antes de recuperar los datos de los empleados:

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

En el HQL anterior, aunque sólo mencionamos explícitamente una restricción de salario en los resultados, debido al filtro habilitado la consulta sólo retornará empleados actualmente activos que tengan un salario mayor a un millón de dólares.

Si quiere utilizar filtros con unión externa, ya sea a través de HQL, o bien de recuperación de carga, tenga cuidado en la dirección de expresión de la condición. Lo más seguro es configurar esto para una unión externa izquierda. Coloque el parámetro primero seguido del nombre(s) de la(s) columna(s) después del operador.

Después de definir un filtro, este se puede unir a múltiples entidades y/o colecciones cada una con su propia condición. Esto puede llegar a ser problemático cuando las condiciones son las mismas. Así que el usar <filter-def/> le permite definir una condición por defecto, ya sea como atributo o como CDATA:


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

Esta condición predeterminada se utilizará cuando se una el filtro a algo sin especificar una condición. Esto significa que usted le puede dar una condición especifica como parte del anexo del filtro, el cual substituye la condición por defecto en ese caso en particular.