In an unidirectional one-to-many relation, with a join column on many side, Hibernate seems to forget about nulling foreign keys when removing object on 'one' side if entities are instrumented.
In my test-case (please see it attached) there is Garage entity keeping a set of Cars entities. During removal (without bytecode enhancement) of Garage entity, Hibernate issues the following statements:
However when entities are instrumented using 'enableLazyInitialization' mode, the first SQL statement is not generated which leads to constraint violation when the delete statement is executed.
In order to run my test-case with bytecode enhancement (which fails), please issue the following command:
A build run without 'enhancement' profile works correctly.
Please note that this happens only when 'enableLazyInitialization' mode is on; other modes doesn't cause this issue.
A brief description on the mechanics of this issue and the solution for it.
The 'nulling' of foreign keys is called a cascading action, in particular the CollectionRemoveAction was not being called in this case. CollectionRemoveAction are created on AbstractFlushingEventListener where it iterates over a list CollectionEntry in the PersistenceContext. For collections not initialized yet there was no CollectionEntry and therefore their keys were not being 'nulled'.
CollectionEntry are added as part of the load process, and in particular in the type resolution of CollectionType. For lazy fields, type resolution is always skipped on load because the value that results from that process is not needed. Resolution can occur on later if there is a lazy loading. This clearly has to change, so that type resolution is always done for collections.
There is still one difference between resolving a lazy and a eager collection. In the lazy case, the PersistentCollection must not be added to the 'hydratedState' of the entity or else the collection will be loaded when the attribute values are set on the entity object.
Fixed in 5.1 branch as well.