使用复合主键时EclipseLink为可嵌入类额外建表的问题
问题描述
我在JPA中为Oracle数据库已有的含两列复合主键的表(TABLE_PKSTAT_DATA_STATUS)建模:
- 通过实体类
PkstatDataStatus与标注@Embeddable的可嵌入类PkstatDataStatusPK,用@EmbeddedId关联复合主键; - 测试时改用
@IdClass替代@EmbeddedId/@Embeddable,问题依旧; - 移除实体中与
UmUser的多对一关联后,问题仍存在。
启动服务器时,EclipseLink会额外创建一张名为TABLE_PKSTAT_DATA_STATUS_TABLE_PKSTAT_DATA_STATUS的表,包含原表的两个主键列period和company_number,并添加外键关联原表。
环境信息:
- Java 17
- Eclipse 2023-03(4.27.0)
- EclipseLink JPA 3.4.101.v202301061019
可能原因与解决方案
1. 实体类重复定义主键字段
使用@EmbeddedId或@IdClass时,实体类中若重复单独定义主键列(比如给period、company_number加@Column或@Id),会导致EclipseLink误将这些字段识别为新的关联字段,进而生成额外关联表。
错误示例:
@Entity @Table(name = "TABLE_PKSTAT_DATA_STATUS") public class PkstatDataStatus { @EmbeddedId private PkstatDataStatusPK id; // 错误:重复定义主键字段,引发元数据解析歧义 @Column(name = "PERIOD") private String period; }
修正:移除实体类中重复的主键字段定义,仅保留@EmbeddedId的主键对象。
2. Schema生成策略配置不当
若persistence.xml中javax.persistence.schema-generation.database.action设置为create或create-drop,EclipseLink会尝试根据实体元数据重建Schema。当元数据存在歧义时,就会生成额外表。
修正:因为你的表是已存在的,建议将该属性设置为validate(仅校验映射匹配)或none(不修改数据库):
<property name="javax.persistence.schema-generation.database.action" value="validate"/>
3. 主键类未正确实现equals/hashCode
@Embeddable或@IdClass标注的主键类必须正确实现equals()和hashCode()方法,否则EclipseLink无法正确识别主键结构,导致元数据解析错误。
正确示例:
@Embeddable public class PkstatDataStatusPK implements Serializable { @Column(name = "PERIOD") private String period; @Column(name = "COMPANY_NUMBER") private String companyNumber; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; PkstatDataStatusPK that = (PkstatDataStatusPK) o; return Objects.equals(period, that.period) && Objects.equals(companyNumber, that.companyNumber); } @Override public int hashCode() { return Objects.hash(period, companyNumber); } // getter/setter方法 }
4. 未正确配置的自关联
若PkstatDataStatus实体存在自关联字段(比如@OneToMany指向自身)但未指定mappedBy属性,EclipseLink会默认生成关联表维护关系,也就是你看到的拼接名表。
错误示例:
@Entity public class PkstatDataStatus { @EmbeddedId private PkstatDataStatusPK id; // 错误:自关联未指定mappedBy,导致生成额外关联表 @OneToMany private List<PkstatDataStatus> relatedItems; }
修正:若确实需要自关联,补充mappedBy指向关联字段;若不需要,直接移除该自关联定义。
内容的提问来源于stack exchange,提问作者Alf

