Spring Specification - conjunction of Predicates

匿名 (未验证) 提交于 2019-12-03 08:33:39

问题:

I need a function that will be filter parameters and build query. I have 4 parameters therefore if I would try to implement query for each condition I would have to write 16 (2^4) implementations - it's not good idea.

I try to improve my code with interface Specification from Spring Data JPA but I cannot create conjunction of predicates.

Implementation of Specification interface :

public class UserSpecification implements Specification {      private final UserSearchCriteria criteria;      public UserSpecification(UserSearchCriteria criteria) {         this.criteria = criteria;     }      @Override     public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder builder) {         final List predicates = new ArrayList();         if (criteria.getName() != null) {             final Predicate name = builder.equal(root.get("name"), criteria.getName());             predicates.add(name);         } else if (criteria.getSurname() != null) {             final Predicate surname = builder.equal(root.get("surname"), criteria.getSurname());             predicates.add(surname);         } else if (criteria.getCity() != null) {             final Predicate city = builder.equal(root.get("city"), criteria.getCity());             predicates.add(city);         } else if (criteria.getCountry() != null) {             final Predicate country = builder.equal(root.get("country"), criteria.getCountry());             predicates.add(country);         }         return builder.and(predicates.toArray(new Predicate[predicates.size()]));     } } 

And test doesn't work :

@Test     @Sql(             scripts = "classpath:sql/specification.sql",             executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD     )     public void specificationTest() {         // given         final UserSearchCriteria criteria = UserSearchCriteria.builder()                 .name("john")                 .surname("smith")                 .build();          final UserSpecification specification = new UserSpecification(criteria);          // when         final List result = userRepository.findAll(specification);         userRepository.flush();          // then         assertThat(result).hasSize(3);     } 

Before test I insert to database following users:

INSERT INTO users (id, name, surname, city, country) VALUES (1, 'john', 'smith', null, null); INSERT INTO users (id, name, surname, city, country) VALUES (2, 'john', 'smith', null, null); INSERT INTO users (id, name, surname, city, country) VALUES (3, 'john', 'smith', null, null); INSERT INTO users (id, name, surname, city, country) VALUES (4, 'john', 'abc', null, null); INSERT INTO users (id, name, surname, city, country) VALUES (5, 'abcd', 'abc', null, null); INSERT INTO users (id, name, surname, city, country) VALUES (6, 'abcd', 'abc', null, null); 

And as a result I get first four rows. Repository matches only first parameter "name" and doesn't match "surname". What is the cause?

(UserSearchCriteria has the same fields as User: name, surname, city, country).

回答1:

You are using a single if-else, so only one conditions is matched each time.

Try changing it to a sequence of standalone ifs:

@Override public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder builder) {     final List predicates = new ArrayList();     if (criteria.getName() != null) {         final Predicate name = builder.equal(root.get("name"), criteria.getName());         predicates.add(name);     }     if (criteria.getSurname() != null) {         final Predicate surname = builder.equal(root.get("surname"), criteria.getSurname());         predicates.add(surname);     }     if (criteria.getCity() != null) {         final Predicate city = builder.equal(root.get("city"), criteria.getCity());         predicates.add(city);     }     if (criteria.getCountry() != null) {         final Predicate country = builder.equal(root.get("country"), criteria.getCountry());         predicates.add(country);     }     return builder.and(predicates.toArray(new Predicate[predicates.size()])); } 


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!