简体   繁体   中英

Query with dynamic criteria in Spring-boot extending CrudRepository

I have a spring-boot application, and I would like to have a dynamic query criteria, ie, I want to create a method that can receive the following optional parameters: Age and Name. My problem is that, these parameters are optional, that means they can be NULL sometimes, and I wanted to build my query dynamically, eg, if the parameters are not null or empty I put them in my query as criteria, otherwise I don't.

The solution that I found for this problem was basically to create a custom implementation for my repository (UserRepositoryCustomImpl), and build the query by myself. However I was wondering if there is no "spring oriented solution", like some annotations, or something like that in which I could say, "Hey use this Map, to build this query dynamically".

I feel I've lived your same situation: my HTML form has N filters but I want they only apply to the search if they are selected or changed. Once you model your form binded with it's respective selects, inputs, etc... from the View, if any of these fields aren't selected or have the default value, just want to ignore but still using the convenience and ease of the Spring Repository (in my case JpaRespository).

With my little Spring perspective I've tried to use the Specification approach (IMO better than implement your custom Repository). It works perfectly, but don't know if it's the best way.

Here is an official Spring example https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/


And here a personal example a little simplified (and probably breaking some best coding practices, with the aim to be understandable):

MyObjectRepository.java

    public interface MyObjectRepository extends JpaRepository<MyObject, Long>, JpaSpecificationExecutor<MyObject> { }           

MyObjectServiceImpl.java

@Service("MyObjectService")
public class MyObjectServiceImpl implements MyObjectService {

@Autowired
MyObjectRepository myObjectRespository;

@Override
public Page<MyObject> getAllMyObjectByFields(int pageIndex, FormMyObject formMyObject) {
    Specification<MyObject> spec = new Specification<MyObject>() {
          @Override
          public Predicate toPredicate(Root<MyObject> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
            if (formMyObject == null) {
              throw new IllegalStateException("At least one parameter should be provided to construct complex query");
            }
            List<Predicate> predicates = new ArrayList<Predicate>();
                // only if the content is present add a criteria to the search, you decide/know if will be null, or empty...
                if (formMyObject.getYourField() != null && formMyObject.getYourField().length() > 0) {
                   predicates.add(
                           builder.and(builder.equal(root.get("field"), formMyObject.getYourField())));
                }

                // add as many criteria as you want/need
                if(){
                   predicates.add( ... );
                }


                Predicate[] predicatesArray = new Predicate[predicates.size()];
            return builder.and(predicates.toArray(predicatesArray));
          }
    };

    PageRequest page = new PageRequest(pageIndex, formMyObject.getMaxResult());     
    // using the built in findAll method from Repository with dynamic custom filters 
    return myObjectRespository.findAll(spec, page);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM