Spring数据存储库中的可选参数

使用Spring Data的每个人都面临这样的情况:您拥有一个用于处理实体的存储库,并且您想编写一种通用的find方法,以通过用户可以在搜索表单上设置或跳过的一组参数进行搜索。 Spring Data中find方法的基本实现仅在考虑所有参数的情况下查找实体,而不允许您按有限的集合进行搜索。 我找到了解决此问题的方法,并创建了一个OpenSource库以在其他项目中快速使用。

为了理解这些问题,让我们想象一下,我们正在创建一个简单的笔记本应用程序,在其中定义一个实体-具有字段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; } 


假设我们必须通过名字,姓氏和电话号码的一部分或这些参数的任意组合进行搜索,并且希望搜索方法不考虑值为空的参数。 要解决此问题,可以采取几种方法:

  1. 通过SQL直接与数据库一起使用,在服务中创建一个将动态生成SQL查询的方法。 像

    动态查询
      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. Query注释用于带有参数检查为null的搜索方法。

    @查询
      @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. 为所有可能的参数组合创建搜索方法,并在检查参数为null之后调用所需的方法。

    很多查找方法
      @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); } } } } } 



我不会分析每种方法的优缺点,它们是显而易见的。 我只是说,我选择了第三个选项,并为参数组合的每个变体添加了搜索方法,并创建了一个使用注释处理器机制的OpenSource库,并在编译阶段为您完成了所有工作。 要使用它,您必须连接该库(请参见https://github.com/ukman/kolobokhttps://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> 

然后,您需要标记该方法,该方法应使用@FindWithOptionalParams注释以新方式工作。

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

库本身将生成所有搜索方法和默认实现,并检查参数是否为null并调用所需的方法。

PS:在注释中写下其他注释可以简化您使用Spring的工作,也许我也会添加它们。

Source: https://habr.com/ru/post/zh-CN483796/


All Articles