Optionale Parameter in Spring-Datenrepositorys

Jeder, der Spring Data verwendet hat, war mit einer Situation konfrontiert, in der Sie ein Repository für die Arbeit mit einer Entität haben und eine universelle Suchmethode schreiben möchten, um nach einer Reihe von Parametern zu suchen, die der Benutzer im Suchformular festlegen oder überspringen kann. Bei der grundlegenden Implementierung von Suchmethoden in Spring Data werden Entitäten nur unter Berücksichtigung aller Parameter gesucht, sodass Sie nicht nach einer begrenzten Menge suchen können. Ich habe einen Weg gefunden, dieses Problem zu lösen, und eine OpenSource-Bibliothek für den schnellen Einsatz in anderen Projekten erstellt.

Um die Probleme zu verstehen, stellen wir uns vor, wir erstellen eine einfache Notizbuchanwendung, in der wir eine Entität definieren - Person mit den Feldern 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; } 


Angenommen, wir müssen eine Suche nach Vorname, Nachname und Teil der Telefonnummer oder nach einer beliebigen Kombination dieser Parameter durchführen und möchten, dass die Suchmethode keine Parameter berücksichtigt, deren Werte null sind. Um dieses Problem zu lösen, haben Sie verschiedene Möglichkeiten:

  1. Arbeiten Sie direkt mit der Datenbank über SQL, und erstellen Sie im Service eine Methode, mit der die SQL-Abfrage dynamisch generiert wird. So etwas wie

    Dynamische Abfrage
      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. Verwenden Sie Query Annotation für eine Suchmethode mit Parameterprüfung auf 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. Erstellen Sie Suchmethoden für alle möglichen Kombinationen von Parametern und rufen Sie die gewünschte Methode auf, nachdem Sie die Parameter auf Null überprüft haben.

    Viele Suchmethoden
      @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); } } } } } 



Ich werde nicht die Vor- und Nachteile jeder Methode analysieren, sie liegen auf der Hand. Ich kann nur sagen, dass ich die dritte Option mit zusätzlichen Suchmethoden für jede Variante der Parameterkombination ausgewählt und eine OpenSource-Bibliothek erstellt habe, die den Annotation Processor-Mechanismus verwendet und in der Kompilierungsphase die ganze Arbeit für Sie erledigt. Um es zu verwenden, müssen Sie die Bibliothek verbinden (siehe die neueste Version unter https://github.com/ukman/kolobok oder 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> 

Dann müssen Sie die Methode markieren, die auf neue Weise mit der Annotation @FindWithOptionalParams funktionieren soll.

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

Die Bibliothek selbst generiert alle Suchmethoden und die Standardimplementierung, indem sie die Parameter auf null überprüft und die erforderliche Methode aufruft.

PS: Schreiben Sie in die Kommentare, welche anderen Anmerkungen Ihre Arbeit mit Spring vereinfachen könnten. Vielleicht füge ich sie auch hinzu.

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


All Articles