HHH-16117 Querying entity with collection in Embeddable causes 'A collection with cascade=all-delete-orphan was no longer referenced by the owning entity instance'

This commit is contained in:
Andrea Boriero 2023-01-31 11:19:02 +01:00 committed by Christian Beikov
parent 7b6d158245
commit 974afe26f0
5 changed files with 112 additions and 13 deletions

View File

@ -18,10 +18,13 @@ import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.Status; import org.hibernate.engine.spi.Status;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.NaturalIdMapping; import org.hibernate.metamodel.mapping.NaturalIdMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.AbstractEntityPersister; import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.AttributeMappingsList;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import static org.hibernate.engine.internal.Versioning.getVersion; import static org.hibernate.engine.internal.Versioning.getVersion;
@ -148,9 +151,56 @@ public abstract class AbstractEntityInsertAction extends EntityAction {
protected void addCollectionsByKeyToPersistenceContext(PersistenceContext persistenceContext, Object[] objects) { protected void addCollectionsByKeyToPersistenceContext(PersistenceContext persistenceContext, Object[] objects) {
for ( int i = 0; i < objects.length; i++ ) { for ( int i = 0; i < objects.length; i++ ) {
if ( objects[i] instanceof PersistentCollection<?> ) { final AttributeMapping attributeMapping = getPersister().getAttributeMapping( i );
final PersistentCollection<?> persistentCollection = (PersistentCollection<?>) objects[i]; if ( attributeMapping.isEmbeddedAttributeMapping() ) {
final CollectionPersister collectionPersister = ( (PluralAttributeMapping) getPersister().getAttributeMapping( i ) ).getCollectionDescriptor(); visitEmbeddedAttributeMapping(
attributeMapping.asEmbeddedAttributeMapping(),
objects[i],
persistenceContext
);
}
else if ( attributeMapping.isPluralAttributeMapping() ) {
addCollectionKey(
attributeMapping.asPluralAttributeMapping(),
objects[i],
persistenceContext
);
}
}
}
private void visitEmbeddedAttributeMapping(
EmbeddedAttributeMapping attributeMapping,
Object object,
PersistenceContext persistenceContext) {
if ( object != null ) {
final AttributeMappingsList attributeMappings = attributeMapping.getEmbeddableTypeDescriptor().getAttributeMappings();
for ( int i = 0; i < attributeMappings.size(); i++ ) {
final AttributeMapping attribute = attributeMappings.get( i );
if ( attribute.isPluralAttributeMapping() ) {
addCollectionKey(
attribute.asPluralAttributeMapping(),
attribute.getPropertyAccess().getGetter().get( object ),
persistenceContext
);
}
else if ( attribute.isEmbeddedAttributeMapping() ) {
visitEmbeddedAttributeMapping(
attribute.asEmbeddedAttributeMapping(),
attribute.getPropertyAccess().getGetter().get( object ),
persistenceContext
);
}
}
}
}
private void addCollectionKey(
PluralAttributeMapping pluralAttributeMapping,
Object o,
PersistenceContext persistenceContext) {
if ( o instanceof PersistentCollection ) {
final CollectionPersister collectionPersister = pluralAttributeMapping.getCollectionDescriptor();
final CollectionKey collectionKey = new CollectionKey( final CollectionKey collectionKey = new CollectionKey(
collectionPersister, collectionPersister,
( (AbstractEntityPersister) getPersister() ).getCollectionKey( ( (AbstractEntityPersister) getPersister() ).getCollectionKey(
@ -160,8 +210,10 @@ public abstract class AbstractEntityInsertAction extends EntityAction {
getSession() getSession()
) )
); );
persistenceContext.addCollectionByKey( collectionKey, persistentCollection ); persistenceContext.addCollectionByKey(
} collectionKey,
(PersistentCollection<?>) o
);
} }
} }

View File

@ -100,7 +100,7 @@ public class EntityInsertAction extends AbstractEntityInsertAction {
final EntityPersister persister = getPersister(); final EntityPersister persister = getPersister();
final Object instance = getInstance(); final Object instance = getInstance();
persister.insert( id, getState(), instance, session ); persister.insert( id, getState(), instance, session );
PersistenceContext persistenceContext = session.getPersistenceContextInternal(); final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityEntry entry = persistenceContext.getEntry( instance ); final EntityEntry entry = persistenceContext.getEntry( instance );
if ( entry == null ) { if ( entry == null ) {
throw new AssertionFailure( "possible non-threadsafe access to session" ); throw new AssertionFailure( "possible non-threadsafe access to session" );

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.metamodel.mapping; package org.hibernate.metamodel.mapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.sql.results.graph.DatabaseSnapshotContributor; import org.hibernate.sql.results.graph.DatabaseSnapshotContributor;
import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Fetchable;
@ -92,4 +93,30 @@ public interface AttributeMapping
return this; return this;
} }
/**
* A utility method to avoid casting explicitly to PluralAttributeMapping
*
* @return PluralAttributeMapping if this is an instance of PluralAttributeMapping otherwise {@code null}
*/
default PluralAttributeMapping asPluralAttributeMapping() {
return null;
}
default boolean isPluralAttributeMapping() {
return false;
}
/**
* A utility method to avoid casting explicitly to EmbeddedAttributeMapping
*
* @return EmbeddedAttributeMapping if this is an instance of EmbeddedAttributeMapping otherwise {@code null}
*/
default EmbeddedAttributeMapping asEmbeddedAttributeMapping(){
return null;
}
default boolean isEmbeddedAttributeMapping(){
return false;
}
} }

View File

@ -175,4 +175,14 @@ public interface PluralAttributeMapping
SqlAstCreationState creationState) { SqlAstCreationState creationState) {
getCollectionDescriptor().applyWhereRestrictions( predicateConsumer, tableGroup, useQualifier, creationState ); getCollectionDescriptor().applyWhereRestrictions( predicateConsumer, tableGroup, useQualifier, creationState );
} }
@Override
default PluralAttributeMapping asPluralAttributeMapping() {
return this;
}
@Override
default boolean isPluralAttributeMapping() {
return true;
}
} }

View File

@ -437,4 +437,14 @@ public class EmbeddedAttributeMapping
} }
return parentInjectionAttributePropertyAccess; return parentInjectionAttributePropertyAccess;
} }
@Override
public EmbeddedAttributeMapping asEmbeddedAttributeMapping() {
return this;
}
@Override
public boolean isEmbeddedAttributeMapping() {
return true;
}
} }