java.lang.IllegalArgumentException: Already registered a copy: SqmBasicValuedSimplePath

Hi I am migration to hibernate 6 and I am getting this error

java.lang.IllegalArgumentException: Already registered a copy: SqmBasicValuedSimplePath(ca.ulaval.gin.attribut.AttributEntity(318348975481600).dateDebutEffet)

this is m y code

 public ResultatPartielAvecTotal<AttributEntity> findBy(CriteresRechercheAttribut criteres, Pagination pagination) {
        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<AttributEntity> query = criteriaBuilder.createQuery(AttributEntity.class);
        Root<AttributEntity> root = query.from(AttributEntity.class);
        CriteresRechercheAttributToJpaConverter criteresRechercheAttributToJpaConverter = new CriteresRechercheAttributToJpaConverter(root, criteriaBuilder);
        query.where(criteresRechercheAttributToJpaConverter.toPredicat(criteres, query));
        query.orderBy(toOrder(pagination.getTri(), root, criteriaBuilder));

        CriteriaQuery<Long> queryCount = criteriaBuilder.createQuery(Long.class);
        queryCount.select(criteriaBuilder.count(queryCount.from(AttributEntity.class)))
            .where(criteresRechercheAttributToJpaConverter.toPredicat(criteres, queryCount));

        return new ResultatPartielAvecTotal<>(
                entityManager.createQuery(query)
                .setMaxResults(pagination.getTaillePage())
                .setFirstResult(pagination.getIndexRecuperationElements())
                .getResultList(),
                entityManager.createQuery(queryCount).getSingleResult());
    }

this is the toPredicat method

public Predicate[] toPredicat(CriteresRechercheAttribut criteres, CriteriaQuery<?> query) {
       List<Predicate> predicats = new ArrayList<>();
       Subquery<LocalDateTime> subqueryMaxDateDebut = query.subquery(LocalDateTime.class);
       Root<AttributEntity> rootSubQuery = subqueryMaxDateDebut.from(AttributEntity.class);
       Path<LocalDateTime> pathDateDebutEffet = rootSubQuery.get("dateDebutEffet");
       subqueryMaxDateDebut.select(criteriaBuilder.greatest(pathDateDebutEffet))
           .where(criteriaBuilder.equal(root.get("code"), rootSubQuery.get("code")));
       predicats.add(criteriaBuilder.equal(root.get("dateDebutEffet"), subqueryMaxDateDebut));

       if (!criteres.code.isEmpty()) {
           predicats.add(criteriaBuilder.equal(root.get("code"), criteres.code));
       }

       if (Boolean.TRUE.equals(criteres.isActif)) {
           predicats.add(criteriaBuilder.isNull(root.get("dateFinEffet")));
       } else if (Boolean.FALSE.equals(criteres.isActif)) {
           predicats.add(criteriaBuilder.isNotNull(root.get("dateFinEffet")));
       }

       return predicats.toArray(new Predicate[predicats.size()]);
   }

I tried to do like what was done here https://discourse.hibernate.org/t/possible-regression-5-6-to-6-1-sqmroot-not-yet-resolved-to-tablegroup/6554/21

  public Predicate[] toPredicat(CriteresRechercheAttribut criteres, CriteriaQuery<?> query) {
        List<Predicate> predicats = new ArrayList<>();
        SqmSubQuery<LocalDateTime> subqueryMaxDateDebut = (SqmSubQuery<LocalDateTime>) query.subquery(LocalDateTime.class);
        var sqmOriginalQuery = (SqmSelectStatement) query;
        var sqmOriginalQuerySpec = sqmOriginalQuery.getQuerySpec();
        var sqmSubQuerySpec = sqmOriginalQuerySpec.copy(SqmCopyContext.simpleContext());
        subqueryMaxDateDebut.setQueryPart(sqmSubQuerySpec);
        Root<AttributEntity> rootSubQuery = subqueryMaxDateDebut.from(AttributEntity.class);
        Path<LocalDateTime> pathDateDebutEffet = rootSubQuery.get("dateDebutEffet");
        subqueryMaxDateDebut.select(criteriaBuilder.greatest(pathDateDebutEffet))
                .where(criteriaBuilder.equal(root.get("code"), rootSubQuery.get("code")));
        predicats.add(criteriaBuilder.equal(root.get("dateDebutEffet"), subqueryMaxDateDebut));

        if (!criteres.code.isEmpty()) {
            predicats.add(criteriaBuilder.equal(root.get("code"), criteres.code));
        }

        if (Boolean.TRUE.equals(criteres.isActif)) {
            predicats.add(criteriaBuilder.isNull(root.get("dateFinEffet")));
        } else if (Boolean.FALSE.equals(criteres.isActif)) {
            predicats.add(criteriaBuilder.isNotNull(root.get("dateFinEffet")));
        }

        return predicats.toArray(new Predicate[predicats.size()]);
    }

but I don’t seem to have a good understanding of that because Ikeep having the same issue

thank you

Please consider using our search box in the forum. This question was asked multiple times already and has plenty of answers:

You’re doing exactly the same wrong thing as everyone else, you use expressions in a count query, but the Paths which the expressions are based on are from a different query.
This simply can’t work and only worked by accident in a very particular circumstance in ORM 5.

The solution to this is the same that I explained multiple times already. Either you copy the original query parts with the SqmNode#copy method or build the expressions/paths and hence also predicates for the count query freshly based on the Path and From/Root objects of that count query.

Thanks for your reply so much! I checked topics again and create working method:
I hope it helps someone.

	public Long count() {
		var countBuilder = (HibernateCriteriaBuilder) builder; //CriteriaBuilder from class level
		var countQuery = countBuilder.createQuery(Long.class);
		var subQuery = countQuery.subquery(Tuple.class);

		var sqmSubQuery = (SqmSubQuery<Tuple>) subQuery;
		var sqmOriginalQuery = (SqmSelectStatement) query; // CriteriaQuery from class level
		var sqmOriginalQuerySpec = sqmOriginalQuery.getQuerySpec();
		var sqmSubQuerySpec = sqmOriginalQuerySpec.copy(SqmCopyContext.simpleContext());

		sqmSubQuery.setQueryPart(sqmSubQuerySpec);
		Root<?> subQuerySelectRoot = subQuery.getRoots().iterator().next();
		sqmSubQuery.multiselect(subQuerySelectRoot.get("id").alias("id"));

		countQuery.multiselect(countBuilder.count(countBuilder.literal(1)));
		countQuery.from(sqmSubQuery.distinct(true).orderBy(builder.asc(subQuerySelectRoot.get("id"))));

		return entityManager.createQuery(countQuery).getSingleResult();
	}

You’ll be happy to see that with Hibernate ORM 6.4, I implemented support for creating the count query directly: [HHH-17410] - Hibernate JIRA

1 Like

Hi @dbesan / @beikov , I’m trying to implement the above and at the line:
countQuery.from(sqmSubQuery.distinct(true).orderBy(builder.asc(subQuerySelectRoot.get(“id”))));
I am receiving the error:
Cannot resolve method ‘from(org.hibernate.query.criteria.JpaSubQuery<jakarta.persistence.Tuple>)’

from() is expecting entityClass or entity as parameter.

Any idea on how to resolve this?
Appreciate your help. Thanks!

Looks like your countQuery method is not of the type org.hibernate.query.criteria.JpaCriteriaQuery.

Thanks for the help @beikov . This worked! Much appreciated! :slight_smile: