martes, 28 de junio de 2011

JPA - Ejemplo de Paginación

A continuacion daremos un breve ejemplo de como desarrollar una paginacion utilizando SQL nativo y luego utilizando JPQL

Temas a tratar:

  • Paginación utilizando SQL nativo
  • Paginación utilizando JPQL

Seguimos como lo venimos haciendo en las entregas anteriores, con los mismos ejemplos de tablas  y datos. Para mas detalle de como son la relaciones entre las tablas Ver tutorial Tutorial JPA I - Manejo de relaciones

TABLA CUSTOMER
 
 CUSTOMER_ID     FIRST_NAME     GENDER     LAST_NAME     NAME1     NAME2     REFEREE_ID    
 --------------  -------------  ---------  ------------  --------  --------  -------------
 1               First name 1   FEMALE     Last name 1   Damian    (null)    1             
 2               First name 2   FEMALE     Last name 2   (null)    (null)    2             
 3               First name 3   FEMALE     Last name 3   (null)    (null)    1             
 4               First name 4   MALE       Last name 4   (null)    (null)    (null)      


Paginación con SQL nativo

A continuacion desarrollaremos el metodo que realizara la paginacion sobre la tabla CUSTOMER:  Se obtendran todos los customer sin ningun tipo de filtro y de dos en dos. Es decir, la paginacion se realizara trayendo de a dos registros por vez. La consulta de negocio en este caso sera traer todos los customers y dicha consulta estara en SQL nativa.

/**
 * Este metodo sera invocado cada vez que el usuario lleve a cabo la paginacion, es decir, cada vez que el usuario pase a la   
 * siguiente pagina del listado de datos. Los valores que recibira iran cambiando teniendo en cuenta la pagina que se este 
 * mostrando del listado como asi tambien el prmer resultado a mostrar.
*  Este metodo tranquilamente podra ir en un DAO
 */

private List<CustomerDef> getAllCustomersWithPaginationAndSQLQuery(Long paginationFirstResult, 
                                           Long paginationMaxResult, 
                                           Long paginationActivePage) {
       
          Session session = (Session) em.getDelegate();
        
          // Armamos la query de negocio en SQL nativo envuelta con de la query que realiza el 
          // paginado mediante la key rownum de SQL
        StringBuilder querySt = new StringBuilder();
        querySt = querySt.append("SELECT * FROM ( ");
        querySt = querySt.append("SELECT row_.*, rownum rownum_ FROM ( ");       
        querySt = querySt.append("SELECT c.FIRST_NAME as firstName, " +
                                      "  c.LAST_NAME as lastName " +
                                 "FROM CUSTOMER c");
        querySt = querySt.append(") row_ where rownum <= :rownumMax) WHERE rownum_ > :rownumMin");       
   
        // Le seteamos a la query los valores de paginacion 
          // Agregamos los addScalar para llevar a cabo la transformacion del
          // resultado a CustomerDef
        SQLQuery sqlQuery = session.createSQLQuery(querySt.toString());
        sqlQuery.setLong("rownumMin", paginationFirstResult);
        sqlQuery.setLong("rownumMax", new Long(paginationMaxResult * paginationActivePage));       
        sqlQuery.addScalar("firstName");
        sqlQuery.addScalar("lastName");

          // Transformamos y bindeamos el resultado de la consulta SQL nativa al POJO CustoemerDef     
        sqlQuery.setResultTransformer(Transformers.aliasToBean(
                                                             CustomerDef.class));
               
        // Ejecutamos la query
        List<CustomerDef> result = sqlQuery.list();
       
        // Logueamos el resultado
        for (CustomerDef customerDef : result) {
            log.debug("CUSTOMER First Name: " + customerDef.getFirstName()
                          + "   Last Name: " + customerDef.getLastName());
        } 
       
        return result;
}

Este metodo debera ser llamado de la siguiente manera: 

Tener en cuenta que los valores deberan llegar como parametros a los metodos de los DAOs que tengan la paginacion para efectuar correctamente el paginado. En este ejemplo, el metodo getAllCustomersWithPagination() cumple con este requisito ya que recibe como parametros los valores necesarios para llevar a cabo la paginacion.

Una opcion es tener un objeto llamado PaginationData donde tendremos estas propiedades con los valores adecuados y pasaremos dicho objeto en cada consulta que tengamos que hacer. (en cada metodo de cada DAO) 

