Reputation: 722
The where
method of CriteriBuilder
restricts the query result according to the conjunction of the specified restriction predicates
In other words, concatenate all predicates with AND. I pass a list of predicates to this method in this way:
criteria.where(preds.toArray(new Predicate[0]));
The result query is something like this:
... where p1 and p2 and p3
however what I need is:
... where p1 and p2 or p3
I tried to use two list of preds, one for "ANDS" and another one for "ORS":
if(preds.isEmpty() && !orPreds.isEmpty()) {
criteria.where(cb.or(orPreds.toArray(new Predicate[orPreds.size()])));
}
else if(!preds.isEmpty() && !orPreds.isEmpty()) {
criteria.where(cb.and(preds.toArray(new Predicate[preds.size()])),
cb.or(orPreds.toArray(new Predicate[orPreds.size()])));
}
else {
criteria.where(preds.toArray(new Predicate[0]));
}
But the result query is the same:
... where p1 and p2 and p3
Any idea?
Upvotes: 1
Views: 9160
Reputation: 384
By default all predicates are understood as "AND".
You can "play" adding more complexity to the predicates using cb.and / cb.or (nested if needed)
You can create a list like this:
Root<BeanA> queryRoot = cq.from(BeanA.class);
List<Predicate> predicates = new ArrayList<>();
predicates.add(cb.equal(queryRoot.get("id"), valueA);
predicates.add(cb.or(
cb.equal(queryRoot.get("id"), valueA,
cb.equal(queryRoot.get("id"), valueB
));
predicates.add(cb.and(
cb.equal(queryRoot.get("valueC"), valueC),
cb.or(
cb.equal(queryRoot.get("id"), valueA,
cb.equal(queryRoot.get("id"), valueB
))
);
cq.where(predicates.toArray(Predicate[]::new));
If needed, you can use a multiselect too (adding here the result of subqueries if you want to handle them)
List<Selection> selectList = new ArrayList<>();
selectList.add(queryRoot.get("id"));
selectList.add(queryRoot.get("title"));
cq.multiselect(selectList.toArray(Selection[]::new));
After adding a multiselect you could need an orderBy. you can follow the same concept but using a Expression list
List<Expression> groupByList = new ArrayList<>();
groupByList.add(proyectoJoin.get("id"));
groupByList.add(proyectoJoin.get("title"));
cq.groupBy(groupByList.toArray(Expression[]::new));
Upvotes: 0
Reputation: 16273
Simply combine your arrays of predicates into simple predicates, using CriteriaBuilder.and(Predicate... restrictions)
and CriteriaBuilder.or(Predicate... restrictions)
For getting where (p1 and p2) or p3
, where p1
, p2
and p3
are all arrays of predicates concatenated with and
statements:
Predicate[] p1 = new Predicate[2];
Predicate[] p2 = new Predicate[2];
Predicate[] p3 = new Predicate[2];
// add your predicates to the arrays.
Predicate p1all = cb.and(p1);
Predicate p2all = cb.and(p2);
Predicate p3all = cb.and(p3);
Predicate pFinal = cb.or(cb.and(p1all, p2all), p3all);
criteria.where(pFinal);
For getting where p1 and (p2 or p3)
:
Predicate pFinal = cb.and(cb.or(p2all, p3all), p1all);
criteria.where(pFinal);
Finally, if you want to build a single predicate by concatenating an array of predicates with or
statements, use this:
Predicate p1all = cb.or(p1);
Upvotes: 2