HHH-14176 Handle embedded composite ids in envers specially to avoid lazy loading

This commit is contained in:
Christian Beikov 2023-06-27 12:41:41 +02:00
parent f175581180
commit 940259dc4c
2 changed files with 20 additions and 18 deletions

View File

@ -14,6 +14,8 @@ import java.util.Map;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.envers.internal.entities.PropertyData; import org.hibernate.envers.internal.entities.PropertyData;
import org.hibernate.mapping.Component; import org.hibernate.mapping.Component;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
/** /**
@ -25,12 +27,16 @@ import org.hibernate.service.ServiceRegistry;
*/ */
public class MultipleIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder { public class MultipleIdMapper extends AbstractCompositeIdMapper implements SimpleIdMapperBuilder {
private final boolean embedded;
public MultipleIdMapper(Component component) { public MultipleIdMapper(Component component) {
super( component.getComponentClass(), component.getServiceRegistry() ); super( component.getComponentClass(), component.getServiceRegistry() );
this.embedded = component.isEmbedded();
} }
private MultipleIdMapper(Class<?> compositeIdClass, ServiceRegistry serviceRegistry) { private MultipleIdMapper(boolean embedded, Class<?> compositeIdClass, ServiceRegistry serviceRegistry) {
super( compositeIdClass, serviceRegistry ); super( compositeIdClass, serviceRegistry );
this.embedded = embedded;
} }
@Override @Override
@ -41,6 +47,12 @@ public class MultipleIdMapper extends AbstractCompositeIdMapper implements Simpl
@Override @Override
public void mapToMapFromId(Session session, Map<String, Object> data, Object obj) { public void mapToMapFromId(Session session, Map<String, Object> data, Object obj) {
if ( compositeIdClass.isInstance( obj ) ) { if ( compositeIdClass.isInstance( obj ) ) {
if ( embedded ) {
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( obj );
if ( lazyInitializer != null ) {
obj = lazyInitializer.getInternalIdentifier();
}
}
for ( Map.Entry<PropertyData, AbstractIdMapper> entry : ids.entrySet() ) { for ( Map.Entry<PropertyData, AbstractIdMapper> entry : ids.entrySet() ) {
final PropertyData propertyData = entry.getKey(); final PropertyData propertyData = entry.getKey();
final AbstractIdMapper idMapper = entry.getValue(); final AbstractIdMapper idMapper = entry.getValue();
@ -67,6 +79,12 @@ public class MultipleIdMapper extends AbstractCompositeIdMapper implements Simpl
@Override @Override
public void mapToMapFromEntity(Map<String, Object> data, Object obj) { public void mapToMapFromEntity(Map<String, Object> data, Object obj) {
if ( embedded ) {
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( obj );
if ( lazyInitializer != null ) {
obj = lazyInitializer.getInternalIdentifier();
}
}
for ( IdMapper idMapper : ids.values() ) { for ( IdMapper idMapper : ids.values() ) {
idMapper.mapToMapFromEntity( data, obj ); idMapper.mapToMapFromEntity( data, obj );
} }
@ -84,7 +102,7 @@ public class MultipleIdMapper extends AbstractCompositeIdMapper implements Simpl
@Override @Override
public IdMapper prefixMappedProperties(String prefix) { public IdMapper prefixMappedProperties(String prefix) {
final MultipleIdMapper ret = new MultipleIdMapper( compositeIdClass, getServiceRegistry() ); final MultipleIdMapper ret = new MultipleIdMapper( embedded, compositeIdClass, getServiceRegistry() );
for ( PropertyData propertyData : ids.keySet() ) { for ( PropertyData propertyData : ids.keySet() ) {
final String propertyName = propertyData.getName(); final String propertyName = propertyData.getName();

View File

@ -19,11 +19,8 @@ import org.hibernate.envers.internal.reader.AuditReaderImplementor;
import org.hibernate.envers.internal.tools.EntityTools; import org.hibernate.envers.internal.tools.EntityTools;
import org.hibernate.envers.internal.tools.query.Parameters; import org.hibernate.envers.internal.tools.query.Parameters;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import jakarta.persistence.PersistenceException;
/** /**
* @author Adam Warski (adam at warski dot org) * @author Adam Warski (adam at warski dot org)
* @author HernпїЅn Chanfreau * @author HernпїЅn Chanfreau
@ -64,19 +61,6 @@ public class ToOneIdMapper extends AbstractToOneMapper {
// to this field. It is the responsibility of the collection to properly update it if it really changed. // to this field. It is the responsibility of the collection to properly update it if it really changed.
Object entity = nonInsertableFake ? oldObj : newObj; Object entity = nonInsertableFake ? oldObj : newObj;
// fix HHH-13760 - try to aggressively un-proxy this entity to help get the correct type of data later
// in mapToMapFromEntity. But it might fail while getImplementation() if object is deleted or other reasons.
// We catch the exception and fallback to call mapToMapFromEntity directly with the HibernateProxy entity
if ( lazyMapping && entity instanceof HibernateProxy ) {
try {
entity = ((HibernateProxy) entity).getHibernateLazyInitializer().getImplementation();
}
catch ( PersistenceException e ) {
log.debug( "Ignore PersistenceException while initializing the entity, " +
"and fallback to call mapToMapFromEntity directly" );
}
}
delegate.mapToMapFromEntity( newData, entity ); delegate.mapToMapFromEntity( newData, entity );
for ( Map.Entry<String, Object> entry : newData.entrySet() ) { for ( Map.Entry<String, Object> entry : newData.entrySet() ) {