You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在JPA中实现含复合主键表的@ManyToMany关联?

JPA多对多关联(复合主键场景)修正方案

核心问题

  1. Table2映射冲突:错误地给单独的id和language字段添加@MapsId注解,与@EmbeddedId的table2Id形成重复映射,导致Hibernate解析实体时出现异常。
  2. 多对多关联不完整:关联Table2时仅指定了复合主键的id字段,未包含language字段,JPA无法识别完整的关联条件。
  3. 冗余字段:Table1中的table2Id属于冗余字段,多对多关系通过中间表维护,无需单独存储该外键。

修正后的代码实现

1. 复合主键类Table2Id

@Embeddable
data class Table2Id(
    val id: Long,
    val language: Languages // 确保枚举类Languages已正确定义
) : Serializable

Kotlin的data class会自动生成equals、hashCode方法,满足JPA对嵌入式主键的序列化要求。

2. Table2实体类

@Entity
@Table(name = "table_2")
class Table2(
    @EmbeddedId
    val table2Id: Table2Id,
    @Column val title: String,
    @Column val tag: String
) {
    // 通过嵌入式主键间接暴露id和language,避免重复映射
    val id: Long get() = table2Id.id
    val language: Languages get() = table2Id.language
}

3. Table1实体类

@Entity
@Table(name = "table_1")
class Table1(
    @Column val foo: Double,
    @Column val bar: Double,
    @ManyToMany
    @JoinTable(
        name = "table_1_table_2_link",
        joinColumns = [JoinColumn(name = "table_1_id", referencedColumnName = "id")],
        // 必须指定复合主键的全部字段,对应中间表和Table2的主键属性
        inverseJoinColumns = [
            JoinColumn(name = "table_2_id", referencedColumnName = "id"),
            JoinColumn(name = "table_2_language", referencedColumnName = "language")
        ]
    )
    val table2: MutableList<Table2> = mutableListOf() // 用可变集合方便后续关联操作
) {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long = 0
}

注意事项

  • 中间表table_1_table_2_link需要创建三个字段:table_1_id、table_2_id、table_2_language,这三个字段共同构成中间表的复合主键。
  • 如果需要双向关联,可在Table2中添加如下代码:
    @ManyToMany(mappedBy = "table2")
    val table1: MutableList<Table1> = mutableListOf()
    

内容的提问来源于stack exchange,提问作者four-eyes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 11:18:16