Skip to content

Instantly share code, notes, and snippets.

@cherniag
Created April 17, 2018 12:56
Show Gist options
  • Save cherniag/fb74cd1626d46812009333582043c91a to your computer and use it in GitHub Desktop.
Save cherniag/fb74cd1626d46812009333582043c91a to your computer and use it in GitHub Desktop.
complicated jpa criteria api
// Select Page with sorts and filters by children entities and distinct parent
// 1. Create DTO with sortable fields and id of parent, perform paging, sorting and filtering over this DTO
CriteriaQuery<ParentEntityDto> parentEntityQuery = cb.createQuery(ParentEntityDto.class);
Root<ParentEntity> parentEntityRoot = query.from(ParentEntity.class);
// filter here as usual, no special treatment
Predicate predicate = ...
parentEntityQuery.where(predicate);
parentEntityQuery.distinct(true);
// need to prevent duplication in select and order
Map<String, Expression> selectExpressions = ImmutableMap.<String, Expression>builder()
.put(ID, parentEntityRoot.get(ID))
.put(CHILD_NAME, parentEntityRoot.join(CHILD_FIELD, JoinType.LEFT).get(CHILD_NAME))
... // all other order fields
.build();
// select dto
parentEntityQuery.select(cb.construct(ParentEntityDto.class,
selectExpressions.get(ID),
selectExpressions.get(CHILD_NAME),
... // all other order fields
));
// order
List<Order> orders = new ArrayList<>();
for (Sort.Order order : pageable.getSort()) {
String orderProperty = order.getProperty();
Expression orderExpression = selectExpressions.get(orderProperty);
if (orderExpression == null) {
throw new InternalException("No order column for " + orderProperty);
}
orders.add(order.isAscending() ? cb.asc(orderExpression) : cb.desc(orderExpression));
}
parentEntityQuery.orderBy(orders);
TypedQuery<ParentEntityDto> dtoTypedQuery = entityManager.createQuery(parentEntityQuery);
// page
dtoTypedQuery.setFirstResult(pageable.getOffset());
dtoTypedQuery.setMaxResults(pageable.getPageSize());
// distinct ids - sorted, filtered and paged
List<Long> parentIds = dtoTypedQuery.getResultList()
.stream()
.map(ParentEntityDto::getId)
.collect(Collectors.toList());
// 2. Get parent entities by ids
CriteriaQuery<ParentEntity> query = cb.createQuery(ParentEntity.class);
Root<ParentEntity> root = query.from(ParentEntity.class);
query.where(root.get(ID).in(ids));
TypedQuery<ParentEntity> typedQuery = entityManager.createQuery(query);
List<ParentEntity> selected = typedQuery.getResultList();
List<ParentEntity> ordered = parentIds.stream()
.map(id -> selected.stream().filter(br ->
br.getId().equals(id)).findAny().get())
.collect(Collectors.toList());
// 3. Get total count for page:
CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
Root<ParentEntity> countRoot = countQuery.from(ParentEntity.class);
countQuery.select(cb.count(countRoot));
Predicate predicate = ... // the same predicate!
countQuery.where(predicate);
TypedQuery<Long> typedQuery = entityManager.createQuery(countQuery);
Long totalCount = typedQuery.getSingleResult();
// done
return new PageImpl<>(ordered, pageable, totalCount);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment