When trying to copy the Critria builder for the Count, using the existing criteria. seems getting the below error in Hibernate 6, but the same seems working in Hibernate 5.
Caused by: java.lang.IllegalArgumentException: Already registered a copy:
SqmBasicValuedSimplePath(com.example.domain.Test(175781908930100).name)
Adding the full code.
public static <Q, R> Page<Q> getResultsPage(final EntityManager entityManager, final CriteriaQuery<Q> criteria, final Root<R> root, final Pageable pageable,
final List<Order> defaultOrderList) {
return PageableExecutionUtils.getPage(getResultList(entityManager, criteria, root, pageable, defaultOrderList), pageable, () -> count(entityManager, criteria));
}
public static <Q, R> List<Q> getResultList(final EntityManager entityManager, final CriteriaQuery<Q> criteria, final Root<R> root, final Pageable pageable,
final List<Order> defaultOrderList) {
CriteriaUtils.setOrderBy(entityManager, criteria, root, pageable, defaultOrderList);
TypedQuery<Q> resultQuery = entityManager.createQuery(criteria);
if (Objects.nonNull(pageable) && pageable.isPaged()) {
resultQuery.setFirstResult((int) pageable.getOffset()).setMaxResults(pageable.getPageSize());
}
return resultQuery.getResultList();
}
public static <T> Long count(EntityManager em, CriteriaQuery<T> criteria) {
return em.createQuery(countCriteria(em, criteria)).getSingleResult();
}
public static <T> CriteriaQuery<Long> countCriteria(EntityManager em, CriteriaQuery<T> criteria) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Long> countCriteria = builder.createQuery(Long.class);
copyCriteriaWithoutSelectionAndOrder(criteria, countCriteria);
Expression<Long> countExpression;
if (criteria.isDistinct()) {
countExpression = builder.countDistinct(findRoot(countCriteria, criteria.getResultType()));
} else {
countExpression = builder.count(findRoot(countCriteria, criteria.getResultType()));
}
return countCriteria.select(countExpression);
}
private static void copyCriteriaWithoutSelectionAndOrder(
CriteriaQuery<?> from, CriteriaQuery<?> to) {
// Copy Roots
for (Root<?> root : from.getRoots()) {
Root<?> dest = to.from(root.getJavaType());
dest.alias(getOrCreateAlias(root));
copyJoins(root, dest);
}
to.groupBy(from.getGroupList());
to.distinct(from.isDistinct());
if (from.getGroupRestriction() != null)
to.having(from.getGroupRestriction());
Predicate predicate = from.getRestriction();
if (predicate != null)
to.where(predicate);
}
It seems that in Hibernate 6 it's no longer possible to reuse objects across different
CriteriaQueries
in this way. We encountered this error inCriteriaQueries
where we copy the predicate from one query to another, and the fix was to refactor the code so a newPredicate
object is created for eachCriteriaQuery
(see my answer on a similar issue). Unfortunately here it looks like it will be more difficult for you to do that - perhaps you can use the SQM copy functionality discussed here instead?