En este ejemplo estamos paginando de a dos resultados ( en primer lugar mostraremos los dos primeros customers, luego mostraremos los otros dos y luego no mostraremos mas nada porque en la tabla de customers solo existen 4 registros)

.......
.......
.......
        long paginationFirstResult = 0;  // Este valor se ira incrementado dependiendo de la cantidad de registros max a mostrar por pagina
          long paginationMaxResult = 2;   // Este valor no debera cambiar
          long paginationActivePage = 1; // Este valor se ira incrementado de a uno cuando el usuario pase a la 2da pagina.
          paginationQueries(paginationFirstResult, paginationMaxResult, paginationActivePage);
       
        long paginationFirstResult1 = 2;  // Este valor se ira incrementado dependiendo de la cantidad de registros max a mostrar por pagina
         long paginationMaxResult1 = 2;   // Este valor no debera cambiar
         long paginationActivePage1 = 2; // Este valor se ira incrementado de a uno cuando el usuario pase a la 3er pagina.
         paginationQueries(paginationFirstResult1, paginationMaxResult1, paginationActivePage1);
       
        long paginationFirstResult2 = 4;  // Este valor se ira incrementado dependiendo de la cantidad de registros max a mostrar por pagina
         long paginationMaxResult2 = 2; // Este valor no debera cambiar
         long paginationActivePage2 = 3; // Este valor se ira incrementado de a uno cuando el usuario pase a la 4ta pagina. .
         paginationQueries(paginationFirstResult2, paginationMaxResult2, paginationActivePage2);
.....
.....
.....

El resultado de las 3 llamadas al metodo paginationQueries con los distintos parametros es el sieguiente (traza SQL + logs de la paginacion)

3875 [main] DEBUG module1.JpqlAndHqlQueryTest  - --------------------------------
3875 [main] DEBUG module1.JpqlAndHqlQueryTest  - -------pagination Queries-------
3875 [main] DEBUG module1.JpqlAndHqlQueryTest  - --------------------------------
Hibernate:
    SELECT
        *
    FROM
        ( SELECT
            row_.*,
            rownum rownum_
        FROM
            ( SELECT
                c.FIRST_NAME as firstName,
                LAST_NAME as lastName
            FROM
                CUSTOMER c) row_
        where
            rownum <= ?
        )
    WHERE
        rownum_ > ?
3875 [main] DEBUG module1.JpqlAndHqlQueryTest  - CUSTOMER First Name: First name 1 Last Name: Last name 1
3875 [main] DEBUG module1.JpqlAndHqlQueryTest  - CUSTOMER First Name: First name 2 Last Name: Last name 2
Hibernate:
    SELECT
        *
    FROM
        ( SELECT
            row_.*,
            rownum rownum_
        FROM
            ( SELECT
                c.FIRST_NAME as firstName,
                LAST_NAME as lastName
            FROM
                CUSTOMER c) row_
        where
            rownum <= ?
        )
    WHERE
        rownum_ > ?
3875 [main] DEBUG module1.JpqlAndHqlQueryTest  - CUSTOMER First Name: First name 3 Last Name: Last name 3
3875 [main] DEBUG module1.JpqlAndHqlQueryTest  - CUSTOMER First Name: First name 4 Last Name: Last name 4
Hibernate:
    SELECT
        *
    FROM
        ( SELECT
            row_.*,
            rownum rownum_
        FROM
            ( SELECT
                c.FIRST_NAME as firstName,
                LAST_NAME as lastName
            FROM
                CUSTOMER c) row_
        where
            rownum <= ?
        )
    WHERE
        rownum_ > ?

No trajo registros la 3er busqueda ya que como sabemos, solo existen 4 registros en la tabla de Customers. 


Paginación con JPQL



*****************
SITIO EN CONSTRUCCION
*****************



Descargas de ejemplos de mapeos JPA, consultas JPQL y paginación

Por favor, haga clic en: Descargar ejemplos JPA

Bibliografia



* Java Persistence with Hibernate - Revised Edition fo Hiernate In Action - Christian Bauer and Gavin King - 2007

* EJB 3 Developer Guide - A Practical Guide for developers and architects to the Enterprise Java Beans
   Standard - Michael Sikora - 2008

No hay comentarios:

Publicar un comentario