Volver a la página principal
lunes 27 enero 2025
29

Spring Boot: Consultas Personalizadas con JPQL y Criteria API

Cuando trabajamos con Spring Boot y bases de datos, una de las herramientas más utilizadas es JPA (Java Persistence API), que nos permite interactuar con la base de datos de forma eficiente y sencilla. Sin embargo, en muchas ocasiones, las consultas generadas automáticamente por Spring Data JPA no son suficientes, y necesitamos construir consultas personalizadas.

Para ello, JPA nos proporciona dos mecanismos clave:

  • JPQL (Java Persistence Query Language): Un lenguaje de consultas orientado a objetos similar a SQL pero que opera sobre entidades.
  • Criteria API: Una API fluida y programática para construir consultas dinámicas en tiempo de ejecución.

1. ¿Qué es JPQL?

JPQL (Java Persistence Query Language) es un lenguaje de consultas basado en objetos que permite realizar búsquedas sobre entidades JPA en lugar de tablas de base de datos. La principal diferencia con SQL es que JPQL trabaja con nombres de entidades y atributos en lugar de nombres de tablas y columnas, lo que lo hace más portable y orientado a objetos.

Características de JPQL

  • Se basa en la estructura de las entidades JPA.
  • Soporta cláusulas como SELECT, WHERE, JOIN, ORDER BY, GROUP BY, etc.
  • Se puede utilizar directamente en repositorios de Spring Data JPA mediante la anotación @Query.
  • Admite parámetros posicionados y nombrados.

1.1 Consultas JPQL en Spring Boot

Para realizar consultas personalizadas con JPQL en Spring Boot, podemos utilizar la anotación @Query en los repositorios de JPA.

Ejemplo básico de JPQL

Supongamos que tenemos una entidad Usuario:

@Entity
public class Usuario {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String nombre;
    private String email;
    private int edad;
    
    // Getters y Setters
}

Consulta JPQL en el repositorio

@Repository
public interface UsuarioRepository extends JpaRepository<Usuario, Long> {

    // Buscar usuarios por nombre
    @Query("SELECT u FROM Usuario u WHERE u.nombre = ?1")
    List<Usuario> buscarPorNombre(String nombre);

    // Buscar usuarios mayores de cierta edad
    @Query("SELECT u FROM Usuario u WHERE u.edad > :edad")
    List<Usuario> buscarUsuariosMayores(@Param("edad") int edad);
}

1.2 Uso de consultas JPQL con relaciones

JPQL permite realizar consultas sobre relaciones entre entidades utilizando JOIN.

Por ejemplo, si tenemos una relación entre Usuario y Pedido:

@Entity
public class Pedido {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String descripcion;
    
    @ManyToOne
    @JoinColumn(name = "usuario_id")
    private Usuario usuario;
}

Podemos realizar consultas con JOIN en JPQL:

@Query("SELECT p FROM Pedido p JOIN p.usuario u WHERE u.nombre = :nombre")
List<Pedido> buscarPedidosPorNombreUsuario(@Param("nombre") String nombre);

1.3 Uso de parámetros en JPQL

JPQL admite dos tipos de parámetros:

1. Parámetros posicionales: Se identifican con ?1, ?2, etc.

2. Parámetros con nombre: Se identifican con :nombre, :edad, etc.

Ejemplo de ambos enfoques:

@Query("SELECT u FROM Usuario u WHERE u.nombre = ?1 AND u.edad = ?2")
List<Usuario> buscarPorNombreYEdad(String nombre, int edad);

@Query("SELECT u FROM Usuario u WHERE u.email = :email")
Usuario buscarPorEmail(@Param("email") String email);

2. ¿Qué es la Criteria API?

La Criteria API es una herramienta más flexible y poderosa que permite construir consultas de forma dinámica mediante código Java en lugar de escribir directamente JPQL. Esto es especialmente útil cuando:

  • Se requiere construir consultas dinámicas basadas en condiciones variables.
  • Se necesita mayor flexibilidad en la composición de consultas.

Características de Criteria API

  • Es completamente programática.
  • Ofrece seguridad frente a inyecciones SQL.
  • Permite construir consultas con filtros dinámicos.
  • Compatible con todas las funciones de JPQL.

2.1 Uso de Criteria API en Spring Boot

Para utilizar Criteria API, necesitamos el objeto EntityManager, el cual nos permite interactuar con la base de datos directamente.

Ejemplo de uso de Criteria API

@Service
public class UsuarioService {
    
    @PersistenceContext
    private EntityManager entityManager;

    public List<Usuario> buscarUsuariosPorEdadMayorA(int edadMinima) {
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<Usuario> query = criteriaBuilder.createQuery(Usuario.class);
        Root<Usuario> root = query.from(Usuario.class);
        
        // Condición WHERE u.edad > edadMinima
        query.select(root).where(criteriaBuilder.gt(root.get("edad"), edadMinima));
        
        return entityManager.createQuery(query).getResultList();
    }
}

2.2 Construcción de consultas dinámicas

La Criteria API es útil para construir consultas dinámicas según condiciones opcionales. Por ejemplo:

public List<Usuario> buscarUsuariosDinamicamente(String nombre, Integer edad) {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Usuario> query = cb.createQuery(Usuario.class);
    Root<Usuario> root = query.from(Usuario.class);

    List<Predicate> predicates = new ArrayList<>();

    if (nombre != null) {
        predicates.add(cb.equal(root.get("nombre"), nombre));
    }
    if (edad != null) {
        predicates.add(cb.greaterThan(root.get("edad"), edad));
    }

    query.select(root).where(cb.and(predicates.toArray(new Predicate[0])));
    return entityManager.createQuery(query).getResultList();
}

En este ejemplo, si nombre o edad son nulos, no se incluirán en la consulta, lo que permite una consulta flexible.

2.3 Uso de joins en Criteria API

Podemos realizar joins entre entidades de manera similar a JPQL.

public List<Pedido> buscarPedidosPorUsuario(String nombreUsuario) {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Pedido> query = cb.createQuery(Pedido.class);
    Root<Pedido> pedido = query.from(Pedido.class);
    Join<Pedido, Usuario> usuario = pedido.join("usuario");

    query.select(pedido).where(cb.equal(usuario.get("nombre"), nombreUsuario));

    return entityManager.createQuery(query).getResultList();
}

3. ¿Cuál usar? JPQL vs Criteria API

Característica JPQL Criteria API
Facilidad de uso Más simple y fácil de leer. Más complejo, basado en código.
Flexibilidad Menos flexible, consultas fijas. Muy flexible, consultas dinámicas.
Mantenibilidad Más difícil de mantener si hay cambios. Más fácil de modificar.
Seguridad Moderada. Alta, evita inyecciones SQL.

Si necesitas consultas simples y predefinidas, JPQL es una mejor opción. Si requieres consultas dinámicas y complejas, Criteria API es la elección correcta.

Conclusión

Spring Boot nos proporciona herramientas poderosas para realizar consultas personalizadas con JPQL y Criteria API, cada una con sus ventajas y casos de uso específicos. Elegir entre una u otra dependerá de los requerimientos de la aplicación y la flexibilidad deseada.

Etiquetas:
springboot
Compartir:
Creado por:
Author photo

Jorge García

Fullstack developer