I am trying to express a @ManyToMany
relationship where one of the table has a composite primary key. In table_1
I have a column named table2Id
which is foreign key to table_2
. The primary key in table_2
is a composite key of language
and id
. I do not know how to express a @ManyToMany
relationship between the two tables.
This is the "owning" table
@Entity
@Table(name = "table_1")
class Table1(
@Column val foo Double,
@Column val bar: Double,
@Column table2Id: Long,
@ManyToMany
@JoinTable(
name = "table_1_table_2_link",
joinColumns = [JoinColumn(name = "table_1_id", referencedColumnName = "id")],
inverseJoinColumns = [JoinColumn(name = "table_2_id", referencedColumnName = "id")]
)
val table2: List<Table2>
) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0
}
And this is the table with the composite primary key
@Embeddable
class Table2Id (
private var id: Long,
private var language: Languages // enum
) : Serializable
@Entity
@Table(name = "table_2",)
class Table2 (
@EmbeddedId
val table2Id: Table2Id,
@Column val title String,
@Column val tag String,
) {
@MapsId
val id: Long = 0
@MapsId
@Enumerated(EnumType.STRING)
val language: Languages = Languages.en
}
Which gives me
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Cannot invoke "org.hibernate.mapping.PersistentClass.getTable()" because "classMapping" is null
This error typically occurs when there's an issue with how the entities are defined or how their relationships are mapped.
Make sure you initialize the Table2Id.
This is what I came up with:
@Entity
@Table(name = "table_1")
class Table1(
@Column val foo: Double,
@Column val bar: Double)
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id: Long = 0
// Default constructor required by Hibernate
constructor() : this(0.0, 0.0)
@ManyToMany
var table2: List<Table2> = mutableListOf() // Initialize as empty list
fun addTable2(table2: Table2) {
this.table2 = listOf(table2)
}
}
Table2Id
@Embeddable
class Table2Id(
@Column(name = "id")
var id: Long,
@Column
@Enumerated(EnumType.STRING)
var language: Table2.Languages
) : Serializable {
constructor() : this(0L, Table2.Languages.en) // Required for JPA
// Implement equals and hashCode methods
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Table2Id) return false
if (id != other.id) return false
if (language != other.language) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + language.hashCode()
return result
}
}
Table2
@Entity
@Table(name = "table_2")
class Table2() {
@EmbeddedId
lateinit var table2Id: Table2Id
@Column
var title: String = ""
@Column
var tag: String = ""
constructor(id: Long, title: String, tag: String) : this() {
this.table2Id = Table2Id(id, Languages.en) // Initializing Table2Id
this.title = title
this.tag = tag
}
enum class Languages {
en,
sw
}
}
Sample results when I query
{
"foo": 2.2,
"bar": 2.3,
"id": 1,
"table2": [
{
"table2Id": {
"id": 1,
"language": "en"
},
"title": "My title",
"tag": "My tag"
}
]
}