
When I talk with my colleague about my experience with Hibernate merge behavior on lazy associations
with cascade type merge, he suggested me to check if Hibernate allows us to change fetch logic it applies on detached
entities during merge operation. That way, it would be possible to suppress eager initialization of those associations
during merge.
Hibernate executes every operation on Session through its corresponding EventListener implementation. Merge is no
different in that respect. Therefore, I focused first on DefaultMergeEventListener in order to find the exact location
in which load is performed. I reached at the following code block within DefaultMergeEventListener;
String previousFetchProfile = source.getLoadQueryInfluencers().getInternalFetchProfile();
source.getLoadQueryInfluencers().setInternalFetchProfile( "merge" );
//we must clone embedded composite identifiers, or
//we will get back the same instance that we pass in
final Serializable clonedIdentifier = (Serializable) persister.getIdentifierType()
.deepCopy( id, source.getFactory() );
final Object result = source.get( entityName, clonedIdentifier );
source.getLoadQueryInfluencers().setInternalFetchProfile( previousFetchProfile );
The key part in the above code is source.getLoadQueryInfluencers().setInternalFetchProfile("merge");, which implies that
Hibernate employs an internal fetch profile identified with "merge" during load operation, and then it reverts back
to the previous fetch profile after load completes. When the final Object result = source.get(entityName, clonedIdentifier);
line executes, Hibernate fires load event this time, and DefaultLoadEventListener gets triggered, and a specific
EntityPersister instance is used to load the entity specified with its name and identifier. EntityPersister uses
EntityLoader implementation resolved (CascadeEntityLoader, in that case) according to some criteria including
“internal fetch profile” information.
Unfortunately, neither DefaultMergeEventListener provides an easy way to modify “internal fetch profile” mode used, nor
EntityPersister implementation to replace CascadeEntityLoader with another one. Hence, I had to stop my investigation
inside Hibernate source code at this point without any useful result.