Reading Hibernate code found that when the merge is done, there's a piece of code that search for the id before creating a new one.
Code:
Serializable id = event.getRequestedId();
if ( id == null ) {
id = persister.getIdentifier( entity, source );
}
else {
// check that entity id = requestedId
Serializable entityId = persister.getIdentifier( entity, source );
if ( !persister.getIdentifierType().isEqual( id, entityId, source.getFactory() ) ) {
throw new HibernateException( "merge requested with id not matching id of passed entity" );
}
}
Unfortunately there's no way to set that requested id. The only function I found can do it is SaveOrUpdate:
Code:
/**
* Handle the given update event.
*
* @param event The update event to be handled.
*/
public void onSaveOrUpdate(SaveOrUpdateEvent event) {
final SessionImplementor source = event.getSession();
final Object object = event.getObject();
final Serializable requestedId = event.getRequestedId();
[b] if ( requestedId != null ) {
//assign the requested id to the proxy, *beforeQuery*
//reassociating the proxy
if ( object instanceof HibernateProxy ) {
( (HibernateProxy) object ).getHibernateLazyInitializer().setIdentifier( requestedId );
}
}[/b]
// For an uninitialized proxy, noop, don't even need to return an id, since it is never a save()
if ( reassociateIfUninitializedProxy( object, source ) ) {
LOG.trace( "Reassociated uninitialized proxy" );
}
else {
//initialize properties of the event:
final Object entity = source.getPersistenceContext().unproxyAndReassociate( object );
event.setEntity( entity );
event.setEntry( source.getPersistenceContext().getEntry( entity ) );
//return the id in the event object
event.setResultId( performSaveOrUpdate( event ) );
}
}
But again it seems that the version of Hibernate + JPA we use doesn't support that method in the entityManager. So there's no way to do it.
Should we upgrade?