Skip to content

Different behavior between Spring Boot 3.0.5 & 2.7.10, when using @EntityGraph with @ElementCollection/@CollectionTable #2894

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Eng-Fouad opened this issue Mar 30, 2023 · 8 comments
Assignees
Labels
for: external-project For an external project and not something we can fix

Comments

@Eng-Fouad
Copy link
Contributor

Eng-Fouad commented Mar 30, 2023

I have this field inside UserEntity:

@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "users_roles_mapping", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"))
@Enumerated(EnumType.ORDINAL)
@Column(name = "role_id")
Set<Role> roles;

and I have this method inside UsersRepository:

@EntityGraph(attributePaths = {"roles"})
Optional<User> queryFirstById(int id);

On Spring Boot v3.0.5, user.getRoles() always contain single role despite the user has multiple roles. On Spring Boot v2.7.10, user.getRoles() works as expected and it contains all assigned roles.


Here is a reproducer: https://github.com/Eng-Fouad/spring-entity-graph-bug

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Mar 30, 2023
@schauder
Copy link
Contributor

This sounds very much like a Hibernate issue, since all the JPA mapping is done by it.
I recommend creating a reproducer based purely on Hibernate and submitting an issue with them.

If you think this is actually a Spring Data issue, please provide a reproducer for the issue including a test case that demonstrates the correct behaviour using the EntityManager and the Criteria API directly.

@schauder schauder added for: external-project For an external project and not something we can fix status: waiting-for-feedback We need additional information before we can continue and removed status: waiting-for-triage An issue we've not yet triaged labels Mar 30, 2023
@Eng-Fouad
Copy link
Contributor Author

Eng-Fouad commented Mar 30, 2023

@schauder What Hibernate versions that Spring Boot 3.0.5 & 2.7.10 use?

Also, I don't know how to use Hibernate API that corresponds to @EntityGraph spring annotation.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Mar 30, 2023
@schauder
Copy link
Contributor

schauder commented Mar 30, 2023

3.0.5 uses Hibernate 6.1.7
2.7.10 uses Hibernate 5.6.15.Final

See: https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa/2.7.10

For how to use a fetch graph there is a decent description at
https://www.baeldung.com/jpa-entity-graph

The hint names are defined in Hibernates QueryHints. Using them avoids errors due to the javax -> jakarta change
https://docs.jboss.org/hibernate/orm/5.1/javadocs/org/hibernate/jpa/QueryHints.html

@schauder schauder added status: waiting-for-feedback We need additional information before we can continue and removed status: feedback-provided Feedback has been provided labels Mar 30, 2023
@Eng-Fouad
Copy link
Contributor Author

Eng-Fouad commented Mar 30, 2023

I couldn't figure out how to replicate the issue using JPA API only.

Using Spring Boot 3.0.5, and given:

@Repository
public interface UsersRepository extends JpaRepository<UserEntity, Integer> {
	@EntityGraph(attributePaths = {"roles"})
	UserEntity queryFirstById(int id);
}
@RequiredArgsConstructor
@Slf4j
@Service
public class UsersService {

	private final UsersRepository usersRepository;

	@PersistenceContext
	private EntityManager entityManager;

	@Transactional(isolation = Isolation.READ_COMMITTED, readOnly = true)
	public Set<Role> getUserRolesByIdV1(int id) {
		return usersRepository.queryFirstById(id).getRoles();
	}

	@Transactional(isolation = Isolation.READ_COMMITTED, readOnly = true)
	public Set<Role> getUserRolesByIdV2(int id) {
		var cb = entityManager.getCriteriaBuilder();
		var criteriaQuery = cb.createQuery(UserEntity.class);
		Root<UserEntity> root = criteriaQuery.from(UserEntity.class);
		criteriaQuery.where(cb.equal(root.<Integer>get("id"), id));
		TypedQuery<UserEntity> typedQuery = entityManager.createQuery(criteriaQuery);

		EntityGraph<UserEntity> entityGraph = entityManager.createEntityGraph(UserEntity.class);
		entityGraph.addAttributeNodes("roles");
		typedQuery.setHint(EntityGraphType.FETCH.getKey(), entityGraph);

		UserEntity userEntity = typedQuery.getSingleResult();
		return userEntity.getRoles();
	}
}

getUserRolesByIdV2 returns 2 items while getUserRolesByIdV1 returns 1 item.

How to make getUserRolesByIdV2 do the exact same thing as getUserRolesByIdV1? I need your help.

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Mar 30, 2023
@Eng-Fouad
Copy link
Contributor Author

I was able to replicate the bug using JPA API:

EntityGraph<UserEntity> entityGraph = entityManager.createEntityGraph(UserEntity.class);
entityGraph.addAttributeNodes("roles");

Query query = entityManager.createQuery("SELECT u FROM UserEntity u WHERE u.id = 1");
query.setMaxResults(1);
query.setHint(EntityGraphType.FETCH.getKey(), entityGraph);

UserEntity userEntity = (UserEntity) query.getSingleResult();
return userEntity.getRoles();

This returns 2 roles in 2.7.10 and 1 role in 3.0.5.

@Eng-Fouad
Copy link
Contributor Author

Submitted a bug report to Hibernate team: https://hibernate.atlassian.net/browse/HHH-16408

@schauder
Copy link
Contributor

Thanks for the confirmation.

@schauder schauder closed this as not planned Won't fix, can't repro, duplicate, stale Mar 31, 2023
@schauder schauder removed the status: feedback-provided Feedback has been provided label Mar 31, 2023
@schauder schauder self-assigned this Mar 31, 2023
@Eng-Fouad
Copy link
Contributor Author

This bug should be fixed in Hibernate 6.2.0: https://hibernate.atlassian.net/jira/software/c/projects/HHH/issues/HHH-15964

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants