多对多关联中间表迁移至Hibernate时出现注解异常求助
问题根源
Hibernate对@JoinColumn的referencedColumnName参数要求严格:必须指向关联实体(这里是ReaEconomicAgentCatalog)已映射的数据库主键列。你的代码中,referencedColumnName="rea_economic_agent_catalog_id"指向的是**次级表(Secondary Table)**的主键列,但该列并未作为实体属性直接映射,而是通过@SecondaryTable的pkJoinColumns关联到父类EavEntity的主键列eav_entity_id。EclipseLink允许这种模糊引用,但Hibernate不支持。
解决方案
方案1:修改referencedColumnName为父类主键列名
直接将joinColumns中的referencedColumnName改为父类EavEntity的主键列名eav_entity_id,因为次级表的rea_economic_agent_catalog_id与eav_entity_id是一对一关联的,数据库中两者值完全一致:
@JoinTable( inverseJoinColumns = @JoinColumn( name = "rea_economic_resource_kind_id", referencedColumnName = "rea_economic_resource_kind_id" ), joinColumns = @JoinColumn( name = "rea_economic_agent_catalog_id", referencedColumnName = "eav_entity_id" // 替换为父类主键列名 ), name = "rea_economic_agent_catalog_resources" ) @ManyToMany(fetch = FetchType.LAZY, targetEntity = ReaEconomicResourceKind.class) private Set<ReaEconomicResourceKind> reaEconomicResourceKinds;
方案2:省略referencedColumnName让Hibernate自动推断
如果关联表的外键列名称与目标实体的主键列逻辑对应,Hibernate可以自动推断关联关系,无需显式指定referencedColumnName:
@JoinTable( inverseJoinColumns = @JoinColumn( name = "rea_economic_resource_kind_id", referencedColumnName = "rea_economic_resource_kind_id" ), joinColumns = @JoinColumn(name = "rea_economic_agent_catalog_id"), // 去掉referencedColumnName name = "rea_economic_agent_catalog_resources" ) @ManyToMany(fetch = FetchType.LAZY, targetEntity = ReaEconomicResourceKind.class) private Set<ReaEconomicResourceKind> reaEconomicResourceKinds;
方案3:显式映射次级表主键列(不推荐)
如果必须保留对rea_economic_agent_catalog_id的引用,可以在ReaEconomicAgentCatalog中显式映射该列作为主键属性(需确保与父类主键逻辑一致):
@SecondaryTables( { @SecondaryTable( name = ReaEconomicAgentCatalog.TABLE_NAME , pkJoinColumns = { @PrimaryKeyJoinColumn( name = "rea_economic_agent_catalog_id" , referencedColumnName = "eav_entity_id" ) } ) } ) public class ReaEconomicAgentCatalog extends EavEntity implements HasZonedAvailabilityPeriod, Serializable { // 显式映射次级表的主键列 @Id @Column(name = "rea_economic_agent_catalog_id", table = ReaEconomicAgentCatalog.TABLE_NAME) private Long reaEconomicAgentCatalogId; // ... 其他属性 @JoinTable( inverseJoinColumns = @JoinColumn( name = "rea_economic_resource_kind_id", referencedColumnName = "rea_economic_resource_kind_id" ), joinColumns = @JoinColumn( name = "rea_economic_agent_catalog_id", referencedColumnName = "rea_economic_agent_catalog_id" ), name = "rea_economic_agent_catalog_resources" ) @ManyToMany(fetch = FetchType.LAZY, targetEntity = ReaEconomicResourceKind.class) private Set<ReaEconomicResourceKind> reaEconomicResourceKinds; }
注意:此方案需确保父类
EavEntity的主键与该属性值完全同步,否则可能导致数据不一致,因此优先推荐方案1或方案2。
内容的提问来源于stack exchange,提问作者Paul Corbett

