How to properly manage associated JPA entities wit

2019-08-18 19:16发布

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.

2条回答
我欲成王,谁敢阻挡
2楼-- · 2019-08-18 19:51

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.

查看更多
forever°为你锁心
3楼-- · 2019-08-18 20:01

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.

查看更多
登录 后发表回答