jpa - @ManyToOne,其中目标 PK 是 FK 的一部分
问题描述
我正在关注一篇文章来配置两个实体之间的关系:
+-----------------------------+ +---------------------------------+
| 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);
}
但是当刷新发生时,它会尝试写入一个完全错误的表:
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)。
我的实体设计有什么问题/缺失?
解决方案
我缺少mappedBy
父实体中的属性。我正在检查的文章可能认为这是理所当然的:
@OneToMany(mappedBy = "redactedIdentifier", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<RedactedIdentifierYear> redactedIdentifierYearList;
推荐阅读
- sql - Oracle 数据库 12c:ORACLE JSON 查询搜索
- apache-kafka - kafka-connect - s3-connector - JVM堆 - 估计堆大小计算
- c# - C# 泛型错误 - 类型字符串必须不可为空
- firebase - Firebase 规则 - 嵌套 ifs
- c# - 检查 Enum 是否等于由 Enum 标志组成的 Enum 值
- java - 将具有多种数据类型的文件放入数组中,然后对一个数组进行排序,同时将记录放在一起
- r - 无法获取 cookie?
- windows - 访问被拒绝执行编译的程序
- shell - 无法通过 Jenkins 作业使用 openssl 生成证书
- ios - iOS:使用 AVAssetExportSession 覆盖(混合)两个视频文件