Skip to content

Commit 903271b

Browse files
committed
HHH-19248 - Fix for issue
Signed-off-by: Jan Schatteman <[email protected]>
1 parent 04ccc40 commit 903271b

File tree

7 files changed

+158
-50
lines changed

7 files changed

+158
-50
lines changed

hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,6 @@ public EntityDeleteAction(
6060
this.version = version;
6161
this.isCascadeDeleteEnabled = isCascadeDeleteEnabled;
6262
this.state = state;
63-
64-
final NaturalIdMapping naturalIdMapping = persister.getNaturalIdMapping();
65-
if ( naturalIdMapping != null ) {
66-
naturalIdValues = session.getPersistenceContextInternal().getNaturalIdResolutions()
67-
.removeLocalResolution(
68-
getId(),
69-
naturalIdMapping.extractNaturalIdFromEntityState( state ),
70-
getPersister()
71-
);
72-
}
7363
}
7464

7565
/**
@@ -125,6 +115,16 @@ public void execute() throws HibernateException {
125115

126116
final boolean veto = isInstanceLoaded() && preDelete();
127117

118+
final NaturalIdMapping naturalIdMapping = persister.getNaturalIdMapping();
119+
if ( naturalIdMapping != null ) {
120+
naturalIdValues = session.getPersistenceContextInternal().getNaturalIdResolutions()
121+
.removeLocalResolution(
122+
getId(),
123+
naturalIdMapping.extractNaturalIdFromEntityState( state ),
124+
getPersister()
125+
);
126+
}
127+
128128
final Object ck = lockCacheItem();
129129

130130
if ( !isCascadeDeleteEnabled && !veto ) {

hibernate-core/src/main/java/org/hibernate/internal/NaturalIdMultiLoadAccessStandard.java

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,24 @@
44
*/
55
package org.hibernate.internal;
66

7+
import java.util.Collection;
78
import java.util.List;
8-
import java.util.Set;
99

1010
import org.hibernate.CacheMode;
1111
import org.hibernate.LockOptions;
1212
import org.hibernate.NaturalIdMultiLoadAccess;
1313
import org.hibernate.engine.spi.EffectiveEntityGraph;
14+
import org.hibernate.engine.spi.EntityEntry;
15+
import org.hibernate.engine.spi.EntityKey;
1416
import org.hibernate.engine.spi.LoadQueryInfluencers;
17+
import org.hibernate.engine.spi.PersistenceContext;
18+
import org.hibernate.engine.spi.Status;
1519
import org.hibernate.graph.GraphSemantic;
1620
import org.hibernate.graph.RootGraph;
1721
import org.hibernate.graph.spi.RootGraphImplementor;
18-
import org.hibernate.internal.util.collections.CollectionHelper;
22+
import org.hibernate.loader.LoaderLogging;
1923
import org.hibernate.loader.ast.spi.MultiNaturalIdLoadOptions;
24+
import org.hibernate.metamodel.mapping.NaturalIdMapping;
2025
import org.hibernate.persister.entity.EntityPersister;
2126

