如何映射共享列的实体并支持增改?解决JPA重复列映射错误
解决JPA多共享列实体关联的重复列映射错误
问题场景
配置多共享列的实体关联时触发错误:Repeated column in mapping for entity: Aula column: no_entity (should be mapped with insert="false" update="false")
原始实体类代码:
@Entity @Table(name = "AULAS") public class Aula { @Id private String cveAula; // 该关联非空 @ManyToOne(optional = false) @JoinColumns({ @JoinColumn(name = "NO_PAIS", referencedColumnName = "NO_PAIS", nullable = false), @JoinColumn(name = "NO_ENTIDAD", referencedColumnName = "NO_ENTIDAD", nullable = false), @JoinColumn(name = "NO_DELEGACION", referencedColumnName = "NO_DELEGACION", nullable = false) }) private DelegacionMunicipio delegacionMunicipio; // 该关联可为空,复用delegacionMunicipio的外键字段 @ManyToOne @JoinColumns({ @JoinColumn(name = "NO_PAIS", referencedColumnName = "NO_PAIS"), @JoinColumn(name = "NO_ENTIDAD", referencedColumnName = "NO_ENTIDAD"), @JoinColumn(name = "NO_DELEGACION", referencedColumnName = "NO_DELEGACION"), @JoinColumn(name = "NO_LOCALIDAD", referencedColumnName = "NO_LOCALIDAD") }) private Localidad localidad; // 与localidad关联逻辑类似 @ManyToOne @JoinColumns({ @JoinColumn(name = "NO_PAIS", referencedColumnName = "NO_PAIS"), @JoinColumn(name = "NO_ENTIDAD", referencedColumnName = "NO_ENTIDAD"), @JoinColumn(name = "NO_DELEGACION", referencedColumnName = "NO_MUNICIPIO"), @JoinColumn(name = "NO_ASENTAMIENTO", referencedColumnName = "NO_ASENTAMIENTO") }) private CodigoPostal entCodigoPostal; }
数据库表结构:
CREATE TABLE DELEGACIONES_MUNICIPIOS ( NO_PAIS NUMBER(3) NOT NULL, NO_ENTIDAD NUMBER(3) NOT NULL, NO_DELEGACION NUMBER(3) NOT NULL, PRIMARY KEY (NO_PAIS, NO_ENTIDAD, NO_DELEGACION) ); CREATE TABLE LOCALIDADES ( NO_PAIS NUMBER(3) NOT NULL, NO_ENTIDAD NUMBER(3) NOT NULL, NO_DELEGACION NUMBER(4) NOT NULL, NO_LOCALIDAD NUMBER(4) NOT NULL, PRIMARY KEY (NO_PAIS, NO_ENTIDAD, NO_DELEGACION, NO_LOCALIDAD) ); CREATE TABLE CODIGOS_POSTALES ( NO_PAIS NUMBER(3) NOT NULL, NO_ENTIDAD NUMBER(3) NOT NULL, NO_DELEGACION NUMBER(4) NOT NULL, NO_ASENTAMIENTO NUMBER(4) NOT NULL, PRIMARY KEY (NO_PAIS, NO_ENTIDAD, NO_DELEGACION, NO_ASENTAMIENTO) ); CREATE TABLE AULAS ( CVE_AULA VARCHAR2(6) NOT NULL PRIMARY KEY, NO_PAIS NUMBER(3) NOT NULL, NO_ENTIDAD NUMBER(3) NOT NULL, NO_DELEGACION NUMBER(3) NOT NULL, NO_LOCALIDAD NUMBER(4), NO_ASENTAMIENTO NUMBER(4) );
当前已通过新增单独字段+配置insertable = false, updatable = false实现正常运行,但希望直接以对象形式处理关联,无需单独定义noLocalidad这类字段。
错误原因
JPA不允许数据库中同一列被多个可执行插入/更新操作的关联映射。Aula实体中,NO_PAIS、NO_ENTIDAD、NO_DELEGACION这三个列同时被delegacionMunicipio、localidad、entCodigoPostal三个关联引用,且默认情况下这些关联的列都具备插入/更新权限,导致冲突。
解决方案
指定其中一个关联(这里选择delegacionMunicipio,因为它是非空的主关联)负责共享列的插入和更新,其他关联的共享列则设置insertable = false, updatable = false,同时保留对象关联,无需新增单独字段。
修改后的实体类代码:
@Entity @Table(name = "AULAS") public class Aula { @Id private String cveAula; // 主关联,负责共享列的插入与更新 @ManyToOne(optional = false) @JoinColumns({ @JoinColumn(name = "NO_PAIS", referencedColumnName = "NO_PAIS", nullable = false), @JoinColumn(name = "NO_ENTIDAD", referencedColumnName = "NO_ENTIDAD", nullable = false), @JoinColumn(name = "NO_DELEGACION", referencedColumnName = "NO_DELEGACION", nullable = false) }) private DelegacionMunicipio delegacionMunicipio; // 关联localidad,共享列设为不可插入/更新,专属列NO_LOCALIDAD正常映射 @ManyToOne @JoinColumns({ @JoinColumn(name = "NO_PAIS", referencedColumnName = "NO_PAIS", insertable = false, updatable = false), @JoinColumn(name = "NO_ENTIDAD", referencedColumnName = "NO_ENTIDAD", insertable = false, updatable = false), @JoinColumn(name = "NO_DELEGACION", referencedColumnName = "NO_DELEGACION", insertable = false, updatable = false), @JoinColumn(name = "NO_LOCALIDAD", referencedColumnName = "NO_LOCALIDAD") }) private Localidad localidad; // 关联CodigoPostal,共享列设为不可插入/更新,专属列NO_ASENTAMIENTO正常映射 @ManyToOne @JoinColumns({ @JoinColumn(name = "NO_PAIS", referencedColumnName = "NO_PAIS", insertable = false, updatable = false), @JoinColumn(name = "NO_ENTIDAD", referencedColumnName = "NO_ENTIDAD", insertable = false, updatable = false), @JoinColumn(name = "NO_DELEGACION", referencedColumnName = "NO_MUNICIPIO", insertable = false, updatable = false), @JoinColumn(name = "NO_ASENTAMIENTO", referencedColumnName = "NO_ASENTAMIENTO") }) private CodigoPostal entCodigoPostal; }
说明
- 主关联
delegacionMunicipio保持原有配置,负责NO_PAIS、NO_ENTIDAD、NO_DELEGACION的插入和更新操作; - 其他关联的共享列添加
insertable = false, updatable = false,告知JPA这些列由主关联维护,当前关联仅用于查询和对象关联展示; - 专属列(如
NO_LOCALIDAD、NO_ASENTAMIENTO)无需单独定义字段,直接通过关联对象的赋值来维护,JPA会自动映射对应列的值。
内容的提问来源于stack exchange,提问作者AlejandroAC
相关产品推荐
相关产品推荐

