@ManyToOne 其中目标 PK 是 FK 的一部分

@ManyToOne where target PK is part of FK

我正在按照 an article 配置两个实体之间的关系:

+-----------------------------+      +---------------------------------+
| redacted_identifier         |      | redacted_identifier_year        |
+-----------------------------+      +---------------------------------+
| redacted_identifier_id (PK) |      | redacted_identifier_id (PK, FK) |
| ...                         |      | year (PK)                       |
+-----------------------------+      | ...                             |
                                     +---------------------------------+

我省略了与问题不相关的字段并删除了原始名称,请原谅可能存在的不一致之处。编辑后的名称保持相同的长度,稍后会详细介绍。

我创建了这些 类:

@Entity
@Table(identifier = "REDACTED_IDENTIFIER")
@SequenceGenerator(identifier = "REDACTED_IDENTIFIER_ID_SEQ", sequenceIdentifier = "REDACTED_IDENTIFIER_ID_SEQ", allocationSize = 1)
public class RedactedIdentifier implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "REDACTED_IDENTIFIER_ID_SEQ")
    @Column(identifier="REDACTED_IDENTIFIER_ID", nullable = false)
    private Long redactedIdentifierId;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<RedactedIdentifierYear> redactedIdentifierYearList;

    public RedactedIdentifier() {
    }

    public void setRedactedIdentifierId(Long redactedIdentifierId) {
        this.redactedIdentifierId = redactedIdentifierId;
    }

    public Long getRedactedIdentifierId() {
        return redactedIdentifierId;
    }

    public List<RedactedIdentifierYear> getRedactedIdentifierYearList() {
        if(this.redactedIdentifierYearList == null){
            this.redactedIdentifierYearList = new ArrayList<RedactedIdentifierYear>();
        }
        return this.redactedIdentifierYearList;
    }

    public void setRedactedIdentifierYearList(List<RedactedIdentifierYear> redactedIdentifierYearList) {
        this.redactedIdentifierYearList = redactedIdentifierYearList;
    }

    public RedactedIdentifierYear addRedactedIdentifierYear(RedactedIdentifierYear redactedIdentifierYear) {
        getRedactedIdentifierYearList().add(redactedIdentifierYear);
        redactedIdentifierYear.setRedactedIdentifier(this);
        return redactedIdentifierYear;
    }

    public RedactedIdentifierYear removeRedactedIdentifierYear(RedactedIdentifierYear redactedIdentifierYear) {
        getRedactedIdentifierYearList().remove(redactedIdentifierYear);
        redactedIdentifierYear.setRedactedIdentifier(null);
        return redactedIdentifierYear;
    }
}
@Entity
@Table(identifier = "REDACTED_IDENTIFIER_YEAR")
@IdClass(RedactedIdentifierYearPK.class)
public class RedactedIdentifierYear implements Serializable {
    @Id
    @Column(nullable = false)
    private Integer year;

    @Id
    @ManyToOne
    @JoinColumn(identifier = "REDACTED_IDENTIFIER_ID", referencedColumnIdentifier = "REDACTED_IDENTIFIER_ID")
    private RedactedIdentifier redactedIdentifier;

    public RedactedIdentifierYear() {
    }

    public RedactedIdentifierYear(Integer year) {
        this.year = year;
    }

    public void setYear(Integer year) {
        this.year = year;
    }

    public Integer getYear() {
        return year;
    }

    public void setRedactedIdentifier(RedactedIdentifier redactedIdentifier) {
        this.redactedIdentifier = redactedIdentifier;
    }

    public RedactedIdentifier getRedactedIdentifier() {
        return redactedIdentifier;
    }
}
public class RedactedIdentifierYearPK implements Serializable {
    private Long redactedIdentifier;
    private Integer year;

    public RedactedIdentifierYearPK() {
    }

    public RedactedIdentifierYearPK(Long redactedIdentifier, Integer year) {
        this.redactedIdentifier = redactedIdentifier;
        this.year = year;
    }

    public boolean equals(Object other) {
        if (other instanceof RedactedIdentifierYearPK) {
            final RedactedIdentifierYearPK otherRedactedIdentifierYearPK = (RedactedIdentifierYearPK)other;
            final boolean areEqual = otherRedactedIdentifierYearPK.redactedIdentifier.equals(redactedIdentifier)
                && otherRedactedIdentifierYearPK.year.equals(year);
            return areEqual;
        }
        return false;
    }

    public int hashCode() {
        return super.hashCode();
    }

    public void setRedactedIdentifier(Long redactedIdentifier) {
        this.redactedIdentifier = redactedIdentifier;
    }

    public Long getRedactedIdentifier() {
        return redactedIdentifier;
    }

    public void setYear(Integer year) {
        this.year = year;
    }

    public Integer getYear() {
        return year;
    }
}

然后我使用它们如下:

public float assignRedactedIdentifierYear(RedactedIdentifier redactedIdentifier, Integer year) {
    RedactedIdentifierYear redactedIdentifierYear = new RedactedIdentifierYear(year);
    redactedIdentifier.addRedactedIdentifierYear(redactedIdentifierYear);
}

但是当刷新发生时,它试图写入一个完全错误的table:

INSERT INTO REDACTED_IDENTIFIER_REDACTED_IDENTIFIER_YEAR (REDACTE_REDACTED_IDENTIFIER_ID, REDACTEDIDENTIFIERYEARLIST_RED, REDACTEDIDENTIFIERYEARLIST_YEA) VALUES (?, ?, ?)
[params=(long) 2082, (long) 2082, (int) 2020]
               ^^^^         ^^^^
               Correct ID from sequence (twice)

一些名称已明确截断为 30 个字符以符合 RDBMS (Oracle)。

我的实体设计中 wrong/missing 是什么?

我在父实体中缺少 mappedBy 属性。我正在检查的文章可能是理所当然的:

@OneToMany(mappedBy = "redactedIdentifier", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<RedactedIdentifierYear> redactedIdentifierYearList;