JPA Criteria API with multiple parameters

前端 未结 5 1763
礼貌的吻别
礼貌的吻别 2020-11-30 22:39

I need to make a search method that uses the JPA Criteria API with multiple parameters. Now the problem is that not every parameter is required. So some could be null, and t

5条回答
  •  一生所求
    2020-11-30 23:20

    First, Mikko's answer got me to my answer. Upvote for that.

    My scenario was I wanted to parent/child relationship and I wanted to find a match on ~any~ child.

    Employee has multiple JobTitle(s).

    I wanted to find an employee (where the has many job titles), but find it on ~any of the jobtitles I send in.

    SQL would look like:

    Select * from dbo.Employee e join dbo.JobTitle jt on e.EmployeeKey = jt.EmployeeKey WHERE ( jt.JobTitleName = 'programmer' OR jt.JobTitleName = 'badcop' )

    I threw in gender and date-of-birth to complete the example (and give more "optional") criteria)

    My JPA code

    import org.apache.commons.lang3.StringUtils;
    import org.springframework.data.jpa.domain.Specification;
    
    import javax.persistence.criteria.CriteriaBuilder;
    import javax.persistence.criteria.CriteriaQuery;
    import javax.persistence.criteria.Join;
    import javax.persistence.criteria.Predicate;
    import javax.persistence.criteria.Root;
    import java.util.ArrayList;
    import java.util.List;
    
    public class MyEmployeeSpecification implements Specification {
    
        private MyEmployee filter;
    
        public MyEmployeeSpecification(MyEmployee filter) {
            super();
            this.filter = filter;
        }
    
        public Predicate toPredicate(Root root, CriteriaQuery cq,
                                     CriteriaBuilder cb) {
    
            Predicate returnPred = cb.disjunction();
    
            List patientLevelPredicates = new ArrayList();
    
            if (filter.getBirthDate() != null) {
                patientLevelPredicates.add(
                        cb.equal(root.get("birthDate"), filter.getBirthDate()));
            }
    
            if (filter.getBirthDate() != null) {
                patientLevelPredicates.add(
                        cb.equal(root.get("gender"), filter.getGender()));
            }
    
            if (null != filter.getJobTitles() && filter.getJobTitles().size() > 0) {
    
                List jobTitleLevelPredicates = new ArrayList();
    
                Join hnJoin = root.join("jobtitles");
    
                for (JobTitle hnw : filter.getJobTitles()) {
                    if (null != hnw) {
                        if (StringUtils.isNotBlank(hnw.getJobTitleName())) {
                            jobTitleLevelPredicates.add(cb.equal(hnJoin.get("getJobTitleName"), hnw.getFamily()));
                        }
                    }
                }
    
                patientLevelPredicates.add(cb.or(jobTitleLevelPredicates.toArray(new Predicate[]{})));
            }
    
            returnPred = cb.and(patientLevelPredicates.toArray(new Predicate[]{}));
    
            return returnPred;
        }
    }
    

    But I figured mine out because of predicates.toArray(new Predicate[]{}) , aka, the varargs trick. (Thanks Mikko)

    I'm also doing the "implements Specifiction" method.

    Other helpful links:

    JPA Specifications by Example

    JPA CriteriaBuilder conjunction criteria into a disjunction criteria

提交回复
热议问题