Parámetros opcionales en repositorios de datos de Spring

Todos los que usaron Spring Data se enfrentaron a una situación en la que tiene un repositorio para trabajar con una entidad y desea escribir un método de búsqueda universal para buscar por un conjunto de parámetros que el usuario puede establecer u omitir en el formulario de búsqueda. La implementación básica de los métodos de búsqueda en Spring Data encuentra entidades que solo tienen en cuenta todos los parámetros, no permitiéndole buscar por un conjunto limitado. Encontré una manera de resolver este problema y creé una biblioteca OpenSource para un uso rápido en otros proyectos.

Para comprender los problemas, imaginemos que estamos creando una aplicación de cuaderno simple en la que definimos una entidad: Persona con los campos id, firstName, lastName, phoneNumber.

Person.java
@Entity @Data @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode(of = "id") public class Person { @Id private Long id; private String firstName; private String lastName; private String phoneNumber; } 


Supongamos que debemos proporcionar una búsqueda por nombre, apellido y parte del número de teléfono o por cualquier combinación de estos parámetros y queremos que el método de búsqueda no tenga en cuenta los parámetros cuyos valores son nulos. Para resolver este problema, puede ir de varias maneras:

  1. Trabaje directamente con la base de datos a través de SQL, cree un método en el servicio que generará dinámicamente la consulta SQL. Algo como

    Consulta dinámica
      Iterable<Person> find(String firstName, String lastName, String phoneNumber) { List<String> where = new ArrayList(); List params = new ArrayList(); if(firstName != null) { params.add(firstName); where.add("first_name = ?"); } if(lastName != null) { params.add(lastName); where.add("last_name = ?"); } if(phoneNumber != null) { params.add(phoneNumber); where.add("phone_number = ?"); } String sql = "SELECT * FROM person " + (where.isEmpty() ? "" : " WHERE " + String.join(" AND ", where)); //  SQL  JDBCTemplate // ... } 

  2. Utilice la anotación de consulta para un método de búsqueda con comprobación de parámetros para nulo.

    @Query
      @Query("SELECT p FROM Person p " + "WHERE " + "(firstName = :firstName or :firstName is null) and " + "(lastName = :lastName or :lastName is null) and " + "(phoneNumber = :phoneNumber or :phoneNumber is null)" ) Iterable<Person> find( @Param("firstName") String firstName, @Param("lastName") String lastName, @Param("phoneNumber") String phoneNumber ); 


  3. Cree métodos de búsqueda para todas las combinaciones posibles de parámetros y llame al método deseado después de verificar los parámetros como nulos.

    Muchos métodos de búsqueda
      @Repository public interface PersonRepo extends PagingAndSortingRepository<Person, Long> { //       Iterable<Person> phoneNumberContains(String number); Iterable<Person> lastName(String lastName); Iterable<Person> lastNameAndPhoneNumberContains(String lastName, String number); Iterable<Person> firstName(String firstName); Iterable<Person> firstNameAndPhoneNumberContains(String firstName, String number); Iterable<Person> firstNameAndLastName(String firstName, String lastName); Iterable<Person> firstNameAndLastNameAndPhoneNumberContains(String firstName, String lastName, String number); //  ,      default Iterable<Person> findByFirstNameAndLastNameAndPhoneNumberContains(String firstName, String lastName, String number) { if(firstName == null) { if(lastName == null) { if(number == null) { return findAll(); } else { return phoneNumberContains(number); } } else { if(number == null) { return lastName(lastName); } else { return lastNameAndPhoneNumberContains(lastName, number); } } } else { if(lastName == null) { if(number == null) { return firstName(firstName); } else { return firstNameAndPhoneNumberContains(firstName, number); } } else { if(number == null) { return firstNameAndLastName(firstName, lastName); } else { return firstNameAndLastNameAndPhoneNumberContains(firstName, lastName, number); } } } } } 



No analizaré las ventajas y desventajas de cada método, son obvias. Permítanme decir que elegí la tercera opción con la adición de métodos de búsqueda para cada variante de la combinación de parámetros y creé una biblioteca OpenSource que utiliza el mecanismo del procesador de anotaciones y en la etapa de compilación hace todo el trabajo por usted. Para usarlo, debe conectar la biblioteca (consulte la última versión en https://github.com/ukman/kolobok o https://mvnrepository.com/artifact/com.github.ukman/kolobok ).

 <dependency> <groupId>com.github.ukman</groupId> <artifactId>kolobok</artifactId> <version>0.1.2</version> <scope>compile</scope> </dependency> 

Luego, debe marcar el método, que debería funcionar de una nueva manera con la anotación @FindWithOptionalParams.

 @Repository public interface PersonRepo extends PagingAndSortingRepository<Person, Long> { @FindWithOptionalParams Iterable<Person> findByFirstNameAndLastNameAndPhoneNumberContains(String firstName, String lastName, String number); } 

La biblioteca en sí generará todos los métodos de búsqueda y la implementación predeterminada al verificar los parámetros para nulos y llamar al método requerido.

PD: escribe en los comentarios qué otras anotaciones podrían simplificar tu trabajo con Spring, tal vez las agregaré también.

Source: https://habr.com/ru/post/483796/


All Articles