I have a complex query written with a QueryBuilder to create a Specification that will be passed to the repository.findAll(Specification<...>)
function to filter results.
The query worked fine in Spring 2.7, but after the migration it stopped to work. I have been experimenting with the code and I have found that if I comment the line builder.in(equip.get("id")).value(subqueryEquip),
the query works (of course, I need this line of code for filtering).
The error that throws in console is:
class org.hibernate.metamodel.mapping.internal.BasicAttributeMapping cannot be cast to class org.hibernate.metamodel.mapping.EntityValuedModelPart (org.hibernate.metamodel.mapping.internal.BasicAttributeMapping and org.hibernate.metamodel.mapping.EntityValuedModelPart are in unnamed module of loader 'app')
I suspect that the in with a Subquery is now giving errors.
So the function in question (the one that returns the predicate) is:
public static Specification<Usuari> filterByLaboratorisAndEquipsAssignatsToUser(UsuariFilterParams usuariFilterParams, UsuariLogat usuariLogat) {
return (root, query, builder) -> {
List<Predicate> predicates = buildListOfPredicates(root, builder, usuariFilterParams);
query.select(root.get("id")).distinct(true);
Subquery<Equip> subqueryEquip = buildSubqueryEquip(query, builder, usuariLogat.getId());
Join<Usuari, Equip> equip = root.join("equips", JoinType.LEFT);
Join<Usuari, Rol> rol = root.join("rol");
predicates.add(builder.and(
builder.notEqual(root.get("id"), usuariLogat.getId()),
builder.or(
builder.in(equip.get("id")).value(subqueryEquip),
builder.equal(rol.get("id"), (RolsEnum.ROLE_USUARI_LABORATORI.getId()))
),
builder.greaterThan(rol.get("id"), usuariLogat.getFirstRole().getId())));
query.where(builder.and(predicates.toArray(new Predicate[0])));
return query.getRestriction();
};
}
And this generate the subquery used in previous function:
private static Subquery<Equip> buildSubqueryEquip(CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder, long usuariLogatId) {
Subquery<Equip> subqueryEquip = query.subquery(Equip.class);
Root<Equip> subEquip = subqueryEquip.from(Equip.class);
Join<Equip, Usuari> subUsuariEquip = subEquip.join("usuaris");
return subqueryEquip.select(subEquip).where(criteriaBuilder.equal(subUsuariEquip.get("id"), usuariLogatId));
}
Did you experiment this error while migrating to 3.0.6? How did you solve?
After continuing my research trough the migration guides of Springboot and Hibernate, I found the solution here:
https://docs.jboss.org/hibernate/orm/6.0/migration-guide/migration-guide.html#query-criteria-copy
where it is said:
The same is true for the left and right hand side types of a comparison predicate. Queries like
Root<Participation> root = criteria.from( Participation.class );
Root<Submission> rootSubQuery = subQuery.from( Submission.class );
subQuery.select( rootSubQuery.join( "submitters" ) );
// left hand side of type Submission.id and right hand side of Submissions types
criteria.where( root.get( "id" ).in( subQuery ) );
will be considered invalid and should be changed into
Root<Participation> root = criteria.from( Participation.class );
Root<Submission> rootSubQuery = subQuery.from( Submission.class );
subQuery.select( rootSubQuery.join( "submitters" ) );
// left hand side of type Submission.id and right hand side of Submissions types
criteria.where( root.in( subQuery ) );
So in my case the line:
builder.in(equip.get("id")).value(subqueryEquip),
has to be replaced for:
equip.in(subqueryEquip),