title: AND/OR grouping WHERE conditions with Criteria Predicates in Hibernate
body: <p>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:</p>
  
  <pre><code>SELECT *
  WHERE ( foo = 1 AND bar = 2) 
  OR (foo = 3 AND bar = 4)
  OR (foo = 5 AND bar = 6)
  </code></pre>
  
  <p>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.</p>
  
  <pre><code>List&lt;Waybill&gt; getWaybillsByCriteriaOrderItemList(List&lt; OrderItem &gt; orderItems ) {
      CriteriaBuilder cb = em.getCriteriaBuilder()
      CriteriaQuery&lt;Waybill&gt; q = cb.createQuery( Waybill )
      Root&lt;Waybill&gt; waybillRoot = q.from(Waybill)
      q.select( waybillRoot )
      List&lt;Predicate&gt; predicates = []
  
  
      orderItems.each { OrderItem item -&gt;
          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 &lt;&lt; thisCar
      }
      q.where(predicates.toArray(new Predicate[predicates.size()]))
      TypedQuery&lt;Waybill&gt; tq = em.createQuery(q)
      List&lt;Waybill&gt; result = tq.getResultList()
      result
  }
  </code></pre>
  
  <p>Unfortunately, the AND/OR grouping is exactly the opposite of what I would expect.  Here is the generated HQL</p>
  
  <pre><code>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 ) ) 
  </code></pre>
  
  <p>Simply reversing those and() and or() methods did not solve my issue either.  It resulted in everything being AND like so:</p>
  
  <pre><code> Predicate thisCar = cb.and (
       cb.or( carInit ),
       cb.or( carNumb )
   )
  </code></pre>
  
  <p>~~~~</p>
  
  <pre><code>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 ) )
  </code></pre>
  
  <p>I have tried every combination that I can think of. Can anyone point out what it is that I am doing wrong?  </p>