I am trying convert this JPA QL to criteria builder. JBoss 6.0.
\"SELECT ba FROM BankAccount ba WHERE ba.balance >= :amt ORDER BY ba.ownerName ASC\"
Well, I finally found the right way to call the gt() method. Here is the complete solution. Fully tested in JBoss 6.
public List<BankAccount> findWithBalance(int amount) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<BankAccount> cq = cb.createQuery(BankAccount.class);
Root<BankAccount> from = cq.from(BankAccount.class);
ParameterExpression<Integer> balance = cb.parameter(Integer.class);
cq.select(from);
//Here is the trick!
Predicate predicate = cb.gt(from.<Integer> get("balance"), balance);
cq.where(predicate);
cq.orderBy(cb.asc(from.get("ownerName")));
TypedQuery<BankAccount> query = em.createQuery(cq);
query.setParameter(balance, amount);
return query.getResultList();
}
The type safety feature in JPA restricts such comparisons with incompatible types, the compiler itself will raise error.
Here, from.get("balance")
returns the Path<Object>
, but the method can accept parameter of type java.lang.Number
, therefore results in error.
You can try the below code.
//--
Metamodel metamodel = em.getMetamodel();
EntityType<BankAccount> pClass = metamodel.entity(BankAccount.class);
Predicate predicate = cb.gt(from.get(pClass.getSingularAttribute("balance", Integer.class)), balance);
//--
If you are using Metamodel API, then you can retieve directly by specifying ClassName_.field as cb.gt(from.get(BankAccount_.balance), balance)
which is much cleaner & easy to debug.
But if you are having many entities, then it may be difficult to write their Metamodel classes manually, if the JPA provider doesn't generate them.
The compiler is complaining because amount
is an int
, not an Expression
, see if you can figure out how to build an Expression
that's a constant and use that and you should be good.