|
See it in 4.3.7 as well. I've done some extensive debugging on this so I'll share what I've found.
At first I thought it might be related to
HHH-9106
so I enabled debugging for the EntityCopyObserver. That was a dead end because EntityCopyObserver isn't involved in this scenario. MergeContext.put() won't execute the path that invokes entityCopyObserver.entityCopyDetected(...)
The start of the problem is in DefaultMergeEventListener.entityIsTransient(..) during the first copyValues(...) call. This first call will follow the path that calls TypeHelper.replace(...) where AbstractType.replace() is called which might call the Type's specific .replace().
I think the problem is in how AbstractType.replace(...) is implemented:
public Object replace(
Object original,
Object target,
SessionImplementor session,
Object owner,
Map copyCache,
ForeignKeyDirection foreignKeyDirection)
throws HibernateException {
boolean include;
if ( isAssociationType() ) { AssociationType atype = (AssociationType) this;
include = atype.getForeignKeyDirection()==foreignKeyDirection;
}
else {
include = ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT==foreignKeyDirection;
}
return include ? replace(original, target, session, owner, copyCache) : target;
}
Any CollectionType is also an AssociationType as explained in the JavaDoc:
/**
* Note: return true because this type is castable to <tt>AssociationType</tt>. Not because
* all collections are associations.
*/
@Override
public boolean isAssociationType() {
return true;
}
I believe this invites some semantic confusion. It may be necessary to change AbstractType to handle isCollectionType() separately than the isAssociationType() case.
|