sábado, 28 de enero de 2017

Consultas dinámicas con Spring Data

Buenas, esta claro que el uso de Spring Data facilita muchas cosas y permite hacer consultas muy potentes con muy poco. Pero con un uso básico siempre estaremos limitados a una única entidad o por ejemplo repetir un mismo método de búsqueda para cada uno de los atributos, ¿O no?. 

Para ello nuestro DAO tendrá que implementar la interfaz 'JpaSpecificationExecutor'. Esta interfaz nos proveerá de nuevos métodos que permitirán el uso de consultas dinámicas en base a la especificación pasada como argumento. 

Vamos a hacer un ejemplo genérico para que nos sirva para más de un DAO, creando una interfaz propia que extienda de las interfaces de Spring Data. Como curiosidad este paso tiene la utilización de la anotación '@NoRepositoryBean'. Esta nos permite crear una interfaz de carácter genérico que implemente JpaRepository pero que no tendrá asociada toda la lógica de los repositorios.

@NoRepositoryBean
public interface GenericDao<E, K> extends JpaRepository<E, K>, JpaSpecificationExecutor<E> {  }

En cuanto a DAOs, lo único que tendríamos hacer es que extiendan de este 'GenericDao' y nada mas.

El siguiente paso sería crear un método genérico (por ejemplo en nuestro GenericService, si es que tenemos), que nos permita hacer uso de las 'Specification'. Con estas 'Specification', podremos crear predicados y hacer consultas al 'viejo' estilo, a través de 'Criteria'.

protected abstract GenericDao<E, K> getDao();
@Override
public Page<D> getPageableSearchByField( final String searchField, final String searchString, final Pageable page ) {
   Specification<E> specification = new Specification<E>() {
      @Override
      public Predicate toPredicate( final Root<E> root, final CriteriaQuery<?> query, final CriteriaBuilder builder ) {
         Path<Object> path = root.get( searchField );
         return builder.equal( path, searchString );
      }
   };
   Page<E> pageEntities = getDao().findAll( specification, page );
   return pageEntities.map( getConverterToDTO() );
}

En el ejemplo hemos creado un método que nos permita buscar por el valor y el nombre del campo que queremos buscar. Y ahora mostraremos el uso múltiple con este único método.


Page<Book> page1= bookService.getPageableSearchByField( "author", "Alfred Bester", pageable );
Page<Book> page2= bookService.getPageableSearchByField( "title", "The Stars My Destination", pageable );
Page<Disc> page3= discService.getPageableSearchByField( "group", "Tool", pageable );

No hay comentarios:

Publicar un comentario