HHH-17406 Change EntityPersister mutation api to expose coordinators
This commit is contained in:
parent
d72856fef0
commit
599be89308
|
@ -128,7 +128,7 @@ public class EntityDeleteAction extends EntityAction {
|
|||
final Object ck = lockCacheItem();
|
||||
|
||||
if ( !isCascadeDeleteEnabled && !veto ) {
|
||||
persister.delete( id, version, instance, session );
|
||||
persister.getDeleteCoordinator().delete( instance, id, version, session );
|
||||
}
|
||||
|
||||
if ( isInstanceLoaded() ) {
|
||||
|
|
|
@ -107,7 +107,12 @@ public class EntityInsertAction extends AbstractEntityInsertAction {
|
|||
if ( !veto ) {
|
||||
final EntityPersister persister = getPersister();
|
||||
final Object instance = getInstance();
|
||||
final GeneratedValues generatedValues = persister.insertReturning( id, getState(), instance, session );
|
||||
final GeneratedValues generatedValues = persister.getInsertCoordinator().insert(
|
||||
instance,
|
||||
id,
|
||||
getState(),
|
||||
session
|
||||
);
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||
final EntityEntry entry = persistenceContext.getEntry( instance );
|
||||
if ( entry == null ) {
|
||||
|
|
|
@ -166,15 +166,15 @@ public class EntityUpdateAction extends EntityAction {
|
|||
final Object instance = getInstance();
|
||||
final Object previousVersion = getPreviousVersion();
|
||||
final Object ck = lockCacheItem( previousVersion );
|
||||
final GeneratedValues generatedValues = persister.updateReturning(
|
||||
final GeneratedValues generatedValues = persister.getUpdateCoordinator().update(
|
||||
instance,
|
||||
id,
|
||||
rowId,
|
||||
state,
|
||||
previousVersion,
|
||||
previousState,
|
||||
dirtyFields,
|
||||
hasDirtyCollection,
|
||||
previousState,
|
||||
previousVersion,
|
||||
instance,
|
||||
rowId,
|
||||
session
|
||||
);
|
||||
final EntityEntry entry = session.getPersistenceContextInternal().getEntry( instance );
|
||||
|
|
|
@ -77,6 +77,7 @@ public class UniqueKeySelectingDelegate extends AbstractSelectingDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSelectSQL() {
|
||||
return selectString;
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ import static org.hibernate.engine.internal.Versioning.incrementVersion;
|
|||
import static org.hibernate.engine.internal.Versioning.seedVersion;
|
||||
import static org.hibernate.engine.internal.Versioning.setVersion;
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
import static org.hibernate.internal.util.NullnessUtil.castNonNull;
|
||||
import static org.hibernate.pretty.MessageHelper.infoString;
|
||||
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
|
||||
|
||||
|
@ -108,11 +109,11 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
persister.setValues( entity, state );
|
||||
}
|
||||
}
|
||||
persister.insertReturning( id, state, entity, this );
|
||||
persister.getInsertCoordinator().insert( entity, id, state, this );
|
||||
}
|
||||
else {
|
||||
final GeneratedValues generatedValues = persister.insertReturning( state, entity, this );
|
||||
id = generatedValues.getGeneratedValue( persister.getIdentifierMapping() );
|
||||
final GeneratedValues generatedValues = persister.getInsertCoordinator().insert( entity, state, this );
|
||||
id = castNonNull( generatedValues ).getGeneratedValue( persister.getIdentifierMapping() );
|
||||
}
|
||||
persister.setIdentifier( entity, id, this );
|
||||
return id;
|
||||
|
@ -133,7 +134,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
final EntityPersister persister = getEntityPersister( entityName, entity );
|
||||
final Object id = persister.getIdentifier( entity, this );
|
||||
final Object version = persister.getVersion( entity );
|
||||
persister.delete( id, version, entity, this );
|
||||
persister.getDeleteCoordinator().delete( entity, id, version, this );
|
||||
}
|
||||
|
||||
|
||||
|
@ -167,7 +168,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
else {
|
||||
oldVersion = null;
|
||||
}
|
||||
persister.updateReturning( id, state, null, false, null, oldVersion, entity, null, this );
|
||||
persister.getUpdateCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -203,7 +204,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
else {
|
||||
oldVersion = null;
|
||||
}
|
||||
persister.merge( id, state, null, false, null, oldVersion, entity, null, this );
|
||||
persister.getMergeCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this );
|
||||
// persister.setIdentifier( entity, id, this );
|
||||
}
|
||||
|
||||
|
|
|
@ -216,6 +216,7 @@ import org.hibernate.persister.entity.mutation.DeleteCoordinatorStandard;
|
|||
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
|
||||
import org.hibernate.persister.entity.mutation.EntityTableMapping;
|
||||
import org.hibernate.persister.entity.mutation.InsertCoordinator;
|
||||
import org.hibernate.persister.entity.mutation.InsertCoordinatorStandard;
|
||||
import org.hibernate.persister.entity.mutation.MergeCoordinator;
|
||||
import org.hibernate.persister.entity.mutation.UpdateCoordinator;
|
||||
import org.hibernate.persister.entity.mutation.UpdateCoordinatorNoOp;
|
||||
|
@ -1050,22 +1051,22 @@ public abstract class AbstractEntityPersister
|
|||
return lazyLoadPlanByFetchGroup.get( fetchGroup );
|
||||
}
|
||||
|
||||
@Internal
|
||||
@Override
|
||||
public InsertCoordinator getInsertCoordinator() {
|
||||
return insertCoordinator;
|
||||
}
|
||||
|
||||
@Internal
|
||||
@Override
|
||||
public UpdateCoordinator getUpdateCoordinator() {
|
||||
return updateCoordinator;
|
||||
}
|
||||
|
||||
@Internal
|
||||
@Override
|
||||
public DeleteCoordinator getDeleteCoordinator() {
|
||||
return deleteCoordinator;
|
||||
}
|
||||
|
||||
@Internal
|
||||
@Override
|
||||
public UpdateCoordinator getMergeCoordinator() {
|
||||
return mergeCoordinator;
|
||||
}
|
||||
|
@ -2813,60 +2814,6 @@ public abstract class AbstractEntityPersister
|
|||
return select.toStatementString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an object
|
||||
*/
|
||||
@Override
|
||||
public GeneratedValues updateReturning(
|
||||
final Object id,
|
||||
final Object[] values,
|
||||
int[] dirtyAttributeIndexes,
|
||||
final boolean hasDirtyCollection,
|
||||
final Object[] oldValues,
|
||||
final Object oldVersion,
|
||||
final Object object,
|
||||
final Object rowId,
|
||||
final SharedSessionContractImplementor session) throws HibernateException {
|
||||
return updateCoordinator.coordinateUpdate(
|
||||
object,
|
||||
id,
|
||||
rowId,
|
||||
values,
|
||||
oldVersion,
|
||||
oldValues,
|
||||
dirtyAttributeIndexes,
|
||||
hasDirtyCollection,
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge an object
|
||||
*/
|
||||
@Override
|
||||
public void merge(
|
||||
final Object id,
|
||||
final Object[] values,
|
||||
int[] dirtyAttributeIndexes,
|
||||
final boolean hasDirtyCollection,
|
||||
final Object[] oldValues,
|
||||
final Object oldVersion,
|
||||
final Object object,
|
||||
final Object rowId,
|
||||
final SharedSessionContractImplementor session) throws HibernateException {
|
||||
mergeCoordinator.coordinateUpdate(
|
||||
object,
|
||||
id,
|
||||
rowId,
|
||||
values,
|
||||
oldVersion,
|
||||
oldValues,
|
||||
dirtyAttributeIndexes,
|
||||
hasDirtyCollection,
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
@Internal
|
||||
public boolean hasLazyDirtyFields(int[] dirtyFields) {
|
||||
final boolean[] propertyLaziness = getPropertyLaziness();
|
||||
|
@ -2888,16 +2835,6 @@ public abstract class AbstractEntityPersister
|
|||
return updateDelegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeneratedValues insertReturning(Object[] fields, Object object, SharedSessionContractImplementor session) {
|
||||
return insertCoordinator.coordinateInsert( null, fields, object, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeneratedValues insertReturning(Object id, Object[] fields, Object object, SharedSessionContractImplementor session) {
|
||||
return insertCoordinator.coordinateInsert( id, fields, object, session );
|
||||
}
|
||||
|
||||
protected EntityTableMapping[] getTableMappings() {
|
||||
return tableMappings;
|
||||
}
|
||||
|
@ -3001,7 +2938,7 @@ public abstract class AbstractEntityPersister
|
|||
*/
|
||||
@Override
|
||||
public void delete(Object id, Object version, Object object, SharedSessionContractImplementor session) {
|
||||
deleteCoordinator.coordinateDelete( object, id, version, session );
|
||||
deleteCoordinator.delete( object, id, version, session );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3023,7 +2960,7 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
{
|
||||
final MutationOperationGroup staticInsertGroup = insertCoordinator.getStaticInsertGroup();
|
||||
final MutationOperationGroup staticInsertGroup = insertCoordinator.getStaticMutationOperationGroup();
|
||||
if ( staticInsertGroup != null ) {
|
||||
for ( int i = 0; i < staticInsertGroup.getNumberOfOperations(); i++ ) {
|
||||
final MutationOperation mutation = staticInsertGroup.getOperation( i );
|
||||
|
@ -3035,7 +2972,7 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
{
|
||||
final MutationOperationGroup staticUpdateGroup = updateCoordinator.getStaticUpdateGroup();
|
||||
final MutationOperationGroup staticUpdateGroup = updateCoordinator.getStaticMutationOperationGroup();
|
||||
if ( staticUpdateGroup != null ) {
|
||||
for ( int i = 0; i < staticUpdateGroup.getNumberOfOperations(); i++ ) {
|
||||
final MutationOperation mutation = staticUpdateGroup.getOperation( i );
|
||||
|
@ -3047,7 +2984,7 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
{
|
||||
final MutationOperationGroup staticDeleteGroup = deleteCoordinator.getStaticDeleteGroup();
|
||||
final MutationOperationGroup staticDeleteGroup = deleteCoordinator.getStaticMutationOperationGroup();
|
||||
if ( staticDeleteGroup != null ) {
|
||||
for ( int i = 0; i < staticDeleteGroup.getNumberOfOperations(); i++ ) {
|
||||
final MutationOperation mutation = staticDeleteGroup.getOperation( i );
|
||||
|
@ -3672,7 +3609,7 @@ public abstract class AbstractEntityPersister
|
|||
protected abstract boolean isIdentifierTable(String tableExpression);
|
||||
|
||||
protected InsertCoordinator buildInsertCoordinator() {
|
||||
return new InsertCoordinator( this, factory );
|
||||
return new InsertCoordinatorStandard( this, factory );
|
||||
}
|
||||
|
||||
protected UpdateCoordinator buildUpdateCoordinator() {
|
||||
|
@ -6409,7 +6346,7 @@ public abstract class AbstractEntityPersister
|
|||
@Deprecated(forRemoval = true)
|
||||
@Remove
|
||||
public String[] getSQLDeleteStrings() {
|
||||
return extractSqlStrings( deleteCoordinator.getStaticDeleteGroup() );
|
||||
return extractSqlStrings( deleteCoordinator.getStaticMutationOperationGroup() );
|
||||
}
|
||||
|
||||
private String[] extractSqlStrings(MutationOperationGroup operationGroup) {
|
||||
|
@ -6431,7 +6368,7 @@ public abstract class AbstractEntityPersister
|
|||
@Deprecated(forRemoval = true)
|
||||
@Remove
|
||||
public String[] getSQLUpdateStrings() {
|
||||
return extractSqlStrings( updateCoordinator.getStaticUpdateGroup() );
|
||||
return extractSqlStrings( updateCoordinator.getStaticMutationOperationGroup() );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -47,7 +47,10 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
|||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType;
|
||||
import org.hibernate.metamodel.spi.EntityRepresentationStrategy;
|
||||
import org.hibernate.persister.entity.mutation.DeleteCoordinator;
|
||||
import org.hibernate.persister.entity.mutation.EntityMutationTarget;
|
||||
import org.hibernate.persister.entity.mutation.InsertCoordinator;
|
||||
import org.hibernate.persister.entity.mutation.UpdateCoordinator;
|
||||
import org.hibernate.persister.walking.spi.AttributeSource;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
|
@ -627,34 +630,45 @@ public interface EntityPersister extends EntityMappingType, EntityMutationTarget
|
|||
|
||||
/**
|
||||
* Persist an instance
|
||||
*
|
||||
* @see #getInsertCoordinator()
|
||||
* @deprecated Use {@link InsertCoordinator#insert(Object, Object, Object[], SharedSessionContractImplementor)} instead.
|
||||
*/
|
||||
@Deprecated( forRemoval = true, since = "6.5" )
|
||||
default void insert(Object id, Object[] fields, Object object, SharedSessionContractImplementor session) {
|
||||
insertReturning( id, fields, object, session );
|
||||
getInsertCoordinator().insert( object, id, fields, session );
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist an instance
|
||||
*
|
||||
* @see #getInsertCoordinator()
|
||||
* @deprecated Use {@link InsertCoordinator#insert(Object, Object[], SharedSessionContractImplementor)} instead.
|
||||
*/
|
||||
GeneratedValues insertReturning(Object id, Object[] fields, Object object, SharedSessionContractImplementor session);
|
||||
|
||||
/**
|
||||
* Persist an instance
|
||||
*/
|
||||
@Deprecated( forRemoval = true, since = "6.5" )
|
||||
default Object insert(Object[] fields, Object object, SharedSessionContractImplementor session) {
|
||||
final GeneratedValues generatedValues = insertReturning( fields, object, session );
|
||||
return generatedValues.getGeneratedValue( getIdentifierMapping() );
|
||||
final GeneratedValues generatedValues = getInsertCoordinator().insert( object, fields, session );
|
||||
return generatedValues == null ? null : generatedValues.getGeneratedValue( getIdentifierMapping() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist an instance, using a natively generated identifier (optional operation)
|
||||
*/
|
||||
GeneratedValues insertReturning(Object[] fields, Object object, SharedSessionContractImplementor session);
|
||||
|
||||
/**
|
||||
* Delete a persistent instance
|
||||
*
|
||||
* @see #getDeleteCoordinator()
|
||||
* @deprecated Use {@link DeleteCoordinator#delete} instead.
|
||||
*/
|
||||
void delete(Object id, Object version, Object object, SharedSessionContractImplementor session);
|
||||
@Deprecated( forRemoval = true, since = "6.5" )
|
||||
default void delete(Object id, Object version, Object object, SharedSessionContractImplementor session) {
|
||||
getDeleteCoordinator().delete( object, id, version, session );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a persistent instance
|
||||
*
|
||||
* @see #getUpdateCoordinator()
|
||||
* @deprecated Use {@link UpdateCoordinator#update} instead.
|
||||
*/
|
||||
@Deprecated( forRemoval = true, since = "6.5" )
|
||||
default void update(
|
||||
Object id,
|
||||
Object[] fields,
|
||||
|
@ -665,26 +679,26 @@ public interface EntityPersister extends EntityMappingType, EntityMutationTarget
|
|||
Object object,
|
||||
Object rowId,
|
||||
SharedSessionContractImplementor session) {
|
||||
updateReturning( id, fields, dirtyFields, hasDirtyCollection, oldFields, oldVersion, object, rowId, session );
|
||||
getUpdateCoordinator().update(
|
||||
object,
|
||||
id,
|
||||
rowId,
|
||||
fields,
|
||||
oldVersion,
|
||||
oldFields,
|
||||
dirtyFields,
|
||||
hasDirtyCollection,
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a persistent instance
|
||||
*/
|
||||
GeneratedValues updateReturning(
|
||||
Object id,
|
||||
Object[] fields,
|
||||
int[] dirtyFields,
|
||||
boolean hasDirtyCollection,
|
||||
Object[] oldFields,
|
||||
Object oldVersion,
|
||||
Object object,
|
||||
Object rowId,
|
||||
SharedSessionContractImplementor session);
|
||||
|
||||
/**
|
||||
* Merge a persistent instance
|
||||
*
|
||||
* @see #getMergeCoordinator()
|
||||
* @deprecated Use {@link UpdateCoordinator#update} instead.
|
||||
*/
|
||||
@Deprecated( forRemoval = true, since = "6.5" )
|
||||
default void merge(
|
||||
Object id,
|
||||
Object[] fields,
|
||||
|
@ -695,6 +709,46 @@ public interface EntityPersister extends EntityMappingType, EntityMutationTarget
|
|||
Object object,
|
||||
Object rowId,
|
||||
SharedSessionContractImplementor session) {
|
||||
getMergeCoordinator().update(
|
||||
object,
|
||||
id,
|
||||
rowId,
|
||||
fields,
|
||||
oldVersion,
|
||||
oldFields,
|
||||
dirtyFields,
|
||||
hasDirtyCollection,
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the insert coordinator instance.
|
||||
*
|
||||
* @since 6.5
|
||||
*/
|
||||
InsertCoordinator getInsertCoordinator();
|
||||
|
||||
/**
|
||||
* Get the update coordinator instance.
|
||||
*
|
||||
* @since 6.5
|
||||
*/
|
||||
UpdateCoordinator getUpdateCoordinator();
|
||||
|
||||
/**
|
||||
* Get the delete coordinator instance.
|
||||
*
|
||||
* @since 6.5
|
||||
*/
|
||||
DeleteCoordinator getDeleteCoordinator();
|
||||
|
||||
/**
|
||||
* Get the merge coordinator instance.
|
||||
*
|
||||
* @since 6.5
|
||||
*/
|
||||
default UpdateCoordinator getMergeCoordinator() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -811,7 +865,7 @@ public interface EntityPersister extends EntityMappingType, EntityMutationTarget
|
|||
|
||||
/**
|
||||
* The batch size for batch loading.
|
||||
*
|
||||
*
|
||||
* @see org.hibernate.engine.spi.LoadQueryInfluencers#effectiveBatchSize(EntityPersister)
|
||||
*/
|
||||
default int getBatchSize() {
|
||||
|
|
|
@ -52,7 +52,7 @@ public abstract class AbstractDeleteCoordinator
|
|||
}
|
||||
|
||||
@Override
|
||||
public MutationOperationGroup getStaticDeleteGroup() {
|
||||
public MutationOperationGroup getStaticMutationOperationGroup() {
|
||||
return staticOperationGroup;
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ public abstract class AbstractDeleteCoordinator
|
|||
SharedSessionContractImplementor session);
|
||||
|
||||
@Override
|
||||
public void coordinateDelete(
|
||||
public void delete(
|
||||
Object entity,
|
||||
Object id,
|
||||
Object version,
|
||||
|
|
|
@ -7,28 +7,16 @@
|
|||
package org.hibernate.persister.entity.mutation;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.sql.model.MutationOperationGroup;
|
||||
|
||||
/**
|
||||
* Coordinates the deleting of an entity.
|
||||
*
|
||||
* @see #coordinateDelete
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @see #delete
|
||||
*/
|
||||
public interface DeleteCoordinator {
|
||||
public interface DeleteCoordinator extends MutationCoordinator {
|
||||
/**
|
||||
* The operation group used to perform the deletion unless some form
|
||||
* of dynamic delete is necessary
|
||||
* Delete a persistent instance.
|
||||
*/
|
||||
MutationOperationGroup getStaticDeleteGroup();
|
||||
|
||||
/**
|
||||
* Perform the deletions
|
||||
*/
|
||||
void coordinateDelete(
|
||||
Object entity,
|
||||
Object id,
|
||||
Object version,
|
||||
SharedSessionContractImplementor session);
|
||||
void delete(Object entity, Object id, Object version, SharedSessionContractImplementor session);
|
||||
}
|
||||
|
|
|
@ -1,457 +1,39 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.persister.entity.mutation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.MutationExecutor;
|
||||
import org.hibernate.engine.jdbc.mutation.ParameterUsage;
|
||||
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.generator.OnExecutionGenerator;
|
||||
import org.hibernate.generator.values.GeneratedValues;
|
||||
import org.hibernate.generator.values.GeneratedValuesMutationDelegate;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.AttributeMappingsList;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.sql.model.MutationOperation;
|
||||
import org.hibernate.sql.model.MutationOperationGroup;
|
||||
import org.hibernate.sql.model.MutationType;
|
||||
import org.hibernate.sql.model.TableMapping;
|
||||
import org.hibernate.sql.model.ValuesAnalysis;
|
||||
import org.hibernate.sql.model.ast.builder.MutationGroupBuilder;
|
||||
import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
|
||||
import org.hibernate.sql.model.ast.builder.TableInsertBuilderStandard;
|
||||
import org.hibernate.sql.model.ast.builder.TableMutationBuilder;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Coordinates the insertion of an entity.
|
||||
* Coordinates the inserting of an entity.
|
||||
*
|
||||
* @see #coordinateInsert
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Marco Belladelli
|
||||
* @see #insert(Object, Object[], SharedSessionContractImplementor)
|
||||
* @see #insert(Object, Object, Object[], SharedSessionContractImplementor)
|
||||
*/
|
||||
@Internal
|
||||
public class InsertCoordinator extends AbstractMutationCoordinator {
|
||||
private final MutationOperationGroup staticInsertGroup;
|
||||
private final BasicBatchKey batchKey;
|
||||
|
||||
public InsertCoordinator(AbstractEntityPersister entityPersister, SessionFactoryImplementor factory) {
|
||||
super( entityPersister, factory );
|
||||
|
||||
if ( entityPersister.isIdentifierAssignedByInsert() || entityPersister.hasInsertGeneratedProperties() ) {
|
||||
// disable batching in case of insert generated identifier or properties
|
||||
batchKey = null;
|
||||
}
|
||||
else {
|
||||
batchKey = new BasicBatchKey(
|
||||
entityPersister.getEntityName() + "#INSERT",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
if ( entityPersister.getEntityMetamodel().isDynamicInsert() ) {
|
||||
// the entity specified dynamic-insert - skip generating the
|
||||
// static inserts as we will create them every time
|
||||
staticInsertGroup = null;
|
||||
}
|
||||
else {
|
||||
staticInsertGroup = generateStaticOperationGroup();
|
||||
}
|
||||
}
|
||||
|
||||
public MutationOperationGroup getStaticInsertGroup() {
|
||||
return staticInsertGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BatchKey getBatchKey() {
|
||||
return batchKey;
|
||||
}
|
||||
public interface InsertCoordinator extends MutationCoordinator {
|
||||
/**
|
||||
* Persist an entity instance with a generated identifier.
|
||||
*
|
||||
* @return The {@linkplain GeneratedValues generated values} if any, {@code null} otherwise.
|
||||
*/
|
||||
@Nullable GeneratedValues insert(Object entity, Object[] values, SharedSessionContractImplementor session);
|
||||
|
||||
/**
|
||||
* Perform the insert(s).
|
||||
* Persist an entity instance using the provided identifier.
|
||||
*
|
||||
* @param id This is the id as known in memory. For post-insert id generation (IDENTITY, etc)
|
||||
* this will be null.
|
||||
* @param values The extracted attribute values
|
||||
* @param entity The entity instance being persisted
|
||||
* @param session The originating context
|
||||
*
|
||||
* @return The id
|
||||
* @return The {@linkplain GeneratedValues generated values} if any, {@code null} otherwise.
|
||||
*/
|
||||
public GeneratedValues coordinateInsert(
|
||||
Object id,
|
||||
Object[] values,
|
||||
@Nullable GeneratedValues insert(
|
||||
Object entity,
|
||||
SharedSessionContractImplementor session) {
|
||||
// apply any pre-insert in-memory value generation
|
||||
final boolean needsDynamicInsert = preInsertInMemoryValueGeneration( values, entity, session );
|
||||
|
||||
final EntityMetamodel entityMetamodel = entityPersister().getEntityMetamodel();
|
||||
final boolean forceIdentifierBinding = entityPersister().getGenerator().generatedOnExecution() && id != null;
|
||||
if ( entityMetamodel.isDynamicInsert() || needsDynamicInsert || forceIdentifierBinding ) {
|
||||
return doDynamicInserts( id, values, entity, session, forceIdentifierBinding );
|
||||
}
|
||||
else {
|
||||
return doStaticInserts( id, values, entity, session );
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean preInsertInMemoryValueGeneration(Object[] values, Object entity, SharedSessionContractImplementor session) {
|
||||
final AbstractEntityPersister persister = entityPersister();
|
||||
final EntityMetamodel entityMetamodel = persister.getEntityMetamodel();
|
||||
boolean foundStateDependentGenerator = false;
|
||||
if ( entityMetamodel.hasPreInsertGeneratedValues() ) {
|
||||
final Generator[] generators = entityMetamodel.getGenerators();
|
||||
for ( int i = 0; i < generators.length; i++ ) {
|
||||
final Generator generator = generators[i];
|
||||
if ( generator != null
|
||||
&& !generator.generatedOnExecution( entity, session )
|
||||
&& generator.generatesOnInsert() ) {
|
||||
values[i] = ( (BeforeExecutionGenerator) generator ).generate( session, entity, values[i], INSERT );
|
||||
persister.setPropertyValue( entity, i, values[i] );
|
||||
foundStateDependentGenerator = foundStateDependentGenerator || generator.generatedOnExecution();
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundStateDependentGenerator;
|
||||
}
|
||||
|
||||
protected static class InsertValuesAnalysis implements ValuesAnalysis {
|
||||
private final List<TableMapping> tablesWithNonNullValues = new ArrayList<>();
|
||||
|
||||
public InsertValuesAnalysis(EntityMutationTarget mutationTarget, Object[] values) {
|
||||
mutationTarget.forEachMutableTable( (tableMapping) -> {
|
||||
final int[] tableAttributeIndexes = tableMapping.getAttributeIndexes();
|
||||
for ( int i = 0; i < tableAttributeIndexes.length; i++ ) {
|
||||
if ( values[tableAttributeIndexes[i]] != null ) {
|
||||
tablesWithNonNullValues.add( tableMapping );
|
||||
break;
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public boolean hasNonNullBindings(TableMapping tableMapping) {
|
||||
return tablesWithNonNullValues.contains( tableMapping );
|
||||
}
|
||||
}
|
||||
|
||||
protected GeneratedValues doStaticInserts(Object id, Object[] values, Object object, SharedSessionContractImplementor session) {
|
||||
final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values );
|
||||
|
||||
final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis );
|
||||
|
||||
final MutationExecutor mutationExecutor = executor( session, staticInsertGroup, false );
|
||||
|
||||
decomposeForInsert(
|
||||
mutationExecutor,
|
||||
id,
|
||||
values,
|
||||
staticInsertGroup,
|
||||
entityPersister().getPropertyInsertability(),
|
||||
tableInclusionChecker,
|
||||
session
|
||||
);
|
||||
|
||||
try {
|
||||
return mutationExecutor.execute(
|
||||
object,
|
||||
insertValuesAnalysis,
|
||||
tableInclusionChecker,
|
||||
(statementDetails, affectedRowCount, batchPosition) -> {
|
||||
statementDetails.getExpectation().verifyOutcome(
|
||||
affectedRowCount,
|
||||
statementDetails.getStatement(),
|
||||
batchPosition,
|
||||
statementDetails.getSqlString()
|
||||
);
|
||||
return true;
|
||||
},
|
||||
session
|
||||
);
|
||||
}
|
||||
finally {
|
||||
mutationExecutor.release();
|
||||
}
|
||||
}
|
||||
|
||||
protected void decomposeForInsert(
|
||||
MutationExecutor mutationExecutor,
|
||||
Object id,
|
||||
Object[] values,
|
||||
MutationOperationGroup mutationGroup,
|
||||
boolean[] propertyInclusions,
|
||||
TableInclusionChecker tableInclusionChecker,
|
||||
SharedSessionContractImplementor session) {
|
||||
final JdbcValueBindings jdbcValueBindings = mutationExecutor.getJdbcValueBindings();
|
||||
final AttributeMappingsList attributeMappings = entityPersister().getAttributeMappings();
|
||||
|
||||
for ( int position = 0; position < mutationGroup.getNumberOfOperations(); position++ ) {
|
||||
final MutationOperation operation = mutationGroup.getOperation( position );
|
||||
final EntityTableMapping tableDetails = (EntityTableMapping) operation.getTableDetails();
|
||||
if ( tableInclusionChecker.include( tableDetails ) ) {
|
||||
final int[] attributeIndexes = tableDetails.getAttributeIndexes();
|
||||
for ( int i = 0; i < attributeIndexes.length; i++ ) {
|
||||
final int attributeIndex = attributeIndexes[ i ];
|
||||
if ( propertyInclusions[attributeIndex] ) {
|
||||
final AttributeMapping mapping = attributeMappings.get( attributeIndex );
|
||||
decomposeAttribute( values[attributeIndex], session, jdbcValueBindings, mapping );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( id == null ) {
|
||||
assert entityPersister().getInsertDelegate() != null;
|
||||
}
|
||||
else {
|
||||
for ( int position = 0; position < mutationGroup.getNumberOfOperations(); position++ ) {
|
||||
final MutationOperation jdbcOperation = mutationGroup.getOperation( position );
|
||||
final EntityTableMapping tableDetails = (EntityTableMapping) jdbcOperation.getTableDetails();
|
||||
breakDownJdbcValue( id, session, jdbcValueBindings, tableDetails );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void breakDownJdbcValue(
|
||||
Object id,
|
||||
SharedSessionContractImplementor session,
|
||||
JdbcValueBindings jdbcValueBindings,
|
||||
EntityTableMapping tableDetails) {
|
||||
final String tableName = tableDetails.getTableName();
|
||||
tableDetails.getKeyMapping().breakDownKeyJdbcValues(
|
||||
id,
|
||||
(jdbcValue, columnMapping) -> {
|
||||
jdbcValueBindings.bindValue(
|
||||
jdbcValue,
|
||||
tableName,
|
||||
columnMapping.getColumnName(),
|
||||
ParameterUsage.SET
|
||||
);
|
||||
},
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
protected void decomposeAttribute(
|
||||
Object value,
|
||||
SharedSessionContractImplementor session,
|
||||
JdbcValueBindings jdbcValueBindings,
|
||||
AttributeMapping mapping) {
|
||||
if ( !(mapping instanceof PluralAttributeMapping) ) {
|
||||
mapping.decompose(
|
||||
value,
|
||||
0,
|
||||
jdbcValueBindings,
|
||||
null,
|
||||
(valueIndex, bindings, noop, jdbcValue, selectableMapping) -> {
|
||||
if ( selectableMapping.isInsertable() ) {
|
||||
bindings.bindValue(
|
||||
jdbcValue,
|
||||
entityPersister().physicalTableNameForMutation( selectableMapping ),
|
||||
selectableMapping.getSelectionExpression(),
|
||||
ParameterUsage.SET
|
||||
);
|
||||
}
|
||||
},
|
||||
session
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected GeneratedValues doDynamicInserts(
|
||||
Object id,
|
||||
Object[] values,
|
||||
Object object,
|
||||
SharedSessionContractImplementor session,
|
||||
boolean forceIdentifierBinding) {
|
||||
final boolean[] insertability = getPropertiesToInsert( values );
|
||||
final MutationOperationGroup insertGroup = generateDynamicInsertSqlGroup( insertability, object, session, forceIdentifierBinding );
|
||||
|
||||
final MutationExecutor mutationExecutor = executor( session, insertGroup, true );
|
||||
|
||||
final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values );
|
||||
|
||||
final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis );
|
||||
|
||||
decomposeForInsert( mutationExecutor, id, values, insertGroup, insertability, tableInclusionChecker, session );
|
||||
|
||||
try {
|
||||
return mutationExecutor.execute(
|
||||
object,
|
||||
insertValuesAnalysis,
|
||||
tableInclusionChecker,
|
||||
(statementDetails, affectedRowCount, batchPosition) -> {
|
||||
statementDetails.getExpectation().verifyOutcome(
|
||||
affectedRowCount,
|
||||
statementDetails.getStatement(),
|
||||
batchPosition,
|
||||
statementDetails.getSqlString()
|
||||
);
|
||||
return true;
|
||||
},
|
||||
session
|
||||
);
|
||||
}
|
||||
finally {
|
||||
mutationExecutor.release();
|
||||
}
|
||||
}
|
||||
|
||||
private MutationExecutor executor(SharedSessionContractImplementor session, MutationOperationGroup group, boolean dynamicUpdate) {
|
||||
return mutationExecutorService
|
||||
.createExecutor( resolveBatchKeyAccess( dynamicUpdate, session ), group, session );
|
||||
}
|
||||
|
||||
protected static TableInclusionChecker getTableInclusionChecker(InsertValuesAnalysis insertValuesAnalysis) {
|
||||
return tableMapping -> !tableMapping.isOptional() || insertValuesAnalysis.hasNonNullBindings( tableMapping );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transform the array of property indexes to an array of booleans,
|
||||
* true when the property is insertable and non-null
|
||||
*/
|
||||
public boolean[] getPropertiesToInsert(Object[] fields) {
|
||||
boolean[] notNull = new boolean[fields.length];
|
||||
boolean[] insertable = entityPersister().getPropertyInsertability();
|
||||
for ( int i = 0; i < fields.length; i++ ) {
|
||||
notNull[i] = insertable[i] && fields[i] != null;
|
||||
}
|
||||
return notNull;
|
||||
}
|
||||
|
||||
protected MutationOperationGroup generateDynamicInsertSqlGroup(
|
||||
boolean[] insertable,
|
||||
Object object,
|
||||
SharedSessionContractImplementor session,
|
||||
boolean forceIdentifierBinding) {
|
||||
final MutationGroupBuilder insertGroupBuilder = new MutationGroupBuilder( MutationType.INSERT, entityPersister() );
|
||||
entityPersister().forEachMutableTable(
|
||||
(tableMapping) -> insertGroupBuilder.addTableDetailsBuilder( createTableInsertBuilder( tableMapping, forceIdentifierBinding ) )
|
||||
);
|
||||
applyTableInsertDetails( insertGroupBuilder, insertable, object, session, forceIdentifierBinding );
|
||||
return createOperationGroup( null, insertGroupBuilder.buildMutationGroup() );
|
||||
}
|
||||
|
||||
public MutationOperationGroup generateStaticOperationGroup() {
|
||||
final MutationGroupBuilder insertGroupBuilder = new MutationGroupBuilder( MutationType.INSERT, entityPersister() );
|
||||
entityPersister().forEachMutableTable(
|
||||
(tableMapping) -> insertGroupBuilder.addTableDetailsBuilder( createTableInsertBuilder( tableMapping, false ) )
|
||||
);
|
||||
applyTableInsertDetails( insertGroupBuilder, entityPersister().getPropertyInsertability(), null, null, false );
|
||||
return createOperationGroup( null, insertGroupBuilder.buildMutationGroup() );
|
||||
}
|
||||
|
||||
private TableMutationBuilder<?> createTableInsertBuilder(EntityTableMapping tableMapping, boolean forceIdentifierBinding) {
|
||||
final GeneratedValuesMutationDelegate delegate = entityPersister().getInsertDelegate();
|
||||
if ( tableMapping.isIdentifierTable() && delegate != null && !forceIdentifierBinding ) {
|
||||
return delegate.createTableMutationBuilder( tableMapping.getInsertExpectation(), factory() );
|
||||
}
|
||||
else {
|
||||
return new TableInsertBuilderStandard( entityPersister(), tableMapping, factory() );
|
||||
}
|
||||
}
|
||||
|
||||
private void applyTableInsertDetails(
|
||||
MutationGroupBuilder insertGroupBuilder,
|
||||
boolean[] attributeInclusions,
|
||||
Object object,
|
||||
SharedSessionContractImplementor session,
|
||||
boolean forceIdentifierBinding) {
|
||||
final AttributeMappingsList attributeMappings = entityPersister().getAttributeMappings();
|
||||
|
||||
insertGroupBuilder.forEachTableMutationBuilder( (builder) -> {
|
||||
final EntityTableMapping tableMapping = (EntityTableMapping) builder.getMutatingTable().getTableMapping();
|
||||
assert !tableMapping.isInverse();
|
||||
|
||||
// `attributeIndexes` represents the indexes (relative to `attributeMappings`) of
|
||||
// the attributes mapped to the table
|
||||
final int[] attributeIndexes = tableMapping.getAttributeIndexes();
|
||||
for ( int i = 0; i < attributeIndexes.length; i++ ) {
|
||||
final int attributeIndex = attributeIndexes[ i ];
|
||||
final AttributeMapping attributeMapping = attributeMappings.get( attributeIndex );
|
||||
if ( attributeInclusions[attributeIndex] ) {
|
||||
attributeMapping.forEachInsertable( insertGroupBuilder );
|
||||
}
|
||||
else {
|
||||
final Generator generator = attributeMapping.getGenerator();
|
||||
if ( isValueGenerated( generator ) ) {
|
||||
if ( session != null && !generator.generatedOnExecution( object, session ) ) {
|
||||
attributeInclusions[attributeIndex] = true;
|
||||
attributeMapping.forEachInsertable( insertGroupBuilder );
|
||||
}
|
||||
else if ( isValueGenerationInSql( generator, factory().getJdbcServices().getDialect() ) ) {
|
||||
handleValueGeneration( attributeMapping, insertGroupBuilder, (OnExecutionGenerator) generator );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
// add the discriminator
|
||||
entityPersister().addDiscriminatorToInsertGroup( insertGroupBuilder );
|
||||
entityPersister().addSoftDeleteToInsertGroup( insertGroupBuilder );
|
||||
|
||||
// add the keys
|
||||
insertGroupBuilder.forEachTableMutationBuilder( (tableMutationBuilder) -> {
|
||||
final TableInsertBuilder tableInsertBuilder = (TableInsertBuilder) tableMutationBuilder;
|
||||
final EntityTableMapping tableMapping = (EntityTableMapping) tableInsertBuilder.getMutatingTable().getTableMapping();
|
||||
if ( tableMapping.isIdentifierTable() && entityPersister().isIdentifierAssignedByInsert() && !forceIdentifierBinding ) {
|
||||
assert entityPersister().getInsertDelegate() != null;
|
||||
final OnExecutionGenerator generator = (OnExecutionGenerator) entityPersister().getGenerator();
|
||||
if ( generator.referenceColumnsInSql( dialect() ) ) {
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityPersister().getIdentifierMapping();
|
||||
final String[] columnValues = generator.getReferencedColumnValues( dialect );
|
||||
tableMapping.getKeyMapping().forEachKeyColumn( (i, column) -> tableInsertBuilder.addKeyColumn(
|
||||
column.getColumnName(),
|
||||
columnValues[i],
|
||||
identifierMapping.getJdbcMapping()
|
||||
) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
tableMapping.getKeyMapping().forEachKeyColumn( tableInsertBuilder::addKeyColumn );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
private static boolean isValueGenerated(Generator generator) {
|
||||
return generator != null
|
||||
&& generator.generatesOnInsert()
|
||||
&& generator.generatedOnExecution();
|
||||
}
|
||||
|
||||
private static boolean isValueGenerationInSql(Generator generator, Dialect dialect) {
|
||||
assert isValueGenerated( generator );
|
||||
return ( (OnExecutionGenerator) generator ).referenceColumnsInSql(dialect);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getBatchKey()}
|
||||
*/
|
||||
@Deprecated
|
||||
public BasicBatchKey getInsertBatchKey() {
|
||||
return batchKey;
|
||||
}
|
||||
SharedSessionContractImplementor session);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,474 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
|
||||
*/
|
||||
package org.hibernate.persister.entity.mutation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
|
||||
import org.hibernate.engine.jdbc.batch.spi.BatchKey;
|
||||
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||
import org.hibernate.engine.jdbc.mutation.MutationExecutor;
|
||||
import org.hibernate.engine.jdbc.mutation.ParameterUsage;
|
||||
import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.generator.OnExecutionGenerator;
|
||||
import org.hibernate.generator.values.GeneratedValues;
|
||||
import org.hibernate.generator.values.GeneratedValuesMutationDelegate;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.AttributeMappingsList;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.sql.model.MutationOperation;
|
||||
import org.hibernate.sql.model.MutationOperationGroup;
|
||||
import org.hibernate.sql.model.MutationType;
|
||||
import org.hibernate.sql.model.TableMapping;
|
||||
import org.hibernate.sql.model.ValuesAnalysis;
|
||||
import org.hibernate.sql.model.ast.builder.MutationGroupBuilder;
|
||||
import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
|
||||
import org.hibernate.sql.model.ast.builder.TableInsertBuilderStandard;
|
||||
import org.hibernate.sql.model.ast.builder.TableMutationBuilder;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
|
||||
/**
|
||||
* Coordinates the insertion of an entity.
|
||||
*
|
||||
* @see #coordinateInsert
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@Internal
|
||||
public class InsertCoordinatorStandard extends AbstractMutationCoordinator implements InsertCoordinator {
|
||||
private final MutationOperationGroup staticInsertGroup;
|
||||
private final BasicBatchKey batchKey;
|
||||
|
||||
public InsertCoordinatorStandard(AbstractEntityPersister entityPersister, SessionFactoryImplementor factory) {
|
||||
super( entityPersister, factory );
|
||||
|
||||
if ( entityPersister.isIdentifierAssignedByInsert() || entityPersister.hasInsertGeneratedProperties() ) {
|
||||
// disable batching in case of insert generated identifier or properties
|
||||
batchKey = null;
|
||||
}
|
||||
else {
|
||||
batchKey = new BasicBatchKey(
|
||||
entityPersister.getEntityName() + "#INSERT",
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
if ( entityPersister.getEntityMetamodel().isDynamicInsert() ) {
|
||||
// the entity specified dynamic-insert - skip generating the
|
||||
// static inserts as we will create them every time
|
||||
staticInsertGroup = null;
|
||||
}
|
||||
else {
|
||||
staticInsertGroup = generateStaticOperationGroup();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutationOperationGroup getStaticMutationOperationGroup() {
|
||||
return staticInsertGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BatchKey getBatchKey() {
|
||||
return batchKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable GeneratedValues insert(Object entity, Object[] values, SharedSessionContractImplementor session) {
|
||||
return coordinateInsert( null, values, entity, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable GeneratedValues insert(
|
||||
Object entity,
|
||||
Object id,
|
||||
Object[] values,
|
||||
SharedSessionContractImplementor session) {
|
||||
return coordinateInsert( id, values, entity, session );
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the insert(s).
|
||||
*
|
||||
* @param id This is the id as known in memory. For post-insert id generation (IDENTITY, etc)
|
||||
* this will be null.
|
||||
* @param values The extracted attribute values
|
||||
* @param entity The entity instance being persisted
|
||||
* @param session The originating context
|
||||
*
|
||||
* @return The {@linkplain GeneratedValues generated values} if any, {@code null} otherwise.
|
||||
*/
|
||||
public GeneratedValues coordinateInsert(
|
||||
Object id,
|
||||
Object[] values,
|
||||
Object entity,
|
||||
SharedSessionContractImplementor session) {
|
||||
// apply any pre-insert in-memory value generation
|
||||
final boolean needsDynamicInsert = preInsertInMemoryValueGeneration( values, entity, session );
|
||||
|
||||
final EntityMetamodel entityMetamodel = entityPersister().getEntityMetamodel();
|
||||
final boolean forceIdentifierBinding = entityPersister().getGenerator().generatedOnExecution() && id != null;
|
||||
if ( entityMetamodel.isDynamicInsert() || needsDynamicInsert || forceIdentifierBinding ) {
|
||||
return doDynamicInserts( id, values, entity, session, forceIdentifierBinding );
|
||||
}
|
||||
else {
|
||||
return doStaticInserts( id, values, entity, session );
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean preInsertInMemoryValueGeneration(Object[] values, Object entity, SharedSessionContractImplementor session) {
|
||||
final AbstractEntityPersister persister = entityPersister();
|
||||
final EntityMetamodel entityMetamodel = persister.getEntityMetamodel();
|
||||
boolean foundStateDependentGenerator = false;
|
||||
if ( entityMetamodel.hasPreInsertGeneratedValues() ) {
|
||||
final Generator[] generators = entityMetamodel.getGenerators();
|
||||
for ( int i = 0; i < generators.length; i++ ) {
|
||||
final Generator generator = generators[i];
|
||||
if ( generator != null
|
||||
&& !generator.generatedOnExecution( entity, session )
|
||||
&& generator.generatesOnInsert() ) {
|
||||
values[i] = ( (BeforeExecutionGenerator) generator ).generate( session, entity, values[i], INSERT );
|
||||
persister.setPropertyValue( entity, i, values[i] );
|
||||
foundStateDependentGenerator = foundStateDependentGenerator || generator.generatedOnExecution();
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundStateDependentGenerator;
|
||||
}
|
||||
|
||||
protected static class InsertValuesAnalysis implements ValuesAnalysis {
|
||||
private final List<TableMapping> tablesWithNonNullValues = new ArrayList<>();
|
||||
|
||||
public InsertValuesAnalysis(EntityMutationTarget mutationTarget, Object[] values) {
|
||||
mutationTarget.forEachMutableTable( (tableMapping) -> {
|
||||
final int[] tableAttributeIndexes = tableMapping.getAttributeIndexes();
|
||||
for ( int i = 0; i < tableAttributeIndexes.length; i++ ) {
|
||||
if ( values[tableAttributeIndexes[i]] != null ) {
|
||||
tablesWithNonNullValues.add( tableMapping );
|
||||
break;
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public boolean hasNonNullBindings(TableMapping tableMapping) {
|
||||
return tablesWithNonNullValues.contains( tableMapping );
|
||||
}
|
||||
}
|
||||
|
||||
protected GeneratedValues doStaticInserts(Object id, Object[] values, Object object, SharedSessionContractImplementor session) {
|
||||
final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values );
|
||||
|
||||
final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis );
|
||||
|
||||
final MutationExecutor mutationExecutor = executor( session, staticInsertGroup, false );
|
||||
|
||||
decomposeForInsert(
|
||||
mutationExecutor,
|
||||
id,
|
||||
values,
|
||||
staticInsertGroup,
|
||||
entityPersister().getPropertyInsertability(),
|
||||
tableInclusionChecker,
|
||||
session
|
||||
);
|
||||
|
||||
try {
|
||||
return mutationExecutor.execute(
|
||||
object,
|
||||
insertValuesAnalysis,
|
||||
tableInclusionChecker,
|
||||
(statementDetails, affectedRowCount, batchPosition) -> {
|
||||
statementDetails.getExpectation().verifyOutcome(
|
||||
affectedRowCount,
|
||||
statementDetails.getStatement(),
|
||||
batchPosition,
|
||||
statementDetails.getSqlString()
|
||||
);
|
||||
return true;
|
||||
},
|
||||
session
|
||||
);
|
||||
}
|
||||
finally {
|
||||
mutationExecutor.release();
|
||||
}
|
||||
}
|
||||
|
||||
protected void decomposeForInsert(
|
||||
MutationExecutor mutationExecutor,
|
||||
Object id,
|
||||
Object[] values,
|
||||
MutationOperationGroup mutationGroup,
|
||||
boolean[] propertyInclusions,
|
||||
TableInclusionChecker tableInclusionChecker,
|
||||
SharedSessionContractImplementor session) {
|
||||
final JdbcValueBindings jdbcValueBindings = mutationExecutor.getJdbcValueBindings();
|
||||
final AttributeMappingsList attributeMappings = entityPersister().getAttributeMappings();
|
||||
|
||||
for ( int position = 0; position < mutationGroup.getNumberOfOperations(); position++ ) {
|
||||
final MutationOperation operation = mutationGroup.getOperation( position );
|
||||
final EntityTableMapping tableDetails = (EntityTableMapping) operation.getTableDetails();
|
||||
if ( tableInclusionChecker.include( tableDetails ) ) {
|
||||
final int[] attributeIndexes = tableDetails.getAttributeIndexes();
|
||||
for ( int i = 0; i < attributeIndexes.length; i++ ) {
|
||||
final int attributeIndex = attributeIndexes[ i ];
|
||||
if ( propertyInclusions[attributeIndex] ) {
|
||||
final AttributeMapping mapping = attributeMappings.get( attributeIndex );
|
||||
decomposeAttribute( values[attributeIndex], session, jdbcValueBindings, mapping );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( id == null ) {
|
||||
assert entityPersister().getInsertDelegate() != null;
|
||||
}
|
||||
else {
|
||||
for ( int position = 0; position < mutationGroup.getNumberOfOperations(); position++ ) {
|
||||
final MutationOperation jdbcOperation = mutationGroup.getOperation( position );
|
||||
final EntityTableMapping tableDetails = (EntityTableMapping) jdbcOperation.getTableDetails();
|
||||
breakDownJdbcValue( id, session, jdbcValueBindings, tableDetails );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void breakDownJdbcValue(
|
||||
Object id,
|
||||
SharedSessionContractImplementor session,
|
||||
JdbcValueBindings jdbcValueBindings,
|
||||
EntityTableMapping tableDetails) {
|
||||
final String tableName = tableDetails.getTableName();
|
||||
tableDetails.getKeyMapping().breakDownKeyJdbcValues(
|
||||
id,
|
||||
(jdbcValue, columnMapping) -> {
|
||||
jdbcValueBindings.bindValue(
|
||||
jdbcValue,
|
||||
tableName,
|
||||
columnMapping.getColumnName(),
|
||||
ParameterUsage.SET
|
||||
);
|
||||
},
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
protected void decomposeAttribute(
|
||||
Object value,
|
||||
SharedSessionContractImplementor session,
|
||||
JdbcValueBindings jdbcValueBindings,
|
||||
AttributeMapping mapping) {
|
||||
if ( !(mapping instanceof PluralAttributeMapping) ) {
|
||||
mapping.decompose(
|
||||
value,
|
||||
0,
|
||||
jdbcValueBindings,
|
||||
null,
|
||||
(valueIndex, bindings, noop, jdbcValue, selectableMapping) -> {
|
||||
if ( selectableMapping.isInsertable() ) {
|
||||
bindings.bindValue(
|
||||
jdbcValue,
|
||||
entityPersister().physicalTableNameForMutation( selectableMapping ),
|
||||
selectableMapping.getSelectionExpression(),
|
||||
ParameterUsage.SET
|
||||
);
|
||||
}
|
||||
},
|
||||
session
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected GeneratedValues doDynamicInserts(
|
||||
Object id,
|
||||
Object[] values,
|
||||
Object object,
|
||||
SharedSessionContractImplementor session,
|
||||
boolean forceIdentifierBinding) {
|
||||
final boolean[] insertability = getPropertiesToInsert( values );
|
||||
final MutationOperationGroup insertGroup = generateDynamicInsertSqlGroup( insertability, object, session, forceIdentifierBinding );
|
||||
|
||||
final MutationExecutor mutationExecutor = executor( session, insertGroup, true );
|
||||
|
||||
final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values );
|
||||
|
||||
final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis );
|
||||
|
||||
decomposeForInsert( mutationExecutor, id, values, insertGroup, insertability, tableInclusionChecker, session );
|
||||
|
||||
try {
|
||||
return mutationExecutor.execute(
|
||||
object,
|
||||
insertValuesAnalysis,
|
||||
tableInclusionChecker,
|
||||
(statementDetails, affectedRowCount, batchPosition) -> {
|
||||
statementDetails.getExpectation().verifyOutcome(
|
||||
affectedRowCount,
|
||||
statementDetails.getStatement(),
|
||||
batchPosition,
|
||||
statementDetails.getSqlString()
|
||||
);
|
||||
return true;
|
||||
},
|
||||
session
|
||||
);
|
||||
}
|
||||
finally {
|
||||
mutationExecutor.release();
|
||||
}
|
||||
}
|
||||
|
||||
private MutationExecutor executor(SharedSessionContractImplementor session, MutationOperationGroup group, boolean dynamicUpdate) {
|
||||
return mutationExecutorService
|
||||
.createExecutor( resolveBatchKeyAccess( dynamicUpdate, session ), group, session );
|
||||
}
|
||||
|
||||
protected static TableInclusionChecker getTableInclusionChecker(InsertValuesAnalysis insertValuesAnalysis) {
|
||||
return tableMapping -> !tableMapping.isOptional() || insertValuesAnalysis.hasNonNullBindings( tableMapping );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Transform the array of property indexes to an array of booleans,
|
||||
* true when the property is insertable and non-null
|
||||
*/
|
||||
public boolean[] getPropertiesToInsert(Object[] fields) {
|
||||
boolean[] notNull = new boolean[fields.length];
|
||||
boolean[] insertable = entityPersister().getPropertyInsertability();
|
||||
for ( int i = 0; i < fields.length; i++ ) {
|
||||
notNull[i] = insertable[i] && fields[i] != null;
|
||||
}
|
||||
return notNull;
|
||||
}
|
||||
|
||||
protected MutationOperationGroup generateDynamicInsertSqlGroup(
|
||||
boolean[] insertable,
|
||||
Object object,
|
||||
SharedSessionContractImplementor session,
|
||||
boolean forceIdentifierBinding) {
|
||||
final MutationGroupBuilder insertGroupBuilder = new MutationGroupBuilder( MutationType.INSERT, entityPersister() );
|
||||
entityPersister().forEachMutableTable(
|
||||
(tableMapping) -> insertGroupBuilder.addTableDetailsBuilder( createTableInsertBuilder( tableMapping, forceIdentifierBinding ) )
|
||||
);
|
||||
applyTableInsertDetails( insertGroupBuilder, insertable, object, session, forceIdentifierBinding );
|
||||
return createOperationGroup( null, insertGroupBuilder.buildMutationGroup() );
|
||||
}
|
||||
|
||||
public MutationOperationGroup generateStaticOperationGroup() {
|
||||
final MutationGroupBuilder insertGroupBuilder = new MutationGroupBuilder( MutationType.INSERT, entityPersister() );
|
||||
entityPersister().forEachMutableTable(
|
||||
(tableMapping) -> insertGroupBuilder.addTableDetailsBuilder( createTableInsertBuilder( tableMapping, false ) )
|
||||
);
|
||||
applyTableInsertDetails( insertGroupBuilder, entityPersister().getPropertyInsertability(), null, null, false );
|
||||
return createOperationGroup( null, insertGroupBuilder.buildMutationGroup() );
|
||||
}
|
||||
|
||||
private TableMutationBuilder<?> createTableInsertBuilder(EntityTableMapping tableMapping, boolean forceIdentifierBinding) {
|
||||
final GeneratedValuesMutationDelegate delegate = entityPersister().getInsertDelegate();
|
||||
if ( tableMapping.isIdentifierTable() && delegate != null && !forceIdentifierBinding ) {
|
||||
return delegate.createTableMutationBuilder( tableMapping.getInsertExpectation(), factory() );
|
||||
}
|
||||
else {
|
||||
return new TableInsertBuilderStandard( entityPersister(), tableMapping, factory() );
|
||||
}
|
||||
}
|
||||
|
||||
private void applyTableInsertDetails(
|
||||
MutationGroupBuilder insertGroupBuilder,
|
||||
boolean[] attributeInclusions,
|
||||
Object object,
|
||||
SharedSessionContractImplementor session,
|
||||
boolean forceIdentifierBinding) {
|
||||
final AttributeMappingsList attributeMappings = entityPersister().getAttributeMappings();
|
||||
|
||||
insertGroupBuilder.forEachTableMutationBuilder( (builder) -> {
|
||||
final EntityTableMapping tableMapping = (EntityTableMapping) builder.getMutatingTable().getTableMapping();
|
||||
assert !tableMapping.isInverse();
|
||||
|
||||
// `attributeIndexes` represents the indexes (relative to `attributeMappings`) of
|
||||
// the attributes mapped to the table
|
||||
final int[] attributeIndexes = tableMapping.getAttributeIndexes();
|
||||
for ( int i = 0; i < attributeIndexes.length; i++ ) {
|
||||
final int attributeIndex = attributeIndexes[ i ];
|
||||
final AttributeMapping attributeMapping = attributeMappings.get( attributeIndex );
|
||||
if ( attributeInclusions[attributeIndex] ) {
|
||||
attributeMapping.forEachInsertable( insertGroupBuilder );
|
||||
}
|
||||
else {
|
||||
final Generator generator = attributeMapping.getGenerator();
|
||||
if ( isValueGenerated( generator ) ) {
|
||||
if ( session != null && !generator.generatedOnExecution( object, session ) ) {
|
||||
attributeInclusions[attributeIndex] = true;
|
||||
attributeMapping.forEachInsertable( insertGroupBuilder );
|
||||
}
|
||||
else if ( isValueGenerationInSql( generator, factory().getJdbcServices().getDialect() ) ) {
|
||||
handleValueGeneration( attributeMapping, insertGroupBuilder, (OnExecutionGenerator) generator );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
// add the discriminator
|
||||
entityPersister().addDiscriminatorToInsertGroup( insertGroupBuilder );
|
||||
entityPersister().addSoftDeleteToInsertGroup( insertGroupBuilder );
|
||||
|
||||
// add the keys
|
||||
insertGroupBuilder.forEachTableMutationBuilder( (tableMutationBuilder) -> {
|
||||
final TableInsertBuilder tableInsertBuilder = (TableInsertBuilder) tableMutationBuilder;
|
||||
final EntityTableMapping tableMapping = (EntityTableMapping) tableInsertBuilder.getMutatingTable().getTableMapping();
|
||||
if ( tableMapping.isIdentifierTable() && entityPersister().isIdentifierAssignedByInsert() && !forceIdentifierBinding ) {
|
||||
assert entityPersister().getInsertDelegate() != null;
|
||||
final OnExecutionGenerator generator = (OnExecutionGenerator) entityPersister().getGenerator();
|
||||
if ( generator.referenceColumnsInSql( dialect() ) ) {
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityPersister().getIdentifierMapping();
|
||||
final String[] columnValues = generator.getReferencedColumnValues( dialect );
|
||||
tableMapping.getKeyMapping().forEachKeyColumn( (i, column) -> tableInsertBuilder.addKeyColumn(
|
||||
column.getColumnName(),
|
||||
columnValues[i],
|
||||
identifierMapping.getJdbcMapping()
|
||||
) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
tableMapping.getKeyMapping().forEachKeyColumn( tableInsertBuilder::addKeyColumn );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
private static boolean isValueGenerated(Generator generator) {
|
||||
return generator != null
|
||||
&& generator.generatesOnInsert()
|
||||
&& generator.generatedOnExecution();
|
||||
}
|
||||
|
||||
private static boolean isValueGenerationInSql(Generator generator, Dialect dialect) {
|
||||
assert isValueGenerated( generator );
|
||||
return ( (OnExecutionGenerator) generator ).referenceColumnsInSql(dialect);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getBatchKey()}
|
||||
*/
|
||||
@Deprecated
|
||||
public BasicBatchKey getInsertBatchKey() {
|
||||
return batchKey;
|
||||
}
|
||||
}
|
|
@ -11,7 +11,6 @@ import org.hibernate.persister.entity.AbstractEntityPersister;
|
|||
import org.hibernate.sql.model.MutationOperation;
|
||||
import org.hibernate.sql.model.ast.builder.AbstractTableUpdateBuilder;
|
||||
import org.hibernate.sql.model.ast.builder.TableMergeBuilder;
|
||||
import org.hibernate.sql.model.ast.builder.TableUpdateBuilder;
|
||||
|
||||
/**
|
||||
* Specialized {@link UpdateCoordinator} for {@code merge into}.
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.persister.entity.mutation;
|
||||
|
||||
import org.hibernate.sql.model.MutationOperationGroup;
|
||||
|
||||
/**
|
||||
* Coordinates the mutation operations of an entity.
|
||||
*
|
||||
* @see InsertCoordinator
|
||||
* @see DeleteCoordinator
|
||||
* @see UpdateCoordinator
|
||||
* @see MergeCoordinator
|
||||
*
|
||||
* @author Marco Belladelli
|
||||
*/
|
||||
public interface MutationCoordinator {
|
||||
/**
|
||||
* The operation group used to perform the mutation unless some form
|
||||
* of dynamic mutation is necessary.
|
||||
*/
|
||||
MutationOperationGroup getStaticMutationOperationGroup();
|
||||
}
|
|
@ -6,23 +6,24 @@
|
|||
*/
|
||||
package org.hibernate.persister.entity.mutation;
|
||||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.generator.values.GeneratedValues;
|
||||
import org.hibernate.sql.model.MutationOperationGroup;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Coordinates the updating of an entity.
|
||||
*
|
||||
* @see #coordinateUpdate
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @see #update
|
||||
*/
|
||||
@Internal
|
||||
public interface UpdateCoordinator {
|
||||
MutationOperationGroup getStaticUpdateGroup();
|
||||
|
||||
GeneratedValues coordinateUpdate(
|
||||
public interface UpdateCoordinator extends MutationCoordinator {
|
||||
/**
|
||||
* Update a persistent instance.
|
||||
*
|
||||
* @return The {@linkplain GeneratedValues generated values} if any, {@code null} otherwise.
|
||||
*/
|
||||
@Nullable GeneratedValues update(
|
||||
Object entity,
|
||||
Object id,
|
||||
Object rowId,
|
||||
|
@ -44,7 +45,7 @@ public interface UpdateCoordinator {
|
|||
Object currentVersion,
|
||||
Object nextVersion,
|
||||
boolean batching,
|
||||
SharedSessionContractImplementor session){
|
||||
SharedSessionContractImplementor session) {
|
||||
forceVersionIncrement( id, currentVersion, nextVersion, session );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,12 @@ public class UpdateCoordinatorNoOp implements UpdateCoordinator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public MutationOperationGroup getStaticUpdateGroup() {
|
||||
public MutationOperationGroup getStaticMutationOperationGroup() {
|
||||
return operationGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeneratedValues coordinateUpdate(Object entity, Object id, Object rowId, Object[] values, Object oldVersion, Object[] incomingOldValues, int[] dirtyAttributeIndexes, boolean hasDirtyCollection, SharedSessionContractImplementor session) {
|
||||
public GeneratedValues update(Object entity, Object id, Object rowId, Object[] values, Object oldVersion, Object[] incomingOldValues, int[] dirtyAttributeIndexes, boolean hasDirtyCollection, SharedSessionContractImplementor session) {
|
||||
// nothing to do
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ import static org.hibernate.internal.util.collections.ArrayHelper.trim;
|
|||
/**
|
||||
* Coordinates the updating of an entity.
|
||||
*
|
||||
* @see #coordinateUpdate
|
||||
* @see #update
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -125,7 +125,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
}
|
||||
|
||||
@Override
|
||||
public MutationOperationGroup getStaticUpdateGroup() {
|
||||
public MutationOperationGroup getStaticMutationOperationGroup() {
|
||||
return staticUpdateGroup;
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
}
|
||||
|
||||
@Override
|
||||
public GeneratedValues coordinateUpdate(
|
||||
public GeneratedValues update(
|
||||
Object entity,
|
||||
Object id,
|
||||
Object rowId,
|
||||
|
|
|
@ -408,7 +408,7 @@ public class DefaultCatalogAndSchemaTest {
|
|||
// because ID generators table/sequence names are prefixed with the owning entity name.
|
||||
|
||||
{
|
||||
final MutationOperationGroup staticSqlInsertGroup = persister.getInsertCoordinator().getStaticInsertGroup();
|
||||
final MutationOperationGroup staticSqlInsertGroup = persister.getInsertCoordinator().getStaticMutationOperationGroup();
|
||||
final String[] insertSqls = new String[staticSqlInsertGroup.getNumberOfOperations()];
|
||||
for ( int tablePosition = 0;
|
||||
tablePosition < staticSqlInsertGroup.getNumberOfOperations();
|
||||
|
@ -427,7 +427,7 @@ public class DefaultCatalogAndSchemaTest {
|
|||
}
|
||||
|
||||
{
|
||||
final MutationOperationGroup staticSqlUpdateGroup = persister.getUpdateCoordinator().getStaticUpdateGroup();
|
||||
final MutationOperationGroup staticSqlUpdateGroup = persister.getUpdateCoordinator().getStaticMutationOperationGroup();
|
||||
final String[] sqlUpdateStrings = new String[staticSqlUpdateGroup.getNumberOfOperations()];
|
||||
for ( int tablePosition = 0;
|
||||
tablePosition < staticSqlUpdateGroup.getNumberOfOperations();
|
||||
|
@ -442,7 +442,7 @@ public class DefaultCatalogAndSchemaTest {
|
|||
|
||||
|
||||
{
|
||||
final MutationOperationGroup staticDeleteGroup = persister.getDeleteCoordinator().getStaticDeleteGroup();
|
||||
final MutationOperationGroup staticDeleteGroup = persister.getDeleteCoordinator().getStaticMutationOperationGroup();
|
||||
final String[] sqlDeleteStrings = new String[staticDeleteGroup.getNumberOfOperations()];
|
||||
for ( int tablePosition = 0; tablePosition < staticDeleteGroup.getNumberOfOperations(); tablePosition++ ) {
|
||||
final MutationOperation operation = staticDeleteGroup.getOperation( tablePosition );
|
||||
|
|
|
@ -64,7 +64,10 @@ import org.hibernate.metamodel.spi.EntityRepresentationStrategy;
|
|||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.UniqueKeyEntry;
|
||||
import org.hibernate.persister.entity.mutation.DeleteCoordinator;
|
||||
import org.hibernate.persister.entity.mutation.EntityTableMapping;
|
||||
import org.hibernate.persister.entity.mutation.InsertCoordinator;
|
||||
import org.hibernate.persister.entity.mutation.UpdateCoordinator;
|
||||
import org.hibernate.persister.spi.PersisterClassResolver;
|
||||
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
|
@ -403,30 +406,17 @@ public class GoofyPersisterClassProvider implements PersisterClassResolver {
|
|||
}
|
||||
|
||||
@Override
|
||||
public GeneratedValues insertReturning(Object id, Object[] fields, Object object, SharedSessionContractImplementor session) {
|
||||
public InsertCoordinator getInsertCoordinator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeneratedValues insertReturning(Object[] fields, Object object, SharedSessionContractImplementor session) {
|
||||
public UpdateCoordinator getUpdateCoordinator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Object id, Object version, Object object, SharedSessionContractImplementor session) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeneratedValues updateReturning(
|
||||
Object id,
|
||||
Object[] fields,
|
||||
int[] dirtyFields,
|
||||
boolean hasDirtyCollection,
|
||||
Object[] oldFields,
|
||||
Object oldVersion,
|
||||
Object object,
|
||||
Object rowId,
|
||||
SharedSessionContractImplementor session) {
|
||||
public DeleteCoordinator getDeleteCoordinator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,10 @@ import org.hibernate.orm.test.jpa.SettingsGenerator;
|
|||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.UniqueKeyEntry;
|
||||
import org.hibernate.persister.entity.mutation.DeleteCoordinator;
|
||||
import org.hibernate.persister.entity.mutation.EntityTableMapping;
|
||||
import org.hibernate.persister.entity.mutation.InsertCoordinator;
|
||||
import org.hibernate.persister.entity.mutation.UpdateCoordinator;
|
||||
import org.hibernate.persister.internal.PersisterClassResolverInitiator;
|
||||
import org.hibernate.persister.spi.PersisterClassResolver;
|
||||
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||
|
@ -445,21 +448,17 @@ public class PersisterClassProviderTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
public GeneratedValues insertReturning(Object id, Object[] fields, Object object, SharedSessionContractImplementor session) {
|
||||
public InsertCoordinator getInsertCoordinator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeneratedValues insertReturning(Object[] fields, Object object, SharedSessionContractImplementor session) {
|
||||
public UpdateCoordinator getUpdateCoordinator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(Object id, Object version, Object object, SharedSessionContractImplementor session) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public GeneratedValues updateReturning(Object id, Object[] fields, int[] dirtyFields, boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object object, Object rowId, SharedSessionContractImplementor session) {
|
||||
public DeleteCoordinator getDeleteCoordinator() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,13 +60,17 @@ import org.hibernate.metamodel.model.domain.NavigableRole;
|
|||
import org.hibernate.metamodel.spi.EntityRepresentationStrategy;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.UniqueKeyEntry;
|
||||
import org.hibernate.persister.entity.mutation.DeleteCoordinator;
|
||||
import org.hibernate.persister.entity.mutation.EntityTableMapping;
|
||||
import org.hibernate.persister.entity.mutation.InsertCoordinator;
|
||||
import org.hibernate.persister.entity.mutation.UpdateCoordinator;
|
||||
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy;
|
||||
import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.model.MutationOperationGroup;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
|
@ -77,6 +81,8 @@ import org.hibernate.type.descriptor.java.StringJavaType;
|
|||
import org.hibernate.type.descriptor.jdbc.VarcharJdbcType;
|
||||
import org.hibernate.type.internal.BasicTypeImpl;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
public class CustomPersister implements EntityPersister {
|
||||
|
||||
private static final Hashtable<Object,Object> INSTANCES = new Hashtable<>();
|
||||
|
@ -503,52 +509,80 @@ public class CustomPersister implements EntityPersister {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public GeneratedValues insertReturning(
|
||||
Object id,
|
||||
Object[] fields,
|
||||
Object object,
|
||||
SharedSessionContractImplementor session
|
||||
) throws HibernateException {
|
||||
@Override
|
||||
public InsertCoordinator getInsertCoordinator() {
|
||||
return new InsertCoordinator() {
|
||||
@Override
|
||||
public @Nullable GeneratedValues insert(
|
||||
Object entity,
|
||||
Object[] values,
|
||||
SharedSessionContractImplementor session) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
INSTANCES.put(id, ( (Custom) object ).clone() );
|
||||
@Override
|
||||
public @Nullable GeneratedValues insert(
|
||||
Object entity,
|
||||
Object id,
|
||||
Object[] values,
|
||||
SharedSessionContractImplementor session) {
|
||||
INSTANCES.put( id, ( (Custom) entity ).clone() );
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
@Override
|
||||
public MutationOperationGroup getStaticMutationOperationGroup() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public GeneratedValues insertReturning(Object[] fields, Object object, SharedSessionContractImplementor session)
|
||||
throws HibernateException {
|
||||
@Override
|
||||
public UpdateCoordinator getUpdateCoordinator() {
|
||||
return new UpdateCoordinator() {
|
||||
@Override
|
||||
public @Nullable GeneratedValues update(
|
||||
Object entity,
|
||||
Object id,
|
||||
Object rowId,
|
||||
Object[] values,
|
||||
Object oldVersion,
|
||||
Object[] incomingOldValues,
|
||||
int[] dirtyAttributeIndexes,
|
||||
boolean hasDirtyCollection,
|
||||
SharedSessionContractImplementor session) {
|
||||
INSTANCES.put( id, ( (Custom) entity ).clone() );
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
@Override
|
||||
public void forceVersionIncrement(
|
||||
Object id,
|
||||
Object currentVersion,
|
||||
Object nextVersion,
|
||||
SharedSessionContractImplementor session) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutationOperationGroup getStaticMutationOperationGroup() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void delete(
|
||||
Object id,
|
||||
Object version,
|
||||
Object object,
|
||||
SharedSessionContractImplementor session
|
||||
) throws HibernateException {
|
||||
@Override
|
||||
public DeleteCoordinator getDeleteCoordinator() {
|
||||
return new DeleteCoordinator() {
|
||||
@Override
|
||||
public void delete(Object entity, Object id, Object version, SharedSessionContractImplementor session) {
|
||||
INSTANCES.remove( id );
|
||||
}
|
||||
|
||||
INSTANCES.remove(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see EntityPersister
|
||||
*/
|
||||
public GeneratedValues updateReturning(
|
||||
Object id,
|
||||
Object[] fields,
|
||||
int[] dirtyFields,
|
||||
boolean hasDirtyCollection,
|
||||
Object[] oldFields,
|
||||
Object oldVersion,
|
||||
Object object,
|
||||
Object rowId,
|
||||
SharedSessionContractImplementor session
|
||||
) throws HibernateException {
|
||||
|
||||
INSTANCES.put( id, ( (Custom) object ).clone() );
|
||||
|
||||
return null;
|
||||
@Override
|
||||
public MutationOperationGroup getStaticMutationOperationGroup() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static final BasicType<String> STRING_TYPE = new BasicTypeImpl<>(
|
||||
|
|
|
@ -50,9 +50,9 @@ public class CustomSqlSchemaResolvingIdentityTest {
|
|||
String className = CustomEntity.class.getName();
|
||||
|
||||
final AbstractEntityPersister persister = (AbstractEntityPersister) scope.getSessionFactory().getMappingMetamodel().getEntityDescriptor(className);
|
||||
String insertQuery = ( (JdbcMutationOperation) persister.getInsertCoordinator().getStaticInsertGroup().getSingleOperation() ).getSqlString();
|
||||
String updateQuery = ( (JdbcMutationOperation) persister.getUpdateCoordinator().getStaticUpdateGroup().getSingleOperation() ).getSqlString();
|
||||
String deleteQuery = ( (JdbcMutationOperation) persister.getDeleteCoordinator().getStaticDeleteGroup().getSingleOperation() ).getSqlString();
|
||||
String insertQuery = ( (JdbcMutationOperation) persister.getInsertCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString();
|
||||
String updateQuery = ( (JdbcMutationOperation) persister.getUpdateCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString();
|
||||
String deleteQuery = ( (JdbcMutationOperation) persister.getDeleteCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString();
|
||||
|
||||
assertEquals( "Incorrect custom SQL for insert in Entity: " + className,
|
||||
"INSERT INTO FOO (name) VALUES (?)", insertQuery );
|
||||
|
|
|
@ -45,9 +45,9 @@ public class CustomSqlSchemaResolvingTest {
|
|||
String className = CustomEntity.class.getName();
|
||||
|
||||
final AbstractEntityPersister persister = (AbstractEntityPersister) scope.getSessionFactory().getMappingMetamodel().getEntityDescriptor(className);
|
||||
String insertQuery = ( (JdbcMutationOperation) persister.getInsertCoordinator().getStaticInsertGroup().getSingleOperation() ).getSqlString();
|
||||
String updateQuery = ( (JdbcMutationOperation) persister.getUpdateCoordinator().getStaticUpdateGroup().getSingleOperation() ).getSqlString();
|
||||
String deleteQuery = ( (JdbcMutationOperation) persister.getDeleteCoordinator().getStaticDeleteGroup().getSingleOperation() ).getSqlString();
|
||||
String insertQuery = ( (JdbcMutationOperation) persister.getInsertCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString();
|
||||
String updateQuery = ( (JdbcMutationOperation) persister.getUpdateCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString();
|
||||
String deleteQuery = ( (JdbcMutationOperation) persister.getDeleteCoordinator().getStaticMutationOperationGroup().getSingleOperation() ).getSqlString();
|
||||
|
||||
assertEquals( "Incorrect custom SQL for insert in Entity: " + className,
|
||||
"INSERT INTO FOO (name, id) VALUES (?, ?)", insertQuery );
|
||||
|
|
Loading…
Reference in New Issue