Spring Integración con QueryDSL
Seguimos con nuestra serie de cursos sobre acceso a datos con Spring, seguimos trabajando sobre el proyecto del tutorial anterior Spring Data JPA, en esta ocasión integraremos la librería QueryDSL a nuestro proyecto, la misma nos permite generar consultas de una manera, rápida, consistente y segura, esta librería fue en principio diseñada para HQL Hibernate pero hoy en día soporta varias tecnologías de persistencia de datos, como: JPA, JDBC, Lucene, MongoDB, etc.
Utilizando QueryDSL nos olvidamos de escribir consultas en cadenas de texto, por lo que no requerimos los lenguajes, SQL, HQL, JPQL para consultar datos en sus respectivas tecnologías.
Para usar esta tecnología con Spring Data JPA requerimos las siguientes dependencias:
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
<version>${querydsl.version}</version>
</dependency>
También debemos configurar el siguiente maven plugin:
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
El procesador de anotaciones JPAAnnotationProcessor
buscara las clases anotadas con @Entity
y generará las clases especiales que serán utilizadas para crear las consultas, las mismas se almacenarán en el directorio target/generated-sources y normalmente tienen el mismo nombre de entidad más la letra inicial Q, por ejemplo, para la clase que hemos venido trabajando desde el inicio de esta seria de tutoriales, Product
se creará una clase llamada QProduct
.
En Netbeans damos clic derecho y seleccionamos Clean and Build una vez terminado el proceso tendremos lo siguiente:
La clase Product
se define de la siguiente manera:
@Data
@Entity
public class Product {
@Id private Long id;
private String name;
private Double price;
}
Si abrimos la clase QProduct
, veremos lo siguiente:
@Generated("com.mysema.query.codegen.EntitySerializer")
public class QProduct extends EntityPathBase<Product> {
private static final long serialVersionUID = -2093252856L;
public static final QProduct product = new QProduct("product");
public final NumberPath<Long> id = createNumber("id", Long.class);
public final StringPath name = createString("name");
public final NumberPath<Double> price = createNumber("price", Double.class);
public QProduct(String variable) {
super(Product.class, forVariable(variable));
}
public QProduct(Path<? extends Product> path) {
super(path.getType(), path.getMetadata());
}
public QProduct(PathMetadata<?> metadata) {
super(Product.class, metadata);
}
}
De momento nos es necesario entender a profundidad esta clase, lo que debemos saber es que la misma nos permitirá realizar consultas sobre la entidad a la que representa, en este caso, la entidad Product
.
Para utilizar la biblioteca QueryDSL en un proyecto Spring Data JPA debemos modificar el repositorio, para nosotros la interface ProductRepository
que hemos creado previamente, la modificación es muy simple, solo debemos extender la interface QueryDslPredicateExecutor
.
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.repository.CrudRepository;
public interface ProductRepository extends
CrudRepository<Product, Long>,
QueryDslPredicateExecutor<Product> {
}
Esta interface se define como sigue:
Disponemos de los métodos findOne
, findAll
, count
, para enviar consultas a las bases de datos, el primero nos devolverá un resultado, el segundo una colección y el tercero un conteo, la consulta en si la pasamos con el parámetro Predicate
.
Para crear el Predicate
primero debemos obtener un objeto QProduct
esto lo hacemos a través del miembro estático, de la siguiente manera: QProduct qp = QProduct.product;
.
ProductRepository pr = ctx.getBean(ProductRepository.class);
QProduct qp = QProduct.product;
Predicate prdct = qp.price.gt(100.0);
pr.findAll(prdct).forEach(System.out::println);
El Predicate
prdct permite obtener una lista de todos los productos con un precio mayor a 100.0 dólares, este es creado mediante, qp.price.gt(100.0)
, tendremos disponible una variable Path
por cada una de las propiedades de la entidad producto, ellas son: id, price, name, al acceder a cada una de ellas tendremos un conjunto de métodos que podemos usar para crear distintos tipos de consultas, en este primer caso usamos gt(100.0)
, gt indica mayor que (en ingles), de este modo encontraremos más de estos métodos.
Predicate helado = qp.name.contains("Ice");
Este ejemplo busca todos los productos que en su nombre contengan la palabra "Ice", vemos que para consultar con respecto al nombre usamos qp.name
seguido del método de consulta, contains("Ice")
, otros métodos similares a este son: startsWith("...")
y endsWith("...")
que usaríamos para obtener los productos cuyos nombre empiecen o terminen con el texto indicado.
Para crear consultas más complejas podemos utilizar expresiones booleanas para combinar varias consultas, por ejemplo, usando el método and para combinar las dos consultas creadas previamente obtendríamos una lista de todos los productos con un precio mayor a 100.0 y que además en su nombre este la palabra “Ice”.
ProductRepository pr = ctx.getBean(ProductRepository.class);
QProduct qp = QProduct.product;
BooleanExpression precio = qp.price.gt(100.0);
BooleanExpression helado = qp.name.contains("Ice");
Predicate helados_caros = helado.and(precio);
pr.findAll(helados_caros).forEach(System.out::println);
En el siguiente código de ejemplo veremos como listar todos los productos no nulos y ordenarlos según el precio de manera ascendente.
pr.findAll(qp.isNotNull(), qp.price.asc())
.forEach(System.out::println);
Este otro ejemplo nos muestra como contar los productos que tienen un precio entre los valores indicados.
long count = pr.count(qp.price.between(50.0, 220.0));
System.out.println("cantidad: " + count);
De momento quedamos aquí, debes saber que QueryDSL cuenta con gran cantidad de métodos para crear consultas, necesitaríamos una serie de tutoriales para verlas todas, pero una vez comprendas el funcionamiento, utilizarlas será sencillo, nos vemos en la próxima.
- Ver código: Spring Data con QueryDSL
- Ver más tutoriales: Spring Framework (español)
Comentarios
Publicar un comentario