You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Hibernate实现3表嵌套OneToMany映射报错求助

问题描述

数据库表结构

Table 1: KEY
Primary Key: KEY_ID

Table 2: KEY_VERSION
Primary Key: KEY_ID (外键关联 KEY.KEY_ID) 和 VERSION

Table 3: KEY_VERSION_BLOCK
Primary Key: KEY_ID, VERSION (外键关联 KEY_VERSION.KEY_ID, KEY_VERSION.VERSION), BLOCK_TYPE

现有Hibernate映射代码

Key 实体类

public class Key implements Serializable {
    @EmbeddedId
    private KeyId keyId;

    @OneToMany(mappedBy = "Key", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<KeyVersion> keyVersions;
    // 其他代码省略
}

KeyId 嵌入式ID类

// 注:此处仅单键列,无需嵌入式ID,后续会替换,暂时忽略
@Embeddable
public class KeyId implements Serializable {
    @Column(name = "KEY_ID", nullable = false)
    public Long keyId;
    // 其他代码省略
}

KeyVersion 实体类

public class KeyVersion implements Serializable {
    @EmbeddedId
    private KeyVersionId versionId;

    @MapsId("KeyId")
    @JoinColumns({ @JoinColumn(name = "KEY_ID", referencedColumnName = "KEY_ID") })
    @ManyToOne
    public Key key;

    @OneToMany(mappedBy = "KeyVersion", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<KeyVersionBlock> keyVersionBlocks;
    // 其他代码省略
}

KeyVersionId 嵌入式ID类

@Embeddable
public class KeyVersionId implements Serializable {
    @ManyToOne
    private Key key;

    @Column(name = "VERSION")
    private Integer version;
    // 其他代码省略
}

KeyVersionBlock 实体类

public class KeyVersionBlock implements Serializable {
    @EmbeddedId
    private KeyVersionBlockId keyVersionBlockId;

    @MapsId("keyVersionId")
    @JoinColumns({ @JoinColumn(name = "KEY_ID", referencedColumnName = "KEY_ID"),
        @JoinColumn(name = "VERSION", referencedColumnName = "VERSION") })
    @ManyToOne
    private KeyVersion keyVersion;
    // 其他代码省略
}

KeyVersionBlockId 嵌入式ID类

public class KeyVersionBlockId implements Serializable {
    @Column(name = "BLOCK_TYPE")
    private Long blockType;

    private KeyVersionId keyVersionId;
    // 其他代码省略
}

报错信息

Caused by: org.hibernate.AnnotationException:
referencedColumnNames(KEY_ID, VERSION) of
com.akamai.portal.dexp.kms.core.model.KeyVersionBlock.keyVersion
referencing com.akamai.portal.dexp.kms.core.model.KeyVersion not
mapped to a single property
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:203)
~[hibernate-core-5.6.15.Final.jar:5.6.15.Final]
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:104)
~[hibernate-core-5.6.15.Final.jar:5.6.15.Final]
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1750)
~[hibernate-core-5.6.15.Final.jar:5.6.15.Final]

用户已尝试操作

曾在KEY_VERSION实体类中添加@Column(name = "KEY_ID", nullable = false, updatable = false, insertable = false) private Long keyId;,但问题未解决。

解决方案

报错核心原因是嵌入式ID的映射逻辑不匹配,Hibernate无法解析多列外键到目标实体的关联关系。以下是修正后的完整映射方案:


1. 修正KeyVersionId的映射

嵌入式ID类中不能直接使用@ManyToOne,需改为基础字段映射:

@Embeddable
public class KeyVersionId implements Serializable {
    @Column(name = "KEY_ID")
    private Long keyId;

    @Column(name = "VERSION")
    private Integer version;

    // 必须重写equals和hashCode方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        KeyVersionId that = (KeyVersionId) o;
        return Objects.equals(keyId, that.keyId) && Objects.equals(version, that.version);
    }

    @Override
    public int hashCode() {
        return Objects.hash(keyId, version);
    }
}

2. 修正KeyVersion实体类

调整@MapsId参数匹配KeyVersionId字段名,同时修正mappedBy的属性名(需与子实体属性名大小写一致):

public class KeyVersion implements Serializable {
    @EmbeddedId
    private KeyVersionId versionId;

    @MapsId("keyId") // 对应KeyVersionId中的keyId字段
    @JoinColumn(name = "KEY_ID", referencedColumnName = "KEY_ID")
    @ManyToOne(fetch = FetchType.LAZY)
    private Key key;

    @OneToMany(mappedBy = "keyVersion", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<KeyVersionBlock> keyVersionBlocks;
    // 其他代码省略
}

3. 修正KeyVersionBlockId的映射

将嵌入式ID中的关联改为基础字段组合:

@Embeddable
public class KeyVersionBlockId implements Serializable {
    @Column(name = "KEY_ID")
    private Long keyId;

    @Column(name = "VERSION")
    private Integer version;

    @Column(name = "BLOCK_TYPE")
    private Long blockType;

    // 必须重写equals和hashCode方法
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        KeyVersionBlockId that = (KeyVersionBlockId) o;
        return Objects.equals(keyId, that.keyId) && Objects.equals(version, that.version) && Objects.equals(blockType, that.blockType);
    }

    @Override
    public int hashCode() {
        return Objects.hash(keyId, version, blockType);
    }
}

4. 修正KeyVersionBlock实体类

通过@MapsId分别关联KeyVersionBlockId中的字段,添加insertable=false, updatable=false避免列映射冲突:

public class KeyVersionBlock implements Serializable {
    @EmbeddedId
    private KeyVersionBlockId keyVersionBlockId;

    @MapsId("keyId") // 对应KeyVersionBlockId中的keyId
    @JoinColumn(name = "KEY_ID", referencedColumnName = "KEY_ID", insertable = false, updatable = false)
    @ManyToOne(fetch = FetchType.LAZY)
    private Key key;

    @MapsId("version") // 对应KeyVersionBlockId中的version
    @JoinColumn(name = "VERSION", referencedColumnName = "VERSION", insertable = false, updatable = false)
    @ManyToOne(fetch = FetchType.LAZY)
    private KeyVersion keyVersion;
    // 其他代码省略
}

5. 修正Key实体类的mappedBy参数

确保mappedBy的值与KeyVersion中的属性名一致(小写key):

public class Key implements Serializable {
    @EmbeddedId
    private KeyId keyId;

    @OneToMany(mappedBy = "key", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<KeyVersion> keyVersions;
    // 其他代码省略
}

额外说明

  1. 所有嵌入式ID类必须重写equals和hashCode方法,否则Hibernate无法正确识别实体唯一性。
  2. 关联字段添加insertable = false, updatable = false,避免重复映射同一列导致的冲突。
  3. 若后续替换Key的嵌入式ID为普通主键,只需将@EmbeddedId改为@Id并删除KeyId类即可,不影响其他关联逻辑。

内容的提问来源于stack exchange,提问作者Archana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 22:25:01