Issue
I'm on my early days working with Spring and Hibernate and apologies if I'm missing something obvious here but I am a bit confused why I can see an id set for my variable inside a hibernate_interceptor object shown under the debugging tool but it's null for the same variable outside of it.
This comes from a many to many relationship that exists between the Question and User entities but I've noticed this happening for other relationships as well and it's blocking me from being able to save the new row to my join table.
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "userEntity", cascade = CascadeType.ALL, orphanRemoval = true)
private Collection<QuestionEntity> questionEntities;
@ManyToMany
@JoinTable(
name = "question_favourite",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "question_id"))
private Set<QuestionEntity> questionFavouriteEntity;
public UserEntity(UUID id) {
this.id = id;
}
}
public class QuestionEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
@Column(name = "title", nullable = false)
private String title;
@Column(name = "creation_date", nullable = false)
private Long creationDate;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
@JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)
private UserEntity userEntity;
@ManyToMany(mappedBy = "questionFavouriteEntity")
private Set<UserEntity> userEntities;
public QuestionEntity(UUID id) {
this.id = id;
}
public QuestionEntity(UUID id, String title) {
this.id = id;
this.title = title;
}
}
@Override
public QuestionFavouriteCreateDto favouriteQuestion(UUID userId, QuestionFavouriteCreateDto qf) {
if (questionRepository.findById(qf.getQuestionId()).isPresent()) {
QuestionEntity questionEntity = questionRepository.findById(qf.getQuestionId()).get();
UserEntity userEntity = userRepository.findById(userId).get();
questionEntity.getUserEntities().add(userEntity);
userEntity.getQuestionEntities().add(questionEntity);
userRepository.save(userEntity);
}
return null;
}
Many thanks in advance.
UPDATE
As per @christian's answer I understand this seem to be the desired outcome, and my data saving issue has been resolved under this other thread here
Solution
Hibernate creates proxy classes for your entities to implement lazy loading. The proxy classes are just subclasses of your entity classes that delegate all access through the interceptor to lazy load on the first access to not yet loaded state. Due to object identity guarantees Hibernate has to provide according to the JPA specification, you see the proxy object rather than the real entity. If an entity with a certain id is associated with a persistence context once, it has to always return that object while the object is managed by that persistence context.
So this entity was proxied by some lazy to-one association of a different entity or by using entityManager.getReference
. When the collection association for questionFavouriteEntity
is loaded, it sees that the object is part of the persistence context already and uses that object.
Answered By - Christian Beikov
Answer Checked By - Mary Flores (JavaFixing Volunteer)