Consultas dinámicas (Dynamic Query) en Liferay 6

Las consultas dinámicas son una herramienta muy útil para construir métodos en cualquiera de los servicios Liferay.

Estos métodos serán capaces de realizar búsquedas avanzadas en función de diferentes criterios sobre cualquiera de las entidades que maneja Liferay.

Introducción

Todos los servicios de capa de negocio generados mediante el Service Builder incorporan un método sobrecargado llamado dynamicQuery():

public static List dynamicQuery(DynamicQuery dynamicQuery)
throws SystemException
public static List dynamicQuery(DynamicQuery dynamicQuery,
int start,int end)
throws SystemException
public static List dynamicQuery(DynamicQuery dynamicQuery,
int start,int end,
OrderByComparator orderByComparator)
throws SystemException

 

Estos métodos nos permiten recuperar una lista de entidades que cumplen una determinada condición.

Esta condición se define gracias a un conjunto de criterios definidos mediante un objeto que implementa la interface DynamicQuery, por lo tanto, aprender a construir búsquedas avanzadas implica aprender a crear este tipo de objeto. Se pasa a describir a continuación el proceso para conseguirlo:

  • Creación de la consulta.
  • Parametrización de la consulta.
  • Ejecución de la consulta.

Interface DynamicQuery

El conocimiento profundo de esta interface nos permitirá construir consultas avanzadas. Se encuentra en el paquete com.liferay.portal.kernel.dao.orm:

El método add() permite añadir condiciones sobre la búsqueda y el método addOrder() criterios de ordenación.

Los programadores que trabajan habitualmente con Hibernate y su interface Criteria deben estar familiarizados con estos conceptos.
Ahora bien,

¿cómo creo un objeto que implemente la interface DynamicQuery?.

¿busco una implementación?.

A continuación, respondemos a estas preguntas.

Creación de consultas

La clase DynamicQueryFactoryUtil se encarga de construir las consultas dinámicas:

 

El método forClass es el responsable de la generación del objeto:

public static DynamicQuery forClass(Class clazz,
ClassLoader classLoader)
  • clazz: NombreDeClase.class.
  • classLoader: cargador de clases.

Ejemplo:

DynamicQuery consulta =
DynamicQueryFactoryUtil.forClass(
JournalArticle.class,
PortalClassLoaderUtil.getClassLoader());


Si la consulta se realiza sobre una entidad de Liferay debemos incluir el cargador de clases.

DynamicQuery consulta = DynamicQueryFactoryUtil.forClass(
JournalArticle.class,
PortalClassLoaderUtil.getClassLoader());

En cambio, si se realiza sobre una entidad creada por el desarrollador no debemos incluirlo:

DynamicQuery consulta =
DynamicQueryFactoryUtil.forClass(ExpenseSheet.class);

Parametrización de la consulta

Una vez que se ha creado el objeto, se deben añadir criterios de búsqueda y ordenación que definen la consulta:

  • DynamicQuery add(Criterion criterion): el método add() permite incluir nuevos criterios de búsqueda en la consulta.
  • DynamicQuery addOrder(Order order): el método addOrder() permite definir los criterios de ordenación a aplicar.

Un criterio se define como un objeto que implementa la interface Criterion. Una ordenación se define como un objeto que implementa la interface Order.

Definición de criterios de búsqueda

La clase RestrictionsFactoryUtil define un conjunto de métodos estáticos muy útiles que construyen objetos que implementan la interface Criterion, es decir, estos métodos nos permiten definir las restricciones a aplicar en la consulta:

Algunos de estos métodos estáticos son:

  • eq: define una restricción de tipo igual que.
  • ge: define una restricción de tipo mayor o igual que.
  • gt: define una restricción de tipo mayor que.
  • ilike: define una restricción ilike.
  • isNotNull: define una restricción de tipo no es nulo.
  • le: define una restricción de tipo menor o igual que.
  • like: función like.
  • lt: menor que.
  • ne: no es igual.
  • ...

Además, proporciona métodos que permiten construir una consulta con Funciones and y or de forma flexible:

  • public static Conjunction conjunction()
  • public static Disjunction disjunction().
  • public static Criterion and(Criterion lhs, Criterion rhs)
  • public static Criterion or(Criterion lhs, Criterion rhs)

