Filtros Hibernate

PEDRO DELGADO YARZA 2014/01/29 13:51

Hibernate proporciona una utilidad para que, al consultar una entidad, devuelva los resultados filtrada por unas condiciones establecidas de antemano sin tener que estar especificando el filtro en cada consulta HQL.

Esto es especialmente útil por ejemplo cuando en una aplicación, un usuario sólo va a mantener datos a los que él tiene acceso. Sin el filtro de Hibernate cada vez que listaramos una determinada tabla tendríamos que añadir la condición en cada sentecia HQL que hicieramos para la consulta de dicha tabla. Con el filtro especificado, a nivel de entidad, podemos escribir una consulta como “select Locales l from Locales”, que Hibernate le agregará la el fitro “where l.usuario = ….” que corresponda, según lo que especifiquemos.

Otra posible aplicación de estos filtros puede ser en colecciones OneToMany, que se desean que se filtren. Si tenemos una entidad que tiene una relacion OneToMany con otra, pero en la que queremos que al obtener los elementos, se filtre por una condición (no aparezcan todos los elementos con los que está relacionados, si no sólo unos cuantos), se puede especificar un filtro a nivel de colección. Cuando se haga el “getHijos()” se ejecutará el filtro.

En otro caso, tendríamos que “sobreescribir” el mecanismo de Hibernate y lanzar manualmente una HQL cuando quisieramos coger los elementos relacionados y establecérselo al objeto.

Seam proporciona encapsulamiento para esta utilidad de Hibernate, ya que en principio, el filtro está ligado a una conexión y desactivado por defecto. Cuando se abre una conexión hay que habilitar el filtro.

En aplicaciones Web se suele abrir una conexión por cada petición Web por lo que estaríamos obligados a abrir el filtro por cada petición de usuario. Seam encapsula esto, haciéndolo más fácil y basta con configurarlo en un fichero xml, que Seam se encargará de habilitarlo.

Primero declaramos el filtro en la clase que queremos que lo tenga. Si queremos filtrar la entidad Comentario por el campo usuario, nos iríamos a la clase Comentario.java y en la cabecera añadiríamos:

        @FilterDefs(value={
	  @FilterDef(name="usuarioFilter", parameters={@ParamDef(type="string", name="nif")})
	})
	@Filters( {
   	  @Filter(name="usuarioFilter", condition="usuario in (select usuarios.login from FUNDAWEB.Usuarios usuarios where usuarios.dni = :nif) ")
	} )
	@Table(name = "COMENTARIO", uniqueConstraints = @UniqueConstraint(columnNames = "NUMERO"), schema="FUNDEWEB")
	public class Comentario implements java.io.Serializable {
	.............
 

La propiedad condition es la que tiene la sentencia SQL, la sentencia escrita debe de estarlo en SQL. Hibernate la concatenará tal y como viene pudiéndose añadir parámetros que se le establecerán en el xml de configuración (:nif en el ejemplo).

Ahora en el fichero components.xml declararíamos el filtro para que Seam nos lo abra en cada conexión. Se pueden especificar condiciones, que según se cumplan o no, el filtro estará activo o no (atributo enabled). Al mismo tiempo se pueden establecer parámetros ligados expresiones EL, que se evaluarán en el momento de abrir el filtro. Usando ambas utilidades se puede garantizar que un filtro no se habilite hasta que los parámetros que se le pasan no estén establecidos. Contenido del fichero components.xml, (añadir al persistence:managed-persistence-context existente):

       <persistence:filter name="usuarioFilter" enabled="#{identity.loggedIn}">
	  <persistence:name>usuarioFilter</persistence:name>
	  <persistence:parameters>
	    <key>nif</key>
	    <value>#{identity.nif}</value>
	  </persistence:parameters>
	</persistence:filter>
	<persistence:managed-persistence-context name="entityManager"
		auto-create="true" persistence-unit-jndi-name="ejb_prototipo/defaultPU"
		entity-manager-factory="#{defaultEMF}" >
		 <persistence:filters>
		    <value>#{usuarioFilter}</value>
		  </persistence:filters>
	</persistence:managed-persistence-context>

Un filtro asociado a una relación se establecería de manera similar a la anterior, pero declarándolo en vez de a nivel de clase a nivel de método, justo encima del método get() de la relación que queremos “filtrar” por defecto. La definición de filtro (FilterDef) si debe de estar a nivel de clase. Vemos un ejemplo:

        @FilterDef(name="parametrosUsuarios",parameters={@ParamDef(type="string", name="dni")})
	@Entity
	@Table(name = "COMPONENTES", uniqueConstraints = @UniqueConstraint(columnNames = "COMP_WEBID"))
	public class Componentes implements java.io.Serializable {
	....
	@OneToMany(fetch = FetchType.LAZY, mappedBy = "componentes")
	@Filter(name="parametrosUsuarios",condition="dni = :dni")
	public List<ParametrosUsuario> getParametrosUsuarios() {
		return this.parametrosUsuarios;
	}

Si por cualquier cuestión, necesitamos habilitar el filtro manualmente, por ejemplo si al abrir la conexión no se cumple la condición, pero en la misma petición mas tarde sí lo necesitamos, podríamos obtener la conexión de Hibernate que esté activa y habilitarlo nosotros de la siguiente manera:

	((org.hibernate.Session)entityManager.getDelegate()).enableFilter("parametrosUsuarios").setParameter("dni", identity.getUSesion().getDni());

Como se observa los parámetros, en este caso, se pasan manualmente.

  • fdw2.0/fundeweb2.0/gt/filtros_de_hibernate.txt
  • Última modificación: 07/11/2017 10:46
  • (editor externo)