Created
April 17, 2018 12:56
-
-
Save cherniag/fb74cd1626d46812009333582043c91a to your computer and use it in GitHub Desktop.
complicated jpa criteria api
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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