单表继承关联问题:Hibernate映射code_list表报错求解决方案
I’ve run into this exact issue before when working with composite primary keys in Hibernate single-table inheritance—let’s break down what’s going wrong and how to fix it.
What’s Causing the Error?
The error message says it all: your code_list table uses a composite primary key (val_string + id_code_list), but your @ManyToOne association in the Affiliate entity only maps to one column (typ_aff). Hibernate can’t create a valid foreign key because the number of columns doesn’t match the referenced primary key.
The @Where annotation won’t help here—it only filters query results, it doesn’t adjust the underlying entity mapping or foreign key structure.
Step-by-Step Solution
1. Define the Composite Primary Key Class
First, create an embeddable class to represent the composite key of code_list. This is required for Hibernate to properly map the two-column primary key:
@Embeddable public class CodeListId implements Serializable { @Column(name = "val_string") private String value; @Column(name = "id_code_list") private String typeCode; // Hibernate requires a no-arg constructor public CodeListId() {} // Convenience constructor to set both key fields public CodeListId(String value, String typeCode) { this.value = value; this.typeCode = typeCode; } // Getters and setters // Critical: Implement equals() and hashCode() based on both fields @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CodeListId that = (CodeListId) o; return Objects.equals(value, that.value) && Objects.equals(typeCode, that.typeCode); } @Override public int hashCode() { return Objects.hash(value, typeCode); } }
2. Update the Abstract Parent Class
Modify your CodeListString class to use the composite key and properly link the discriminator column (which is part of the primary key):
@Entity @Table(name = "code_list") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "id_code_list", discriminatorType = DiscriminatorType.STRING) public abstract class CodeListString { @EmbeddedId private CodeListId id; // Add shared fields or methods here (if any) // Getters and setters }
3. Configure the AffiliateType Subclass
The subclass’s discriminator value maps directly to the typeCode part of the composite key. We can enforce this with a convenience constructor:
@Entity @DiscriminatorValue("TYP_AFF") public class AffiliateType extends CodeListString { // Add subclass-specific fields (if any) // No-arg constructor required by Hibernate protected AffiliateType() {} // Convenience constructor to ensure the type code is always "TYP_AFF" public AffiliateType(String value) { setId(new CodeListId(value, "TYP_AFF")); } }
4. Fix the Affiliate Association
Update the @ManyToOne association in Affiliate to map both columns of the composite key. You have two solid options:
Option A: Map to a Fixed Type Code Column
Add a dedicated column to Affiliate that’s always set to "TYP_AFF", then link it to the composite key:
@Entity @Table(name = "aff") public class Affiliate { // Other entity fields... // Fixed column to match the AffiliateType discriminator value @Column(name = "aff_type_code", nullable = false, updatable = false) private String affTypeCode = "TYP_AFF"; @ManyToOne @JoinColumns({ @JoinColumn(name = "typ_aff", referencedColumnName = "val_string"), @JoinColumn(name = "aff_type_code", referencedColumnName = "id_code_list") }) private AffiliateType affiliateType; // Getters and setters }
Option B: Mark the Type Code Join Column as Non-Insertable/Updatable
If you don’t want to add a new column, you can reference the existing id_code_list column in aff (ensure it’s always populated with "TYP_AFF" via database default or app logic):
@Entity @Table(name = "aff") public class Affiliate { // Other entity fields... @ManyToOne @JoinColumns({ @JoinColumn(name = "typ_aff", referencedColumnName = "val_string"), @JoinColumn(name = "id_code_list", referencedColumnName = "id_code_list", insertable = false, updatable = false, nullable = false) }) private AffiliateType affiliateType; // Getters and setters }
Why This Works
By explicitly mapping the composite primary key and ensuring the @ManyToOne association references all columns of that key, Hibernate can create a valid foreign key constraint that matches the structure of code_list. The discriminator value is now tied directly to the composite key’s typeCode field, which aligns perfectly with your single-table inheritance strategy.
内容的提问来源于stack exchange,提问作者Grechka Vassili

