|
|
|
|
|
|
Exploring the possibilities on optimistic locking while tracking changes on a {{OneToMany}}-relation we tried to setup the relation in a way where the parent is "owner". This does not seem to be very common nor well documented, so we may be led astray here - it however seems to be supported to some extend:
The easy case is that the relation is unidirectional from parent to child
{code} @OneToMany(cascade=CascadeType.ALL, orphanRemoval= true) @JoinColumn(name = "parent_id") public Set<UnidirectionalChild> getChildren() {code}
with no corresponding relation on the child side the parent is clearly the owner. The parent version is perfectly updated in this case when children are added or removed.
A more complex case is when we add the relation on the child side making it bidirectional - the "optional" case first:
{code} // optional = true is default, just repeated here to clarify @ManyToOne(optional = true) public BidirectionalOptionalParent getParent() {code}
Please note, that there is (still) no {{mappedBy}} at the {{OneToMany}} annotation. If there would be, the child would be the owner of the relation and we would lose the optimistic locking on collection changes.
This bidirectional-optional scenario works as expected as well. However while removing a child Hibernate issues an extra update on that child to set the parent to {{null}} right before deleting it:
{code} update BidirectionalOptionalChild set parent_id=null where parent_id=? and id=? delete from BidirectionalOptionalChild where id=? and version=? {code}
If you now make the child-to-parent-relation mandatory
{code} @ManyToOne(optional = false) public BidirectionalMandatoryParent getParent() {code}
removing a child is no longer possible due to the extra update mentioned above which leads to a "NULL not allowed" exception.
To complete the cycle we finally found a way to handle the mandatory case as well using (abusing?) the {{@OptimisticLock}} annotation:
{code} @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "parent") @OptimisticLock(excluded = false) public Set<BidirectionalOptimisticLockChild> getChildren() {code}
on the parent side and
{code} @ManyToOne(optional = false) @JoinColumn(name = "parent_id") public BidirectionalOptimisticLockParent getParent() {code}
at the child side. This bidirectional-mandatory-optimistic-lock scenario works as expected now.
You may find all cases in a test project on Github https://github.com/abenneke/sandbox/tree/master/hibernate-versions as {{*ParentOwnedTest}} s .
Thank you!
|
|
|
|
|
|