javamysqljpaspring-data-jpacriteria-api

JpaSpecificationExecutor JOIN + ORDER BY in Specification


I have a query using a JOIN and ORDER BY and want to use it within my repository using the Criteria Api.

Here I found, how to wrap such a query into a CriteriaQuery (Link).

CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
Join<Pet, Owner> owner = cq.join(Pet_.owners);
cq.select(pet);
cq.orderBy(cb.asc(owner.get(Owner_.lastName),owner.get(Owner_.firstName)));

On the other side, I found some examples to use the Criteria Api in Combination with a JpaRepository (example).

The Problem is that all methods in the repository expect a Specification:

T findOne(Specification<T> spec);

which is always build like this:

public static Specification<PerfTest> statusSetEqual(final Status... statuses) {
    return new Specification<PerfTest>() {
        @Override

        public Predicate toPredicate(Root<PerfTest> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
            return cb.not(root.get("status").in((Object[]) statuses));
        }
    };

}

So at one side I know how to create a CriteriaQuery, and on the other side I need a Specification which is build from a Predicate, and I can not figure out how to parse the CriteriaQuery into a Specification/Predicate.


Solution

  • Try something like this (I assumed pet has many owners):

    public static Specification<Pet> ownerNameEqual(String ownerName) {
            return new Specification<Pet>() {
                @Override
                public Predicate toPredicate(Root<Pet> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                    Join<Pet, Owner> owners = root.join("owners");
                    criteriaQuery.orderBy(criteriaBuilder.desc(root.get("id")));
                    return criteriaBuilder.equal(owners.get("name"), ownerName);
                }
            };
        }
    

    This is just an example to search all pets whose at least one owner has name equal to ownerName

    But you could add a method List<Pet> findByOwnersNameOrderByIdDesc(String ownerName); in your repository instead (as an equivalent to Specification).