diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ValuedModelPart.java index 2a4c2ab5ce..361818c94b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ValuedModelPart.java @@ -64,6 +64,18 @@ public interface ValuedModelPart extends ModelPart, ValueMapping, SelectableMapp ); } + default void forEachNonFormula(SelectableConsumer consumer) { + ModelPart.super.forEachSelectable( + (selectionIndex, selectableMapping) -> { + if ( selectableMapping.isFormula() ) { + return; + } + + consumer.accept( selectionIndex, selectableMapping ); + } + ); + } + default void forEachUpdatable(SelectableConsumer consumer) { ModelPart.super.forEachSelectable( (selectionIndex, selectableMapping) -> { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java index 59a41a93a7..4082f2c81d 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/BasicCollectionPersister.java @@ -464,8 +464,32 @@ public class BasicCollectionPersister extends AbstractCollectionPersister { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SET - attribute.getElementDescriptor().forEachUpdatable( updateBuilder ); + if ( hasIndex() ) { + /* + Given : + class MyEntity { + @ElementCollection(fetch = FetchType.LAZY) + @OrderColumn + private List myEmbeddables; + } + + @Embeddable + public static class MyEmbeddable { + @Column(updatable = false) + private String embeddedProperty; + } + + we cannot understand if the update is due to a change in the value embeddedProperty or because a + new element has been added to the list in an existing position (update) shifting the old value (insert). + + For this reason we cannot take into consideration the `@Column(updatable = false)` + */ + attribute.getElementDescriptor().forEachNonFormula( updateBuilder ); + } + else { + attribute.getElementDescriptor().forEachUpdatable( updateBuilder ); + } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // WHERE @@ -501,16 +525,28 @@ public class BasicCollectionPersister extends AbstractCollectionPersister { 0, jdbcValueBindings, null, - (valueIndex, bindings, y, jdbcValue, jdbcValueMapping) -> { - if ( !jdbcValueMapping.isUpdateable() || jdbcValueMapping.isFormula() ) { - return; - } - bindings.bindValue( - jdbcValue, - jdbcValueMapping, - ParameterUsage.SET - ); - }, + hasIndex() ? + (valueIndex, bindings, y, jdbcValue, jdbcValueMapping) -> { + if ( jdbcValueMapping.isFormula() ) { + return; + } + bindings.bindValue( + jdbcValue, + jdbcValueMapping, + ParameterUsage.SET + ); + } + : + (valueIndex, bindings, y, jdbcValue, jdbcValueMapping) -> { + if ( !jdbcValueMapping.isUpdateable() || jdbcValueMapping.isFormula() ) { + return; + } + bindings.bindValue( + jdbcValue, + jdbcValueMapping, + ParameterUsage.SET + ); + }, session ); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/mutation/UpdateRowsCoordinatorStandard.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/mutation/UpdateRowsCoordinatorStandard.java index 35f3cef3a6..c489e74e9e 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/mutation/UpdateRowsCoordinatorStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/mutation/UpdateRowsCoordinatorStandard.java @@ -19,7 +19,10 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.sql.model.MutationType; +import org.hibernate.sql.model.internal.AbstractMutationOperationGroup; +import org.hibernate.sql.model.internal.MutationOperationGroupNone; import org.hibernate.sql.model.internal.MutationOperationGroupSingle; +import org.hibernate.sql.model.jdbc.JdbcMutationOperation; /** * UpdateRowsCoordinator implementation for cases with a separate collection table @@ -31,7 +34,7 @@ import org.hibernate.sql.model.internal.MutationOperationGroupSingle; public class UpdateRowsCoordinatorStandard extends AbstractUpdateRowsCoordinator implements UpdateRowsCoordinator { private final RowMutationOperations rowMutationOperations; - private MutationOperationGroupSingle operationGroup; + private AbstractMutationOperationGroup operationGroup; public UpdateRowsCoordinatorStandard( CollectionMutationTarget mutationTarget, @@ -43,7 +46,7 @@ public class UpdateRowsCoordinatorStandard extends AbstractUpdateRowsCoordinator @Override protected int doUpdate(Object key, PersistentCollection collection, SharedSessionContractImplementor session) { - final MutationOperationGroupSingle operationGroup = getOperationGroup(); + final AbstractMutationOperationGroup operationGroup = getOperationGroup(); final MutationExecutorService mutationExecutorService = session .getFactory() @@ -115,42 +118,55 @@ public class UpdateRowsCoordinatorStandard extends AbstractUpdateRowsCoordinator int entryPosition, MutationExecutor mutationExecutor, SharedSessionContractImplementor session) { - final PluralAttributeMapping attribute = getMutationTarget().getTargetPart(); - if ( !collection.needsUpdating( entry, entryPosition, attribute ) ) { + if ( rowMutationOperations.getUpdateRowOperation() != null ) { + final PluralAttributeMapping attribute = getMutationTarget().getTargetPart(); + if ( !collection.needsUpdating( entry, entryPosition, attribute ) ) { + return false; + } + + rowMutationOperations.getUpdateRowValues().applyValues( + collection, + key, + entry, + entryPosition, + session, + mutationExecutor.getJdbcValueBindings() + ); + + rowMutationOperations.getUpdateRowRestrictions().applyRestrictions( + collection, + key, + entry, + entryPosition, + session, + mutationExecutor.getJdbcValueBindings() + ); + + mutationExecutor.execute( collection, null, null, null, session ); + return true; + } + else { return false; } - - rowMutationOperations.getUpdateRowValues().applyValues( - collection, - key, - entry, - entryPosition, - session, - mutationExecutor.getJdbcValueBindings() - ); - - rowMutationOperations.getUpdateRowRestrictions().applyRestrictions( - collection, - key, - entry, - entryPosition, - session, - mutationExecutor.getJdbcValueBindings() - ); - - mutationExecutor.execute( collection, null, null, null, session ); - return true; } - protected MutationOperationGroupSingle getOperationGroup() { + protected AbstractMutationOperationGroup getOperationGroup() { if ( operationGroup == null ) { - operationGroup = new MutationOperationGroupSingle( - MutationType.UPDATE, - getMutationTarget(), - rowMutationOperations.getUpdateRowOperation() - ); + final JdbcMutationOperation updateRowOperation = rowMutationOperations.getUpdateRowOperation(); + if ( updateRowOperation == null ) { + operationGroup = new MutationOperationGroupNone( + MutationType.UPDATE, + getMutationTarget() + ); + } + else { + operationGroup = new MutationOperationGroupSingle( + MutationType.UPDATE, + getMutationTarget(), + updateRowOperation + ); + } } - return operationGroup; }