Hibernate 6 错误:已注册副本:SqmBasicValuedSimplePath(completelyqualifiedclass.name)

问题描述 投票:0回答:2

尝试使用现有条件复制计数的 Critria 构建器时。在 Hibernate 6 中似乎出现以下错误,但在 Hibernate 5 中似乎同样有效。

原因:java.lang.IllegalArgumentException:已经注册了一个副本:

SqmBasicValuedSimplePath(com.example.domain.Test(175781908930100).name)

添加完整代码。

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);
    }

java spring-boot hibernate spring-data-jpa hibernate-6.x
2个回答
2
投票

似乎在 Hibernate 6 中不再可能以这种方式跨不同的

CriteriaQueries
重用对象。我们在
CriteriaQueries
中遇到了这个错误,我们将谓词从一个查询复制到另一个查询,解决方法是重构代码,以便为每个
Predicate
创建一个新的
CriteriaQuery
对象(请参阅我对类似问题的回答) )。不幸的是,您似乎更难做到这一点 - 也许您可以使用此处讨论的 SQM 复制功能


0
投票

这个问题是在https://hibernate.atlassian.net/browse/HHH-15951

中提出的

您需要将 hibernate-core 更新到版本 6.4.4.Final

然后在您的

countCriteria
中,更新这两行

    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Long> countCriteria = builder.createQuery(Long.class);

进入

HibernateCriteriaBuilder hibernateCriteriaBuilder = (HibernateCriteriaBuilder) criteriaBuilder; 
JpaCriteriaQuery<Long> countQuery = hibernateCriteriaBuilder.createQuery(Long.class); 

那么

countCriteria
方法应该返回
JpaCriteriaQuery
而不是
CriteriaQuery

现在更新

public static <T> Long count(EntityManager em, CriteriaQuery<T> criteria) {
    return em.createQuery(countCriteria(em, criteria).createCountQuery()).getSingleResult();
}

这应该可以解决问题。

有关更多信息,您可以查看此示例(在

testParameters
方法下):https://github.com/hibernate/hibernate-orm/blob/main/hibernate-core/src/test/java/org/ hibernate/orm/test/query/criteria/CountQueryTests.java

希望有帮助

© www.soinside.com 2019 - 2024. All rights reserved.