I am having an issue with grouping my WHERE conditions. Ultimately, my goal is to have groups of AND conditions, each of which is an OR. For example:
SELECT *
WHERE ( foo = 1 AND bar = 2)
OR (foo = 3 AND bar = 4)
OR (foo = 5 AND bar = 6)
Below is the code that I am using to accomplish this. As you can see, I am creating 2 'equal' Predicates, and then am creating a Predicate which nests them.
List<Waybill> getWaybillsByCriteriaOrderItemList(List< OrderItem > orderItems ) {
CriteriaBuilder cb = em.getCriteriaBuilder()
CriteriaQuery<Waybill> q = cb.createQuery( Waybill )
Root<Waybill> waybillRoot = q.from(Waybill)
q.select( waybillRoot )
List<Predicate> predicates = []
orderItems.each { OrderItem item ->
Predicate carInit = cb.equal( cb.trim(waybillRoot.get('carInit')), item.carInit)
Predicate carNumb = cb.equal( cb.trim(waybillRoot.get('carNumb')), item.carNum )
Predicate thisCar = cb.or (
cb.and( carInit ),
cb.and( carNumb )
)
predicates << thisCar
}
q.where(predicates.toArray(new Predicate[predicates.size()]))
TypedQuery<Waybill> tq = em.createQuery(q)
List<Waybill> result = tq.getResultList()
result
}
Unfortunately, the AND/OR grouping is exactly the opposite of what I would expect. Here is the generated HQL
select generatedAlias0 from Waybill as generatedAlias0 where
( ( trim(BOTH from generatedAlias0.carInit)=:param0 ) or ( trim(BOTH from generatedAlias0.carNumb)=:param1 ) )
and
( ( trim(BOTH from generatedAlias0.carInit)=:param2 ) or ( trim(BOTH from generatedAlias0.carNumb)=:param3 ) )
and
( ( trim(BOTH from generatedAlias0.carInit)=:param4 ) or ( trim(BOTH from generatedAlias0.carNumb)=:param5 ) )
Simply reversing those and() and or() methods did not solve my issue either. It resulted in everything being AND like so:
Predicate thisCar = cb.and (
cb.or( carInit ),
cb.or( carNumb )
)
~~~~
select generatedAlias0 from Waybill as generatedAlias0 where
( ( trim(BOTH from generatedAlias0.carInit)=:param0 ) and ( trim(BOTH from generatedAlias0.carNumb)=:param1 ) )
and
( ( trim(BOTH from generatedAlias0.carInit)=:param2 ) and ( trim(BOTH from generatedAlias0.carNumb)=:param3 ) )
and
( ( trim(BOTH from generatedAlias0.carInit)=:param4 ) and ( trim(BOTH from generatedAlias0.carNumb)=:param5 ) )
I have tried every combination that I can think of. Can anyone point out what it is that I am doing wrong?
Try to change:
Predicate thisCar = cb.or (
cb.and( carInit ),
cb.and( carNumb )
);
to:
Predicate thisCar = cb.and( carInit , carNumb );
And after the loop, add the or
statement to the array of predicates:
q.where(cb.or(predicates.toArray(new Predicate[] {})));