select
this_.customer_Id as customer1_1_0_,
this_.customer_Name as customer2_1_0_
from
personalCustomer this_
where
1=1
Result Size: 2
The JPA Criteria equivalent:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("examplePU");
EntityManager em = emf.createEntityManager();
List<Predicate> predicates = new ArrayList<>(); // Empty list of predicates
CriteriaQuery<Customer> query = em.getCriteriaBuilder().createQuery(Customer.class);
Root<Customer> from = query.from(Customer.class);
Predicate or = em.getCriteriaBuilder().or(predicates.toArray(new Predicate[0]));
query.where(or);
TypedQuery<Customer> query1 = em.createQuery(query);
List<Customer> resultList = query1.getResultList();
System.out.println("Result Size: " + resultList.size());
This generates:
select c1_0.customer_id,c1_0.customer_name from personalCustomer c1_0 where 1<>1
Result Size: 0
The issue is that an empty Conjunction in legacy criteria generates “1=1” (true), while in JPA Criteria, it generates “1<>1” (false). While I understand we could handle this during construction, are there any other approaches you’d recommend to maintain the legacy behavior?
What you’re writing here makes no sense, I think you might be confusing one or the other. Let me quote the JPA CriteriaBuilder methods:
/**
* Create a conjunction (with zero conjuncts).
* A conjunction with zero conjuncts is true.
* @return and predicate
*/
Predicate conjunction();
/**
* Create a disjunction (with zero disjuncts).
* A disjunction with zero disjuncts is false.
* @return or predicate
*/
Predicate disjunction();
/**
* Create a conjunction of the given restriction predicates.
* A conjunction of zero predicates is true.
* @param restrictions zero or more restriction predicates
* @return and predicate
*/
Predicate and(Predicate... restrictions);
/**
* Create a disjunction of the given restriction predicates.
* A disjunction of zero predicates is false.
* @param restrictions zero or more restriction predicates
* @return or predicate
*/
Predicate or(Predicate... restrictions);
Whatever the legacy Hibernate Criteria implementation did, the behavior of the JPA Criteria API is clearly specified, so there is no “regression”. If you migrate to the JPA Criteria API, you obviously need to understand the differences.
An empty disjunction is specified to be false, so generating 1<>1 is valid.
While I understand we could handle this during construction, are there any other approaches you’d recommend to maintain the legacy behavior?
I recommend you don’t generate empty conjunctions/disjunctions in the first place during construction or if you must, understand the implications of doing so.
I apologize for sharing the wrong example earlier. Here’s the correct legacy code snippet:
Session session = HibernateUtil.getSessionFactory().openSession();
Criteria criteria = session.createCriteria(Customer.class);
Disjunction disjunction = Restrictions.disjunction();
criteria.add(disjunction);
List list = criteria.list();
System.out.println(list.size());
session.close();
Even with an empty disjunction, the legacy criteria generates “1=1”, while in JPA Criteria it generates “1<>1”. I understand this is the expected behavior in JPA where an empty disjunction evaluates to false, and we have a workaround for this. I shouldn’t have termed it as a “regression” but rather a behavior change.
It also isn’t a behavior change
JPA Criteria API is simply a different API with different semantics. There is no expectation like “empty disjunction behaves the same way” and also, the behavior never did change. The JPA Criteria API implementation always was this way.
I understand that you might have been caught by surprise by one API behaving slightly differently than the other since both APIs use the same name/concept, but that’s just how it is. Good that you have a “workaround”, though really it is rather an implementation of your required semantics, so it can hardly be a workaround
Thanks for your response. Yes, we discovered this difference while investigating an API issue in our project that wasn’t working as expected due to the “1<>1” condition. We understand now how to handle this during construction.