diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java index 4619c65a22..e9a91fd757 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java @@ -92,7 +92,7 @@ public final class EntityInsertAction extends AbstractEntityInsertAction { throw new AssertionFailure( "possible nonthreadsafe access to session" ); } - entry.postInsert(); + entry.postInsert( getState() ); if ( persister.hasInsertGeneratedProperties() ) { persister.processInsertGeneratedProperties( id, instance, getState(), session ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java index c6ae439f14..b871dd6c87 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java @@ -1705,54 +1705,53 @@ public class StatefulPersistenceContext implements PersistenceContext { // NATURAL ID RESOLUTION HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override - public void loadedStateInsertedNotification(EntityEntry entityEntry) { + public void loadedStateInsertedNotification(EntityEntry entityEntry, Object[] state) { final EntityPersister persister = entityEntry.getPersister(); if ( !persister.hasNaturalIdentifier() ) { // nothing to do return; } - final Object[] naturalIdValues = getNaturalIdValues( entityEntry, persister ); + final Object[] naturalIdValues = getNaturalIdValues( state, persister ); // cache cacheNaturalIdResolution( persister, entityEntry.getId(), naturalIdValues, CachedNaturalIdValueSource.INSERT ); } @Override - public void loadedStateUpdatedNotification(EntityEntry entityEntry) { + public void loadedStateUpdatedNotification(EntityEntry entityEntry, Object[] state) { final EntityPersister persister = entityEntry.getPersister(); if ( !persister.hasNaturalIdentifier() ) { // nothing to do return; } - final Object[] naturalIdValues = getNaturalIdValues( entityEntry, persister ); + final Object[] naturalIdValues = getNaturalIdValues( state, persister ); // re-cache cacheNaturalIdResolution( persister, entityEntry.getId(), naturalIdValues, CachedNaturalIdValueSource.UPDATE ); } @Override - public void loadedStateDeletedNotification(EntityEntry entityEntry) { + public void loadedStateDeletedNotification(EntityEntry entityEntry, Object[] deletedState) { final EntityPersister persister = entityEntry.getPersister(); if ( !persister.hasNaturalIdentifier() ) { // nothing to do return; } - final Object[] naturalIdValues = getNaturalIdValues( entityEntry, persister ); + final Object[] naturalIdValues = getNaturalIdValues( deletedState, persister ); // evict from cache evictNaturalIdResolution( persister, entityEntry.getId(), naturalIdValues ); } - private Object[] getNaturalIdValues(EntityEntry entityEntry, EntityPersister persister) { + private Object[] getNaturalIdValues(Object[] state, EntityPersister persister) { final int[] naturalIdPropertyIndexes = persister.getNaturalIdentifierProperties(); final Object[] naturalIdValues = new Object[naturalIdPropertyIndexes.length]; - final Object[] loadedState = entityEntry.getLoadedState(); for ( int i = 0; i < naturalIdPropertyIndexes.length; i++ ) { - naturalIdValues[i] = loadedState[naturalIdPropertyIndexes[i]]; + naturalIdValues[i] = state[naturalIdPropertyIndexes[i]]; } return naturalIdValues; @@ -1990,27 +1989,38 @@ public class StatefulPersistenceContext implements PersistenceContext { } } - @Override - public void evictNaturalIdResolution(EntityPersister persister, final Serializable pk, Object[] naturalIdValues) { + private void evictNaturalIdResolution(EntityPersister persister, final Serializable pk, Object[] deletedNaturalIdValues) { if ( !persister.hasNaturalIdentifier() ) { - throw new IllegalArgumentException( "Entity did not define a natural-id" ); + throw new IllegalArgumentException( "Entity did not define a natrual-id" ); } - if ( persister.getNaturalIdentifierProperties().length != naturalIdValues.length ) { + if ( persister.getNaturalIdentifierProperties().length != deletedNaturalIdValues.length ) { throw new IllegalArgumentException( "Mismatch between expected number of natural-id values and found." ); } NaturalIdResolutionCache entityNaturalIdResolutionCache = naturalIdResolutionCacheMap.get( persister ); + Object[] sessionCachedNaturalIdValues = null; if ( entityNaturalIdResolutionCache != null ) { - final LocalNaturalIdCacheKey localNaturalIdCacheKey = new LocalNaturalIdCacheKey( persister, - naturalIdValues ); - entityNaturalIdResolutionCache.pkToNaturalIdMap.remove( pk ); - entityNaturalIdResolutionCache.naturalIdToPkMap.remove( localNaturalIdCacheKey ); + final LocalNaturalIdCacheKey localNaturalIdCacheKey = entityNaturalIdResolutionCache.pkToNaturalIdMap + .remove( pk ); + if ( localNaturalIdCacheKey != null ) { + entityNaturalIdResolutionCache.naturalIdToPkMap.remove( localNaturalIdCacheKey ); + sessionCachedNaturalIdValues = localNaturalIdCacheKey.getValues(); + } } if ( persister.hasNaturalIdCache() ) { - final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy = persister.getNaturalIdCacheAccessStrategy(); - final NaturalIdCacheKey naturalIdCacheKey = new NaturalIdCacheKey( naturalIdValues, persister, session ); + final NaturalIdRegionAccessStrategy naturalIdCacheAccessStrategy = persister + .getNaturalIdCacheAccessStrategy(); + final NaturalIdCacheKey naturalIdCacheKey = new NaturalIdCacheKey( deletedNaturalIdValues, persister, + session ); naturalIdCacheAccessStrategy.evict( naturalIdCacheKey ); + + if ( sessionCachedNaturalIdValues != null + && !Arrays.equals( sessionCachedNaturalIdValues, deletedNaturalIdValues ) ) { + final NaturalIdCacheKey sessionNaturalIdCacheKey = new NaturalIdCacheKey( sessionCachedNaturalIdValues, + persister, session ); + naturalIdCacheAccessStrategy.evict( sessionNaturalIdCacheKey ); + } } } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntry.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntry.java index a769beca84..7fc7d89625 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntry.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/EntityEntry.java @@ -241,7 +241,7 @@ public final class EntityEntry implements Serializable { .getCustomEntityDirtinessStrategy() .resetDirty( entity, getPersister(), (Session) persistenceContext.getSession() ); - notifyLoadedStateUpdated(); + notifyLoadedStateUpdated( updatedState ); } /** @@ -253,17 +253,17 @@ public final class EntityEntry implements Serializable { status = Status.GONE; existsInDatabase = false; - notifyLoadedStateDeleted(); + notifyLoadedStateDeleted( deletedState ); } /** * After actually inserting a row, record the fact that the instance exists on the * database (needed for identity-column key generation) */ - public void postInsert() { + public void postInsert(Object[] insertedState) { existsInDatabase = true; - notifyLoadedStateInserted(); + notifyLoadedStateInserted( insertedState ); } public boolean isNullifiable(boolean earlyInsert, SessionImplementor session) { @@ -360,7 +360,7 @@ public final class EntityEntry implements Serializable { } setStatus( Status.MANAGED ); loadedState = getPersister().getPropertyValues( entity ); - notifyLoadedStateUpdated(); + notifyLoadedStateUpdated( loadedState ); } } @@ -374,28 +374,28 @@ public final class EntityEntry implements Serializable { return loadedWithLazyPropertiesUnfetched; } - private void notifyLoadedStateUpdated() { + private void notifyLoadedStateUpdated(Object[] state) { if ( persistenceContext == null ) { throw new HibernateException( "PersistenceContext was null on attempt to update loaded state" ); } - persistenceContext.loadedStateUpdatedNotification( this ); + persistenceContext.loadedStateUpdatedNotification( this, state ); } - private void notifyLoadedStateInserted() { + private void notifyLoadedStateInserted(Object[] state) { if ( persistenceContext == null ) { throw new HibernateException( "PersistenceContext was null on attempt to insert loaded state" ); } - persistenceContext.loadedStateInsertedNotification( this ); + persistenceContext.loadedStateInsertedNotification( this, state ); } - private void notifyLoadedStateDeleted() { + private void notifyLoadedStateDeleted(Object[] deletedState) { if ( persistenceContext == null ) { throw new HibernateException( "PersistenceContext was null on attempt to delete loaded state" ); } - persistenceContext.loadedStateDeletedNotification( this ); + persistenceContext.loadedStateDeletedNotification( this, deletedState ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java index 72e311e6fd..5f6697e904 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java @@ -683,11 +683,11 @@ public interface PersistenceContext { */ public boolean wasInsertedDuringTransaction(EntityPersister persister, Serializable id); - public void loadedStateUpdatedNotification(EntityEntry entityEntry); + public void loadedStateUpdatedNotification(EntityEntry entityEntry, Object[] state); - public void loadedStateInsertedNotification(EntityEntry entityEntry); + public void loadedStateInsertedNotification(EntityEntry entityEntry, Object[] state); - public void loadedStateDeletedNotification(EntityEntry entityEntry); + public void loadedStateDeletedNotification(EntityEntry entityEntry, Object[] deletedState); public Object[] findCachedNaturalId(EntityPersister persister, Serializable pk); @@ -704,5 +704,4 @@ public interface PersistenceContext { public void cacheNaturalIdResolution(EntityPersister persister, Serializable pk, Object[] naturalId, CachedNaturalIdValueSource valueSource); - public void evictNaturalIdResolution(EntityPersister persister, final Serializable pk, Object[] naturalIdValues ); }