Veshraj Joshi
Veshraj Joshi

Reputation: 3579

JPA specification has no effect with CriteriaBuilder.or() method

What I want to get is like -

SELECT * FROM emials WHERE user_id = ?1 AND (`to` like '%?2%' OR `from` LIKE '%?2%' OR subject LIKE '%?2%');

To get such I have following specification like -

public class VendorEmailSpecification {
    public static Specification<VendorEmail> filter(String filterText) {
        return new Specification<VendorEmail>() {
            @Override
            public Predicate toPredicate(Root<VendorEmail> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                Predicate predicate = criteriaBuilder.conjunction();

                if(!StringUtils.isEmpty(filterText)) {
                    /***
                    * this block donot have any effects
                    **/
                    predicate = criteriaBuilder.or(
                            criteriaBuilder.or(predicate, criteriaBuilder.like(root.get("to"),"%"+ filterText +"%")),
                            criteriaBuilder.or(predicate, criteriaBuilder.like(root.get("from"),"%"+ filterText +"%")),
                            criteriaBuilder.or(predicate, criteriaBuilder.like(root.get("subject"),"%"+ filterText +"%")),
                            criteriaBuilder.or(predicate, criteriaBuilder.like(root.get("message"),"%"+ filterText +"%"))
                   );
                }
                // there is an relation of ManyToOne with user and AuthUserThread.getContext() gives an object of User entity.
                // this working perfectly
                predicate = criteriaBuilder.and(predicate,criteriaBuilder.equal(root.get("user"), AuthUserThread.getContext()));


                return predicate;
            }
        };
    }
}

What mistake is there and how can i fix that?

Upvotes: 0

Views: 2363

Answers (2)

Veshraj Joshi
Veshraj Joshi

Reputation: 3579

I solve this problem in another way -

public class VendorEmailSpecification {
    public static Specification<VendorEmail> filter(String filterText) {
        return new Specification<VendorEmail>() {
            @Override
            public Predicate toPredicate(Root<VendorEmail> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                Predicate predicate = criteriaBuilder.conjunction();
                predicate = criteriaBuilder.equal(root.get("user"), AuthUserThread.getContext());
                if(!StringUtils.isEmpty(filterText)) {
                    Predicate toPredicate = criteriaBuilder.like(root.get("to"), "%"+filterText+"%");
                    Predicate fromPredicate = criteriaBuilder.like(root.get("from"), "%"+filterText+"%");
                    Predicate subjectPredicate = criteriaBuilder.like(root.get("subject"), "%"+filterText+"%");
                    Predicate messagePredicate = criteriaBuilder.like(root.get("message"), "%"+filterText+"%");
                    Predicate orPredicate = criteriaBuilder.or(toPredicate, fromPredicate, subjectPredicate, messagePredicate);
                    predicate = criteriaBuilder.and(predicate, orPredicate);
                    return predicate;
                }

                predicate = criteriaBuilder.and(predicate);
                return predicate;
            }
        };
    }
}

Upvotes: 1

Sean Mickey
Sean Mickey

Reputation: 7716

It looks like the filterText parameter will have gone out of scope when the toPredicate() method is called.

If you add a member to the anonymous Specification<VendorEmail> instance returned by the filter() method, assign the value of the filterText parameter to the member, and update the remaining code to refer to the new member, as shown below, that should resolve the problem:

public class VendorEmailSpecification {
    public static Specification<VendorEmail> filter(String filterText) {
        return new Specification<VendorEmail>() {
            private String filterValue = filterText;

            @Override
            public Predicate toPredicate(Root<VendorEmail> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                Predicate predicate = criteriaBuilder.conjunction();
                if(!StringUtils.isEmpty(this.filterValue)) {
                    /***
                    * this block donot have any effects
                    **/
                    predicate = criteriaBuilder.or(
                        criteriaBuilder.or(predicate, criteriaBuilder.like(root.get("to"),"%"+ this.filterValue +"%")),
                        criteriaBuilder.or(predicate, criteriaBuilder.like(root.get("from"),"%"+ this.filterValue +"%")),
                        criteriaBuilder.or(predicate, criteriaBuilder.like(root.get("subject"),"%"+ this.filterValue +"%")),
                        criteriaBuilder.or(predicate, criteriaBuilder.like(root.get("message"),"%"+ this.filterValue +"%"))
               );
            }
            // there is an relation of ManyToOne with user and AuthUserThread.getContext() gives an object of User entity.
            // this working perfectly
            predicate = criteriaBuilder.and(predicate,criteriaBuilder.equal(root.get("user"), AuthUserThread.getContext()));
            return predicate;
            }
        };
    }
}

Upvotes: 1

Related Questions