I have the following entity structure.
@Entity
class ParentA {
@OneToMany(mappedBy = "parentA", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Child> children = new HashSet<>();
public void addChild(Child c) { children.add(c); c.setParentA(this); }
public void removeChild(Child c) { children.remove(c); c.setParentA(null); }
}
@Entity
class ParentB {
@OneToMany(mappedBy = "parentB")
private Set<Child> children = new HashSet<>();
public void addChild(Child c) { children.add(c); c.setParentB(this); }
public void removeChild(Child c) { children.remove(c); c.setParentB(null); }
}
@Entity
class Child {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_a_id", nullable = true)
private ParentA parentA;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_b_id", nullable = true)
private ParentB parentB;
// Some other properties
}
It feels cumbersome to keep all the associations in sync in many cases. For example when using ParentAService
to delete a child, the service needs to sync the ParentB entity. But it should not be the responsibility of ParentAService
to modify ParentB
i.e.
class ParentAService {
@Transactional
public void deleteChild(ParentA parentA, Child child) {
// transaction details
child.getParentB().removeChild(child)
parentA.removeChild(child);
}
}
Is there a correct way of dealing with these kinds of associations or is this a code smell?
Add a method on the Child
class to cleanup the dependencies it has, call that from your service. You could even annotate that method with @PreRemove
to have it being called before the actual delete to do the cleanup.
@Entity
class Child {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_a_id", nullable = true)
private ParentA parentA;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_b_id", nullable = true)
private ParentB parentB;
// Some other properties
@PreRemove
public void cleanup() {
parentA.removeChild(this)
parentB.removeChild(this)
}
}