如何正确管理具有 OneToOne BiDirectional 关系的关联 JPA 实体?
How to properly manage associated JPA entities with OneToOne BiDirectional relation?
假设给定了 2 个实体:master 和 dependant。
它们在数据库中的定义通常类似于dependants.master_id -> masters.id
,即依赖实体持有对主实体的引用。
在 JPA 中,one2one 双向关联在这种情况下通常如下所示:
class Master {
@OneToOne(mappedBy="master")
Dependant dependant
}
class Dependant {
@OneToOne
@JoinColumn("master_id")
Master master
}
这种方法导致需要处理关系的两边,例如:
Master master = new Master();
Dependant dependant = new Dependant();
dependant.setMaster(master);
master.setDependant(dependant);
repository.save(master);
与其更直观、更接近业务逻辑,不如这样:
Master master = new Master();
Dependant dependant = new Dependant();
master.setDependant(dependant);
repository.save(master);
是否有任何常见的解决方法?我的意思是我不想搞乱从依赖方支持协会。
一种解决方法可能是使用 @PrePersist
。对于这两个实体,您可以实现如下方法:
硕士
@PrePersist
private void prePersist() {
if(null == getDependant().getMaster()) {
getDependant().setMaster(this);
}
}
依赖
@PrePersist
private void prePersist() {
if(null == getMaster().getDependant()) {
getMaster().setDependant(this);
}
}
或者可能只是省略空值检查。
您有多种选择,但都取决于在拥有方正确设置关系,在您的情况下是 Dependant
。最适合您的选择取决于您的需求和使用模式。例如,另一个答案讨论了定义 @PrePersist
方法,如果 Master
和 Dependent
之间的关联是在且仅当 masters 首次持久化时建立的,则该方法可能非常干净。
鉴于您使用的是字段级访问权限,您还可以考虑让 Master.setDependant()
为您完成这项工作:
class Master {
// ...
@OneToOne(mappedBy="master")
private Dependant dependant;
public void setDependant(Dependant dep) {
if (dep != null) {
dep.setMaster(this);
} else if (dependant != null) {
// leaves a dangling dependant ...
dependant.setMaster(null);
}
dependant = dep;
}
// ...
}
这将确保当您将 Dependant
分配给 Master
时,将自动在 Dependant
侧建立互惠关系。然后,您需要确保持久性操作被指定为从 Master
正确级联到 Dependant
。
但是请注意,这不是灵丹妙药。如果您将分离或删除的 Dependant
分配给 Master
,它很容易但令人惊讶地失败。如果您尝试替换 Master
的 Dependant
而没有明确删除原始的(如果有的话),它也可能会失败。还有其他方法可以破解它。
由于以非常简单的方式管理关系需要细心和注意细节,我建议您硬着头皮手动操作,无论何时何地,如果您确实需要创建关系之外的任何东西你坚持一个新的 Master
并遍历现有的关系。
假设给定了 2 个实体:master 和 dependant。
它们在数据库中的定义通常类似于dependants.master_id -> masters.id
,即依赖实体持有对主实体的引用。
在 JPA 中,one2one 双向关联在这种情况下通常如下所示:
class Master {
@OneToOne(mappedBy="master")
Dependant dependant
}
class Dependant {
@OneToOne
@JoinColumn("master_id")
Master master
}
这种方法导致需要处理关系的两边,例如:
Master master = new Master();
Dependant dependant = new Dependant();
dependant.setMaster(master);
master.setDependant(dependant);
repository.save(master);
与其更直观、更接近业务逻辑,不如这样:
Master master = new Master();
Dependant dependant = new Dependant();
master.setDependant(dependant);
repository.save(master);
是否有任何常见的解决方法?我的意思是我不想搞乱从依赖方支持协会。
一种解决方法可能是使用 @PrePersist
。对于这两个实体,您可以实现如下方法:
硕士
@PrePersist
private void prePersist() {
if(null == getDependant().getMaster()) {
getDependant().setMaster(this);
}
}
依赖
@PrePersist
private void prePersist() {
if(null == getMaster().getDependant()) {
getMaster().setDependant(this);
}
}
或者可能只是省略空值检查。
您有多种选择,但都取决于在拥有方正确设置关系,在您的情况下是 Dependant
。最适合您的选择取决于您的需求和使用模式。例如,另一个答案讨论了定义 @PrePersist
方法,如果 Master
和 Dependent
之间的关联是在且仅当 masters 首次持久化时建立的,则该方法可能非常干净。
鉴于您使用的是字段级访问权限,您还可以考虑让 Master.setDependant()
为您完成这项工作:
class Master {
// ...
@OneToOne(mappedBy="master")
private Dependant dependant;
public void setDependant(Dependant dep) {
if (dep != null) {
dep.setMaster(this);
} else if (dependant != null) {
// leaves a dangling dependant ...
dependant.setMaster(null);
}
dependant = dep;
}
// ...
}
这将确保当您将 Dependant
分配给 Master
时,将自动在 Dependant
侧建立互惠关系。然后,您需要确保持久性操作被指定为从 Master
正确级联到 Dependant
。
但是请注意,这不是灵丹妙药。如果您将分离或删除的 Dependant
分配给 Master
,它很容易但令人惊讶地失败。如果您尝试替换 Master
的 Dependant
而没有明确删除原始的(如果有的话),它也可能会失败。还有其他方法可以破解它。
由于以非常简单的方式管理关系需要细心和注意细节,我建议您硬着头皮手动操作,无论何时何地,如果您确实需要创建关系之外的任何东西你坚持一个新的 Master
并遍历现有的关系。