I have three entities: Interview, Question and Answer. Interview can have many Questions (and vice versa, many-to-many), Question can have many Answers (one-to-many).
I persist and fetch entities in the following manner:
@ApplicationScoped
internal class InterviewRepository : PanacheRepository<Interview> {
fun persistInterview(interview: Interview): Uni<Interview> {
return Panache.withTransaction {
persist(interview)
}
}
fun getInterview(interviewId: Long): Uni<Interview> {
return findById(interviewId)
}
}
// same repos for Question and Answer
All persistence operations work fine, interviews and questions are created fine and then both fetched fine as well. But when I create Answer (also fine) and then try to findById Question or Interview entities I get the following error (this one for getting Question):
"org.hibernate.HibernateException: java.util.concurrent.CompletionException: org.hibernate.LazyInitializationException: HR000056: Collection cannot be initialized: com.my.company.question.Question.answers - Fetch the collection using 'Mutiny.fetch', 'Stage.fetch', or 'fetch join' in HQL"
It used to show the same error for findById (interview), but FetchMode.JOIN solved the issue. For some reason FetchMode.JOIN is ignored for fetching answer (?). Instead of using findById I also tried manually writing HQL using left join fetch, but got the same result. What am I missing here?
Interview Entity:
@Entity(name = "interview")
@RegisterForReflection
internal data class Interview (
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
val interviewId: Long? = null,
@Column(name = "client_id", nullable = false)
val clientId: Long = Long.MIN_VALUE,
@ManyToMany(mappedBy = "interviews", fetch = FetchType.LAZY)
@Fetch(FetchMode.JOIN)
val questions: MutableSet<Question> = mutableSetOf(),
)
Question Entity:
@Entity(name = "question")
@RegisterForReflection
internal data class Question (
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
val questionId: Long? = null,
@Column(name = "client_id", nullable = true)
val clientId: Long? = null,
@OneToMany(mappedBy = "question", fetch = FetchType.LAZY)
@OnDelete(action = CASCADE)
@Fetch(FetchMode.JOIN)
val answers: MutableSet<Answer> = mutableSetOf(),
@ManyToMany(cascade = [CascadeType.ALL], fetch = FetchType.LAZY)
@JoinTable(
name = INTERVIEW_QUESTION_TABLE,
joinColumns = [JoinColumn(name = "question_id", referencedColumnName = "id")],
inverseJoinColumns = [JoinColumn(name = "interview_id", referencedColumnName = "id")]
)
@Fetch(FetchMode.JOIN)
@JsonIgnore
val interviews: MutableList<Interview> = mutableListOf(),
)
Answer Entity:
@Entity(name = "answer")
@RegisterForReflection
internal data class Answer (
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
val answerId: Long? = null,
@Column(name = "question_id", nullable = false)
val questionId: Long = Long.MIN_VALUE,
@ManyToOne(fetch = FetchType.LAZY)
@Fetch(FetchMode.JOIN)
@JoinColumn(
name="question_id",
foreignKey = ForeignKey(ConstraintMode.NO_CONSTRAINT),
nullable = false,
insertable = false,
updatable = false,
)
@JsonIgnore
val question: Question = Question(),
)