method renamings and extract method refactorings
- couple of last-minute name changes in Generator stuff for consistency - make logic in Coordinators easier to understand by extracting lots of little methods (there were some very long methods here) - extract a couple of inner classes that didn't need to be
This commit is contained in:
parent
a49beafca4
commit
c754dfacdf
|
@ -274,7 +274,7 @@ public class TemporaryTable implements Exportable, Contributable {
|
|||
.getEntityBinding( entityDescriptor.getEntityName() );
|
||||
|
||||
final Generator identifierGenerator = entityDescriptor.getEntityPersister().getGenerator();
|
||||
final boolean identityColumn = identifierGenerator.generatedOnExecute();
|
||||
final boolean identityColumn = identifierGenerator.generatedOnExecution();
|
||||
final boolean hasOptimizer;
|
||||
if ( identityColumn ) {
|
||||
hasOptimizer = false;
|
||||
|
|
|
@ -116,7 +116,7 @@ public abstract class AbstractSaveEventListener<C>
|
|||
|
||||
final EntityPersister persister = source.getEntityPersister( entityName, entity );
|
||||
Generator generator = persister.getGenerator();
|
||||
if ( !generator.generatedOnExecute() ) {
|
||||
if ( !generator.generatedOnExecution() ) {
|
||||
final Object generatedId = ( (BeforeExecutionGenerator) generator ).generate( source, entity, null, INSERT );
|
||||
if ( generatedId == null ) {
|
||||
throw new IdentifierGenerationException( "null id generated for: " + entity.getClass() );
|
||||
|
|
|
@ -47,7 +47,7 @@ public interface BeforeExecutionGenerator extends Generator {
|
|||
Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType);
|
||||
|
||||
@Override
|
||||
default boolean generatedOnExecute() {
|
||||
default boolean generatedOnExecution() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,8 @@ import static org.hibernate.generator.EventType.UPDATE;
|
|||
*/
|
||||
public interface Generator extends Serializable {
|
||||
/**
|
||||
* Determines if the property value is generated in Java code, or by the database.
|
||||
* Determines if the property value is generated when a row is written to the database,
|
||||
* or in Java code that executes before the row is written.
|
||||
* <ul>
|
||||
* <li>Generators which only implement {@link BeforeExecutionGenerator} must result
|
||||
* {@code false}.
|
||||
|
@ -84,10 +85,11 @@ public interface Generator extends Serializable {
|
|||
* to return.
|
||||
* </ul>
|
||||
*
|
||||
* @return {@code true} if the value is generated by the database, or false if it is
|
||||
* generated in Java code.
|
||||
* @return {@code true} if the value is generated by the database as a side effect of
|
||||
* the execution of an {@code insert} or {@code update} statement, or false if
|
||||
* it is generated in Java code before the statement is executed via JDBC.
|
||||
*/
|
||||
boolean generatedOnExecute();
|
||||
boolean generatedOnExecution();
|
||||
|
||||
/**
|
||||
* The {@linkplain EventType event types} for which this generator should be called
|
||||
|
|
|
@ -142,7 +142,7 @@ public interface OnExecutionGenerator extends Generator {
|
|||
}
|
||||
|
||||
@Override
|
||||
default boolean generatedOnExecute() {
|
||||
default boolean generatedOnExecution() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ public class CurrentTimestampGeneration implements BeforeExecutionGenerator, OnE
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean generatedOnExecute() {
|
||||
public boolean generatedOnExecution() {
|
||||
return generator == null;
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
final Object id;
|
||||
final Object[] state = persister.getValues( entity );
|
||||
final Generator generator = persister.getGenerator();
|
||||
if ( !generator.generatedOnExecute() ) {
|
||||
if ( !generator.generatedOnExecution() ) {
|
||||
id = ( (BeforeExecutionGenerator) generator).generate( this, entity, null, INSERT );
|
||||
if ( persister.isVersioned() ) {
|
||||
if ( seedVersion( entity, state, persister, this ) ) {
|
||||
|
|
|
@ -654,7 +654,7 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
|
|||
|
||||
@Override
|
||||
public void execute(SharedSessionContractImplementor session, Object incomingObject, Object injectionContext) {
|
||||
if ( !subgenerator.generatedOnExecute() ) {
|
||||
if ( !subgenerator.generatedOnExecution() ) {
|
||||
Object generatedId = ( (BeforeExecutionGenerator) subgenerator).generate( session, incomingObject, null, INSERT );
|
||||
injector.set( injectionContext, generatedId );
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ public class GeneratedValuesProcessor {
|
|||
entityDescriptor.forEachAttributeMapping( mapping -> {
|
||||
final Generator generator = generators[ mapping.getStateArrayPosition() ];
|
||||
if ( generator != null
|
||||
&& generator.generatedOnExecute()
|
||||
&& generator.generatedOnExecution()
|
||||
&& generator.getEventTypes().contains(timing) ) {
|
||||
generatedValuesToSelect.add( mapping );
|
||||
}
|
||||
|
|
|
@ -628,7 +628,7 @@ public abstract class AbstractCollectionPersister
|
|||
factory.getJdbcServices().getDialect(),
|
||||
null
|
||||
);
|
||||
if ( generator.generatedOnExecute() ) {
|
||||
if ( generator.generatedOnExecution() ) {
|
||||
throw new MappingException("must be an BeforeExecutionGenerator"); //TODO fix message
|
||||
}
|
||||
if ( generator instanceof IdentifierGenerator ) {
|
||||
|
|
|
@ -150,7 +150,6 @@ import org.hibernate.mapping.Subclass;
|
|||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.metadata.ClassMetadata;
|
||||
import org.hibernate.metamodel.RepresentationMode;
|
||||
import org.hibernate.metamodel.mapping.Association;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.AttributeMetadata;
|
||||
|
@ -280,6 +279,7 @@ import static org.hibernate.engine.internal.ManagedTypeHelper.processIfSelfDirti
|
|||
import static org.hibernate.engine.internal.Versioning.isVersionIncrementRequired;
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
import static org.hibernate.generator.EventType.UPDATE;
|
||||
import static org.hibernate.metamodel.RepresentationMode.POJO;
|
||||
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
|
||||
|
||||
/**
|
||||
|
@ -870,12 +870,9 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
public String getDiscriminatorColumnReaderTemplate() {
|
||||
if ( getSubclassEntityNames().size() == 1 ) {
|
||||
return getDiscriminatorSQLValue();
|
||||
}
|
||||
else {
|
||||
return Template.TEMPLATE + "." + DISCRIMINATOR_ALIAS;
|
||||
}
|
||||
return getSubclassEntityNames().size() == 1
|
||||
? getDiscriminatorSQLValue()
|
||||
: Template.TEMPLATE + "." + DISCRIMINATOR_ALIAS;
|
||||
}
|
||||
|
||||
public String getDiscriminatorAlias() {
|
||||
|
@ -1017,11 +1014,7 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
private boolean determineCanWriteToCache(PersistentClass persistentClass, EntityDataAccess cacheAccessStrategy) {
|
||||
if ( cacheAccessStrategy == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return persistentClass.isCached();
|
||||
return cacheAccessStrategy != null && persistentClass.isCached();
|
||||
}
|
||||
|
||||
private boolean determineCanReadFromCache(PersistentClass persistentClass, EntityDataAccess cacheAccessStrategy) {
|
||||
|
@ -1576,8 +1569,8 @@ public abstract class AbstractEntityPersister
|
|||
final Serializable cachedValue = disassembledValues[lazyPropertyNumbers[j]];
|
||||
final Type lazyPropertyType = lazyPropertyTypes[j];
|
||||
final String propertyName = lazyPropertyNames[j];
|
||||
if (cachedValue == LazyPropertyInitializer.UNFETCHED_PROPERTY) {
|
||||
if (fieldName.equals(propertyName)) {
|
||||
if ( cachedValue == LazyPropertyInitializer.UNFETCHED_PROPERTY ) {
|
||||
if ( fieldName.equals(propertyName) ) {
|
||||
result = LazyPropertyInitializer.UNFETCHED_PROPERTY;
|
||||
}
|
||||
// don't try to initialize the unfetched property
|
||||
|
@ -1945,7 +1938,7 @@ public abstract class AbstractEntityPersister
|
|||
throw new AssertionFailure( "cannot force version increment on non-versioned entity" );
|
||||
}
|
||||
|
||||
if ( entityMetamodel.isVersionGeneratedOnExecute() ) {
|
||||
if ( isVersionGeneratedOnExecution() ) {
|
||||
// the difficulty here is exactly what we update in order to
|
||||
// force the version to be incremented in the db...
|
||||
throw new HibernateException( "LockMode.FORCE is currently not supported for generated version properties" );
|
||||
|
@ -2739,7 +2732,7 @@ public abstract class AbstractEntityPersister
|
|||
private static final boolean[] SINGLE_TRUE = new boolean[] { true };
|
||||
|
||||
public final boolean checkVersion(final boolean[] includeProperty) {
|
||||
return includeProperty[getVersionProperty()] || entityMetamodel.isVersionGeneratedOnExecute();
|
||||
return includeProperty[getVersionProperty()] || isVersionGeneratedOnExecution();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3947,8 +3940,7 @@ public abstract class AbstractEntityPersister
|
|||
@Override
|
||||
public boolean isVersionPropertyGenerated() {
|
||||
return isVersioned()
|
||||
&& ( getEntityMetamodel().isVersionGeneratedOnExecute()
|
||||
|| getEntityMetamodel().isVersionGeneratedBeforeExecute() );
|
||||
&& ( isVersionGeneratedOnExecution() || isVersionGeneratedBeforeExecution() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3956,9 +3948,19 @@ public abstract class AbstractEntityPersister
|
|||
return isVersioned() && getPropertyInsertability()[getVersionProperty()];
|
||||
}
|
||||
|
||||
public boolean isVersionGeneratedOnExecution() {
|
||||
final Generator strategy = getEntityMetamodel().getGenerators()[ getVersionProperty() ];
|
||||
return strategy != null && strategy.generatesSometimes() && strategy.generatedOnExecution();
|
||||
}
|
||||
|
||||
public boolean isVersionGeneratedBeforeExecution() {
|
||||
final Generator strategy = getEntityMetamodel().getGenerators()[ getVersionProperty() ];
|
||||
return strategy != null && strategy.generatesSometimes() && !strategy.generatedOnExecution();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterInitialize(Object entity, SharedSessionContractImplementor session) {
|
||||
if ( isPersistentAttributeInterceptable( entity ) && getRepresentationStrategy().getMode() == RepresentationMode.POJO ) {
|
||||
if ( isPersistentAttributeInterceptable( entity ) && getRepresentationStrategy().getMode() == POJO ) {
|
||||
final BytecodeLazyAttributeInterceptor interceptor = getEntityMetamodel().getBytecodeEnhancementMetadata()
|
||||
.extractLazyInterceptor( entity );
|
||||
assert interceptor != null;
|
||||
|
|
|
@ -29,6 +29,8 @@ import org.hibernate.sql.model.internal.MutationOperationGroupSingle;
|
|||
import org.hibernate.sql.model.internal.MutationOperationGroupStandard;
|
||||
import org.hibernate.generator.OnExecutionGenerator;
|
||||
|
||||
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
||||
|
||||
/**
|
||||
* Base support for coordinating mutations against an entity
|
||||
*
|
||||
|
@ -58,43 +60,35 @@ public abstract class AbstractMutationCoordinator {
|
|||
return factory().getJdbcServices().getDialect();
|
||||
}
|
||||
|
||||
|
||||
protected MutationOperationGroup createOperationGroup(ValuesAnalysis valuesAnalysis, MutationGroup mutationGroup) {
|
||||
if ( mutationGroup.getNumberOfTableMutations() == 0 ) {
|
||||
return new MutationOperationGroupNone( mutationGroup.getMutationType(), mutationGroup.getMutationTarget() );
|
||||
final int numberOfTableMutations = mutationGroup.getNumberOfTableMutations();
|
||||
switch ( numberOfTableMutations ) {
|
||||
case 0:
|
||||
return new MutationOperationGroupNone( mutationGroup );
|
||||
case 1: {
|
||||
final MutationOperation operation = mutationGroup.getSingleTableMutation()
|
||||
.createMutationOperation( valuesAnalysis, factory() );
|
||||
return operation == null
|
||||
? new MutationOperationGroupNone( mutationGroup )
|
||||
: new MutationOperationGroupSingle( mutationGroup, operation );
|
||||
}
|
||||
default: {
|
||||
final List<MutationOperation> operations = arrayList( numberOfTableMutations );
|
||||
mutationGroup.forEachTableMutation( (integer, tableMutation) -> {
|
||||
final MutationOperation operation = tableMutation.createMutationOperation( valuesAnalysis, factory );
|
||||
if ( operation != null ) {
|
||||
operations.add( operation );
|
||||
}
|
||||
else {
|
||||
ModelMutationLogging.MODEL_MUTATION_LOGGER.debugf(
|
||||
"Skipping table update - %s",
|
||||
tableMutation.getTableName()
|
||||
);
|
||||
}
|
||||
} );
|
||||
return new MutationOperationGroupStandard( mutationGroup.getMutationType(), entityPersister, operations );
|
||||
}
|
||||
}
|
||||
|
||||
if ( mutationGroup.getNumberOfTableMutations() == 1 ) {
|
||||
final MutationOperation operation = mutationGroup.getSingleTableMutation().createMutationOperation( valuesAnalysis, factory() );
|
||||
if ( operation == null ) {
|
||||
return new MutationOperationGroupNone( mutationGroup.getMutationType(), mutationGroup.getMutationTarget() );
|
||||
}
|
||||
return new MutationOperationGroupSingle(
|
||||
mutationGroup.getMutationType(),
|
||||
mutationGroup.getMutationTarget(),
|
||||
operation
|
||||
);
|
||||
}
|
||||
|
||||
final List<MutationOperation> operations = CollectionHelper.arrayList( mutationGroup.getNumberOfTableMutations() );
|
||||
mutationGroup.forEachTableMutation( (integer, tableMutation) -> {
|
||||
final MutationOperation operation = tableMutation.createMutationOperation( valuesAnalysis, factory );
|
||||
if ( operation != null ) {
|
||||
operations.add( operation );
|
||||
}
|
||||
else {
|
||||
ModelMutationLogging.MODEL_MUTATION_LOGGER.debugf(
|
||||
"Skipping table update - %s",
|
||||
tableMutation.getTableName()
|
||||
);
|
||||
}
|
||||
} );
|
||||
|
||||
return new MutationOperationGroupStandard(
|
||||
mutationGroup.getMutationType(),
|
||||
entityPersister,
|
||||
operations
|
||||
);
|
||||
}
|
||||
|
||||
void handleValueGeneration(
|
||||
|
|
|
@ -12,12 +12,12 @@ 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.group.PreparedStatementDetails;
|
||||
import org.hibernate.engine.jdbc.mutation.internal.ModelMutationHelper;
|
||||
import org.hibernate.engine.jdbc.mutation.spi.MutationExecutorService;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityRowIdMapping;
|
||||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
|
@ -29,6 +29,8 @@ import org.hibernate.sql.model.ast.builder.TableDeleteBuilder;
|
|||
import org.hibernate.sql.model.ast.builder.TableDeleteBuilderSkipped;
|
||||
import org.hibernate.sql.model.ast.builder.TableDeleteBuilderStandard;
|
||||
|
||||
import static org.hibernate.engine.jdbc.mutation.internal.ModelMutationHelper.identifiedResultsCheck;
|
||||
|
||||
/**
|
||||
* Coordinates the deleting of an entity.
|
||||
*
|
||||
|
@ -91,16 +93,7 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
|
|||
SharedSessionContractImplementor session) {
|
||||
final MutationOperationGroup operationGroup = generateOperationGroup( loadedState, true, session );
|
||||
|
||||
final MutationExecutorService mutationExecutorService = session
|
||||
.getFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( MutationExecutorService.class );
|
||||
|
||||
final MutationExecutor mutationExecutor = mutationExecutorService.createExecutor(
|
||||
() -> batchKey,
|
||||
operationGroup,
|
||||
session
|
||||
);
|
||||
final MutationExecutor mutationExecutor = executor( session, operationGroup );
|
||||
|
||||
operationGroup.forEachOperation( (position, mutation) -> {
|
||||
if ( mutation != null ) {
|
||||
|
@ -118,7 +111,7 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
|
|||
entity,
|
||||
null,
|
||||
null,
|
||||
(statementDetails, affectedRowCount, batchPosition) -> ModelMutationHelper.identifiedResultsCheck(
|
||||
(statementDetails, affectedRowCount, batchPosition) -> identifiedResultsCheck(
|
||||
statementDetails,
|
||||
affectedRowCount,
|
||||
batchPosition,
|
||||
|
@ -134,21 +127,70 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
|
|||
}
|
||||
}
|
||||
|
||||
private MutationExecutor executor(SharedSessionContractImplementor session, MutationOperationGroup group) {
|
||||
return session.getFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( MutationExecutorService.class )
|
||||
.createExecutor( () -> batchKey, group, session );
|
||||
}
|
||||
|
||||
protected void applyLocking(
|
||||
Object version,
|
||||
Object[] loadedState,
|
||||
MutationExecutor mutationExecutor,
|
||||
SharedSessionContractImplementor session) {
|
||||
final OptimisticLockStyle optimisticLockStyle = entityPersister().optimisticLockStyle();
|
||||
if ( optimisticLockStyle == OptimisticLockStyle.NONE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final JdbcValueBindings jdbcValueBindings = mutationExecutor.getJdbcValueBindings();
|
||||
final OptimisticLockStyle optimisticLockStyle = entityPersister().optimisticLockStyle();
|
||||
switch ( optimisticLockStyle ) {
|
||||
case VERSION:
|
||||
applyVersionLocking( version, session, jdbcValueBindings );
|
||||
break;
|
||||
case ALL:
|
||||
case DIRTY:
|
||||
applyAllOrDirtyLocking( loadedState, session, jdbcValueBindings );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( version != null
|
||||
&& optimisticLockStyle.isVersion()
|
||||
&& entityPersister().getVersionMapping() != null ) {
|
||||
private void applyAllOrDirtyLocking(
|
||||
Object[] loadedState,
|
||||
SharedSessionContractImplementor session,
|
||||
JdbcValueBindings jdbcValueBindings) {
|
||||
if ( loadedState != null ) {
|
||||
final boolean[] versionability = entityPersister().getPropertyVersionability();
|
||||
entityPersister().forEachAttributeMapping( (attributeIndex, attribute) -> {
|
||||
if ( versionability[attributeIndex] && attribute instanceof SingularAttributeMapping ) {
|
||||
final Object loadedValue = loadedState[attributeIndex];
|
||||
if (loadedValue != null) {
|
||||
attribute.breakDownJdbcValues(
|
||||
loadedValue,
|
||||
(jdbcValue, jdbcValueMapping) -> {
|
||||
if ( jdbcValue == null ) {
|
||||
// presumably the SQL was generated with `is null`
|
||||
return;
|
||||
}
|
||||
|
||||
jdbcValueBindings.bindValue(
|
||||
jdbcValue,
|
||||
entityPersister().getAttributeMutationTableName( attributeIndex ),
|
||||
jdbcValueMapping.getSelectionExpression(),
|
||||
ParameterUsage.RESTRICT,
|
||||
session
|
||||
);
|
||||
},
|
||||
session
|
||||
);
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
private void applyVersionLocking(
|
||||
Object version,
|
||||
SharedSessionContractImplementor session,
|
||||
JdbcValueBindings jdbcValueBindings) {
|
||||
if ( version != null && entityPersister().getVersionMapping() != null ) {
|
||||
jdbcValueBindings.bindValue(
|
||||
version,
|
||||
entityPersister().getIdentifierTableMapping().getTableName(),
|
||||
|
@ -156,52 +198,6 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
|
|||
ParameterUsage.RESTRICT,
|
||||
session
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ( loadedState == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( optimisticLockStyle.isAllOrDirty() ) {
|
||||
final boolean[] versionability = entityPersister().getPropertyVersionability();
|
||||
|
||||
entityPersister().forEachAttributeMapping( (attributeIndex, attribute) -> {
|
||||
if ( ! versionability[attributeIndex] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !( attribute instanceof SingularAttributeMapping ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Object loadedValue = loadedState[ attributeIndex ];
|
||||
if ( loadedValue == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
attribute.breakDownJdbcValues(
|
||||
loadedValue,
|
||||
(jdbcValue, jdbcValueMapping) -> {
|
||||
if ( jdbcValue == null ) {
|
||||
// presumably the SQL was generated with `is null`
|
||||
return;
|
||||
}
|
||||
|
||||
final String physicalTableName = entityPersister().getAttributeMutationTableName( attributeIndex );
|
||||
|
||||
jdbcValueBindings.bindValue(
|
||||
jdbcValue,
|
||||
physicalTableName,
|
||||
jdbcValueMapping.getSelectionExpression(),
|
||||
ParameterUsage.RESTRICT,
|
||||
session
|
||||
);
|
||||
},
|
||||
session
|
||||
);
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -216,31 +212,7 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
|
|||
|
||||
operationGroup.forEachOperation( (position, jdbcMutation) -> {
|
||||
final EntityTableMapping tableDetails = (EntityTableMapping) jdbcMutation.getTableDetails();
|
||||
if ( rowId != null
|
||||
&& rowIdMapping != null
|
||||
&& tableDetails.isIdentifierTable() ) {
|
||||
jdbcValueBindings.bindValue(
|
||||
rowId,
|
||||
tableDetails.getTableName(),
|
||||
rowIdMapping.getRowIdName(),
|
||||
ParameterUsage.RESTRICT,
|
||||
session
|
||||
);
|
||||
}
|
||||
else {
|
||||
tableDetails.getKeyMapping().breakDownKeyJdbcValues(
|
||||
id,
|
||||
(jdbcValue, columnMapping) -> jdbcValueBindings.bindValue(
|
||||
jdbcValue,
|
||||
tableDetails.getTableName(),
|
||||
columnMapping.getColumnName(),
|
||||
ParameterUsage.RESTRICT,
|
||||
session
|
||||
),
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
breakDownIdJdbcValues( id, rowId, session, jdbcValueBindings, rowIdMapping, tableDetails );
|
||||
final PreparedStatementDetails statementDetails = mutationExecutor.getPreparedStatementDetails( tableDetails.getTableName() );
|
||||
if ( statementDetails != null ) {
|
||||
// force creation of the PreparedStatement
|
||||
|
@ -250,16 +222,43 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
|
|||
} );
|
||||
}
|
||||
|
||||
private static void breakDownIdJdbcValues(
|
||||
Object id,
|
||||
Object rowId,
|
||||
SharedSessionContractImplementor session,
|
||||
JdbcValueBindings jdbcValueBindings,
|
||||
EntityRowIdMapping rowIdMapping,
|
||||
EntityTableMapping tableDetails) {
|
||||
if ( rowId != null && rowIdMapping != null && tableDetails.isIdentifierTable() ) {
|
||||
jdbcValueBindings.bindValue(
|
||||
rowId,
|
||||
tableDetails.getTableName(),
|
||||
rowIdMapping.getRowIdName(),
|
||||
ParameterUsage.RESTRICT,
|
||||
session
|
||||
);
|
||||
}
|
||||
else {
|
||||
tableDetails.getKeyMapping().breakDownKeyJdbcValues(
|
||||
id,
|
||||
(jdbcValue, columnMapping) -> jdbcValueBindings.bindValue(
|
||||
jdbcValue,
|
||||
tableDetails.getTableName(),
|
||||
columnMapping.getColumnName(),
|
||||
ParameterUsage.RESTRICT,
|
||||
session
|
||||
),
|
||||
session
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected void doStaticDelete(
|
||||
Object entity,
|
||||
Object id,
|
||||
Object[] loadedState,
|
||||
Object version,
|
||||
SharedSessionContractImplementor session) {
|
||||
final MutationExecutorService mutationExecutorService = session
|
||||
.getFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( MutationExecutorService.class );
|
||||
|
||||
final boolean applyVersion;
|
||||
final MutationOperationGroup operationGroupToUse;
|
||||
|
@ -272,16 +271,11 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
|
|||
operationGroupToUse = staticOperationGroup;
|
||||
}
|
||||
|
||||
final MutationExecutor mutationExecutor = mutationExecutorService.createExecutor(
|
||||
() -> batchKey,
|
||||
operationGroupToUse,
|
||||
session
|
||||
);
|
||||
final MutationExecutor mutationExecutor = executor( session, operationGroupToUse );
|
||||
|
||||
staticOperationGroup.forEachOperation( (position, mutation) -> {
|
||||
if ( mutation != null ) {
|
||||
final String tableName = mutation.getTableDetails().getTableName();
|
||||
mutationExecutor.getPreparedStatementDetails( tableName );
|
||||
mutationExecutor.getPreparedStatementDetails( mutation.getTableDetails().getTableName() );
|
||||
}
|
||||
} );
|
||||
|
||||
|
@ -298,7 +292,7 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
|
|||
entity,
|
||||
null,
|
||||
null,
|
||||
(statementDetails, affectedRowCount, batchPosition) -> ModelMutationHelper.identifiedResultsCheck(
|
||||
(statementDetails, affectedRowCount, batchPosition) -> identifiedResultsCheck(
|
||||
statementDetails,
|
||||
affectedRowCount,
|
||||
batchPosition,
|
||||
|
@ -327,19 +321,9 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
|
|||
final MutationGroupBuilder deleteGroupBuilder = new MutationGroupBuilder( MutationType.DELETE, entityPersister() );
|
||||
|
||||
entityPersister().forEachMutableTableReverse( (tableMapping) -> {
|
||||
|
||||
final TableDeleteBuilder tableDeleteBuilder;
|
||||
if ( tableMapping.isCascadeDeleteEnabled() ) {
|
||||
tableDeleteBuilder = new TableDeleteBuilderSkipped( tableMapping );
|
||||
}
|
||||
else {
|
||||
tableDeleteBuilder = new TableDeleteBuilderStandard(
|
||||
entityPersister(),
|
||||
tableMapping,
|
||||
factory()
|
||||
);
|
||||
|
||||
}
|
||||
final TableDeleteBuilder tableDeleteBuilder = tableMapping.isCascadeDeleteEnabled()
|
||||
? new TableDeleteBuilderSkipped( tableMapping )
|
||||
: new TableDeleteBuilderStandard( entityPersister(), tableMapping, factory() );
|
||||
deleteGroupBuilder.addTableDetailsBuilder( tableDeleteBuilder );
|
||||
} );
|
||||
|
||||
|
@ -354,16 +338,10 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
|
|||
boolean applyVersion,
|
||||
SharedSessionContractImplementor session) {
|
||||
// first, the table key column(s)
|
||||
deleteGroupBuilder.forEachTableMutationBuilder( (tableMutationBuilder) -> {
|
||||
final TableDeleteBuilder tableDeleteBuilder = (TableDeleteBuilder) tableMutationBuilder;
|
||||
|
||||
final EntityTableMapping tableMapping = (EntityTableMapping) tableDeleteBuilder.getMutatingTable().getTableMapping();
|
||||
final EntityTableMapping.KeyMapping keyMapping = tableMapping.getKeyMapping();
|
||||
keyMapping.forEachKeyColumn( (columnMapping) -> tableDeleteBuilder.addKeyRestriction(
|
||||
columnMapping.getColumnName(),
|
||||
columnMapping.getWriteExpression(),
|
||||
columnMapping.getJdbcMapping()
|
||||
) );
|
||||
deleteGroupBuilder.forEachTableMutationBuilder( (builder) -> {
|
||||
final EntityTableMapping tableMapping = (EntityTableMapping) builder.getMutatingTable().getTableMapping();
|
||||
final TableDeleteBuilder tableDeleteBuilder = (TableDeleteBuilder) builder;
|
||||
applyKeyDetails( tableDeleteBuilder, tableMapping );
|
||||
} );
|
||||
|
||||
if ( applyVersion ) {
|
||||
|
@ -386,6 +364,16 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
|
|||
// todo (6.2) : apply where + where-fragments
|
||||
}
|
||||
|
||||
private static void applyKeyDetails(TableDeleteBuilder tableDeleteBuilder, EntityTableMapping tableMapping) {
|
||||
tableMapping.getKeyMapping().forEachKeyColumn(
|
||||
(columnMapping) -> tableDeleteBuilder.addKeyRestriction(
|
||||
columnMapping.getColumnName(),
|
||||
columnMapping.getWriteExpression(),
|
||||
columnMapping.getJdbcMapping()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
protected void applyOptimisticLocking(
|
||||
MutationGroupBuilder mutationGroupBuilder,
|
||||
Object[] loadedState,
|
||||
|
@ -424,38 +412,37 @@ public class DeleteCoordinator extends AbstractMutationCoordinator {
|
|||
assert session != null;
|
||||
|
||||
final boolean[] versionability = entityPersister().getPropertyVersionability();
|
||||
|
||||
entityPersister().forEachAttributeMapping( (attributeIndex, attribute) -> {
|
||||
if ( ! versionability[attributeIndex] ) {
|
||||
// the attribute is excluded from optimistic locking
|
||||
return;
|
||||
// only makes sense to lock on singular attributes which are not excluded from optimistic locking
|
||||
if ( versionability[attributeIndex] && attribute instanceof SingularAttributeMapping ) {
|
||||
breakDownJdbcValues( mutationGroupBuilder, session, attribute, loadedState[attributeIndex] );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
if ( !( attribute instanceof SingularAttributeMapping ) ) {
|
||||
// only makes sense to lock on singular attributes
|
||||
return;
|
||||
}
|
||||
|
||||
final Object loadedValue = loadedState[ attributeIndex ];
|
||||
attribute.breakDownJdbcValues(
|
||||
loadedValue,
|
||||
(jdbcValue, columnMapping) -> {
|
||||
final String physicalTableName = entityPersister().physicalTableNameForMutation( columnMapping );
|
||||
final RestrictedTableMutationBuilder<?,?> tableMutationBuilder = mutationGroupBuilder.findTableDetailsBuilder( physicalTableName );
|
||||
if ( tableMutationBuilder == null ) {
|
||||
// there is no actual delete statement for that table. this
|
||||
// generally indicates we have an on-delete=cascade situation
|
||||
return;
|
||||
}
|
||||
if ( jdbcValue == null ) {
|
||||
private void breakDownJdbcValues(
|
||||
MutationGroupBuilder mutationGroupBuilder,
|
||||
SharedSessionContractImplementor session,
|
||||
AttributeMapping attribute,
|
||||
Object loadedValue) {
|
||||
attribute.breakDownJdbcValues(
|
||||
loadedValue,
|
||||
(jdbcValue, columnMapping) -> {
|
||||
final String physicalTableName = entityPersister().physicalTableNameForMutation( columnMapping );
|
||||
final RestrictedTableMutationBuilder<?, ?> tableMutationBuilder =
|
||||
mutationGroupBuilder.findTableDetailsBuilder( physicalTableName );
|
||||
if ( tableMutationBuilder != null ) {
|
||||
if (jdbcValue == null) {
|
||||
tableMutationBuilder.addNullOptimisticLockRestriction( columnMapping );
|
||||
}
|
||||
else {
|
||||
tableMutationBuilder.addOptimisticLockRestriction( columnMapping );
|
||||
}
|
||||
},
|
||||
session
|
||||
);
|
||||
} );
|
||||
}
|
||||
// else there is no actual delete statement for that table,
|
||||
// generally indicates we have an on-delete=cascade situation
|
||||
},
|
||||
session
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
|||
import org.hibernate.engine.jdbc.mutation.spi.MutationExecutorService;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.generator.EventType;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
|
@ -38,6 +37,8 @@ import org.hibernate.generator.OnExecutionGenerator;
|
|||
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
|
||||
/**
|
||||
* Coordinates the insertion of an entity.
|
||||
*
|
||||
|
@ -111,9 +112,9 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
for ( int i = 0; i < generators.length; i++ ) {
|
||||
final Generator generator = generators[i];
|
||||
if ( generator != null
|
||||
&& !generator.generatedOnExecute()
|
||||
&& !generator.generatedOnExecution()
|
||||
&& generator.generatesOnInsert() ) {
|
||||
values[i] = ( (BeforeExecutionGenerator) generator ).generate( session, entity, values[i], EventType.INSERT );
|
||||
values[i] = ( (BeforeExecutionGenerator) generator ).generate( session, entity, values[i], INSERT );
|
||||
entityPersister().setPropertyValue( entity, i, values[i] );
|
||||
}
|
||||
}
|
||||
|
@ -145,15 +146,7 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
|
||||
final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis );
|
||||
|
||||
final MutationExecutorService mutationExecutorService = session.getSessionFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( MutationExecutorService.class );
|
||||
|
||||
final MutationExecutor mutationExecutor = mutationExecutorService.createExecutor(
|
||||
() -> insertBatchKey,
|
||||
staticInsertGroup,
|
||||
session
|
||||
);
|
||||
final MutationExecutor mutationExecutor = executor( session, staticInsertGroup );
|
||||
|
||||
decomposeForInsert(
|
||||
mutationExecutor,
|
||||
|
@ -197,85 +190,79 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
SharedSessionContractImplementor session) {
|
||||
final JdbcValueBindings jdbcValueBindings = mutationExecutor.getJdbcValueBindings();
|
||||
|
||||
final AttributeMappingsList attributeMappings = entityPersister().getAttributeMappings();
|
||||
mutationGroup.forEachOperation( (position, operation) -> {
|
||||
final EntityTableMapping tableDetails = (EntityTableMapping) operation.getTableDetails();
|
||||
|
||||
if ( !tableInclusionChecker.include( tableDetails ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int[] attributeIndexes = tableDetails.getAttributeIndexes();
|
||||
for ( int i = 0; i < attributeIndexes.length; i++ ) {
|
||||
final int attributeIndex = attributeIndexes[ i ];
|
||||
|
||||
if ( !propertyInclusions[attributeIndex] ) {
|
||||
continue;
|
||||
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 = entityPersister().getAttributeMappings().get( attributeIndex );
|
||||
decomposeAttribute( values[attributeIndex], session, jdbcValueBindings, mapping );
|
||||
}
|
||||
}
|
||||
|
||||
final AttributeMapping attributeMapping = attributeMappings.get( attributeIndex );
|
||||
if ( attributeMapping instanceof PluralAttributeMapping ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
attributeMapping.decompose(
|
||||
values[ attributeIndex ],
|
||||
(jdbcValue, selectableMapping) -> {
|
||||
if ( !selectableMapping.isInsertable() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
final String tableName = entityPersister().physicalTableNameForMutation( selectableMapping );
|
||||
jdbcValueBindings.bindValue(
|
||||
jdbcValue,
|
||||
tableName,
|
||||
selectableMapping.getSelectionExpression(),
|
||||
ParameterUsage.SET,
|
||||
session
|
||||
);
|
||||
},
|
||||
session
|
||||
);
|
||||
}
|
||||
} );
|
||||
|
||||
mutationGroup.forEachOperation( (position, jdbcOperation) -> {
|
||||
final EntityTableMapping tableDetails = (EntityTableMapping) jdbcOperation.getTableDetails();
|
||||
|
||||
final String tableName = tableDetails.getTableName();
|
||||
|
||||
if ( id == null ) {
|
||||
assert entityPersister().getIdentityInsertDelegate() != null;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
final EntityTableMapping tableDetails = (EntityTableMapping) jdbcOperation.getTableDetails();
|
||||
breakDownJdbcValue( id, session, jdbcValueBindings, tableDetails );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
tableDetails.getKeyMapping().breakDownKeyJdbcValues(
|
||||
id,
|
||||
(jdbcValue, columnMapping) -> jdbcValueBindings.bindValue(
|
||||
jdbcValue,
|
||||
tableName,
|
||||
columnMapping.getColumnName(),
|
||||
ParameterUsage.SET,
|
||||
session
|
||||
),
|
||||
private static 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
|
||||
),
|
||||
session
|
||||
);
|
||||
}
|
||||
|
||||
private void decomposeAttribute(
|
||||
Object value,
|
||||
SharedSessionContractImplementor session,
|
||||
JdbcValueBindings jdbcValueBindings,
|
||||
AttributeMapping mapping) {
|
||||
if ( !(mapping instanceof PluralAttributeMapping) ) {
|
||||
mapping.decompose(
|
||||
value,
|
||||
(jdbcValue, selectableMapping) -> {
|
||||
if ( selectableMapping.isInsertable() ) {
|
||||
jdbcValueBindings.bindValue(
|
||||
jdbcValue,
|
||||
entityPersister().physicalTableNameForMutation( selectableMapping ),
|
||||
selectableMapping.getSelectionExpression(),
|
||||
ParameterUsage.SET,
|
||||
session
|
||||
);
|
||||
}
|
||||
},
|
||||
session
|
||||
);
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
protected Object doDynamicInserts(Object id, Object[] values, Object object, SharedSessionContractImplementor session) {
|
||||
final boolean[] insertability = getPropertiesToInsert( values );
|
||||
final MutationOperationGroup insertGroup = generateDynamicInsertSqlGroup( insertability );
|
||||
|
||||
final MutationExecutorService mutationExecutorService = session
|
||||
.getFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( MutationExecutorService.class );
|
||||
final MutationExecutor mutationExecutor = mutationExecutorService.createExecutor(
|
||||
() -> insertBatchKey,
|
||||
insertGroup,
|
||||
session
|
||||
);
|
||||
final MutationExecutor mutationExecutor = executor( session, insertGroup );
|
||||
|
||||
final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values );
|
||||
|
||||
|
@ -305,6 +292,13 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
}
|
||||
}
|
||||
|
||||
private MutationExecutor executor(SharedSessionContractImplementor session, MutationOperationGroup insertGroup) {
|
||||
return session.getFactory()
|
||||
.getServiceRegistry()
|
||||
.getService( MutationExecutorService.class )
|
||||
.createExecutor( () -> insertBatchKey, insertGroup, session );
|
||||
}
|
||||
|
||||
protected static TableInclusionChecker getTableInclusionChecker(InsertValuesAnalysis insertValuesAnalysis) {
|
||||
return tableMapping -> !tableMapping.isOptional() || insertValuesAnalysis.hasNonNullBindings( tableMapping );
|
||||
}
|
||||
|
@ -325,63 +319,35 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
|
||||
protected MutationOperationGroup generateDynamicInsertSqlGroup(boolean[] insertable) {
|
||||
assert entityPersister().getEntityMetamodel().isDynamicInsert();
|
||||
|
||||
final MutationGroupBuilder insertGroupBuilder = new MutationGroupBuilder( MutationType.INSERT, entityPersister() );
|
||||
|
||||
entityPersister().forEachMutableTable( (tableMapping) -> {
|
||||
final TableInsertBuilder tableInsertBuilder;
|
||||
final InsertGeneratedIdentifierDelegate identityDelegate = entityPersister().getIdentityInsertDelegate();
|
||||
if ( tableMapping.isIdentifierTable() && identityDelegate != null ) {
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityPersister().getIdentifierMapping();
|
||||
tableInsertBuilder = identityDelegate.createTableInsertBuilder(
|
||||
identifierMapping,
|
||||
tableMapping.getInsertExpectation(),
|
||||
factory()
|
||||
);
|
||||
}
|
||||
else {
|
||||
tableInsertBuilder = new TableInsertBuilderStandard(
|
||||
entityPersister(),
|
||||
tableMapping,
|
||||
factory()
|
||||
);
|
||||
}
|
||||
insertGroupBuilder.addTableDetailsBuilder( tableInsertBuilder );
|
||||
} );
|
||||
|
||||
entityPersister().forEachMutableTable(
|
||||
(tableMapping) -> insertGroupBuilder.addTableDetailsBuilder( createTableInsertBuilder( tableMapping ) )
|
||||
);
|
||||
applyTableInsertDetails( insertGroupBuilder, insertable );
|
||||
|
||||
return createOperationGroup( null, insertGroupBuilder.buildMutationGroup() );
|
||||
}
|
||||
|
||||
public MutationOperationGroup generateStaticOperationGroup() {
|
||||
final MutationGroupBuilder insertGroupBuilder = new MutationGroupBuilder( MutationType.INSERT, entityPersister() );
|
||||
|
||||
entityPersister().forEachMutableTable( (tableMapping) -> {
|
||||
final TableInsertBuilder tableInsertBuilder;
|
||||
final InsertGeneratedIdentifierDelegate identityDelegate = entityPersister().getIdentityInsertDelegate();
|
||||
if ( tableMapping.isIdentifierTable() && identityDelegate != null ) {
|
||||
tableInsertBuilder = identityDelegate.createTableInsertBuilder(
|
||||
(BasicEntityIdentifierMapping) entityPersister().getIdentifierMapping(),
|
||||
tableMapping.getInsertExpectation(),
|
||||
factory()
|
||||
);
|
||||
}
|
||||
else {
|
||||
tableInsertBuilder = new TableInsertBuilderStandard(
|
||||
entityPersister(),
|
||||
tableMapping,
|
||||
factory()
|
||||
);
|
||||
}
|
||||
insertGroupBuilder.addTableDetailsBuilder( tableInsertBuilder );
|
||||
} );
|
||||
|
||||
entityPersister().forEachMutableTable(
|
||||
(tableMapping) -> insertGroupBuilder.addTableDetailsBuilder( createTableInsertBuilder( tableMapping ) )
|
||||
);
|
||||
applyTableInsertDetails( insertGroupBuilder, entityPersister().getPropertyInsertability() );
|
||||
|
||||
return createOperationGroup( null, insertGroupBuilder.buildMutationGroup() );
|
||||
}
|
||||
|
||||
private TableInsertBuilder createTableInsertBuilder(EntityTableMapping tableMapping) {
|
||||
final InsertGeneratedIdentifierDelegate identityDelegate = entityPersister().getIdentityInsertDelegate();
|
||||
if ( tableMapping.isIdentifierTable() && identityDelegate != null ) {
|
||||
final BasicEntityIdentifierMapping mapping =
|
||||
(BasicEntityIdentifierMapping) entityPersister().getIdentifierMapping();
|
||||
return identityDelegate.createTableInsertBuilder( mapping, tableMapping.getInsertExpectation(), factory() );
|
||||
}
|
||||
else {
|
||||
return new TableInsertBuilderStandard( entityPersister(), tableMapping, factory() );
|
||||
}
|
||||
}
|
||||
|
||||
private void applyTableInsertDetails(
|
||||
MutationGroupBuilder insertGroupBuilder,
|
||||
boolean[] attributeInclusions) {
|
||||
|
@ -397,16 +363,15 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
for ( int i = 0; i < attributeIndexes.length; i++ ) {
|
||||
final int attributeIndex = attributeIndexes[ i ];
|
||||
final AttributeMapping attributeMapping = attributeMappings.get( attributeIndex );
|
||||
|
||||
if ( !attributeInclusions[ attributeIndex ] ) {
|
||||
if ( attributeInclusions[attributeIndex] ) {
|
||||
attributeMapping.forEachInsertable( insertGroupBuilder );
|
||||
}
|
||||
else {
|
||||
final Generator generator = attributeMapping.getGenerator();
|
||||
if ( isValueGenerationInSql( generator, factory().getJdbcServices().getDialect()) ) {
|
||||
if ( isValueGenerationInSql( generator, factory().getJdbcServices().getDialect() ) ) {
|
||||
handleValueGeneration( attributeMapping, insertGroupBuilder, (OnExecutionGenerator) generator );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
attributeMapping.forEachInsertable( insertGroupBuilder );
|
||||
}
|
||||
} );
|
||||
|
||||
|
@ -431,7 +396,7 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
private static boolean isValueGenerationInSql(Generator generator, Dialect dialect) {
|
||||
return generator != null
|
||||
&& generator.generatesOnInsert()
|
||||
&& generator.generatedOnExecute()
|
||||
&& generator.generatedOnExecution()
|
||||
&& ( (OnExecutionGenerator) generator ).referenceColumnsInSql(dialect);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -272,7 +272,7 @@ public class CteInsertHandler implements InsertHandler {
|
|||
rowNumberColumn
|
||||
);
|
||||
}
|
||||
if ( !assignsId && entityDescriptor.getGenerator().generatedOnExecute() ) {
|
||||
if ( !assignsId && entityDescriptor.getGenerator().generatedOnExecution() ) {
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
1,
|
||||
|
@ -336,7 +336,7 @@ public class CteInsertHandler implements InsertHandler {
|
|||
processingStateStack.push( oldState );
|
||||
sqmConverter.pruneTableGroupJoins();
|
||||
|
||||
if ( !assignsId && entityDescriptor.getGenerator().generatedOnExecute() ) {
|
||||
if ( !assignsId && entityDescriptor.getGenerator().generatedOnExecution() ) {
|
||||
// Add the row number to the assignments
|
||||
final CteColumn rowNumberColumn = cteTable.getCteColumns()
|
||||
.get( cteTable.getCteColumns().size() - 1 );
|
||||
|
@ -580,7 +580,7 @@ public class CteInsertHandler implements InsertHandler {
|
|||
statement.addCteStatement( entityCte );
|
||||
}
|
||||
}
|
||||
else if ( !assignsId && entityDescriptor.getGenerator().generatedOnExecute() ) {
|
||||
else if ( !assignsId && entityDescriptor.getGenerator().generatedOnExecution() ) {
|
||||
final String baseTableName = "base_" + entityCteTable.getTableExpression();
|
||||
final CteStatement baseEntityCte = new CteStatement(
|
||||
entityCteTable.withName( baseTableName ),
|
||||
|
@ -777,7 +777,7 @@ public class CteInsertHandler implements InsertHandler {
|
|||
final Generator identifierGenerator = entityDescriptor.getEntityPersister().getGenerator();
|
||||
final List<Map.Entry<List<CteColumn>, Assignment>> tableAssignments = assignmentsByTable.get( rootTableReference );
|
||||
if ( ( tableAssignments == null || tableAssignments.isEmpty() )
|
||||
&& !identifierGenerator.generatedOnExecute() ) {
|
||||
&& !identifierGenerator.generatedOnExecution() ) {
|
||||
throw new IllegalStateException( "There must be at least a single root table assignment" );
|
||||
}
|
||||
|
||||
|
@ -805,7 +805,7 @@ public class CteInsertHandler implements InsertHandler {
|
|||
final QuerySpec insertSelectSpec = new QuerySpec( true );
|
||||
CteStatement finalCteStatement = null;
|
||||
final CteTable dmlResultCte;
|
||||
if ( i == 0 && !assignsId && identifierGenerator.generatedOnExecute() ) {
|
||||
if ( i == 0 && !assignsId && identifierGenerator.generatedOnExecution() ) {
|
||||
// Special handling for identity generation
|
||||
final String cteTableName = getCteTableName( tableExpression, "base_" );
|
||||
if ( statement.getCteStatement( cteTableName ) != null ) {
|
||||
|
@ -1074,7 +1074,7 @@ public class CteInsertHandler implements InsertHandler {
|
|||
if ( finalCteStatement != null ) {
|
||||
statement.addCteStatement( finalCteStatement );
|
||||
}
|
||||
if ( i == 0 && !assignsId && identifierGenerator.generatedOnExecute() ) {
|
||||
if ( i == 0 && !assignsId && identifierGenerator.generatedOnExecution() ) {
|
||||
// Special handling for identity generation
|
||||
statement.addCteStatement( queryCte );
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import org.hibernate.internal.util.collections.ArrayHelper;
|
|||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressible;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
|
@ -79,6 +80,8 @@ import org.hibernate.generator.OnExecutionGenerator;
|
|||
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||
import org.hibernate.type.descriptor.ValueBinder;
|
||||
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
* @author Steve Ebersole
|
||||
|
@ -178,7 +181,6 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
if ( assignmentTableReference != null && assignmentTableReference != tableReference ) {
|
||||
throw new SemanticException( "Assignment referred to columns from multiple tables: " + i );
|
||||
}
|
||||
|
||||
assignmentTableReference = tableReference;
|
||||
}
|
||||
|
||||
|
@ -308,7 +310,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
final Generator generator = entityPersister.getGenerator();
|
||||
final List<Assignment> assignments = assignmentsByTable.get( updatingTableReference );
|
||||
if ( ( assignments == null || assignments.isEmpty() )
|
||||
&& !generator.generatedOnExecute()
|
||||
&& !generator.generatedOnExecution()
|
||||
&& ( !( generator instanceof BulkInsertionCapableIdentifierGenerator )
|
||||
|| ( (BulkInsertionCapableIdentifierGenerator) generator ).supportsBulkInsertionIdentifierGeneration() ) ) {
|
||||
throw new IllegalStateException( "There must be at least a single root table assignment" );
|
||||
|
@ -335,8 +337,9 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
insertStatement.setSourceSelectStatement( querySpec );
|
||||
if ( assignments != null ) {
|
||||
for ( Assignment assignment : assignments ) {
|
||||
insertStatement.addTargetColumnReferences( assignment.getAssignable().getColumnReferences() );
|
||||
for ( ColumnReference columnReference : assignment.getAssignable().getColumnReferences() ) {
|
||||
final Assignable assignable = assignment.getAssignable();
|
||||
insertStatement.addTargetColumnReferences( assignable.getColumnReferences() );
|
||||
for ( ColumnReference columnReference : assignable.getColumnReferences() ) {
|
||||
querySpec.getSelectClause().addSqlSelection(
|
||||
new SqlSelectionImpl(
|
||||
1,
|
||||
|
@ -356,8 +359,10 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
}
|
||||
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
|
||||
final Map<Object, Object> entityTableToRootIdentity;
|
||||
if ( generator.generatedOnExecute() ) {
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
final SharedSessionContractImplementor session = executionContext.getSession();
|
||||
if ( generator.generatedOnExecution() ) {
|
||||
final BasicEntityIdentifierMapping identifierMapping =
|
||||
(BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
final QuerySpec idSelectQuerySpec = new QuerySpec( true );
|
||||
idSelectQuerySpec.getFromClause().addRoot( temporaryTableGroup );
|
||||
final ColumnReference columnReference = new ColumnReference(
|
||||
|
@ -368,7 +373,8 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
null,
|
||||
identifierMapping.getJdbcMapping()
|
||||
);
|
||||
idSelectQuerySpec.getSelectClause().addSqlSelection( new SqlSelectionImpl( 1, 0, columnReference ) );
|
||||
idSelectQuerySpec.getSelectClause()
|
||||
.addSqlSelection( new SqlSelectionImpl( 1, 0, columnReference ) );
|
||||
idSelectQuerySpec.addSortSpecification(
|
||||
new SortSpecification(
|
||||
columnReference,
|
||||
|
@ -420,21 +426,13 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
if ( needsIdentifierGeneration( generator )
|
||||
&& insertStatement.getTargetColumns().stream()
|
||||
.noneMatch( c -> keyColumns[0].equals( c.getColumnExpression() ) ) ) {
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
|
||||
final BasicEntityIdentifierMapping identifierMapping =
|
||||
(BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
final JdbcParameter rowNumber = new JdbcParameterImpl( identifierMapping.getJdbcMapping() );
|
||||
final JdbcParameter rootIdentity = new JdbcParameterImpl( identifierMapping.getJdbcMapping() );
|
||||
final List<Assignment> temporaryTableAssignments = new ArrayList<>( 1 );
|
||||
final ColumnReference idColumnReference = new ColumnReference(
|
||||
(String) null,
|
||||
identifierMapping
|
||||
);
|
||||
temporaryTableAssignments.add(
|
||||
new Assignment(
|
||||
idColumnReference,
|
||||
rootIdentity
|
||||
)
|
||||
);
|
||||
final ColumnReference idColumnReference = new ColumnReference( (String) null, identifierMapping );
|
||||
temporaryTableAssignments.add( new Assignment( idColumnReference, rootIdentity ) );
|
||||
final TemporaryTableColumn rowNumberColumn;
|
||||
final TemporaryTableColumn sessionUidColumn;
|
||||
final Predicate sessionUidPredicate;
|
||||
|
@ -493,11 +491,12 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
sessionUidParameter,
|
||||
new JdbcParameterBindingImpl(
|
||||
sessionUidColumn.getJdbcMapping(),
|
||||
UUID.fromString( sessionUidAccess.apply( executionContext.getSession() ) )
|
||||
UUID.fromString( sessionUidAccess.apply(session) )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
final BeforeExecutionGenerator beforeExecutionGenerator = (BeforeExecutionGenerator) generator;
|
||||
for ( int i = 0; i < rows; i++ ) {
|
||||
updateBindings.addBinding(
|
||||
rowNumber,
|
||||
|
@ -510,18 +509,17 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
rootIdentity,
|
||||
new JdbcParameterBindingImpl(
|
||||
identifierMapping.getJdbcMapping(),
|
||||
( (BeforeExecutionGenerator) generator ).generate( executionContext.getSession(), null, null, EventType.INSERT )
|
||||
beforeExecutionGenerator.generate( session, null, null, INSERT )
|
||||
)
|
||||
);
|
||||
jdbcServices.getJdbcMutationExecutor().execute(
|
||||
jdbcUpdate,
|
||||
updateBindings,
|
||||
sql -> executionContext.getSession()
|
||||
sql -> session
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
(integer, preparedStatement) -> {
|
||||
},
|
||||
(integer, preparedStatement) -> {},
|
||||
executionContext
|
||||
);
|
||||
}
|
||||
|
@ -558,23 +556,23 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
.buildInsertTranslator( sessionFactory, insertStatement )
|
||||
.translate( null, executionContext.getQueryOptions() );
|
||||
|
||||
if ( generator.generatedOnExecute() ) {
|
||||
if ( generator.generatedOnExecution() ) {
|
||||
final OnExecutionGenerator databaseGenerator = (OnExecutionGenerator) generator;
|
||||
final InsertGeneratedIdentifierDelegate identifierDelegate =
|
||||
databaseGenerator.getGeneratedIdentifierDelegate( (PostInsertIdentityPersister) entityPersister );
|
||||
final String finalSql = identifierDelegate.prepareIdentifierGeneratingInsert( jdbcInsert.getSqlString() );
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
final BasicEntityIdentifierMapping identifierMapping =
|
||||
(BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
final ValueBinder jdbcValueBinder = identifierMapping.getJdbcMapping().getJdbcValueBinder();
|
||||
for ( Map.Entry<Object, Object> entry : entityTableToRootIdentity.entrySet() ) {
|
||||
final Object rootIdentity = identifierDelegate.performInsert(
|
||||
finalSql,
|
||||
executionContext.getSession(),
|
||||
session,
|
||||
new Binder() {
|
||||
@Override
|
||||
public void bindValues(PreparedStatement ps) throws SQLException {
|
||||
jdbcValueBinder.bind( ps, entry.getKey(), 1, executionContext.getSession() );
|
||||
jdbcValueBinder.bind( ps, entry.getKey(), 1, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getEntity() {
|
||||
return null;
|
||||
|
@ -589,10 +587,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
final List<Assignment> temporaryTableAssignments = new ArrayList<>( 1 );
|
||||
temporaryTableAssignments.add(
|
||||
new Assignment(
|
||||
new ColumnReference(
|
||||
(String) null,
|
||||
identifierMapping
|
||||
),
|
||||
new ColumnReference( (String) null, identifierMapping ),
|
||||
rootIdentity
|
||||
)
|
||||
);
|
||||
|
@ -620,12 +615,13 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
final JdbcParameterBindings updateBindings = new JdbcParameterBindingsImpl( 2 );
|
||||
|
||||
for ( Map.Entry<Object, Object> entry : entityTableToRootIdentity.entrySet() ) {
|
||||
updateBindings.addBinding( entityIdentity, new JdbcParameterBindingImpl( identifierMapping.getJdbcMapping(), entry.getKey() ) );
|
||||
updateBindings.addBinding( rootIdentity, new JdbcParameterBindingImpl( identifierMapping.getJdbcMapping(), entry.getValue() ) );
|
||||
JdbcMapping jdbcMapping = identifierMapping.getJdbcMapping();
|
||||
updateBindings.addBinding( entityIdentity, new JdbcParameterBindingImpl( jdbcMapping, entry.getKey() ) );
|
||||
updateBindings.addBinding( rootIdentity, new JdbcParameterBindingImpl( jdbcMapping, entry.getValue() ) );
|
||||
jdbcServices.getJdbcMutationExecutor().execute(
|
||||
jdbcUpdate,
|
||||
updateBindings,
|
||||
sql -> executionContext.getSession()
|
||||
sql -> session
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
|
@ -639,7 +635,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
jdbcServices.getJdbcMutationExecutor().execute(
|
||||
jdbcInsert,
|
||||
JdbcParameterBindings.NO_BINDINGS,
|
||||
sql -> executionContext.getSession()
|
||||
sql -> session
|
||||
.getJdbcCoordinator()
|
||||
.getStatementPreparer()
|
||||
.prepareStatement( sql ),
|
||||
|
@ -651,14 +647,19 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
}
|
||||
|
||||
private boolean needsIdentifierGeneration(Generator identifierGenerator) {
|
||||
if ( !( identifierGenerator instanceof OptimizableGenerator ) ) {
|
||||
if (identifierGenerator instanceof OptimizableGenerator) {
|
||||
// If the generator uses an optimizer or is not bulk insertion capable,
|
||||
// we have to generate identifiers for the new rows, as that couldn't
|
||||
// have been done via a SQL expression
|
||||
final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer();
|
||||
return optimizer != null && optimizer.getIncrementSize() > 1
|
||||
|| identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator
|
||||
&& !( (BulkInsertionCapableIdentifierGenerator) identifierGenerator )
|
||||
.supportsBulkInsertionIdentifierGeneration();
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
// If the generator uses an optimizer or is not bulk insertion capable, we have to generate identifiers for the new rows,
|
||||
// as that couldn't have been done through a SQL expression
|
||||
final Optimizer optimizer = ( (OptimizableGenerator) identifierGenerator ).getOptimizer();
|
||||
return optimizer != null && optimizer.getIncrementSize() > 1 || identifierGenerator instanceof BulkInsertionCapableIdentifierGenerator
|
||||
&& !( (BulkInsertionCapableIdentifierGenerator) identifierGenerator ).supportsBulkInsertionIdentifierGeneration();
|
||||
}
|
||||
|
||||
private void insertTable(
|
||||
|
@ -719,7 +720,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
final AbstractEntityPersister entityPersister = (AbstractEntityPersister) entityDescriptor.getEntityPersister();
|
||||
final Generator identifierGenerator = entityPersister.getGenerator();
|
||||
final boolean needsKeyInsert;
|
||||
if ( identifierGenerator.generatedOnExecute() ) {
|
||||
if ( identifierGenerator.generatedOnExecution() ) {
|
||||
needsKeyInsert = true;
|
||||
}
|
||||
else if ( identifierGenerator instanceof OptimizableGenerator ) {
|
||||
|
@ -733,7 +734,8 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
if ( needsKeyInsert && insertStatement.getTargetColumns()
|
||||
.stream()
|
||||
.noneMatch( c -> targetKeyColumnName.equals( c.getColumnExpression() ) ) ) {
|
||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
final BasicEntityIdentifierMapping identifierMapping =
|
||||
(BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||
insertStatement.addTargetColumnReferences(
|
||||
new ColumnReference(
|
||||
dmlTargetTableReference.getIdentificationVariable(),
|
||||
|
|
|
@ -1355,7 +1355,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
|
||||
}
|
||||
// This uses identity generation, so we don't need to list the column
|
||||
if ( identifierGenerator != null && identifierGenerator.generatedOnExecute()
|
||||
if ( identifierGenerator != null && identifierGenerator.generatedOnExecution()
|
||||
|| identifierGenerator instanceof CompositeNestedGeneratedValueGenerator ) {
|
||||
identifierGenerator = null;
|
||||
}
|
||||
|
@ -1440,7 +1440,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
if ( discriminatorExpression != null ) {
|
||||
expressions.add( discriminatorExpression );
|
||||
}
|
||||
if ( identifierGenerator != null && !identifierGenerator.generatedOnExecute() ) {
|
||||
if ( identifierGenerator != null && !identifierGenerator.generatedOnExecution() ) {
|
||||
if ( identifierGeneratorParameter == null ) {
|
||||
identifierGeneratorParameter =
|
||||
new IdGeneratorParameter( identifierMapping, (BeforeExecutionGenerator) identifierGenerator );
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.function.BiFunction;
|
|||
import org.hibernate.sql.model.MutationOperation;
|
||||
import org.hibernate.sql.model.MutationTarget;
|
||||
import org.hibernate.sql.model.MutationType;
|
||||
import org.hibernate.sql.model.ast.MutationGroup;
|
||||
|
||||
/**
|
||||
* Specialized MutationOperationGroup for case of no operations
|
||||
|
@ -24,6 +25,9 @@ public class MutationOperationGroupNone extends AbstractMutationOperationGroup {
|
|||
public MutationOperationGroupNone(MutationType mutationType, MutationTarget<?> mutationTarget) {
|
||||
super( mutationType, mutationTarget );
|
||||
}
|
||||
public MutationOperationGroupNone(MutationGroup mutationGroup) {
|
||||
this( mutationGroup.getMutationType(), mutationGroup.getMutationTarget() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfOperations() {
|
||||
|
|
|
@ -14,6 +14,7 @@ import java.util.function.BiFunction;
|
|||
import org.hibernate.sql.model.MutationOperation;
|
||||
import org.hibernate.sql.model.MutationTarget;
|
||||
import org.hibernate.sql.model.MutationType;
|
||||
import org.hibernate.sql.model.ast.MutationGroup;
|
||||
|
||||
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER;
|
||||
|
||||
|
@ -28,6 +29,10 @@ public class MutationOperationGroupSingle extends AbstractMutationOperationGroup
|
|||
this.operation = operation;
|
||||
}
|
||||
|
||||
public MutationOperationGroupSingle(MutationGroup mutationGroup, MutationOperation operation) {
|
||||
this( mutationGroup.getMutationType(), mutationGroup.getMutationTarget(), operation );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfOperations() {
|
||||
return 1;
|
||||
|
|
|
@ -42,7 +42,7 @@ public class IdentifierProperty extends AbstractAttribute implements IdentifierA
|
|||
this.embedded = embedded;
|
||||
this.hasIdentifierMapper = false;
|
||||
this.identifierGenerator = identifierGenerator;
|
||||
this.identifierAssignedByInsert = identifierGenerator.generatedOnExecute();
|
||||
this.identifierAssignedByInsert = identifierGenerator.generatedOnExecution();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -63,7 +63,7 @@ public class IdentifierProperty extends AbstractAttribute implements IdentifierA
|
|||
this.embedded = embedded;
|
||||
this.hasIdentifierMapper = hasIdentifierMapper;
|
||||
this.identifierGenerator = identifierGenerator;
|
||||
this.identifierAssignedByInsert = identifierGenerator.generatedOnExecute();
|
||||
this.identifierAssignedByInsert = identifierGenerator.generatedOnExecution();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -83,7 +83,7 @@ public interface ValueGeneration extends BeforeExecutionGenerator, OnExecutionGe
|
|||
|
||||
/**
|
||||
* A SQL expression indicating how to calculate the generated value when the property value
|
||||
* is {@linkplain #generatedOnExecute() generated in the database} and the mapped column is
|
||||
* is {@linkplain #generatedOnExecution() generated in the database} and the mapped column is
|
||||
* {@linkplain #referenceColumnInSql() included in the SQL statement}. The SQL expression
|
||||
* might be:
|
||||
* <ul>
|
||||
|
@ -100,7 +100,7 @@ public interface ValueGeneration extends BeforeExecutionGenerator, OnExecutionGe
|
|||
|
||||
/**
|
||||
* A SQL expression indicating how to calculate the generated value when the property value
|
||||
* is {@linkplain #generatedOnExecute() generated in the database} and the mapped column is
|
||||
* is {@linkplain #generatedOnExecution() generated in the database} and the mapped column is
|
||||
* {@linkplain #referenceColumnInSql() included in the SQL statement}. The SQL expression
|
||||
* might be:
|
||||
* <ul>
|
||||
|
@ -140,7 +140,7 @@ public interface ValueGeneration extends BeforeExecutionGenerator, OnExecutionGe
|
|||
* generated in Java using a {@link ValueGenerator}.
|
||||
*/
|
||||
@Override
|
||||
default boolean generatedOnExecute() {
|
||||
default boolean generatedOnExecution() {
|
||||
return getValueGenerator() == null;
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ public interface ValueGeneration extends BeforeExecutionGenerator, OnExecutionGe
|
|||
*/
|
||||
@Override
|
||||
default boolean writePropertyValue() {
|
||||
return !this.generatedOnExecute() // value generated in memory and then written as normal
|
||||
return !this.generatedOnExecution() // value generated in memory and then written as normal
|
||||
// current value of property of entity instance written completely as normal
|
||||
|| referenceColumnInSql() && getDatabaseGeneratedReferencedColumnValue()==null;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* 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.tuple.entity;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||
import org.hibernate.generator.EventType;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.generator.OnExecutionGenerator;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.Property;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import static java.lang.System.arraycopy;
|
||||
import static org.hibernate.generator.EventTypeSets.NONE;
|
||||
|
||||
/**
|
||||
* Handles value generation for composite properties.
|
||||
*/
|
||||
class CompositeGeneratorBuilder {
|
||||
private final Property mappingProperty;
|
||||
private final Dialect dialect;
|
||||
|
||||
private boolean hadBeforeExecutionGeneration;
|
||||
private boolean hadOnExecutionGeneration;
|
||||
|
||||
private List<OnExecutionGenerator> onExecutionGenerators;
|
||||
|
||||
public CompositeGeneratorBuilder(Property mappingProperty, Dialect dialect) {
|
||||
this.mappingProperty = mappingProperty;
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
public void add(Generator generator) {
|
||||
if ( generator != null ) {
|
||||
if ( generator.generatedOnExecution() ) {
|
||||
if ( generator instanceof OnExecutionGenerator ) {
|
||||
add( (OnExecutionGenerator) generator );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( generator instanceof BeforeExecutionGenerator ) {
|
||||
add( (BeforeExecutionGenerator) generator );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void add(BeforeExecutionGenerator beforeExecutionGenerator) {
|
||||
if ( beforeExecutionGenerator.generatesSometimes() ) {
|
||||
hadBeforeExecutionGeneration = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void add(OnExecutionGenerator onExecutionGenerator) {
|
||||
if ( onExecutionGenerators == null ) {
|
||||
onExecutionGenerators = new ArrayList<>();
|
||||
}
|
||||
onExecutionGenerators.add( onExecutionGenerator );
|
||||
|
||||
if ( onExecutionGenerator.generatesSometimes() ) {
|
||||
hadOnExecutionGeneration = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Generator build() {
|
||||
if ( hadBeforeExecutionGeneration && hadOnExecutionGeneration) {
|
||||
throw new CompositeValueGenerationException(
|
||||
"Composite attribute [" + mappingProperty.getName() + "] contained both in-memory"
|
||||
+ " and in-database value generation"
|
||||
);
|
||||
}
|
||||
else if ( hadBeforeExecutionGeneration ) {
|
||||
throw new UnsupportedOperationException("Composite in-memory value generation not supported");
|
||||
|
||||
}
|
||||
else if ( hadOnExecutionGeneration ) {
|
||||
final Component composite = (Component) mappingProperty.getValue();
|
||||
|
||||
// we need the numbers to match up so that we can properly handle 'referenced sql column values'
|
||||
if ( onExecutionGenerators.size() != composite.getPropertySpan() ) {
|
||||
throw new CompositeValueGenerationException(
|
||||
"Internal error : mismatch between number of collected in-db generation strategies" +
|
||||
" and number of attributes for composite attribute : " + mappingProperty.getName()
|
||||
);
|
||||
}
|
||||
|
||||
// the base-line values for the aggregated OnExecutionGenerator we will build here.
|
||||
final EnumSet<EventType> eventTypes = EnumSet.noneOf(EventType.class);
|
||||
boolean referenceColumns = false;
|
||||
final String[] columnValues = new String[composite.getColumnSpan()];
|
||||
|
||||
// start building the aggregate values
|
||||
int propertyIndex = -1;
|
||||
int columnIndex = 0;
|
||||
for ( Property property : composite.getProperties() ) {
|
||||
propertyIndex++;
|
||||
final OnExecutionGenerator generator = onExecutionGenerators.get( propertyIndex );
|
||||
eventTypes.addAll( generator.getEventTypes() );
|
||||
if ( generator.referenceColumnsInSql( dialect ) ) {
|
||||
// override base-line value
|
||||
referenceColumns = true;
|
||||
final String[] referencedColumnValues = generator.getReferencedColumnValues( dialect );
|
||||
if ( referencedColumnValues != null ) {
|
||||
final int span = property.getColumnSpan();
|
||||
if ( referencedColumnValues.length != span ) {
|
||||
throw new CompositeValueGenerationException(
|
||||
"Mismatch between number of collected generated column values and number of columns for composite attribute: "
|
||||
+ mappingProperty.getName() + '.' + property.getName()
|
||||
);
|
||||
}
|
||||
arraycopy( referencedColumnValues, 0, columnValues, columnIndex, span );
|
||||
}
|
||||
}
|
||||
}
|
||||
final boolean referenceColumnsInSql = referenceColumns;
|
||||
|
||||
// then use the aggregated values to build an OnExecutionGenerator
|
||||
return new OnExecutionGenerator() {
|
||||
@Override
|
||||
public EnumSet<EventType> getEventTypes() {
|
||||
return eventTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean referenceColumnsInSql(Dialect dialect) {
|
||||
return referenceColumnsInSql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getReferencedColumnValues(Dialect dialect) {
|
||||
return columnValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writePropertyValue() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
else {
|
||||
return new Generator() {
|
||||
@Override
|
||||
public EnumSet<EventType> getEventTypes() {
|
||||
return NONE;
|
||||
}
|
||||
@Override
|
||||
public boolean generatedOnExecution() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* 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.tuple.entity;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Incubating;
|
||||
|
||||
@Incubating
|
||||
public class CompositeValueGenerationException extends HibernateException {
|
||||
public CompositeValueGenerationException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@ import java.io.Serializable;
|
|||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -31,7 +30,6 @@ import org.hibernate.engine.spi.CascadeStyle;
|
|||
import org.hibernate.engine.spi.CascadeStyles;
|
||||
import org.hibernate.engine.spi.CascadingActions;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.generator.EventType;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.generator.OnExecutionGenerator;
|
||||
import org.hibernate.generator.BeforeExecutionGenerator;
|
||||
|
@ -59,7 +57,6 @@ import org.hibernate.type.EntityType;
|
|||
import org.hibernate.type.ManyToOneType;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import static org.hibernate.generator.EventTypeSets.NONE;
|
||||
import static org.hibernate.internal.CoreLogging.messageLogger;
|
||||
|
||||
/**
|
||||
|
@ -311,7 +308,7 @@ public class EntityMetamodel implements Serializable {
|
|||
// generated value strategies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
final Generator generator = buildGenerator( property, creationContext );
|
||||
if ( generator != null ) {
|
||||
if ( i == tempVersionProperty && !generator.generatedOnExecute() ) {
|
||||
if ( i == tempVersionProperty && !generator.generatedOnExecution() ) {
|
||||
// when we have an in-memory generator for the version, we
|
||||
// want to plug it in to the older infrastructure specific
|
||||
// to version generation, instead of treating it like a
|
||||
|
@ -325,7 +322,7 @@ public class EntityMetamodel implements Serializable {
|
|||
propertyUpdateability[i] = false;
|
||||
}
|
||||
if ( generator.generatesOnInsert() ) {
|
||||
if ( generator.generatedOnExecute() ) {
|
||||
if ( generator.generatedOnExecution() ) {
|
||||
foundPostInsertGeneratedValues = true;
|
||||
}
|
||||
else {
|
||||
|
@ -333,7 +330,7 @@ public class EntityMetamodel implements Serializable {
|
|||
}
|
||||
}
|
||||
if ( generator.generatesOnUpdate() ) {
|
||||
if ( generator.generatedOnExecute() ) {
|
||||
if ( generator.generatedOnExecution() ) {
|
||||
foundPostUpdateGeneratedValues = true;
|
||||
}
|
||||
else {
|
||||
|
@ -463,7 +460,7 @@ public class EntityMetamodel implements Serializable {
|
|||
}
|
||||
|
||||
private static boolean generatedWithNoParameter(Generator generator) {
|
||||
return generator.generatedOnExecute()
|
||||
return generator.generatedOnExecution()
|
||||
&& !((OnExecutionGenerator) generator).writePropertyValue();
|
||||
}
|
||||
|
||||
|
@ -482,7 +479,7 @@ public class EntityMetamodel implements Serializable {
|
|||
final CompositeGeneratorBuilder builder = new CompositeGeneratorBuilder( mappingProperty, dialect );
|
||||
final Component component = (Component) mappingProperty.getValue();
|
||||
for ( Property property : component.getProperties() ) {
|
||||
builder.addPair( property.createGenerator( context ) );
|
||||
builder.add( property.createGenerator( context ) );
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
@ -497,175 +494,13 @@ public class EntityMetamodel implements Serializable {
|
|||
return versionGenerator;
|
||||
}
|
||||
|
||||
public static class ValueGenerationStrategyException extends HibernateException {
|
||||
public ValueGenerationStrategyException(String message) {
|
||||
super( message );
|
||||
}
|
||||
}
|
||||
|
||||
private static class CompositeGeneratorBuilder {
|
||||
private final Property mappingProperty;
|
||||
private final Dialect dialect;
|
||||
|
||||
private boolean hadInMemoryGeneration;
|
||||
private boolean hadInDatabaseGeneration;
|
||||
|
||||
private List<OnExecutionGenerator> inDatabaseStrategies;
|
||||
|
||||
public CompositeGeneratorBuilder(Property mappingProperty, Dialect dialect) {
|
||||
this.mappingProperty = mappingProperty;
|
||||
this.dialect = dialect;
|
||||
}
|
||||
|
||||
public void addPair(Generator generator) {
|
||||
if ( generator != null ) {
|
||||
if ( generator.generatedOnExecute() ) {
|
||||
if ( generator instanceof OnExecutionGenerator ) {
|
||||
add( (OnExecutionGenerator) generator );
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ( generator instanceof BeforeExecutionGenerator ) {
|
||||
add( (BeforeExecutionGenerator) generator );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void add(BeforeExecutionGenerator inMemoryStrategy) {
|
||||
if ( inMemoryStrategy.generatesSometimes() ) {
|
||||
hadInMemoryGeneration = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void add(OnExecutionGenerator inDatabaseStrategy) {
|
||||
if ( inDatabaseStrategies == null ) {
|
||||
inDatabaseStrategies = new ArrayList<>();
|
||||
}
|
||||
inDatabaseStrategies.add( inDatabaseStrategy );
|
||||
|
||||
if ( inDatabaseStrategy.generatesSometimes() ) {
|
||||
hadInDatabaseGeneration = true;
|
||||
}
|
||||
}
|
||||
|
||||
public Generator build() {
|
||||
if ( hadInMemoryGeneration && hadInDatabaseGeneration ) {
|
||||
throw new ValueGenerationStrategyException(
|
||||
"Composite attribute [" + mappingProperty.getName() + "] contained both in-memory"
|
||||
+ " and in-database value generation"
|
||||
);
|
||||
}
|
||||
else if ( hadInMemoryGeneration ) {
|
||||
throw new UnsupportedOperationException( "Composite in-memory value generation not supported" );
|
||||
|
||||
}
|
||||
else if ( hadInDatabaseGeneration ) {
|
||||
final Component composite = (Component) mappingProperty.getValue();
|
||||
|
||||
// we need the numbers to match up so that we can properly handle 'referenced sql column values'
|
||||
if ( inDatabaseStrategies.size() != composite.getPropertySpan() ) {
|
||||
throw new ValueGenerationStrategyException(
|
||||
"Internal error : mismatch between number of collected in-db generation strategies" +
|
||||
" and number of attributes for composite attribute : " + mappingProperty.getName()
|
||||
);
|
||||
}
|
||||
|
||||
// the base-line values for the aggregated InDatabaseValueGenerationStrategy we will build here.
|
||||
EnumSet<EventType> eventTypes = EnumSet.noneOf(EventType.class);
|
||||
boolean referenceColumns = false;
|
||||
String[] columnValues = new String[ composite.getColumnSpan() ];
|
||||
|
||||
// start building the aggregate values
|
||||
int propertyIndex = -1;
|
||||
int columnIndex = 0;
|
||||
for ( Property property : composite.getProperties() ) {
|
||||
propertyIndex++;
|
||||
final OnExecutionGenerator generator = inDatabaseStrategies.get( propertyIndex );
|
||||
eventTypes.addAll( generator.getEventTypes() );
|
||||
if ( generator.referenceColumnsInSql(dialect) ) {
|
||||
// override base-line value
|
||||
referenceColumns = true;
|
||||
}
|
||||
if ( generator.getReferencedColumnValues(dialect) != null ) {
|
||||
if ( generator.getReferencedColumnValues(dialect).length != property.getColumnSpan() ) {
|
||||
throw new ValueGenerationStrategyException(
|
||||
"Internal error : mismatch between number of collected 'referenced column values'" +
|
||||
" and number of columns for composite attribute : " + mappingProperty.getName() +
|
||||
'.' + property.getName()
|
||||
);
|
||||
}
|
||||
System.arraycopy(
|
||||
generator.getReferencedColumnValues(dialect),
|
||||
0,
|
||||
columnValues,
|
||||
columnIndex,
|
||||
property.getColumnSpan()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// then use the aggregated values to build the InDatabaseValueGenerationStrategy
|
||||
return new OnExecutionGeneratorImpl( eventTypes, referenceColumns, columnValues );
|
||||
}
|
||||
else {
|
||||
return new Generator() {
|
||||
@Override
|
||||
public EnumSet<EventType> getEventTypes() {
|
||||
return NONE;
|
||||
}
|
||||
@Override
|
||||
public boolean generatedOnExecute() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class OnExecutionGeneratorImpl implements OnExecutionGenerator {
|
||||
private final EnumSet<EventType> eventTypes;
|
||||
private final boolean referenceColumnInSql;
|
||||
private final String[] referencedColumnValues;
|
||||
|
||||
private OnExecutionGeneratorImpl(
|
||||
EnumSet<EventType> eventTypes,
|
||||
boolean referenceColumnInSql,
|
||||
String[] referencedColumnValues) {
|
||||
this.eventTypes = eventTypes;
|
||||
this.referenceColumnInSql = referenceColumnInSql;
|
||||
this.referencedColumnValues = referencedColumnValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<EventType> getEventTypes() {
|
||||
return eventTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean referenceColumnsInSql(Dialect dialect) {
|
||||
return referenceColumnInSql;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getReferencedColumnValues(Dialect dialect) {
|
||||
return referencedColumnValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean writePropertyValue() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void mapPropertyToIndex(Property prop, int i) {
|
||||
propertyIndexes.put( prop.getName(), i );
|
||||
if ( prop.getValue() instanceof Component ) {
|
||||
Component composite = (Component) prop.getValue();
|
||||
for ( Property subprop : composite.getProperties() ) {
|
||||
private void mapPropertyToIndex(Property property, int i) {
|
||||
propertyIndexes.put( property.getName(), i );
|
||||
if ( property.getValue() instanceof Component ) {
|
||||
Component composite = (Component) property.getValue();
|
||||
for ( Property subproperty : composite.getProperties() ) {
|
||||
propertyIndexes.put(
|
||||
prop.getName() + '.' + subprop.getName(),
|
||||
property.getName() + '.' + subproperty.getName(),
|
||||
i
|
||||
);
|
||||
}
|
||||
|
@ -682,23 +517,13 @@ public class EntityMetamodel implements Serializable {
|
|||
}
|
||||
for ( int i = 0; i < naturalIdPropertyNumbers.length; i++ ) {
|
||||
final Generator strategy = generators[ naturalIdPropertyNumbers[i] ];
|
||||
if ( strategy != null && strategy.generatesOnInsert() && strategy.generatedOnExecute() ) {
|
||||
if ( strategy != null && strategy.generatesOnInsert() && strategy.generatedOnExecution() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isVersionGeneratedOnExecute() {
|
||||
final Generator strategy = generators[ versionPropertyIndex ];
|
||||
return strategy != null && strategy.generatesSometimes() && strategy.generatedOnExecute();
|
||||
}
|
||||
|
||||
public boolean isVersionGeneratedBeforeExecute() {
|
||||
final Generator strategy = generators[ versionPropertyIndex ];
|
||||
return strategy != null && strategy.generatesSometimes() && !strategy.generatedOnExecute();
|
||||
}
|
||||
|
||||
public int[] getNaturalIdentifierProperties() {
|
||||
return naturalIdPropertyNumbers;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue