Ebean单向一对多关联插入操作触发重复列名异常问题
报错根因
该报错并非数据库表结构设计问题,本质是实体映射对同一物理字段的重复定义,触发Ebean的DML生成逻辑缺陷:
- Entry实体的
@OneToMany关联通过@JoinColumn(name = "program_list_uid"),声明要由关联关系维护PROGRAM表上的program_list_uid外键字段 - Program实体的
entryId属性通过@Column(name = "program_list_uid"),单独将同一物理字段映射为实体普通属性
两个映射同时生效时,Ebean生成插入语句会重复拼接program_list_uid字段,最终触发数据库的重复列名校验报错:
insert into program (program_list_uid, program_name, program_list_uid) values (?,?,?)
之前尝试删除Program实体中entryId的临时方案,本质是移除了同一字段的一个映射,自然能解决重复列的问题,但因为该属性被大量业务复用,无法直接删除。
兼容现有业务的解决方案
在完全保留entryId属性读写逻辑不变的前提下,最小改动解决重复映射问题:
调整关联映射的写入权限
修改Entry实体中关联关系的@JoinColumn配置,将关联关系对应的字段映射设置为不可插入、不可更新,完全保留Program实体中entryId原有的可写可查逻辑:
@Entity(name="entry") public class Entry { @Id public int uid; @OneToMany(cascade = CascadeType.ALL) @JoinColumn( name = "program_list_uid", referencedColumnName = "uid", insertable = false, updatable = false ) public List<Program> programList; }
方案说明
- 修改后Ebean生成插入、更新语句时,不会再把关联关系对应的
program_list_uid字段加入列清单,从根源上避免重复列问题 - Program实体的
entryId属性完全保留原有@Column配置,所有依赖该属性的业务逻辑读写行为不受任何影响 - 关联映射仅用于查询时的JOIN条件匹配,不承担字段写入职责
必做配套调整
因为关联关系不再负责外键字段的写入,在通过Entry的programList级联保存子项时,需要手动给每个Program的entryId赋值为对应Entry的uid,避免外键存空:
// 级联保存时的赋值逻辑 program.setEntryId(entry.uid); entry.getProgramList().add(program); ebeanServer.save(entry);
常见踩坑提示
- 不要修改Program实体中
entryId的@Column配置为只读,否则会破坏其他依赖该属性做业务更新的逻辑 - 若Entry的uid为业务层手动赋值(无自动生成策略),在保存前完成entryId同步赋值即可,不存在空值时序问题
内容的提问来源于stack exchange,提问作者Peter
相关产品推荐
相关产品推荐