2227
/**
@@ -81,6 +86,8 @@ public NaturalIdMultiLoadAccess<T> enableOrderedReturn(boolean enabled) {
8186
@Override
8287
@SuppressWarnings( "unchecked" )
8388
public List<T> multiLoad(Object... ids) {
89+
performAnyNeededCrossReferenceSynchronizations();
90+
8491
final CacheMode sessionCacheMode = session.getCacheMode();
8592
boolean cacheModeChanged = false;
8693

@@ -109,7 +116,6 @@ public List<T> multiLoad(Object... ids) {
109116
}
110117

111118
try {
112-
session.autoFlushIfRequired( (Set) CollectionHelper.setOf( entityDescriptor.getQuerySpaces() ) );
113119
return (List<T>) entityDescriptor.getMultiNaturalIdLoader().multiLoad( ids, this, session );
114120
}
115121
finally {
@@ -132,6 +138,53 @@ public List<T> multiLoad(Object... ids) {
132138

133139
}
134140

141+
protected void performAnyNeededCrossReferenceSynchronizations() {
142+
final NaturalIdMapping naturalIdMapping = entityDescriptor.getNaturalIdMapping();
143+
144+
if ( !naturalIdMapping.isMutable() ) {
145+
// only mutable natural-ids need this processing
146+
return;
147+
}
148+
149+
if ( ! session.isTransactionInProgress() ) {
150+
// not in a transaction so skip synchronization
151+
return;
152+
}
153+
154+
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
155+
final Collection<?> cachedPkResolutions =
156+
persistenceContext.getNaturalIdResolutions()
157+
.getCachedPkResolutions( entityDescriptor );
158+
final boolean loggerDebugEnabled = LoaderLogging.LOADER_LOGGER.isDebugEnabled();
159+
for ( Object pk : cachedPkResolutions ) {
160+
final EntityKey entityKey = session.generateEntityKey( pk, entityDescriptor );
161+
final Object entity = persistenceContext.getEntity( entityKey );
162+
final EntityEntry entry = persistenceContext.getEntry( entity );
163+
164+
if ( entry == null ) {
165+
if ( loggerDebugEnabled ) {
166+
LoaderLogging.LOADER_LOGGER.debugf(
167+
"Cached natural-id/pk resolution linked to null EntityEntry in persistence context : %s#%s",
168+
entityDescriptor.getEntityName(),
169+
pk
170+
);
171+
}
172+
continue;
173+
}
174+
175+
if ( !entry.requiresDirtyCheck( entity ) ) {
176+
continue;
177+
}
178+
179+
// MANAGED is the only status we care about here...
180+
if ( entry.getStatus() != Status.MANAGED ) {
181+
continue;
182+
}
183+
184+
persistenceContext.getNaturalIdResolutions().handleSynchronization( pk, entity, entityDescriptor );
185+
}
186+
}
187+
135188
@Override
136189
public List<T> multiLoad(List<?> ids) {
137190
return multiLoad( ids.toArray( new Object[ 0 ] ) );

hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractMultiNaturalIdLoader.java

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414
import org.hibernate.loader.ast.spi.MultiNaturalIdLoader;
1515
import org.hibernate.metamodel.mapping.EntityMappingType;
1616

17-
import java.util.ArrayList;
1817
import java.util.Collections;
1918
import java.util.List;
2019

20+
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
21+
import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty;
22+
import static org.hibernate.loader.ast.internal.LoaderHelper.upgradeLock;
23+
2124
/**
2225
* @author Jan Schatteman
2326
*/
@@ -57,7 +60,18 @@ private <K> List<E> performUnorderedMultiLoad(K[] naturalIds, MultiNaturalIdLoad
5760
);
5861
}
5962

