How to properly manage associated JPA entities with OneToOne BiDirectional relation?

雨燕双飞 提交于 2019-12-25 02:46:07

问题


Let's say 2 entities are given: master and dependant.

They are defined in DB usually like dependants.master_id -> masters.id, i.e. the dependant entity holds the reference to the main entity.

In JPA one2one BiDirectional association in this case usually looks like:

class Master {
    @OneToOne(mappedBy="master")
    Dependant dependant
}
class Dependant {
    @OneToOne
    @JoinColumn("master_id")
    Master master
}

And this approach causes the necessity to deal with both sides of relation like:

Master master = new Master();
Dependant dependant = new Dependant();
dependant.setMaster(master);
master.setDependant(dependant);
repository.save(master);

instead of more intuitive and closer to business logic one like:

Master master = new Master();
Dependant dependant = new Dependant();
master.setDependant(dependant);
repository.save(master);

Are there any common workarounds for this? I mean I don't want to mess with supporting the association from the dependant side.


回答1:


One workaround might be using @PrePersist. For both entities you could implement methods like:

Master

@PrePersist
private void prePersist() {
    if(null == getDependant().getMaster()) {
        getDependant().setMaster(this);
    }
}

Dependant

@PrePersist
private void prePersist() {
    if(null == getMaster().getDependant()) {
        getMaster().setDependant(this);
    }
}

Or maybe just omitting the null checks.




回答2:


You have multiple options, but all depend on setting the relationship correctly on the owning side, which in your case is Dependant. The best choice for you depends on your needs and usage pattern. For example, another answer discusses defining a @PrePersist method, which can be pretty clean if the association between Master and Dependent is established when and only when masters are first persisted.

Given that you are using field-level access, you could also consider making Master.setDependant() do the work for you:

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;
    }

    // ...
}

That will ensure that when you assign a Dependant to a Master, the reciprocal relationship is automatically set up on the Dependant side. You will then want to ensure that persistence operations are specified to cascade correctly from Master to Dependant.

Note, however, that this is no silver bullet. It can easily yet surprisingly fail if you assign a detached or removed Dependant to a Master. It will likely also fail if you try to replace a Master's Dependant without explicitly removing the original one, if any. There are other ways to break it, too.

Inasmuch as managing the relationship in all but very simple ways requires care and attention to detail, I'd suggest that you bite the bullet and do it manually, everywhere, if indeed you need anything more than creating the relationship when you persist a new Master and traversing existing relationships.



来源:https://stackoverflow.com/questions/54988105/how-to-properly-manage-associated-jpa-entities-with-onetoone-bidirectional-relat

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!