How to do a like ignore case query using criteria builder. For description property I want to do something like upper(description) like '%xyz%'
I have the following query
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> personCriteriaQuery = criteriaBuilder.createQuery(Person.class);
Root<Person> personRoot = personCriteriaQuery.from(Person.class);
personCriteriaQuery.select(personRoot);
personCriteriaQuery.where(criteriaBuilder.like(personRoot.get(Person_.description), "%"+filter.getDescription().toUpperCase()+"%"));
List<Person> pageResults = entityManager.createQuery(personCriteriaQuery).getResultList();
There is a CriteriaBuilder.upper() method:
personCriteriaQuery.where(criteriaBuilder.like(
criteriaBuilder.upper(personRoot.get(Person_.description)),
"%"+filter.getDescription().toUpperCase()+"%"));
If the database contains German words with letters like Fußballschuhe in the column, java will modify the parameter in uppercase method to FUSSBALLSCHUHE and the query will not match. Lowercase will work in this case:
personCriteriaQuery.where(criteriaBuilder.like(
criteriaBuilder.lower(personRoot.get(Person_.description)),
"%"+filter.getDescription().toLowerCase()+"%"));
Related
How can I use the "order by" clause with "asc nulls first"?
This is my code:
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<MyClassModel> query = builder.createQuery(MyClassModel.class);
//esprToOrder is a Expression<?> istance that containing the sort field...
query.orderBy(builder.asc(esprToOrder));
TypedQuery<MyClassModel> myQ = em.createQuery(query);
List<MyClassModel> myList = myQ.getResultList();
myList doesn't contain any records with null field sort...
JPA doesn't support specification of "NULLS FIRST|LAST". Some implementations may allow it (by casting to allow extra methods), but it's not part of the JPA spec.
What is the difference between:
criteriaBuilder.in(predicate);
criteriaQuery.where(predicate);
This seems to give the same results. Am I missing something? Should we choose the builder above the query?
Complete example:
List<String> names = new ArrayList<String>();
names.add("John");
names.add("Emma");
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<PersonEntity> criteriaQuery = criteriaBuilder.createQuery(PersonEntity.class);
Root<PersonEntity> root = criteriaQuery.from(PersonEntity.class);
Predicate predicate = root.get(PersonEntity_.name).in(names);
criteriaBuilder.in(predicate);
// or alternative: criteriaQuery.where(predicate);
List<PersonEntity> list = entityManager.createQuery(cq).getResultList();
criteriaBuilder.in(predicate) creates a new predicate. You should file a bug with your provider if it is adding the predicate to the query, as this will not be portable. According to the specification it creates a new predicate, just as root.get(PersonEntity_.name).in(names) does. The query should only use the predicate if it gets added to it such as by calling criteriaQuery.where(predicate).
I am new to Eclipselink JPA. I have a set of complex search queries with a number of search parameters, some of the parameters are optional. Is there a way to specify optional parameters in named query? Is the below approach an efficient way to do?
select o from Product o WHERE :value is null or o.category = :value'
Your approach would probably work, but I normally use the Criteria API in similar situations. For example, you could conditionally add predicates to your criteria query if the parameters are provided:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Product> cq = cb.createQuery(Product.class);
Root<Product> e = cq.from(Product.class);
List<Predicate> predicates = new ArrayList<Predicate>();
if (categoryValue != null)
predicates.add(cb.equal(e.get("category"), categoryValue));
if (someOtherValue != null)
predicates.add(cb.equal(e.get("someField"), someOtherValue));
// AND all of the predicates together:
if (!predicates.isEmpty())
cq.where(cb.and(predicates.toArray(new Predicate[predicates.size()])));
List<Product> products = em.createQuery(cq).getResultList();
This is kind of an ugly example, but the CriteriaBuilder is very powerful once you become familiar with the API.
I'm learning jpa-hibernate basics.
I have this query for getting all users:
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery cq = cb.createQuery();
cq.select(cq.from(Utente.class));
return getEntityManager().createQuery(cq).getResultList();
Now I want to filter by a boolean field named 'ghost' where it equals true (or false, it depends).
Translated:
SELECT * FROM users WHERE ghost = 0;
Do I have to use cq.where() ? How?
Yes, you have to use cq.where().
Try something like this:
Root<Utente> utente = cq.from(Utente.class);
boolean myCondition = true; // or false
Predicate predicate = cb.equal(utente.get(Utente_.ghost), myCondition);
cq.where(predicate);
Where I have used the canonical metamodel class Utente_ that should be generated automatically. This avoids the risk of making errors in typing field names, and enhances type safety. Otherwise you can use
Predicate predicate = cb.equal(utente.get("ghost"), myCondition);
I am trying to use subqueries in an application I am writing using JPA 2.0 type-safe criteria API, with Hibernate 3.6.1.Final as my provider. I have no problem selecting primitive types (Long, MyEntity, etc.), but I want to select multiple columns.
Here's an example of something completely reasonable. Ignore the needless use of subquery -- it is simply meant as illustrative.
EntityManager em = getEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Subquery<Tuple> subQ = cq.subquery(Tuple.class);
Expression<Long> subqCount;
{
Root<MyEntity> root = subQ.from(MyEntity.class);
Path<MyEntity> filter = root.get(MyEntity.challenge);
subqCount = cb.count(root);
// How to select tuple?
Selection<Tuple> tuple = cb.tuple(filter, subqCount);
// !! Run-time exception here
Expression<Tuple> tupleExpr = (Expression<Tuple>) tuple;
// Not sure why I can't use multiSelect on a subQuery
// #select only accepts Expression<Tuple>
createSubQ.select(tupleExpr);
createSubQ.groupBy(filter);
}
cq.multiselect(subqCount);
Although the compiler doesn't complain, I still get a run-time exception.
java.lang.ClassCastException: org.hibernate.ejb.criteria.expression.CompoundSelectionImpl cannot be cast to javax.persistence.criteria.Expression
Is this a bug in hibernate, or am I doing something wrong?
If you can't use multiselect on a subquery, then how can you perform a groupBy?
If you can't use groupBy on a subquery, why is it in the API?
I have the same problem.
I can only attempt to answer your last question by saying you can only really use sub queries to perform very simple queries like:
SELECT name FROM Pets WHERE Pets.ownerID in (
SELECT ID FROM owners WHERE owners.Country = "SOUTH AFRICA"
)
The other thing I wanted to say was how much this incident reminds me of xkcd #979.
I had similar problem.
I had specification, and I wanted to get ids of objects matching this specification.
My solution:
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Tuple> tupleCriteriaQuery = criteriaBuilder.createTupleQuery();
Root<Issue> root = tupleCriteriaQuery.from(Issue.class);
tupleCriteriaQuery = tupleCriteriaQuery.multiselect(root.get(IssueTable.COLUMN_ID));//select did not work.
tupleCriteriaQuery = tupleCriteriaQuery.where(issueFilter.toPredicate(root, tupleCriteriaQuery, criteriaBuilder));
List<Tuple> tupleResult = em.createQuery(tupleCriteriaQuery).getResultList();
First I select columns (In my case I need only one column), and then I call where method to merge with my given specification.