From c30084010ccaea88e3a4663bccc910d207c97150 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 31 Jan 2023 11:19:02 +0100 Subject: [PATCH] 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' --- .../internal/AbstractEntityInsertAction.java | 76 ++++++++++++++++--- .../action/internal/EntityInsertAction.java | 2 +- .../metamodel/mapping/AttributeMapping.java | 27 +++++++ .../mapping/PluralAttributeMapping.java | 10 +++ .../internal/EmbeddedAttributeMapping.java | 10 +++ 5 files changed, 112 insertions(+), 13 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java index bb22b8379d..2a5dbcaac0 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java @@ -18,10 +18,13 @@ import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.Status; import org.hibernate.event.spi.EventSource; +import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.NaturalIdMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping; +import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.entity.AbstractEntityPersister; +import org.hibernate.persister.entity.AttributeMappingsList; import org.hibernate.persister.entity.EntityPersister; import static org.hibernate.engine.internal.Versioning.getVersion; @@ -148,20 +151,69 @@ public abstract class AbstractEntityInsertAction extends EntityAction { protected void addCollectionsByKeyToPersistenceContext(PersistenceContext persistenceContext, Object[] objects) { for ( int i = 0; i < objects.length; i++ ) { - if ( objects[i] instanceof PersistentCollection ) { - final PersistentCollection persistentCollection = (PersistentCollection) objects[i]; - final CollectionPersister collectionPersister = ( (PluralAttributeMapping) getPersister().getAttributeMapping( i ) ).getCollectionDescriptor(); - final CollectionKey collectionKey = new CollectionKey( - collectionPersister, - ( (AbstractEntityPersister) getPersister() ).getCollectionKey( - collectionPersister, - getInstance(), - persistenceContext.getEntry( getInstance() ), - getSession() - ) + final AttributeMapping attributeMapping = getPersister().getAttributeMapping( i ); + if ( attributeMapping.isEmbeddedAttributeMapping() ) { + visitEmbeddedAttributeMapping( + attributeMapping.asEmbeddedAttributeMapping(), + objects[i], + persistenceContext ); - persistenceContext.addCollectionByKey( collectionKey, persistentCollection ); } + 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( + collectionPersister, + ( (AbstractEntityPersister) getPersister() ).getCollectionKey( + collectionPersister, + getInstance(), + persistenceContext.getEntry( getInstance() ), + getSession() + ) + ); + persistenceContext.addCollectionByKey( + collectionKey, + (PersistentCollection) o + ); } } 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 8cae0da982..9e34db5dd7 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 @@ -100,7 +100,7 @@ public class EntityInsertAction extends AbstractEntityInsertAction { final EntityPersister persister = getPersister(); final Object instance = getInstance(); persister.insert( id, getState(), instance, session ); - PersistenceContext persistenceContext = session.getPersistenceContextInternal(); + final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); final EntityEntry entry = persistenceContext.getEntry( instance ); if ( entry == null ) { throw new AssertionFailure( "possible non-threadsafe access to session" ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMapping.java index c52d20fb15..963928a345 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMapping.java @@ -6,6 +6,7 @@ */ package org.hibernate.metamodel.mapping; +import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.sql.results.graph.DatabaseSnapshotContributor; import org.hibernate.sql.results.graph.Fetchable; @@ -92,4 +93,30 @@ public interface AttributeMapping 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; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/PluralAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/PluralAttributeMapping.java index b5365aba6e..1c5bdad280 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/PluralAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/PluralAttributeMapping.java @@ -175,4 +175,14 @@ public interface PluralAttributeMapping SqlAstCreationState creationState) { getCollectionDescriptor().applyWhereRestrictions( predicateConsumer, tableGroup, useQualifier, creationState ); } + + @Override + default PluralAttributeMapping asPluralAttributeMapping() { + return this; + } + + @Override + default boolean isPluralAttributeMapping() { + return true; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java index 408f90706c..191fbf27b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java @@ -437,4 +437,14 @@ public class EmbeddedAttributeMapping } return parentInjectionAttributePropertyAccess; } + + @Override + public EmbeddedAttributeMapping asEmbeddedAttributeMapping() { + return this; + } + + @Override + public boolean isEmbeddedAttributeMapping() { + return true; + } }