Ir al contenido principal

Filtros dinámicos en JPA: Búsqueda por campos nulos y valores específicos

¿Alguna vez has necesitado implementar una búsqueda que maneje tanto valores específicos como campos nulos en tu base de datos? En este artículo te mostraré cómo hacerlo de manera elegante usando JPA y Spring Boot.

El Escenario

Imaginemos que tenemos una tabla de empleados (Employee) y queremos buscar por dos criterios:

  • Departamento (que puede ser null)
  • Salario (que también puede ser null)

La Solución

Aquí está la consulta JPA que resuelve este problema:

SELECT e.* FROM Employee e WHERE ( (:#{#filters.departmentId} IS NULL AND e.department_id IS NULL) OR (:#{#filters.departmentId} IS NOT NULL AND e.department_id = :#{#filters.departmentId}) ) AND ( (:#{#filters.salary} IS NULL AND e.salary IS NULL) OR (:#{#filters.salary} IS NOT NULL AND e.salary >= :#{#filters.salary}) )

¿Cómo funciona?

Vamos a desglosarlo por partes:

1. Filtro por Departamento

(:#{#filters.departmentId} IS NULL AND e.department_id IS NULL) OR (:#{#filters.departmentId} IS NOT NULL AND e.department_id = :#{#filters.departmentId})
  • Si no enviamos departamento: trae empleados sin departamento asignado
  • Si enviamos un departamento: trae empleados de ese departamento específico

2. Filtro por Salario

(:#{#filters.salary} IS NULL AND e.salary IS NULL) OR (:#{#filters.salary} IS NOT NULL AND e.salary >= :#{#filters.salary})
  • Si no especificamos salario: trae empleados sin salario registrado
  • Si especificamos un salario: trae empleados con salario mayor o igual al indicado

Implementación en Spring Boot


@Query(value = """ SELECT e.* FROM Employee e WHERE ( (:#{#filters.departmentId} IS NULL AND e.department_id IS NULL) OR (:#{#filters.departmentId} IS NOT NULL AND e.department_id = :#{#filters.departmentId}) ) AND ( (:#{#filters.salary} IS NULL AND e.salary IS NULL) OR (:#{#filters.salary} IS NOT NULL AND e.salary >= :#{#filters.salary}) ) """) Page<Employee> findEmployeesByFilters( @Param("filters") EmployeeFilters filters, Pageable pageable );

Ventajas de este enfoque

  1. Claridad: La lógica de filtrado es explícita y fácil de entender
  2. Mantenibilidad: Cada condición está bien separada y es fácil de modificar
  3. Flexibilidad: Maneja tanto casos de valores null como específicos
  4. Rendimiento: La consulta es eficiente al usar condiciones OR agrupadas

Ejemplo de uso

// Filtro de búsqueda EmployeeFilters filters = new EmployeeFilters(); filters.setDepartmentId(5L); // Buscar en departamento 5 filters.setSalary(3000.0); // Salario mínimo de 3000 // Paginación Pageable pageable = PageRequest.of(0, 10); // Ejecutar búsqueda Page<Employee> results = employeeRepository.findEmployeesByFilters(filters, pageable);

Conclusión

Este patrón de consulta es muy útil cuando necesitas:

  • Manejar campos que pueden ser null en tu base de datos
  • Permitir búsquedas flexibles donde los criterios son opcionales
  • Mantener una lógica clara y mantenible en tus consultas

¿Has implementado filtros similares en tus proyectos? ¿Qué otros patrones de consulta te han resultado útiles? ¡Déjame tus comentarios!

Comentarios

Entradas más populares de este blog

Arquitectura N-Capas GUÍA COMPLETA .NET Core

Entendiendo la Arquitectura Limpia (Clean Architecture) en .NET: Una Guía Completa La Arquitectura Limpia, también conocida como arquitectura N-Capas, es un patrón de diseño que nos ayuda a crear aplicaciones mantenibles, testables y escalables. En este artículo, exploraremos en detalle cómo implementar esta arquitectura en un proyecto .NET. Si quieres entenderlo más fácil y con código, te dejo este otro artículo:   Arquitectura Limpia explicado con patitos 🐤 ¿Qué es la Arquitectura Limpia? La Arquitectura Limpia es un conjunto de principios de diseño que nos ayuda a separar las responsabilidades en diferentes capas de nuestra aplicación. Cada capa tiene una responsabilidad específica y se comunica con las otras capas a través de interfaces bien definidas. Estructura del Proyecto Una típica estructura de proyecto en Arquitectura Limpia se ve así: ├── Controllers/ │   └── ProductController.cs ├── Domain/ │   ├── Models/ │   └── DTOs/ ├── Repository/ │...

Archivo Application.properties en SPRING BOOT

  Guía Completa: Application.properties en Spring Boot El archivo application.properties es una pieza fundamental en aplicaciones Spring Boot, actuando como el centro de configuración para todo tu proyecto. En esta guía, exploraremos sus características principales y cómo aprovecharlo al máximo. ¿Qué es application.properties? Es un archivo de configuración que permite definir diferentes parámetros y valores para tu aplicación Spring Boot sin necesidad de modificar el código fuente. Se ubica en src/main/resources y Spring Boot lo lee automáticamente al iniciar. Configuraciones Esenciales Configuración del Servidor # Puerto del servidor server.port = 8080 # Contexto de la aplicación server.servlet.context-path = /miapp Conexión a Base de Datos # MySQL spring.datasource.url = jdbc:mysql://localhost:3306/mibasededatos spring.datasource.username = usuario spring.datasource.password = contraseña spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver JPA y Hibernat...

Arquitectura Hexagonal en JAVA Spring Boot

 Esta es la recomendación de estructura de un proyecto para hacer nuestras APIs siguendo la arquitectura N-Capas que te explique aquí también:  Arquitectura Limpia explicado con patitos 🐤 Es un diseño en capas que sigue el patrón de Arquitectura Hexagonal (también conocida como Puertos y Adaptadores): Capa de Dominio ( domain ) Contiene las clases de negocio puras como Product , Category Es el núcleo de la aplicación, independiente de frameworks Capa de Persistencia ( persistence ) entity : Contiene las entidades JPA ( Producto , Categoria , etc.) crud : Interfaces para operaciones básicas de base de datos mapper : Conversores entre entidades y objetos de dominio repository : Implementación concreta del acceso a datos Capa Web ( web.controller ) Controladores que manejan las peticiones HTTP Como HolaMundoController Servicios ( service ) Contiene la lógica de negocio Coordina entre los repositorios y el dominio