diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementAsProxyLazinessInterceptor.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementAsProxyLazinessInterceptor.java index fbe9ad5740..0e88ce0523 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementAsProxyLazinessInterceptor.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementAsProxyLazinessInterceptor.java @@ -35,6 +35,7 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter private final boolean inLineDirtyChecking; private Set writtenFieldNames; + private Set collectionAttributeNames; private Status status; @@ -57,11 +58,22 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter this.entityKey = entityKey; final EntityPersister entityPersister = session.getFactory().getMetamodel().entityPersister( entityName ); + if ( entityPersister.hasCollections() ) { + Type[] propertyTypes = entityPersister.getPropertyTypes(); + collectionAttributeNames = new HashSet<>(); + for ( int i = 0; i < propertyTypes.length; i++ ) { + Type propertyType = propertyTypes[i]; + if ( propertyType.isCollectionType() ) { + collectionAttributeNames.add( entityPersister.getPropertyNames()[i] ); + } + } + } + this.inLineDirtyChecking = entityPersister.getEntityMode() == EntityMode.POJO && SelfDirtinessTracker.class.isAssignableFrom( entityPersister.getMappedClass() ); // if self-dirty tracking is enabled but DynamicUpdate is not enabled then we need to initialise the entity // because the pre-computed update statement contains even not dirty properties and so we need all the values - initializeBeforeWrite = !inLineDirtyChecking || !entityPersister.getEntityMetamodel().isDynamicUpdate(); + initializeBeforeWrite = !( inLineDirtyChecking && entityPersister.getEntityMetamodel().isDynamicUpdate() ); status = Status.UNINITIALIZED; } @@ -245,7 +257,8 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter return newValue; } - if ( initializeBeforeWrite ) { + if ( initializeBeforeWrite + || ( collectionAttributeNames != null && collectionAttributeNames.contains( attributeName ) ) ) { // we need to force-initialize the proxy - the fetch group to which the `attributeName` belongs try { forceInitialize( target, attributeName ); @@ -267,6 +280,8 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter writtenFieldNames = new HashSet<>(); } writtenFieldNames.add( attributeName ); + + ( (SelfDirtinessTracker) target ).$$_hibernate_trackChange( attributeName ); } return newValue; @@ -323,6 +338,10 @@ public class EnhancementAsProxyLazinessInterceptor extends AbstractLazyLoadInter status = Status.INITIALIZED; } + public boolean hasWrittenFieldNames() { + return writtenFieldNames != null && writtenFieldNames.size() != 0; + } + private enum Status { UNINITIALIZED, INITIALIZING, diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractEntityEntry.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractEntityEntry.java index 11a201baef..c203ce2506 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractEntityEntry.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractEntityEntry.java @@ -9,7 +9,6 @@ package org.hibernate.engine.internal; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; -import java.util.function.Supplier; import org.hibernate.AssertionFailure; import org.hibernate.CustomEntityDirtinessStrategy; @@ -353,8 +352,12 @@ public abstract class AbstractEntityEntry implements Serializable, EntityEntry { final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor(); if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) { EnhancementAsProxyLazinessInterceptor enhancementAsProxyLazinessInterceptor = (EnhancementAsProxyLazinessInterceptor) interceptor; + if ( enhancementAsProxyLazinessInterceptor.hasWrittenFieldNames() ) { + return false; + } // When a proxy has dirty attributes, we have to treat it like a normal entity to flush changes - uninitializedProxy = !enhancementAsProxyLazinessInterceptor.isInitialized() && !( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes(); + return !enhancementAsProxyLazinessInterceptor.isInitialized() + || !persister.hasCollections() && !( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes(); } } else if ( entity instanceof HibernateProxy ) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadAndUpateEntitiesWithCollectionsTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadAndUpdateEntitiesWithCollectionsTest.java similarity index 100% rename from hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadAndUpateEntitiesWithCollectionsTest.java rename to hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadAndUpdateEntitiesWithCollectionsTest.java