¿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
- Claridad: La lógica de filtrado es explícita y fácil de entender
- Mantenibilidad: Cada condición está bien separada y es fácil de modificar
- Flexibilidad: Maneja tanto casos de valores null como específicos
- 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
Publicar un comentario