Here is what i am implementing.
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<User> query = cb.createQuery(User.class);
Root<User> userRoot = query.from(User.class);
List<Predicate> predicates = new ArrayList<>();
Expression<String> userExpression = statusRoot.get("firstName");
for (String str : firstNames) {
predicates.add(cb.like(userExpression, "%" + str + "%"));
}
I want to apply like clause on list of values but its appending all Predicate with AND operator. please help.
Actually code given in example does not show use of predicates. That is where the problem is. I will assume it is equivalent to rather typical:
//conjunction, will combine with 'AND'
query.where(predicates.toArray(new Predicate[0]));
As documented, it will combine Predicates with AND:
Modify the query to restrict the query result according to the
conjunction of the specified restriction predicates
One way to combine Predicates with OR is simply using CriteriaBuilder.or:
//disjunction, will combine with 'OR'
Predicate firstNameLikeAnyOf = cb.or(predicates.toArray(new Predicate[0]));
query.where(firstNameLikeAnyOf);
Related
I wanna know is there a way to do something like this in hibernate using criteriaBuilder
select users.first_name,orders.payable,order_item.product_title
from "order" orders
join users on orders.user_id_fk = users.id_pk
join order_item on orders.id_pk = order_id_fk
I need this specially if I have to use group by. I search and google and also read this article but have no clue how can I do this in hibernate:
Query Selection Other Than Entities
querycriteria
hibernate-facts-multi-level-fetching
also I code this for selecting field in first layer and it worked perfectly for selecting first layer but it need some change to work with join and select field from other table than root:
<R> List<R> reportEntityGroupBy(List<String> groupBy, List<String> selects, Class<T> root, Class<R> output) {
CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
CriteriaQuery<R> criteriaQuery = criteriaBuilder.createQuery(output);
Root<T> rootQuery = criteriaQuery.from(root);
if (selects == null || selects.isEmpty()) {
selects = groupBy;
}
criteriaQuery.multiselect(selects.stream().map(rootQuery::get).collect(Collectors.toList()));
criteriaQuery.groupBy(groupBy.stream().map(rootQuery::get).collect(Collectors.toList()));
I use Hibernate 5.4.22.Final and use entityGraph for my join.
I don't know how your selects look like, but I suppose you are using paths i.e. attributes separated by .. In that case, you have to split the paths and call Path#get for each attribute name.
List<Path> paths = selects.stream()
.map(select -> {
Path<?> path = rootQuery;
for (String part : select.split("\\.")) {
path = path.get(part);
}
return path;
})
.collect(Collectors.toList()));
criteriaQuery.multiselect(paths);
criteriaQuery.groupBy(paths);
I have a use-case where I need to search a table on a list of values. Below is the schema:
CASE table
Case_Id
CASE_CIN table
Case_Id
cin
CASE & CASE_CIN table are joined via Many to Many.
I need to search cases based on provided list of CINs. This is the SQL that I'm trying to implement:
select distinct c.* from case c left join case_cin cc on c.case_id = cc.case_id where cc.cin in ("cin1", "cin2", "cin3");
This is how I designed my filter criteria based on just a single CIN:
public static Specification<CaseEntity> buildSpecification(CaseSearchRequestDto criteria, String userName) {
return (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (!isEmpty(criteria.getAssociatePartyCins())) {
predicates.add(buildAssociatePartyCinsFilterPredicate(root, cb, query, criteria.getAssociatePartyCins());
}
return cb.and(predicates.toArray(new Predicate[0]));
};
}
private static Predicate buildAssociatePartyCinsFilterPredicate(Root<CaseEntity> root, CriteriaBuilder cb, CriteriaQuery query, List<String> cins) {
Predicate filterPredicate = cb.disjunction();
ListJoin<CaseEntity, String> cinsJoin = root.joinList(FIELD_CASE_CINS, LEFT);
filterPredicate.getExpressions().add(startWithString(cinsJoin, cb, **cins.get(0)**); // need to change logic here.
query.distinct(true);
return filterPredicate;
}
I'd also like to have the exact match for every CIN rather that startWithString.
Can anyone help modify the code to allow search by multiple values?
It turns out to be way simpler than I thought. Just need to replace the condition with cinsJoin.in(cins).
private static Predicate buildAssociatePartyCinsFilterPredicate(Root<CaseEntity> root, CriteriaBuilder cb, CriteriaQuery query, List<String> cins) {
Predicate filterPredicate = cb.disjunction();
ListJoin<CaseEntity, String> cinsJoin = root.joinList(FIELD_CASE_CINS, LEFT);
filterPredicate.getExpressions().add(cinsJoin.in(cins));
query.distinct(true);
return filterPredicate;
}
I want to join two tables and remove the on clause in join query to set a new custom on clause, however I always get a null predicate from "joinb" so a cant concatenate with more conditions.
My code below.
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<myClass> query = cb.createQuery(myClass.class);
Root<a> a = query.from(a.class);
Join<a, b> joinb = a.join("b", JoinType.INNER);
Predicate joinBOn = b.getOn();
b.on(cb.or(joinBOn, cb.or("condition1", "condition2")));
The problem here is joinBOn is always null.
I'm new so I don't know what is happening.
As documented, getOn()
Return the predicate that corresponds to the ON restriction(s) on the
join, or null if no ON condition has been specified.
In this case there is clearly no ON condition specified, so null is expected. That is not an issue, because fetching current ON restriction is not necessary:
Predicate condition1 = ...
Predicate condition2 = ...
b.on(cb.or(condition1, condition2));
I'm stuck with a simple problem; struggling how to invoke order by on a joined entity. Essentially I am trying to achieve the following with JPA Criteria:
select distinct d from Department d
left join fetch d.children c
left join fetch c.appointments a
where d.parent is null
order by d.name, c.name
I have the following:
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Department> c = cb.createQuery(Department.class);
Root<Department> root = c.from(Department.class);
Fetch<Department, Department> childrenFetch = root.fetch(
Department_.children, JoinType.LEFT);
childrenFetch.fetch(Department_.appointments, JoinType.LEFT);
c.orderBy(cb.asc(root.get(Department_.name)));
c.distinct(true);
c.select(root);
c.where(cb.isNull(root.get(Department_.parent)));
How to achieve order by d.name, c.name with Criteria API? I tried with Expression, Path but didn't work.
Any pointers will be greatly appreciated.
If you need to add couple of orders you can make something like (but for your query and different root objects)
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Route> query = criteriaBuilder.createQuery(Route.class);
Root<Route> routeRoot = query.from(Route.class);
query.select(routeRoot);
List<Order> orderList = new ArrayList();
query.where(routeRoot.get("owner").in(user));
orderList.add(criteriaBuilder.desc(routeRoot.get("date")));
orderList.add(criteriaBuilder.desc(routeRoot.get("rating")));
query.orderBy(orderList);
I have the same problem with order by using Criteria API. I found this solution:
CriteriaQuery<Test> q = cb.createQuery(Test.class);
Root<Test> c = q.from(Test.class);
q.select(c);
q.orderBy(cb.asc(c.get("name")), cb.desc(c.get("prenom")));
I was having trouble doing the same, and I have found a solution on this page:
http://www.objectdb.com/api/java/jpa/criteria/CriteriaQuery/orderBy_Order_
//javax.persistence.criteria.CriteriaQuery
//CriteriaQuery<T> orderBy(Order... o)
Specify the ordering expressions that are used to order the query results. Replaces the previous ordering expressions, if any. If no ordering expressions are specified, the previous ordering, if any, is simply removed, and results will be returned in no particular order. The left-to-right sequence of the ordering expressions determines the precedence, whereby the leftmost has highest precedence.
Parameters:
o - zero or more ordering expressions
Returns:
the modified query
Since:
JPA 2.0
The solucion that work for me is the following
session=HibernateUtil.getSessionJavaConfigFactory_report().openSession();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Object[]> criteriaQuery = builder.createQuery(Object[].class);
List<Order> orderList = new ArrayList();
orderList.add(builder.desc(ejeRoot.get("name")));
criteriaQuery.orderBy(orderList);
Note: ejeRoot is the class object
categoryRepository.findAll(predicates, new Sort(Direction.ASC, "sortOrder", "name"))
.forEach(categoryDtoList::add);
Is there a possibility to use a parameter list in Criteria API .in expression?
I have something like this:
List<Long> list = new ArrayList<Long>();
list.add((long)1);
list.add((long)2);
list.add((long)3);
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Bewerbung> criteriaQuery = cb.createQuery(Bewerbung.class);
Root<Bewerbung> bewerbung = criteriaQuery.from(Bewerbung.class);
criteriaQuery.select(bewerbung).where(
cb.in(bewerbung.get(Bewerbung_.bewerberNummer)).value(list);
return em.createQuery(criteriaQuery).getResultList();
The expression .value(list) does not work as value() is expecting a paramter of type long not a list.
In my case it is not possible to use a subquery.
Can anyone help me on this issue?
No need to use CriteriaBuilder#isTrue. This should suffice:
criteriaQuery.select(bewerbung)
.where(bewerbung.get(Bewerbung_.bewerberNummer)
.in(list));
cb.isTrue(bewerbung.get(Bewerbung_.bewerberNummer).in(list));
should do the trick, AFAIK.