| Some things may be out of date with respect the current state of Hibernate 6. The following is the content of an email I sent that assumed the changes were going to be made for Hibernate 5. Overview: https://gist.github.com/gbadner/f0e635e8fba7b84af233 POC: https://github.com/hibernate/hibernate-orm/commit/3d0e2378cb998788b3205afb1e15c443c5ba77e8 The POC assumes that we only need a single OperationContext for each type of operation. OperationContextManager has a Map of OperationContext by OperationContextType. Each OperationContext object is lazily created on the first occurence of the corresponding type of operation. Currently, when an operation is initiated (e.g., by Session.merge( entity )), OperationContextManager [2] does the following:
- calls ManageableOperationContext#beforeOperation, which puts the OperationContext "in progress";
- executes the operation, which performs cascades according to mappings;
- calls ManageableOperationContext#afterOperation, which puts the OperationContext in an invalid state that is "not in progress".
When an operation cascades to other entities, the same OperationContext is used. Obviously, OperationContextManager needs to know if an operation is "top-level" (meaning that the operation is on the original entity, and not cascaded). In the POC, if the relevant OperationContext is not in progress at the time that an opeation is initiated, then OperationContextManager assumes that the operation is top-level. If the OperationContext is "in progress", then OperationContextManager assumes that this is a cascaded operation. I am not sure this is always correct. Can anyone think of a case where this could break down? In the POC, the following EventSource methods that contain an argument for the operation cache has been deprecated and is no longer used because the contents of that argument has been moved into an OperationContext: public void merge(String entityName, Object object, Map copiedAlready) public void persist(String entityName, Object object, Map createdAlready) public void persistOnFlush(String entityName, Object object, Map copiedAlready) public void refresh(String entityName, Object object, Map refreshedAlready) public void delete(String entityName, Object child, boolean isCascadeDeleteEnabled, Set transientEntities) Before the POC, it was the above methods that indicated that it was not top-level. If it turns out that having a single OperationContext is not valid, then there needs to be some other way to determine if the operation was top-level. I had originally planned to use PersistenceContext#getCascadeLevel == 0 to indicate an operation was at the top-level, but I found that won't work for some operations. For example, the cascade level for a top-level delete can be > 1 when deleting orphans due to merge or save-or-update operations. Another example is that cascade level is not 0 on top-level save-or-update while flushing. I have some ideas to work around this, but I didn't want to get too far down that path if it wasn't an issue. |