Java JPA OneToMany Map映射报错:Repeated column in mapping for collection
问题原因
你出现Repeated column in mapping for collection报错的核心原因是:@JoinTable的joinColumns属性已经将b_name作为B实体和b_p关联表的外键映射,同时@MapKeyJoinColumns中又再次定义了b_name列,JPA检测到同一个列被两个不同的映射规则控制,因此抛出重复列错误。
此外你的代码和表结构还有几处不匹配的问题:
Price实体同时标注了@Entity和@Embeddable,两个注解冲突v_c表的建表语句中字段名和复合主键VCId定义的字段名不匹配b_p表中定义的关联字段是bname,和后续外键引用的b_name不一致
现有结构修复方案
只需要修改B实体中pricing字段的注解,给@MapKeyJoinColumn的b_name字段设置只读属性,避免和joinColumns的映射冲突即可:
@OneToMany(cascade = CascadeType.PERSIST) @JoinTable( name = "b_p", joinColumns = @JoinColumn(name = "b_name", referencedColumnName = "name")) @MapKeyJoinColumns({ // 标记为不可插入不可更新,避免和joinColumns的b_name冲突 @MapKeyJoinColumn(name = "b_name", insertable = false, updatable = false), @MapKeyJoinColumn(name = "p_c"), @MapKeyJoinColumn(name = "c_id") }) private Map<VC, Price> pricing = new LinkedHashMap<>();
同时修正表结构中字段名不匹配、Price实体注解冲突的问题,即可正常运行。
简化表结构方案(仅保留b、b_p两张表)
你期望的简化结构完全可以通过JPA的@ElementCollection实现,不需要单独维护v_c和price表,结构更简单,查询效率更高:
1. 调整实体定义
- VCId保持不变,还是作为复合键的
@Embeddable类 - 把Price改成纯嵌入类,移除
@Entity、@Id等相关注解:
@Setter @Getter @NoArgsConstructor @Embeddable public class Price implements Serializable { @Column(name = "amount") private BigDecimal amount; @Column(name = "discount_amount") private BigDecimal discountAmount; }
- 修改B实体的pricing字段映射:
@ElementCollection @CollectionTable( name = "b_p", joinColumns = @JoinColumn(name = "b_name", referencedColumnName = "name") ) @MapKeyClass(VCId.class) @AttributeOverrides({ @AttributeOverride(name = "key.pc", column = @Column(name = "p_c")), @AttributeOverride(name = "key.cId", column = @Column(name = "c_id")), @AttributeOverride(name = "value.amount", column = @Column(name = "amount")), @AttributeOverride(name = "value.discountAmount", column = @Column(name = "discount_amount")) }) private Map<VCId, Price> pricing = new LinkedHashMap<>();
2. 对应建表语句
CREATE TABLE b ( name VARCHAR(100) NOT NULL PRIMARY KEY -- 其他业务字段 ); CREATE TABLE b_p ( b_name VARCHAR(100) NOT NULL, p_c TEXT NOT NULL, c_id VARCHAR(50) NOT NULL, amount NUMERIC, discount_amount NUMERIC DEFAULT 0.00, FOREIGN KEY (b_name) REFERENCES b (name) ON DELETE CASCADE, PRIMARY KEY (b_name, p_c, c_id) );
调整后直接传入b_name、p_c、c_id三个字段即可查询到对应的amount和discount_amount,完全满足需求,同时没有多余的表关联,维护成本更低。
内容的提问来源于stack exchange,提问作者mr nooby noob
相关产品推荐
相关产品推荐