60-
protected abstract <K> List<E> unorderedMultiLoad(K[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions);
63+
protected <K> List<E> unorderedMultiLoad(K[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions) {
64+
final List<E> results = arrayList( naturalIds.length );
65+
final Object[] unresolvedIds =
66+
checkPersistenceContextForCachedResults( naturalIds, session, lockOptions, results );
67+
if ( !isEmpty( unresolvedIds ) ) {
68+
loadEntitiesWithUnresolvedIds( unresolvedIds, session, lockOptions, results );
69+
}
70+
71+
return results;
72+
}
73+
74+
protected abstract void loadEntitiesWithUnresolvedIds(Object[] unresolvedIds, SharedSessionContractImplementor session, LockOptions lockOptions, List<E> results);
6175

6276
private <K> List<E> performOrderedMultiLoad(K[] naturalIds, MultiNaturalIdLoadOptions options, SharedSessionContractImplementor session) {
6377
if ( MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER.isTraceEnabled() ) {
@@ -75,19 +89,18 @@ protected <K> List<E> orderedMultiLoad( K[] naturalIds, SharedSessionContractImp
7589

7690
unorderedMultiLoad( naturalIds, session, lockOptions );
7791

78-
return handleResults( naturalIds, session, lockOptions );
92+
return sortResults( naturalIds, session, lockOptions );
7993
}
8094

81-
protected <K> List<E> handleResults( K[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions ) {
82-
List<E> results = new ArrayList<>(naturalIds.length);
95+
protected <K> List<E> sortResults( K[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions ) {
96+
List<E> results = arrayList(naturalIds.length);
8397
for ( int i = 0; i < naturalIds.length; i++ ) {
8498
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
8599

86100
Object id = persistenceContext.getNaturalIdResolutions().findCachedIdByNaturalId( naturalIds[i], getEntityDescriptor() );
87101

88102
// Id can be null if a non-existent natural id is requested
89-
Object entity = id == null ? null
90-
: persistenceContext.getEntity( new EntityKey( id, getEntityDescriptor().getEntityPersister() ) );
103+
Object entity = (id == null) ? null : persistenceContext.getEntity( new EntityKey( id, getEntityDescriptor().getEntityPersister() ) );
91104
if ( entity != null && !options.isReturnOfDeletedEntitiesEnabled() ) {
92105
// make sure it is not DELETED
93106
final EntityEntry entry = persistenceContext.getEntry( entity );
@@ -105,6 +118,38 @@ protected <K> List<E> handleResults( K[] naturalIds, SharedSessionContractImplem
105118
return results;
106119
}
107120

121+
private <K> Object[] checkPersistenceContextForCachedResults( K[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions, List<E> results ) {
122+
List<K> unresolvedIds = arrayList(naturalIds.length);
123+
124+
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
125+
for ( int i = 0; i < naturalIds.length; i++ ) {
126+
127+
final Object normalizedNaturalId = getEntityDescriptor().getNaturalIdMapping().normalizeInput( naturalIds[i] );
128+
Object id = persistenceContext.getNaturalIdResolutions().findCachedIdByNaturalId( normalizedNaturalId, getEntityDescriptor() );
129+
130+
// Id can be null if a non-existent natural id is requested, or a mutable natural id was changed and then deleted
131+
Object entity = ( id == null ) ? null : persistenceContext.getEntity( new EntityKey( id, getEntityDescriptor().getEntityPersister() ) );
132+
133+
if ( entity != null ) {
134+
// Entity is already in the persistence context
135+
final EntityEntry entry = persistenceContext.getEntry( entity );
136+
// either a managed entry, or a deleted one with returnDeleted enabled
137+
if ( !entry.getStatus().isDeletedOrGone() || options.isReturnOfDeletedEntitiesEnabled() ) {
138+
results.add( (E) persistenceContext.proxyFor(entity) );
139+
upgradeLock( entity, entry, lockOptions, session.getSession().asEventSource() );
140+
}
141+
}
142+
else {
143+
// entity either doesn't exist or hasn't been loaded in the PC yet, in both cases we add the natural id
144+
// to the ids that still need to be recovered, in case the id corresponds to a non-existent
145+
// instance nothing will be in the results for it, which is ok in unordered multiload
146+
unresolvedIds.add(naturalIds[i]);
147+
}
148+
}
149+
150+
return unresolvedIds.toArray( new Object[0] );
151+
}
152+
108153
@Override
109154
public EntityMappingType getLoadable() {
110155
return getEntityDescriptor();

hibernate-core/src/main/java/org/hibernate/loader/ast/internal/MultiNaturalIdLoaderArrayParam.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ protected BasicAttributeMapping getNaturalIdAttribute() {
4444
}
4545

4646
@Override
47-
public <K> List<E> unorderedMultiLoad( K[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions ) {
47+
public void loadEntitiesWithUnresolvedIds(Object[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions, List<E> results) {
4848

4949
final SessionFactoryImplementor sessionFactory = session.getFactory();
5050

@@ -76,18 +76,20 @@ public LockOptions getLockOptions() {
7676
}
7777
} );
7878

79-
return LoaderHelper.loadByArrayParameter(
80-
naturalIds,
81-
sqlAst,
82-
jdbcSelectOperation,
83-
jdbcParameter,
84-
arrayJdbcMapping,
85-
null,
86-
null,
87-
null,
88-
lockOptions,
89-
session.isDefaultReadOnly(),
90-
session
79+
results.addAll(
80+
LoaderHelper.loadByArrayParameter(
81+
naturalIds,
82+
sqlAst,
83+
jdbcSelectOperation,
84+
jdbcParameter,
85+
arrayJdbcMapping,
86+
null,
87+
null,
88+
null,
89+
lockOptions,
90+
session.isDefaultReadOnly(),
91+
session
92+
)
9193
);
9294
}
9395

hibernate-core/src/main/java/org/hibernate/loader/ast/internal/MultiNaturalIdLoaderInPredicate.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public MultiNaturalIdLoaderInPredicate(EntityMappingType entityDescriptor) {
2222
}
2323

2424
@Override
25-
public <K> List<E> unorderedMultiLoad(K[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions) {
25+
public void loadEntitiesWithUnresolvedIds(Object[] naturalIds, SharedSessionContractImplementor session, LockOptions lockOptions, List<E> results) {
2626

2727
final SessionFactoryImplementor sessionFactory = session.getFactory();
2828

@@ -55,7 +55,7 @@ public <K> List<E> unorderedMultiLoad(K[] naturalIds, SharedSessionContractImple
5555
sessionFactory
5656
);
5757

58-
return batcher.multiLoad( naturalIds, session );
58+
results.addAll( batcher.multiLoad( naturalIds, session ) );
5959
}
6060

6161
}

0 commit comments

Comments
 (0)