Consider the following relationship
Tag <——- M:M ———-> Question
And the two entities are defined as follows in Kotlin, in database the two entities are linked with a joint table tag_question
@Entity
@Table(name="tag")
data class Tag(
override var id: Int,
@Column(name="name")
var name: String,
@Transient
@ManyToMany
@JoinTable(name = "tag_question",
joinColumns = [
JoinColumn(name="tag_id", nullable = false)
],
inverseJoinColumns = [
JoinColumn(name="question_id", nullable = false)
]
)
var questions: List<Question>? = mutableListOf(),
override var createdAt: Timestamp,
override var updatedAt: Timestamp
):Base() {
constructor():this(0,"",
mutableListOf(),
Timestamp(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()) , Timestamp(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()))
fun toDTO():TagDTO {
return this.let {
TagDTO(it.id, it.name,
// it.questions?.map { que -> que.toMemberDTO() },
it.createdAt, it.updatedAt)
}
}
fun toMemberDTO(): TagMemberDTO {
return this.let {
TagMemberDTO(it.id, it.name, it.createdAt, it.updatedAt)
}
}
}
@Entity
@Table(name="question")
data class Question(
override var id: Int,
@Column(name="content")
var content: String,
@Column(name="summary")
var summary: String,
@OneToMany(cascade = [CascadeType.ALL], mappedBy = "questions", fetch = FetchType.EAGER)
var answers: List<Answer>,
@ManyToMany(mappedBy = "questions", targetEntity = Tag::class, fetch = FetchType.LAZY)
var tags: Set<Tag> = mutableSetOf(),
@ManyToMany(mappedBy = "questions", targetEntity = com.questionset.model.Collection::class, fetch = FetchType.EAGER)
var collections: List<com.questionset.model.Collection>,
@ManyToOne(cascade = [(CascadeType.DETACH)], fetch = FetchType.EAGER)
@JoinColumn(name="course_id", nullable = false)
var status: QuestionStatus,
override var createdAt: Timestamp,
override var updatedAt: Timestamp
):Base() {
constructor():this(0,"","", mutableListOf(), mutableSetOf(), mutableListOf(), QuestionStatus(), Timestamp(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()) , Timestamp(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()))
...
I am trying to fetch all tags with its questions in a single repository query
@Query("SELECT t FROM Tag AS t JOIN FETCH t.questions")
override fun findAll(): MutableList<Tag>
However I receive following errors
java.lang.ClassCastException: class org.hibernate.metamodel.mapping.internal.BasicAttributeMapping cannot be cast to class org.hibernate.sql.ast.tree.from.TableGroupJoinProducer (org.hibernate.metamodel.mapping.internal.BasicAttributeMapping and org.hibernate.sql.ast.tree.from.TableGroupJoinProducer are in unnamed module of loader 'app')
Possible errors that I have double checked:
- I am NOT missing
@Entity
annotation for the two classes. - I am using
FetchType.LAZY
forQuestion
andFetchType.EAGER
forTag
How to make hibernate treat questions property like relationship, not basic attribute?