JPA复合主键与仅共享单字段的外键映射问题
JPA复合主键与复合外键映射解决方案
问题场景
PostgreSQL数据库结构(所有字段非空):
File SourceTypes ----------- ----------- country PK country PK filename PK sourcetype PK sourcetype sourcename
- 两张表均为复合主键:File的主键是
(country, filename),SourceTypes的主键是(country, sourcetype) - File表通过复合外键
(country, sourcetype)关联SourceTypes表的主键 - 数据库已执行以下SQL完成约束配置:
alter table sourcetype add primary key (country_cod, source_type_cod); alter table file add primary key (country_cod, file_nam); alter table file add foreign key (country_cod, source_type_cod) references sourcetype(country_cod, source_type_cod);
现有代码遇到的问题:
已经写好了SourceType相关的实体类,但File实体的注解配置总是出问题:
- 用
@MapsId("country")时,JPA会把sourcetype字段从插入语句里排除,导致插入失败 - 去掉
@MapsId的参数,会报错说FilePK类缺少sourcetype列 - 完全删掉
@MapsId,又会出现country字段重复的错误
正确实现代码
1. 修正SourceType主键类(注意原类名拼写错误:SoutceTypePk → SourceTypePk)
@Embeddable class SourceTypePk { @Column(name = "country_cod") String country; @Column(name = "source_type_cod") String sourcetype; }
2. SourceType实体类
@Entity @Table(name = "sourcetype") class SourceType { @Id SourceTypePk id; @Column(name = "sourcename") String sourcename; }
3. File主键类
@Embeddable class FilePk { @Column(name = "country_cod") String country; @Column(name = "file_nam") String filename; }
4. File实体类(核心修正)
@Entity @Table(name = "file") class File { @Id FilePk id; // 单独声明sourcetype字段,对应数据库的source_type_cod列 @Column(name = "source_type_cod", nullable = false) String sourcetype; // 配置复合外键关联SourceType @ManyToOne @JoinColumns({ @JoinColumn(name = "country_cod", referencedColumnName = "country_cod", insertable = false, updatable = false), @JoinColumn(name = "source_type_cod", referencedColumnName = "source_type_cod", insertable = false, updatable = false) }) SourceType sourceType; // 辅助方法:设置关联的SourceType时,同步更新对应的字段值 public void setSourceType(SourceType sourceType) { this.sourceType = sourceType; if (sourceType != null) { this.id.country = sourceType.id.country; this.sourcetype = sourceType.id.sourcetype; } } }
关键要点解释
- File的主键只有
country和filename,不包含sourcetype,所以不能用@MapsId把sourcetype绑定到主键上,必须单独定义这个字段 - 外键的两个字段设置
insertable = false, updatable = false,是为了避免JPA自动处理这两个字段的插入/更新,而是通过业务逻辑(比如setSourceType方法)来维护,防止字段冲突 - 新增的
setSourceType方法是为了方便操作:当设置关联的SourceType时,自动同步File的country和sourcetype字段,保证数据一致性
内容的提问来源于stack exchange,提问作者David Caballero
相关产品推荐
相关产品推荐

