| During cascading of orphan removals, the assumption made there was that the state supplied by the FlushEvent should match the current state maintained by the persistence context. In this issue, the cascade of the logical one-to-one orphan-removal, the Child entity instance is passed as the child method parameter which was sourced from the FlushEvent at the end of the transaction. Internally, the method inspects the sessions persistence context, fetching the associated Parent entity entry and requesting the value which it maintains for the parent's child property which so happens to be a proxy since the mapping is lazy. After which we perform this logic:
if ( child == null || ( loadedValue != null && child != loadedValue ) ) {
EntityEntry valueEntry = eventSource.getPersistenceContext().getEntry( loadedValue );
if ( valueEntry == null && loadedValue instanceof HibernateProxy ) {
loadedValue = eventSource.getPersistenceContext().unproxyAndReassociate( loadedValue );
valueEntry = eventSource.getPersistenceContext().getEntry( loadedValue );
}
...
The problem is then we aren't checking that the actual child method parameter equals the value returned from the unproxy operation that we updated loadedValue to hold; resulting in a false invocation of the orphan removal. Prior to the
HHH-9663 Closed fix, one-to-one orphan removal flat out didn't work in a number of use cases and that presented its own host of problems, so I don't want to revert that for the sake of this use case (which seems highly unusual imo). That said, one option we could introduce to keep
HHH-9663 Closed and preserve backward behavior for this would be to add one additional check in the cascade operation for logical one-to-one orphan-removal
if ( valueEntry == null && loadedValue instanceof HibernateProxy ) {
loadedValue = eventSource.getPersistenceContext().unproxyAndReassociate( loadedValue );
valueEntry = eventSource.getPersistenceContext().getEntry( loadedValue );
if ( child == loadedValue ) {
return;
}
}
In this, we simply compare the final unproxied value with that of the value found from the flush event's emitted entity object state and if they continue to match in reference equality, we assume no cascade is necessary and do nothing. This seems to resolve this issue and preserves the
HHH-9663 Closed behavior fix too. Gail Badner, thoughts? |