Paramètres facultatifs dans les référentiels de données Spring

Tous ceux qui ont utilisé Spring Data ont été confrontés à une situation où vous avez un référentiel pour travailler avec une entité et que vous souhaitez écrire une méthode de recherche universelle pour rechercher par un ensemble de paramètres que l'utilisateur peut définir ou ignorer dans le formulaire de recherche. L'implémentation de base des méthodes de recherche dans Spring Data recherche les entités uniquement en tenant compte de tous les paramètres, ne vous permettant pas de rechercher par un ensemble limité. J'ai trouvé un moyen de résoudre ce problème et j'ai créé une bibliothèque OpenSource pour une utilisation rapide dans d'autres projets.

Pour comprendre les problèmes, imaginons que nous créons une application bloc-notes simple, dans laquelle nous définissons une entité - Personne avec les champs 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; } 


Supposons que nous devons fournir une recherche par prénom, nom et partie du numéro de téléphone ou par n'importe quelle combinaison de ces paramètres et que la méthode de recherche ne tienne pas compte des paramètres dont les valeurs sont nulles. Pour résoudre ce problème, vous pouvez procéder de plusieurs manières:

  1. Travaillez directement avec la base de données via SQL, créez une méthode dans le service qui générera dynamiquement la requête SQL. Quelque chose comme

    Requête dynamique
      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. Utilisez l'annotation de requête pour une méthode de recherche avec une vérification des paramètres pour null.

    @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. Créez des méthodes de recherche pour toutes les combinaisons possibles de paramètres et appelez la méthode souhaitée après avoir vérifié la nullité des paramètres.

    Beaucoup de méthodes de recherche
      @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); } } } } } 



Je n'analyserai pas les avantages et les inconvénients de chaque méthode, ils sont évidents. Permettez-moi de dire que j'ai choisi la troisième option avec l'ajout de méthodes de recherche pour chaque variante de la combinaison de paramètres et créé une bibliothèque OpenSource qui utilise le mécanisme du processeur d'annotation et au stade de la compilation fait tout le travail pour vous. Pour l'utiliser, vous devez connecter la bibliothèque (voir la dernière version sur https://github.com/ukman/kolobok ou 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> 

Ensuite, vous devez marquer la méthode, qui devrait fonctionner d'une nouvelle manière avec l'annotation @FindWithOptionalParams.

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

La bibliothèque elle-même générera toutes les méthodes de recherche et l'implémentation par défaut en vérifiant les paramètres pour null et en appelant la méthode requise.

PS: écrivez dans les commentaires quelles autres annotations pourraient simplifier votre travail avec Spring, peut-être que je les ajouterai aussi.

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


All Articles