Definición de ordenación

La clase OrderFactoryUtil:

 

Proporciona dos métodos para definir ordenación ascendente o descendente en función de una propiedad:

  • public static Order asc(String propertyName)
  • public static Order desc(String propertyName)

Ejecución de la búsqueda

Una vez que la consulta ha sido creada y parametrizada adecuadamente, ésta debe ser pasada como parámetro al método dynamicQuery() asociado a cualquiera de los servicios de negocio nos permite recuperar una lista con los objetos que cumplen la condición definida por la consulta:

public static List dynamicQuery(DynamicQuery dynamicQuery)
throws SystemException

Ejemplo:

List eventos =
CalEventLocalServiceUtil.dynamicQuery(consulta);

Ejercicio

Para ilustrar este artículo, se describe a continuación, cómo incorporar nuevas funcionalidades de búsqueda sobre una entidad definida por el usuario llamada Informe.

El fichero service.xml que se ha utilizado para este ejemplo se muestra a continuación:

<service-builder package-path="com.ematiz.business">
    <author>Jesus Salinas</author>
    <namespace>Tekuento</namespace>
    <entity local-service="true" name="Informe" remote-service="false" uuid="true">
        <column name="informeId" primary="true" type="long"></column>
       
        <column name="userId" type="long"></column>
        <column name="companyId" type="long"></column>
        <column name="groupId" type="long"></column>
       
        <column name="userName" type="String"></column>
        <column name="titulo" type="String"></column>
        <column name="informacion" type="String"></column>
    </entity>
</service-builder>

El método que se crea a modo de ejemplo se llama getInformesByTituloOrUserName(). Como su nombre indica este método recupera todos los informes que tengan un determinado título o que haya sido creado por un determinado usuario.

Este método debe OBLIGATORIAMENTE ser incorporado en la clase InformeLocalServiceImpl.

/**
* El metodo getInformesByTituloOrUserName
* recupera todos los informes que tengan
* el titulo pasado como parametro o que hayan sido
* creado por el usuario pasado
* como parametro.
*
* @param titulo titulo del informe.
* @param userName nombre del usuario que ha
* creado el informe.
* @return lista de informes que cumple la condicion
* pasada como parametros.
* @throws SystemException
*/
@SuppressWarnings("unchecked")
public List getInformesByTituloOrUserName(String titulo, String userName)
                                          throws SystemException{
   
   // Paso 1: Creacion de la consulta.
   DynamicQuery consulta = DynamicQueryFactoryUtil.forClass(Informe.class);

   // Paso 2: Parametrizacion de la consulta.
       
   // Paso 2.1: Se crea el criterio asociado al
   // titulo del informe.
   // En este caso se utiliza la funcion ilike.
   Criterion criterio1 = null;
   if (titulo != null && !titulo.equals("")) {
       // Si titulo existe se construye la restriccion.
       criterio1 = RestrictionsFactoryUtil.ilike("titulo", "%"
       + titulo + "%");
   }
       
   // Paso 2.2: Se crea el criterio asociado al
   // nombre de usuario que ha creado el informe.
   // En este caso se utiliza la funcion eq.
   // Debe coincidir exactamente.
       
   Criterion criterio2 = null;
   if (userName != null && !userName.equals("")) {
           
     // Si userName existe se construye la
     // restriccion.
     criterio2 = RestrictionsFactoryUtil.eq("userName", userName);
   }
       
   // Paso 2.3: Se construye la funcion OR.
   Disjunction funcionOr = RestrictionsFactoryUtil.disjunction();

   if(criterio1!=null){
     funcionOr.add(criterio1);
   }
   if(criterio2!=null){
     funcionOr.add(criterio2);
   }
   // Paso 2.4: Se cargan todos los criterios en la consulta.
   consulta.add(funcionOr);

   // Paso 3: Se ejecuta la consulta previamente creada.
   return dynamicQuery(consulta);
}

Conclusión

La generación de servicios Liferay mediante el Service Builder se complementa mediante la incorporación de nueva funcionalidad de forma manual.

El conocimiento profundo de las consultas dinámicas permite al programador adaptar sus servicios de forma específica incorporando búsquedas avanzadas haciéndolos más completos y útiles.

 

Commenti
URL di Trackback:

comments powered by Disqus