Data inside hibernate interceptor object but null under entity variables - Can't save to repository

Viewed 1150

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.

enter image description here

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

2 Answers

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.

I tried a few options but wasn't able to fix them. Then I realized I need to use

FetchType.EAGER

This is worked for me. Just for FYI

FetchType.LAZY = This does not load the relationships unless you invoke it via the getter method.

FetchType.EAGER = This loads all the relationships.

Pros and Cons of these two fetch types.

Lazy initialization improves performance by avoiding unnecessary computation and reducing memory requirements.

Eager initialization takes more memory consumption and processing speed is slow.

Just posting in case someone doing the same mistake

Related