spring data jpa Specification complex query paging query +

When the Repository interfaces inherited JpaSpecificationExecutor, we can use the following interface paging query:

    /**
     * Returns a {@link Page} of entities matching the given {@link Specification}.
     *
     * @param spec can be {@literal null}.
     * @param pageable must not be {@literal null}.
     * @return never {@literal null}.
     */
    Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable);

 

Binding jpa-spec can be easily constructed Specification:

jpa-spec github Address: https://github.com/wenhao/jpa-spec

public Page<Person> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
            .eq(StringUtils.isNotBlank(request.getName()), "name", request.getName())
            .gt(Objects.nonNull(request.getAge()), "age", 18)
            .between("birthday", new Date(), new Date())
            .like("nickName", "%og%", "%me")
            .build();

    return personRepository.findAll(specification, new PageRequest(0, 15));
}

 

Single-table queries is really very simple, but complex inquiries, some of the complex:

public List<Phone> findAll(SearchRequest request) {
    Specification<Phone> specification = Specifications.<Phone>and()
        .eq(StringUtils.isNotBlank(request.getBrand()), "brand", "HuaWei")
        .eq(StringUtils.isNotBlank(request.getPersonName()), "person.name", "Jack")
        .build();

    return phoneRepository.findAll(specification);
}

Phone here is the main table, using a person's name to make the conditions, methods of use are person.name.

Internal jpa-spec analyzes person.name, the following code:

public From getRoot(String property, Root<T> root) {
        if (property.contains(".")) {
            String joinProperty = StringUtils.split(property, ".")[0];
            return root.join(joinProperty, JoinType.LEFT);
        } else {
            return root;
        }
    }

You can see it with the root.join, then there is a problem, if there are two person field conditions, it would once again join, it will generate this sql:

select * from phone left outer join person on XX=XX left outer join person XX=XX.

This certainly does not meet the demand. It should also be a bug jpa-spec bar

To solve this problem, you can use another way it provides query:

public List<Phone> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
        .between("age", 10, 35)
        .predicate(StringUtils.isNotBlank(jack.getName()), ((root, query, cb) -> {
            Join address = root.join("addresses", JoinType.LEFT);
            return cb.equal(address.get("street"), "Chengdu");
        }))
        .build();

    return phoneRepository.findAll(specification);
}

To this can be resolved in most cases, in addition to paging

Look normal single-table query paging + Sort:

public Page<Person> findAll(SearchRequest request) {
    Specification<Person> specification = Specifications.<Person>and()
            .eq(StringUtils.isNotBlank(request.getName()), "name", request.getName())
            .gt("age", 18)
            .between("birthday", new Date(), new Date())
            .like("nickName", "%og%")
            .build();

    Sort sort = Sorts.builder()
        .desc(StringUtils.isNotBlank(request.getName()), "name"
        .Asc ()"birthday")
        .build();

    return personRepository.findAll(specification, new PageRequest(0, 15, sort));
}

 

If the increase on the basis of this association, the following code:

public Page<Person> findAll(SearchRequest request) {
        Specification<Person> specification = Specifications.<Person>and()
                .predicate(StringUtils.isNotBlank(jack.getName()), ((root, query, cb) -> {
                    Join address = root.join("addresses", JoinType.LEFT);
                    return cb.equal(address.get("street"), "Chengdu");
                }))
                .eq(StringUtils.isNotBlank(request.getName()), "name", request.getName())
                .gt("age", 18)
                .between("birthday", new Date(), new Date())
                .like("nickName", "%og%")
                .build();

        Sort sort = Sorts.builder()
                .desc(StringUtils.isNotBlank(request.getName()), "name")
                .asc("birthday")
                .build();

        return personRepository.findAll(specification, new PageRequest(0, 15, sort));
    }

You will find addresses of lazy loading failure to generate a lot of queries addresses statement, the solution is as follows:

public Page<Person> findAll(SearchRequest request) {
        Specification<Person> specification = Specifications.<Person>and()
                .predicate(StringUtils.isNotBlank(jack.getName()), ((root, query, cb) -> {
                    Join address;
                    if (Long.class != query.getResultType()) {
                        address = (Join) root.fetch("addresses", JoinType.LEFT);
                    } else {
                        address = root.join("addresses", JoinType.LEFT);
                    }
                    return cb.equal(address.get("street"), "Chengdu");
                }))
                .eq(StringUtils.isNotBlank(request.getName()), "name", request.getName())
                .gt("age", 18)
                .between("birthday", new Date(), new Date())
                .like("nickName", "%og%")
                .build();

        Sort sort = Sorts.builder()
                .desc(StringUtils.isNotBlank(request.getName()), "name")
                .asc("birthday")
                .build();

        return personRepository.findAll(specification, new PageRequest(0, 15, sort));
    }

At this point, with Specification inquiries should be enough, coupled with the method JpaRepository (SimpleJpaRepository) provided annotations and @Query methods and criteria api query, the four JPA query can solve the problem for most applications.

Guess you like

Origin www.cnblogs.com/hankuikui/p/11414316.html