unify new ValueGenerationStrategy interfaces with existing ValueGeneration stuff

- introduce ValueGenerationStrategy to abstract over IMVGS and IDVGS
- make ValueGeneration a mixin of IMVGS with IDVGS
- make IDVGS accept a Dialect for SQL fragment generation
  (it was based on an obsolete version of ValueGeneration)
- adapt all the code which only handled single-column value generation
  to handle multiple columns, as introduced by IDVGS

Still to do: the whole AnnotationValueGeneration stuff still requires the use
of the mixin interface, and you can't use IMVGS or IDVGS directly. That bit is
going to require a bit more thinking about backward compatibility.
This commit is contained in:
Gavin 2022-11-29 10:10:39 +01:00 committed by Gavin King
parent 94e2b599e4
commit 3e6fcdeda3
31 changed files with 341 additions and 328 deletions

View File

@ -40,8 +40,10 @@ import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value; import org.hibernate.mapping.Value;
import org.hibernate.metamodel.spi.EmbeddableInstantiator; import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.property.access.spi.PropertyAccessStrategy; import org.hibernate.property.access.spi.PropertyAccessStrategy;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.AnnotationValueGeneration; import org.hibernate.tuple.AnnotationValueGeneration;
import org.hibernate.tuple.AttributeBinder; import org.hibernate.tuple.AttributeBinder;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
import org.hibernate.tuple.GenerationTiming; import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.ValueGeneration; import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.ValueGenerator; import org.hibernate.tuple.ValueGenerator;
@ -383,19 +385,17 @@ public class PropertyBinder {
} }
} }
private ValueGeneration determineValueGenerationStrategy(XProperty property) { private ValueGenerationStrategy determineValueGenerationStrategy(XProperty property) {
ValueGeneration valueGeneration = getValueGenerationFromAnnotations( property ); ValueGenerationStrategy valueGeneration = getValueGenerationFromAnnotations( property );
if ( valueGeneration == null ) { if ( valueGeneration == null ) {
return NoValueGeneration.INSTANCE; return NoValueGeneration.INSTANCE;
} }
if ( valueGeneration instanceof InDatabaseValueGenerationStrategy) {
if ( !valueGeneration.writePropertyValue() ) {
// if we have an in-db generator, mark it as not insertable nor updatable // if we have an in-db generator, mark it as not insertable nor updatable
insertable = false; final boolean writable = ( (InDatabaseValueGenerationStrategy) valueGeneration ).writePropertyValue();
updatable = false; insertable = writable;
updatable = writable;
} }
return valueGeneration; return valueGeneration;
} }

View File

@ -27,7 +27,7 @@ import org.hibernate.property.access.spi.PropertyAccessStrategy;
import org.hibernate.property.access.spi.PropertyAccessStrategyResolver; import org.hibernate.property.access.spi.PropertyAccessStrategyResolver;
import org.hibernate.property.access.spi.Setter; import org.hibernate.property.access.spi.Setter;
import org.hibernate.service.ServiceRegistry; import org.hibernate.service.ServiceRegistry;
import org.hibernate.tuple.ValueGeneration; import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.type.CompositeType; import org.hibernate.type.CompositeType;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -45,7 +45,7 @@ public class Property implements Serializable, MetaAttributable {
private boolean insertable = true; private boolean insertable = true;
private boolean selectable = true; private boolean selectable = true;
private boolean optimisticLocked = true; private boolean optimisticLocked = true;
private ValueGeneration valueGenerationStrategy; private ValueGenerationStrategy valueGenerationStrategy;
private String propertyAccessorName; private String propertyAccessorName;
private PropertyAccessStrategy propertyAccessStrategy; private PropertyAccessStrategy propertyAccessStrategy;
private boolean lazy; private boolean lazy;
@ -216,11 +216,11 @@ public class Property implements Serializable, MetaAttributable {
return insertable && value.hasAnyInsertableColumns(); return insertable && value.hasAnyInsertableColumns();
} }
public ValueGeneration getValueGenerationStrategy() { public ValueGenerationStrategy getValueGenerationStrategy() {
return valueGenerationStrategy; return valueGenerationStrategy;
} }
public void setValueGenerationStrategy(ValueGeneration valueGenerationStrategy) { public void setValueGenerationStrategy(ValueGenerationStrategy valueGenerationStrategy) {
this.valueGenerationStrategy = valueGenerationStrategy; this.valueGenerationStrategy = valueGenerationStrategy;
} }

View File

@ -9,7 +9,7 @@ package org.hibernate.metamodel.mapping;
import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.sql.results.graph.DatabaseSnapshotContributor; import org.hibernate.sql.results.graph.DatabaseSnapshotContributor;
import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.tuple.ValueGeneration; import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.MutabilityPlan; import org.hibernate.type.descriptor.java.MutabilityPlan;
import org.hibernate.type.descriptor.java.MutabilityPlanExposer; import org.hibernate.type.descriptor.java.MutabilityPlanExposer;
@ -70,7 +70,7 @@ public interface AttributeMapping
* *
* @apiNote Only relevant for non-id attributes * @apiNote Only relevant for non-id attributes
*/ */
ValueGeneration getValueGeneration(); ValueGenerationStrategy getValueGeneration();
@Override @Override
default EntityMappingType findContainingEntityMapping() { default EntityMappingType findContainingEntityMapping() {

View File

@ -9,8 +9,9 @@ package org.hibernate.metamodel.mapping;
import org.hibernate.Incubating; import org.hibernate.Incubating;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.internal.NoGeneratedValueResolver; import org.hibernate.metamodel.mapping.internal.NoGeneratedValueResolver;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.GenerationTiming; import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.ValueGeneration; import org.hibernate.tuple.InMemoryValueGenerationStrategy;
/** /**
* Generalized contract covering an attribute's generation handling * Generalized contract covering an attribute's generation handling
@ -20,7 +21,7 @@ import org.hibernate.tuple.ValueGeneration;
@Incubating @Incubating
public interface GeneratedValueResolver { public interface GeneratedValueResolver {
static GeneratedValueResolver from( static GeneratedValueResolver from(
ValueGeneration valueGeneration, ValueGenerationStrategy valueGeneration,
GenerationTiming requestedTiming, GenerationTiming requestedTiming,
int dbSelectionPosition) { int dbSelectionPosition) {
assert requestedTiming != GenerationTiming.NEVER; assert requestedTiming != GenerationTiming.NEVER;
@ -38,7 +39,8 @@ public interface GeneratedValueResolver {
return new InDatabaseGeneratedValueResolver( requestedTiming, dbSelectionPosition ); return new InDatabaseGeneratedValueResolver( requestedTiming, dbSelectionPosition );
} }
else { else {
return new InMemoryGeneratedValueResolver( valueGeneration.getValueGenerator(), requestedTiming ); InMemoryValueGenerationStrategy generation = (InMemoryValueGenerationStrategy) valueGeneration;
return new InMemoryGeneratedValueResolver( generation.getValueGenerator(), requestedTiming );
} }
} }

View File

@ -13,7 +13,7 @@ import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.SingularAttributeMapping; import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.sql.results.graph.FetchOptions; import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.tuple.ValueGeneration; import org.hibernate.tuple.ValueGenerationStrategy;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -23,7 +23,7 @@ public abstract class AbstractSingularAttributeMapping
implements SingularAttributeMapping { implements SingularAttributeMapping {
private final PropertyAccess propertyAccess; private final PropertyAccess propertyAccess;
private final ValueGeneration valueGeneration; private final ValueGenerationStrategy valueGeneration;
public AbstractSingularAttributeMapping( public AbstractSingularAttributeMapping(
String name, String name,
@ -32,7 +32,7 @@ public abstract class AbstractSingularAttributeMapping
FetchOptions mappedFetchOptions, FetchOptions mappedFetchOptions,
ManagedMappingType declaringType, ManagedMappingType declaringType,
PropertyAccess propertyAccess, PropertyAccess propertyAccess,
ValueGeneration valueGeneration) { ValueGenerationStrategy valueGeneration) {
super( name, attributeMetadataAccess, mappedFetchOptions, stateArrayPosition, declaringType ); super( name, attributeMetadataAccess, mappedFetchOptions, stateArrayPosition, declaringType );
this.propertyAccess = propertyAccess; this.propertyAccess = propertyAccess;
this.valueGeneration = valueGeneration != null this.valueGeneration = valueGeneration != null
@ -48,7 +48,7 @@ public abstract class AbstractSingularAttributeMapping
FetchStyle fetchStyle, FetchStyle fetchStyle,
ManagedMappingType declaringType, ManagedMappingType declaringType,
PropertyAccess propertyAccess, PropertyAccess propertyAccess,
ValueGeneration valueGeneration) { ValueGenerationStrategy valueGeneration) {
super( name, attributeMetadataAccess, fetchTiming, fetchStyle, stateArrayPosition, declaringType ); super( name, attributeMetadataAccess, fetchTiming, fetchStyle, stateArrayPosition, declaringType );
this.propertyAccess = propertyAccess; this.propertyAccess = propertyAccess;
this.valueGeneration = valueGeneration != null this.valueGeneration = valueGeneration != null
@ -62,7 +62,7 @@ public abstract class AbstractSingularAttributeMapping
} }
@Override @Override
public ValueGeneration getValueGeneration() { public ValueGenerationStrategy getValueGeneration() {
return valueGeneration; return valueGeneration;
} }
} }

View File

@ -36,7 +36,7 @@ import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.basic.BasicFetch; import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.tuple.ValueGeneration; import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
/** /**
@ -87,7 +87,7 @@ public class BasicAttributeMapping
JdbcMapping jdbcMapping, JdbcMapping jdbcMapping,
ManagedMappingType declaringType, ManagedMappingType declaringType,
PropertyAccess propertyAccess, PropertyAccess propertyAccess,
ValueGeneration valueGeneration) { ValueGenerationStrategy valueGeneration) {
super( super(
attributeName, attributeName,
stateArrayPosition, stateArrayPosition,
@ -126,7 +126,7 @@ public class BasicAttributeMapping
ManagedMappingType declaringType, ManagedMappingType declaringType,
BasicValuedModelPart original, BasicValuedModelPart original,
PropertyAccess propertyAccess, PropertyAccess propertyAccess,
ValueGeneration valueGeneration, ValueGenerationStrategy valueGeneration,
boolean insertable, boolean insertable,
boolean updateable, boolean updateable,
SelectableMapping selectableMapping) { SelectableMapping selectableMapping) {

View File

@ -54,7 +54,7 @@ import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable; import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableFetchImpl; import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableFetchImpl;
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl; import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl;
import org.hibernate.tuple.ValueGeneration; import org.hibernate.tuple.ValueGenerationStrategy;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -80,7 +80,7 @@ public class EmbeddedAttributeMapping
EmbeddableMappingType embeddableMappingType, EmbeddableMappingType embeddableMappingType,
ManagedMappingType declaringType, ManagedMappingType declaringType,
PropertyAccess propertyAccess, PropertyAccess propertyAccess,
ValueGeneration valueGeneration) { ValueGenerationStrategy valueGeneration) {
this( this(
name, name,
navigableRole, navigableRole,
@ -109,7 +109,7 @@ public class EmbeddedAttributeMapping
EmbeddableMappingType embeddableMappingType, EmbeddableMappingType embeddableMappingType,
ManagedMappingType declaringType, ManagedMappingType declaringType,
PropertyAccess propertyAccess, PropertyAccess propertyAccess,
ValueGeneration valueGeneration) { ValueGenerationStrategy valueGeneration) {
super( super(
name, name,
stateArrayPosition, stateArrayPosition,

View File

@ -88,7 +88,6 @@ import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupProducer; import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.type.AssociationType; import org.hibernate.type.AssociationType;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.ComponentType; import org.hibernate.type.ComponentType;
@ -266,7 +265,6 @@ public class MappingModelCreationHelper {
fetchTiming = bootProperty.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE; fetchTiming = bootProperty.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE;
fetchStyle = bootProperty.isLazy() ? FetchStyle.SELECT : FetchStyle.JOIN; fetchStyle = bootProperty.isLazy() ? FetchStyle.SELECT : FetchStyle.JOIN;
} }
final ValueGeneration valueGeneration = bootProperty.getValueGenerationStrategy();
return new BasicAttributeMapping( return new BasicAttributeMapping(
attrName, attrName,
@ -290,7 +288,7 @@ public class MappingModelCreationHelper {
attrType, attrType,
declaringType, declaringType,
propertyAccess, propertyAccess,
valueGeneration bootProperty.getValueGenerationStrategy()
); );
} }

View File

@ -17,7 +17,7 @@ import org.hibernate.metamodel.mapping.VirtualModelPart;
import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.sql.ast.tree.from.TableGroupProducer; import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.tuple.ValueGeneration; import org.hibernate.tuple.ValueGenerationStrategy;
/** /**
* @author Christian Beikov * @author Christian Beikov
@ -35,7 +35,8 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
FetchStyle mappedFetchStyle, FetchStyle mappedFetchStyle,
EmbeddableMappingType embeddableMappingType, EmbeddableMappingType embeddableMappingType,
ManagedMappingType declaringType, ManagedMappingType declaringType,
PropertyAccess propertyAccess, ValueGeneration valueGeneration) { PropertyAccess propertyAccess,
ValueGenerationStrategy valueGeneration) {
super( super(
name, name,
navigableRole, navigableRole,
@ -63,7 +64,8 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
FetchStyle mappedFetchStyle, FetchStyle mappedFetchStyle,
EmbeddableMappingType embeddableMappingType, EmbeddableMappingType embeddableMappingType,
ManagedMappingType declaringType, ManagedMappingType declaringType,
PropertyAccess propertyAccess, ValueGeneration valueGeneration) { PropertyAccess propertyAccess,
ValueGenerationStrategy valueGeneration) {
super( super(
name, name,
navigableRole, navigableRole,

View File

@ -256,9 +256,10 @@ import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
import org.hibernate.sql.results.graph.entity.internal.EntityResultImpl; import org.hibernate.sql.results.graph.entity.internal.EntityResultImpl;
import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
import org.hibernate.tuple.GenerationTiming; import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.NonIdentifierAttribute; import org.hibernate.tuple.NonIdentifierAttribute;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.entity.EntityBasedAssociationAttribute; import org.hibernate.tuple.entity.EntityBasedAssociationAttribute;
import org.hibernate.tuple.entity.EntityMetamodel; import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.type.AnyType; import org.hibernate.type.AnyType;
@ -2758,15 +2759,16 @@ public abstract class AbstractEntityPersister
hasColumns = true; hasColumns = true;
} }
else { else {
final ValueGeneration valueGeneration = attributeMapping.getValueGeneration(); final ValueGenerationStrategy valueGeneration = attributeMapping.getValueGeneration();
if ( valueGeneration.getGenerationTiming().includesUpdate() if ( valueGeneration.getGenerationTiming().includesUpdate()
&& valueGeneration.generatedByDatabase() && valueGeneration.generatedByDatabase() ) {
&& valueGeneration.referenceColumnInSql() ) { final InDatabaseValueGenerationStrategy generation = (InDatabaseValueGenerationStrategy) valueGeneration;
if ( generation.referenceColumnsInSql() ) {
final Dialect dialect = getFactory().getJdbcServices().getDialect(); final Dialect dialect = getFactory().getJdbcServices().getDialect();
update.addColumns( update.addColumns(
getPropertyColumnNames(index), getPropertyColumnNames(index),
SINGLE_TRUE, SINGLE_TRUE,
new String[] { valueGeneration.getDatabaseGeneratedReferencedColumnValue(dialect) } generation.getReferencedColumnValues(dialect)
); );
hasColumns = true; hasColumns = true;
} }
@ -2774,6 +2776,7 @@ public abstract class AbstractEntityPersister
} }
} }
} }
}
// HHH-4635 // HHH-4635
// Oracle expects all Lob properties to be last in inserts // Oracle expects all Lob properties to be last in inserts

View File

@ -9,17 +9,22 @@ package org.hibernate.persister.entity.mutation;
import java.util.List; import java.util.List;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.persister.entity.AbstractEntityPersister; import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.sql.model.ModelMutationLogging; import org.hibernate.sql.model.ModelMutationLogging;
import org.hibernate.sql.model.MutationOperation; import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.MutationOperationGroup; import org.hibernate.sql.model.MutationOperationGroup;
import org.hibernate.sql.model.ValuesAnalysis; import org.hibernate.sql.model.ValuesAnalysis;
import org.hibernate.sql.model.ast.MutationGroup; import org.hibernate.sql.model.ast.MutationGroup;
import org.hibernate.sql.model.ast.builder.ColumnValuesTableMutationBuilder;
import org.hibernate.sql.model.ast.builder.MutationGroupBuilder;
import org.hibernate.sql.model.internal.MutationOperationGroupNone; import org.hibernate.sql.model.internal.MutationOperationGroupNone;
import org.hibernate.sql.model.internal.MutationOperationGroupSingle; import org.hibernate.sql.model.internal.MutationOperationGroupSingle;
import org.hibernate.sql.model.internal.MutationOperationGroupStandard; import org.hibernate.sql.model.internal.MutationOperationGroupStandard;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
/** /**
* Base support for coordinating mutations against an entity * Base support for coordinating mutations against an entity
@ -84,5 +89,21 @@ public abstract class AbstractMutationCoordinator {
); );
} }
void handleValueGeneration(
AttributeMapping attributeMapping,
MutationGroupBuilder mutationGroupBuilder,
InDatabaseValueGenerationStrategy valueGeneration) {
final Dialect dialect = factory.getJdbcServices().getDialect();
final boolean writePropertyValue = valueGeneration.writePropertyValue();
final String[] columnValues = writePropertyValue ? null : valueGeneration.getReferencedColumnValues( dialect );
attributeMapping.forEachSelectable( (j, mapping) -> {
final String tableName = entityPersister.physicalTableNameForMutation( mapping );
final ColumnValuesTableMutationBuilder tableUpdateBuilder = mutationGroupBuilder.findTableDetailsBuilder( tableName );
tableUpdateBuilder.addValueColumn(
mapping.getSelectionExpression(),
writePropertyValue ? "?" : columnValues[j],
mapping.getJdbcMapping()
);
} );
}
} }

View File

@ -11,7 +11,6 @@ import java.util.List;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey; import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings; import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
import org.hibernate.engine.jdbc.mutation.MutationExecutor; import org.hibernate.engine.jdbc.mutation.MutationExecutor;
@ -24,7 +23,6 @@ import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping; import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.AbstractEntityPersister; import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.sql.model.MutationOperationGroup; import org.hibernate.sql.model.MutationOperationGroup;
import org.hibernate.sql.model.MutationType; import org.hibernate.sql.model.MutationType;
@ -33,8 +31,9 @@ import org.hibernate.sql.model.ValuesAnalysis;
import org.hibernate.sql.model.ast.builder.MutationGroupBuilder; import org.hibernate.sql.model.ast.builder.MutationGroupBuilder;
import org.hibernate.sql.model.ast.builder.TableInsertBuilder; import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
import org.hibernate.sql.model.ast.builder.TableInsertBuilderStandard; import org.hibernate.sql.model.ast.builder.TableInsertBuilderStandard;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
import org.hibernate.tuple.InMemoryValueGenerationStrategy; import org.hibernate.tuple.InMemoryValueGenerationStrategy;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.entity.EntityMetamodel; import org.hibernate.tuple.entity.EntityMetamodel;
/** /**
@ -135,14 +134,7 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
private Object doStaticInserts(Object id, Object[] values, Object object, SharedSessionContractImplementor session) { private Object doStaticInserts(Object id, Object[] values, Object object, SharedSessionContractImplementor session) {
final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values ); final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values );
final TableInclusionChecker tableInclusionChecker = (tableMapping) -> { final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis );
if ( tableMapping.isOptional() ) {
return insertValuesAnalysis.hasNonNullBindings( tableMapping );
}
return true;
};
final MutationExecutorService mutationExecutorService = session.getSessionFactory() final MutationExecutorService mutationExecutorService = session.getSessionFactory()
.getServiceRegistry() .getServiceRegistry()
@ -278,13 +270,7 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values ); final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values );
final TableInclusionChecker tableInclusionChecker = (tableMapping) -> { final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis );
if ( tableMapping.isOptional() ) {
return insertValuesAnalysis.hasNonNullBindings( tableMapping );
}
return true;
};
decomposeForInsert( mutationExecutor, id, values, insertGroup, insertability, tableInclusionChecker, session ); decomposeForInsert( mutationExecutor, id, values, insertGroup, insertability, tableInclusionChecker, session );
@ -310,6 +296,10 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
} }
} }
private static TableInclusionChecker getTableInclusionChecker(InsertValuesAnalysis insertValuesAnalysis) {
return (tableMapping) -> !tableMapping.isOptional() || insertValuesAnalysis.hasNonNullBindings( tableMapping );
}
/** /**
* Transform the array of property indexes to an array of booleans, * Transform the array of property indexes to an array of booleans,
@ -387,8 +377,6 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
MutationGroupBuilder insertGroupBuilder, MutationGroupBuilder insertGroupBuilder,
boolean[] attributeInclusions) { boolean[] attributeInclusions) {
final List<AttributeMapping> attributeMappings = entityPersister().getAttributeMappings(); final List<AttributeMapping> attributeMappings = entityPersister().getAttributeMappings();
//noinspection resource
final Dialect dialect = factory().getJdbcServices().getDialect();
insertGroupBuilder.forEachTableMutationBuilder( (builder) -> { insertGroupBuilder.forEachTableMutationBuilder( (builder) -> {
final EntityTableMapping tableMapping = (EntityTableMapping) builder.getMutatingTable().getTableMapping(); final EntityTableMapping tableMapping = (EntityTableMapping) builder.getMutatingTable().getTableMapping();
@ -402,18 +390,12 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
final AttributeMapping attributeMapping = attributeMappings.get( attributeIndex ); final AttributeMapping attributeMapping = attributeMappings.get( attributeIndex );
if ( !attributeInclusions[ attributeIndex ] ) { if ( !attributeInclusions[ attributeIndex ] ) {
final ValueGeneration valueGeneration = attributeMapping.getValueGeneration(); final ValueGenerationStrategy valueGeneration = attributeMapping.getValueGeneration();
if ( valueGeneration.getGenerationTiming().includesInsert() if ( isValueGenerationInSql( valueGeneration ) ) {
&& valueGeneration.getValueGenerator() == null handleValueGeneration(
&& valueGeneration.referenceColumnInSql() ) { attributeMapping,
// value-generation is only valid for basic attributes insertGroupBuilder,
final BasicAttributeMapping basicAttributeMapping = (BasicAttributeMapping) attributeMapping; (InDatabaseValueGenerationStrategy) valueGeneration
final String tableNameForMutation = entityPersister().physicalTableNameForMutation( basicAttributeMapping );
final TableInsertBuilder tableInsertBuilder = insertGroupBuilder.findTableDetailsBuilder( tableNameForMutation );
tableInsertBuilder.addValueColumn(
basicAttributeMapping.getSelectionExpression(),
valueGeneration.getDatabaseGeneratedReferencedColumnValue( dialect ),
basicAttributeMapping.getJdbcMapping()
); );
} }
continue; continue;
@ -454,4 +436,10 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
} }
} ); } );
} }
private static boolean isValueGenerationInSql(ValueGenerationStrategy valueGeneration) {
return valueGeneration.getGenerationTiming().includesInsert()
&& valueGeneration.generatedByDatabase()
&& ( (InDatabaseValueGenerationStrategy) valueGeneration ).referenceColumnsInSql();
}
} }

View File

@ -14,7 +14,6 @@ import java.util.Set;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey; import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
import org.hibernate.engine.jdbc.batch.spi.BatchKey; import org.hibernate.engine.jdbc.batch.spi.BatchKey;
@ -35,7 +34,6 @@ import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.EntityRowIdMapping; import org.hibernate.metamodel.mapping.EntityRowIdMapping;
import org.hibernate.metamodel.mapping.EntityVersionMapping; import org.hibernate.metamodel.mapping.EntityVersionMapping;
import org.hibernate.metamodel.mapping.SingularAttributeMapping; import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.AbstractEntityPersister; import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.sql.ast.SqlAstTranslator; import org.hibernate.sql.ast.SqlAstTranslator;
import org.hibernate.sql.ast.SqlAstTranslatorFactory; import org.hibernate.sql.ast.SqlAstTranslatorFactory;
@ -51,8 +49,9 @@ import org.hibernate.sql.model.ast.builder.TableUpdateBuilderSkipped;
import org.hibernate.sql.model.ast.builder.TableUpdateBuilderStandard; import org.hibernate.sql.model.ast.builder.TableUpdateBuilderStandard;
import org.hibernate.sql.model.internal.MutationOperationGroupSingle; import org.hibernate.sql.model.internal.MutationOperationGroupSingle;
import org.hibernate.sql.model.jdbc.JdbcMutationOperation; import org.hibernate.sql.model.jdbc.JdbcMutationOperation;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
import org.hibernate.tuple.InMemoryValueGenerationStrategy; import org.hibernate.tuple.InMemoryValueGenerationStrategy;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.entity.EntityMetamodel; import org.hibernate.tuple.entity.EntityMetamodel;
import static org.hibernate.engine.OptimisticLockStyle.ALL; import static org.hibernate.engine.OptimisticLockStyle.ALL;
@ -213,10 +212,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
} }
final InclusionChecker updateabilityChecker = (position, attribute) -> { final InclusionChecker updateabilityChecker = (position, attribute) -> {
final ValueGeneration valueGeneration = attribute.getValueGeneration(); if ( isValueGenerationInSql( attribute.getValueGeneration() ) ) {
if ( valueGeneration.getGenerationTiming().includesUpdate()
&& valueGeneration.getValueGenerator() == null
&& valueGeneration.referenceColumnInSql() ) {
return true; return true;
} }
@ -253,8 +249,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
if ( optimisticLockStyle == VERSION ) { if ( optimisticLockStyle == VERSION ) {
return versionMapping != null return versionMapping != null
&& versionMapping.getVersionAttribute() == attribute && versionMapping.getVersionAttribute() == attribute;
;
// && updateableAttributeIndexes[position]; // && updateableAttributeIndexes[position];
} }
@ -313,6 +308,12 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
} }
} }
private static boolean isValueGenerationInSql(ValueGenerationStrategy valueGeneration) {
return valueGeneration.getGenerationTiming().includesUpdate()
&& valueGeneration.generatedByDatabase()
&& ( (InDatabaseValueGenerationStrategy) valueGeneration ).referenceColumnsInSql();
}
/** /**
* Which properties appear in the SQL update? * Which properties appear in the SQL update?
* (Initialized, updateable ones!) * (Initialized, updateable ones!)
@ -657,16 +658,14 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
} }
final IncludedAttributeAnalysis attributeAnalysis = (IncludedAttributeAnalysis) attributeAnalysisRef; final IncludedAttributeAnalysis attributeAnalysis = (IncludedAttributeAnalysis) attributeAnalysisRef;
final ValueGeneration valueGeneration = attributeMapping.getValueGeneration();
if ( attributeAnalysis.includeInSet() ) { if ( attributeAnalysis.includeInSet() ) {
// apply the new values // apply the new values
final boolean includeInSet; final boolean includeInSet;
if ( valueGeneration.getGenerationTiming().includesUpdate() final ValueGenerationStrategy valueGeneration = attributeMapping.getValueGeneration();
&& valueGeneration.getValueGenerator() == null if ( isValueGenerationInSql( valueGeneration )
&& valueGeneration.referenceColumnInSql() && !( (InDatabaseValueGenerationStrategy) valueGeneration ).writePropertyValue() ) {
&& valueGeneration.getDatabaseGeneratedReferencedColumnValue() != null ) {
// we applied `#getDatabaseGeneratedReferencedColumnValue` earlier // we applied `#getDatabaseGeneratedReferencedColumnValue` earlier
includeInSet = false; includeInSet = false;
} }
@ -881,7 +880,6 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
final List<AttributeMapping> attributeMappings = entityPersister().getAttributeMappings(); final List<AttributeMapping> attributeMappings = entityPersister().getAttributeMappings();
final boolean[] versionability = entityPersister().getPropertyVersionability(); final boolean[] versionability = entityPersister().getPropertyVersionability();
final OptimisticLockStyle optimisticLockStyle = entityPersister().optimisticLockStyle(); final OptimisticLockStyle optimisticLockStyle = entityPersister().optimisticLockStyle();
final Dialect dialect = factory().getJdbcServices().getDialect();
updateGroupBuilder.forEachTableMutationBuilder( (builder) -> { updateGroupBuilder.forEachTableMutationBuilder( (builder) -> {
final EntityTableMapping tableMapping = (EntityTableMapping) builder.getMutatingTable().getTableMapping(); final EntityTableMapping tableMapping = (EntityTableMapping) builder.getMutatingTable().getTableMapping();
@ -898,21 +896,12 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
if ( attributeAnalysis.includeInSet() ) { if ( attributeAnalysis.includeInSet() ) {
assert updateValuesAnalysis.tablesNeedingUpdate.contains( tableMapping ); assert updateValuesAnalysis.tablesNeedingUpdate.contains( tableMapping );
final ValueGeneration valueGeneration = attributeMapping.getValueGeneration(); final ValueGenerationStrategy valueGeneration = attributeMapping.getValueGeneration();
if ( valueGeneration.getGenerationTiming().includesUpdate() if ( isValueGenerationInSql( valueGeneration ) ) {
&& valueGeneration.getValueGenerator() == null handleValueGeneration(
&& valueGeneration.referenceColumnInSql() ) { attributeMapping,
// value-generation is only valid for basic attributes updateGroupBuilder,
final BasicAttributeMapping basicAttributeMapping = (BasicAttributeMapping) attributeMapping; (InDatabaseValueGenerationStrategy) valueGeneration
final String databaseGeneratedValue = valueGeneration.getDatabaseGeneratedReferencedColumnValue(
dialect
);
tableUpdateBuilder.addValueColumn(
basicAttributeMapping.getSelectionExpression(),
databaseGeneratedValue == null
? "?"
: databaseGeneratedValue,
basicAttributeMapping.getJdbcMapping()
); );
} }
else if ( versionMapping != null else if ( versionMapping != null
@ -1014,7 +1003,6 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
} ); } );
} }
/** /**
* Contains the aggregated analysis of the update values to determine * Contains the aggregated analysis of the update values to determine
* what SQL UPDATE statement(s) should be used to update the entity * what SQL UPDATE statement(s) should be used to update the entity
@ -1344,10 +1332,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
null, null,
null, null,
(index,attribute) -> { (index,attribute) -> {
final ValueGeneration valueGeneration = attribute.getValueGeneration(); if ( isValueGenerationInSql( attribute.getValueGeneration() ) ) {
if ( valueGeneration.getGenerationTiming().includesUpdate()
&& valueGeneration.getValueGenerator() == null
&& valueGeneration.referenceColumnInSql() ) {
return true; return true;
} }

View File

@ -6,7 +6,6 @@
*/ */
package org.hibernate.sql.ast.spi; package org.hibernate.sql.ast.spi;
import java.util.Objects;
import java.util.function.Function; import java.util.function.Function;
import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.mapping.SelectableMapping;

View File

@ -0,0 +1,50 @@
/*
* 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.sql.model.ast.builder;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.SelectableMapping;
/**
* Common operations of {@link TableUpdateBuilder} and {@link TableInsertBuilder}.
*
* @author Steve Ebersole
* @author Gavin King
*/
public interface ColumnValuesTableMutationBuilder {
/**
* Add a column as part of the values list
*/
void addValueColumn(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping);
/**
* Add a column as part of the values list
*/
default void addValueColumn(SelectableMapping selectableMapping) {
addValueColumn(
selectableMapping.getSelectionExpression(),
selectableMapping.getWriteExpression(),
selectableMapping.getJdbcMapping()
);
}
/**
* Add a key column
*/
void addKeyColumn(String columnName, String valueExpression, JdbcMapping jdbcMapping);
/**
* Add a key column
*/
default void addKeyColumn(SelectableMapping selectableMapping) {
addKeyColumn(
selectableMapping.getSelectionExpression(),
selectableMapping.getWriteExpression(),
selectableMapping.getJdbcMapping()
);
}
}

View File

@ -13,8 +13,10 @@ import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.ast.RestrictedTableMutation; import org.hibernate.sql.model.ast.RestrictedTableMutation;
/** /**
* Specialized TableMutationBuilder implementation for building mutations * Specialized {@link TableMutationBuilder} implementation for building mutations
* which define a where-clause * which have a {@code where} clause.
*
* Common operations of {@link TableUpdateBuilder} and {@link TableDeleteBuilder}.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */

View File

@ -10,6 +10,8 @@ import org.hibernate.sql.model.ast.TableDelete;
import org.hibernate.sql.model.jdbc.JdbcDeleteMutation; import org.hibernate.sql.model.jdbc.JdbcDeleteMutation;
/** /**
* {@link TableMutationBuilder} implementation for {@code delete} statements.
*
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface TableDeleteBuilder extends RestrictedTableMutationBuilder<JdbcDeleteMutation, TableDelete> { public interface TableDeleteBuilder extends RestrictedTableMutationBuilder<JdbcDeleteMutation, TableDelete> {

View File

@ -6,45 +6,13 @@
*/ */
package org.hibernate.sql.model.ast.builder; package org.hibernate.sql.model.ast.builder;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.sql.model.ast.TableInsert; import org.hibernate.sql.model.ast.TableInsert;
/** /**
* TableMutationBuilder implementation for insert statements * {@link TableMutationBuilder} implementation for {@code insert} statements.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface TableInsertBuilder extends TableMutationBuilder<TableInsert> { public interface TableInsertBuilder extends TableMutationBuilder<TableInsert>, ColumnValuesTableMutationBuilder {
/**
* Add a column as part of the values list
*/
default void addValueColumn(SelectableMapping selectableMapping) {
addValueColumn(
selectableMapping.getSelectionExpression(),
selectableMapping.getWriteExpression(),
selectableMapping.getJdbcMapping()
);
}
/**
* Add a column as part of the values list
*/
void addValueColumn(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping);
/**
* Add a key column
*/
default void addKeyColumn(SelectableMapping selectableMapping) {
addKeyColumn(
selectableMapping.getSelectionExpression(),
selectableMapping.getWriteExpression(),
selectableMapping.getJdbcMapping()
);
}
/**
* Add a key column
*/
void addKeyColumn(String columnName, String valueExpression, JdbcMapping jdbcMapping);
} }

View File

@ -6,28 +6,18 @@
*/ */
package org.hibernate.sql.model.ast.builder; package org.hibernate.sql.model.ast.builder;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.sql.model.MutationOperation; import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.ast.RestrictedTableMutation; import org.hibernate.sql.model.ast.RestrictedTableMutation;
/** /**
* {@link TableMutationBuilder} implementation for {@code update} statements.
*
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface TableUpdateBuilder<O extends MutationOperation> public interface TableUpdateBuilder<O extends MutationOperation>
extends RestrictedTableMutationBuilder<O, RestrictedTableMutation<O>> { extends RestrictedTableMutationBuilder<O, RestrictedTableMutation<O>>, ColumnValuesTableMutationBuilder {
/**
* Add a column as part of the values list
*/
default void addValueColumn(SelectableMapping selectableMapping) {
addValueColumn(
selectableMapping.getSelectionExpression(),
selectableMapping.getWriteExpression(),
selectableMapping.getJdbcMapping()
);
}
/** /**
* Convenience form of {@link #addValueColumn(SelectableMapping)} matching the * Convenience form of {@link #addValueColumn(SelectableMapping)} matching the
@ -42,26 +32,5 @@ public interface TableUpdateBuilder<O extends MutationOperation>
addValueColumn( selectableMapping ); addValueColumn( selectableMapping );
} }
/**
* Add a column as part of the values list
*/
void addValueColumn(String columnName, String columnWriteFragment, JdbcMapping jdbcMapping);
/**
* Add a key column
*/
default void addKeyColumn(SelectableMapping selectableMapping) {
addKeyColumn(
selectableMapping.getSelectionExpression(),
selectableMapping.getWriteExpression(),
selectableMapping.getJdbcMapping()
);
}
/**
* Add a key column
*/
void addKeyColumn(String columnName, String valueExpression, JdbcMapping jdbcMapping);
void setWhere(String fragment); void setWhere(String fragment);
} }

View File

@ -69,7 +69,7 @@ public abstract class AbstractNonIdentifierAttribute extends AbstractAttribute i
} }
@Override @Override
public ValueGeneration getValueGenerationStrategy() { public ValueGenerationStrategy getValueGenerationStrategy() {
return attributeInformation.getValueGenerationStrategy(); return attributeInformation.getValueGenerationStrategy();
} }

View File

@ -16,7 +16,7 @@ public class BaselineAttributeInformation {
private final boolean lazy; private final boolean lazy;
private final boolean insertable; private final boolean insertable;
private final boolean updateable; private final boolean updateable;
private final ValueGeneration valueGenerationStrategy; private final ValueGenerationStrategy valueGenerationStrategy;
private final boolean nullable; private final boolean nullable;
private final boolean dirtyCheckable; private final boolean dirtyCheckable;
private final boolean versionable; private final boolean versionable;
@ -28,7 +28,7 @@ public class BaselineAttributeInformation {
boolean lazy, boolean lazy,
boolean insertable, boolean insertable,
boolean updateable, boolean updateable,
ValueGeneration valueGenerationStrategy, ValueGenerationStrategy valueGenerationStrategy,
boolean nullable, boolean nullable,
boolean dirtyCheckable, boolean dirtyCheckable,
boolean versionable, boolean versionable,
@ -57,7 +57,7 @@ public class BaselineAttributeInformation {
return updateable; return updateable;
} }
public ValueGeneration getValueGenerationStrategy() { public ValueGenerationStrategy getValueGenerationStrategy() {
return valueGenerationStrategy; return valueGenerationStrategy;
} }
@ -89,7 +89,7 @@ public class BaselineAttributeInformation {
private boolean lazy; private boolean lazy;
private boolean insertable; private boolean insertable;
private boolean updateable; private boolean updateable;
private ValueGeneration valueGenerationStrategy; private ValueGenerationStrategy valueGenerationStrategy;
private boolean nullable; private boolean nullable;
private boolean dirtyCheckable; private boolean dirtyCheckable;
private boolean versionable; private boolean versionable;
@ -111,7 +111,7 @@ public class BaselineAttributeInformation {
return this; return this;
} }
public Builder setValueGenerationStrategy(ValueGeneration valueGenerationStrategy) { public Builder setValueGenerationStrategy(ValueGenerationStrategy valueGenerationStrategy) {
this.valueGenerationStrategy = valueGenerationStrategy; this.valueGenerationStrategy = valueGenerationStrategy;
return this; return this;
} }

View File

@ -6,37 +6,63 @@
*/ */
package org.hibernate.tuple; package org.hibernate.tuple;
import org.hibernate.dialect.Dialect;
/** /**
* Strategy for describing values which are generated in the database. * A value generated by the database might be generated implicitly, by a trigger, or using
* a {@code default} column value specified in DDL, for example, or it might be generated
* by a SQL expression occurring explicitly in the SQL {@code insert} or {@code update}
* statement. In this case, the generated value is retrieved from the database using a SQL
* {@code select}.
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface InDatabaseValueGenerationStrategy { public interface InDatabaseValueGenerationStrategy extends ValueGenerationStrategy {
/**
* When is this value generated : NEVER, INSERT, ALWAYS (INSERT+UPDATE)
*
* @return When the value is generated.
*/
GenerationTiming getGenerationTiming();
/** /**
* Should the column(s) be referenced in the INSERT / UPDATE SQL? * Determines if the columns whose values are generated are included in the column list of
* <p> * the SQL {@code insert} or {@code update} statement, in the case where the value is
* This will be {@code false} most often to have a DDL-defined DEFAULT value be applied on INSERT. For * generated by the database. For example, this method should return:
* trigger-generated values this could be {@code true} or {@code false} depending on whether the user wants * <ul>
* the trigger to have access to some value for the column passed in. * <li>{@code true} if the value is generated by calling a SQL function like
* {@code current_timestamp}, or
* <li>{@code false} if the value is generated by a trigger,
* by {@link org.hibernate.annotations.GeneratedColumn generated always as}, or
* using a {@linkplain org.hibernate.annotations.ColumnDefault column default value}.
* </ul>
* If the value is generated in Java, this method is not called, and so for backward
* compatibility with Hibernate 5 it is permitted to return any value. On the other hand,
* when a property value is generated in Java, the column certainly must be included in
* the column list, and so it's most correct for this method to return {@code true}!
* *
* @return {@code true} indicates the column should be included in the SQL. * @return {@code true} if the column is included in the column list of the SQL statement.
*/ */
boolean referenceColumnsInSql(); boolean referenceColumnsInSql();
/** /**
* For columns that will be referenced in the SQL (per {@link #referenceColumnsInSql()}), what value * Determines if the property values are written to JDBC as the argument of a JDBC {@code ?}
* should be used in the SQL as the column value. * parameter.
*
* @return The column value to be used in the SQL. {@code null} for any element indicates to use the Column
* defined value ({@link org.hibernate.mapping.Column#getWriteExpr}).
*/ */
String[] getReferencedColumnValues(); boolean writePropertyValue();
/**
* A SQL expression indicating how to calculate the generated values when the property values
* are {@linkplain #generatedByDatabase() generated in the database} and the mapped columns
* are {@linkplain #referenceColumnsInSql() included in the SQL statement}. The SQL expressions
* might be:
* <ul>
* <li>function calls like {@code current_timestamp} or {@code nextval('mysequence')}, or
* <li>syntactic markers like {@code default}.
* </ul>
* When the property values are generated in Java, this method is not called.
*
* @param dialect The {@linkplain Dialect SQL dialect}, allowing generation of an expression
* in dialect-specific SQL.
* @return The column value to be used in the generated SQL statement.
*/
String[] getReferencedColumnValues(Dialect dialect);
default boolean generatedByDatabase() {
return true;
}
} }

View File

@ -7,23 +7,23 @@
package org.hibernate.tuple; package org.hibernate.tuple;
/** /**
* Java value generation is the responsibility of an associated {@link ValueGenerator}.
* In this case, the generated value is written to the database just like any other field
* or property value.
*
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface InMemoryValueGenerationStrategy { public interface InMemoryValueGenerationStrategy extends ValueGenerationStrategy {
/**
* When is this value generated : NEVER, INSERT, ALWAYS (INSERT+UPDATE)
*
* @return When the value is generated.
*/
GenerationTiming getGenerationTiming();
/** /**
* Obtain the in-VM value generator. * Obtain the {@linkplain ValueGenerator Java value generator}, if the value is generated in
* <p> * Java, or return {@code null} if the value is generated by the database.
* May return {@code null}. In fact for values that are generated "in the database" via execution of the
* INSERT/UPDATE statement, the expectation is that {@code null} be returned here
* *
* @return The strategy for performing in-VM value generation * @return The value generator
*/ */
ValueGenerator<?> getValueGenerator(); ValueGenerator<?> getValueGenerator();
default boolean generatedByDatabase() {
return false;
}
} }

View File

@ -19,7 +19,7 @@ public interface NonIdentifierAttribute extends Attribute {
boolean isUpdateable(); boolean isUpdateable();
ValueGeneration getValueGenerationStrategy(); ValueGenerationStrategy getValueGenerationStrategy();
boolean isNullable(); boolean isNullable();

View File

@ -6,24 +6,16 @@
*/ */
package org.hibernate.tuple; package org.hibernate.tuple;
import java.lang.reflect.Constructor;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.metamodel.RepresentationMode;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.property.access.spi.Getter;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.property.access.spi.PropertyAccessStrategy;
import org.hibernate.property.access.spi.PropertyAccessStrategyResolver;
import org.hibernate.tuple.entity.EntityBasedAssociationAttribute; import org.hibernate.tuple.entity.EntityBasedAssociationAttribute;
import org.hibernate.tuple.entity.EntityBasedBasicAttribute; import org.hibernate.tuple.entity.EntityBasedBasicAttribute;
import org.hibernate.tuple.entity.EntityBasedCompositionAttribute; import org.hibernate.tuple.entity.EntityBasedCompositionAttribute;

View File

@ -42,7 +42,7 @@ public class StandardProperty extends AbstractNonIdentifierAttribute implements
boolean lazy, boolean lazy,
boolean insertable, boolean insertable,
boolean updateable, boolean updateable,
ValueGeneration valueGenerationStrategy, ValueGenerationStrategy valueGenerationStrategy,
boolean nullable, boolean nullable,
boolean checkable, boolean checkable,
boolean versionable, boolean versionable,

View File

@ -8,50 +8,14 @@ package org.hibernate.tuple;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import java.io.Serializable;
/** /**
* Describes the generation of values of a certain field or property of an entity. A generated * A value generator that can adapt to both Java value generation and database value
* value might be generated in Java, or by the database. * generation.
* <ul>
* <li>Java value generation is the responsibility of an associated {@link ValueGenerator}.
* In this case, the generated value is written to the database just like any other field
* or property value.
* <li>A value generated by the database might be generated implicitly, by a trigger, or using
* a {@code default} column value specified in DDL, for example, or it might be generated
* by a SQL expression occurring explicitly in the SQL {@code insert} or {@code update}
* statement. In this case, the generated value is retrieved from the database using a SQL
* {@code select}.
* </ul>
*
* @see org.hibernate.annotations.ValueGenerationType
* @see org.hibernate.annotations.Generated
* @see org.hibernate.annotations.GeneratorType
* *
* @author Steve Ebersole * @author Steve Ebersole
* @author Gavin King
*/ */
public interface ValueGeneration extends Serializable { public interface ValueGeneration extends InMemoryValueGenerationStrategy, InDatabaseValueGenerationStrategy {
/**
* Specifies that the property value is generated:
* <ul>
* <li>{@linkplain GenerationTiming#INSERT when the entity is inserted},
* <li>{@linkplain GenerationTiming#UPDATE when the entity is updated},
* <li>{@linkplain GenerationTiming#ALWAYS whenever the entity is inserted or updated}, or
* <li>{@linkplain GenerationTiming#NEVER never}.
* </ul>
*
* @return The {@link GenerationTiming} specifying when the value is generated.
*/
GenerationTiming getGenerationTiming();
/**
* Obtain the {@linkplain ValueGenerator Java value generator}, if the value is generated in
* Java, or return {@code null} if the value is generated by the database.
*
* @return The value generator
*/
ValueGenerator<?> getValueGenerator();
/** /**
* Determines if the column whose value is generated is included in the column list of the * Determines if the column whose value is generated is included in the column list of the
* SQL {@code insert} or {@code update} statement, in the case where the value is generated * SQL {@code insert} or {@code update} statement, in the case where the value is generated
@ -110,6 +74,17 @@ public interface ValueGeneration extends Serializable {
return getDatabaseGeneratedReferencedColumnValue(); return getDatabaseGeneratedReferencedColumnValue();
} }
@Override
default String[] getReferencedColumnValues(Dialect dialect) {
String columnValue = getDatabaseGeneratedReferencedColumnValue( dialect );
return columnValue == null ? null : new String[] { columnValue };
}
@Override
default boolean referenceColumnsInSql() {
return referenceColumnInSql();
}
/** /**
* Determines if the property value is generated in Java, or by the database. * Determines if the property value is generated in Java, or by the database.
* <p> * <p>
@ -137,6 +112,6 @@ public interface ValueGeneration extends Serializable {
default boolean writePropertyValue() { default boolean writePropertyValue() {
return !generatedByDatabase() // value generated in memory and then written as normal return !generatedByDatabase() // value generated in memory and then written as normal
// current value of property of entity instance written completely as normal // current value of property of entity instance written completely as normal
|| referenceColumnInSql() && getDatabaseGeneratedReferencedColumnValue()==null; || referenceColumnsInSql() && getDatabaseGeneratedReferencedColumnValue()==null;
} }
} }

View File

@ -0,0 +1,52 @@
/*
* 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;
import java.io.Serializable;
/**
* Describes the generation of values of a certain field or property of an entity. A generated
* value might be generated in Java, or by the database.
* <ul>
* <li>Java value generation is the responsibility of an associated {@link ValueGenerator}.
* In this case, the generated value is written to the database just like any other field
* or property value.
* <li>A value generated by the database might be generated implicitly, by a trigger, or using
* a {@code default} column value specified in DDL, for example, or it might be generated
* by a SQL expression occurring explicitly in the SQL {@code insert} or {@code update}
* statement. In this case, the generated value is retrieved from the database using a SQL
* {@code select}.
* </ul>
*
* @see org.hibernate.annotations.ValueGenerationType
* @see org.hibernate.annotations.Generated
* @see org.hibernate.annotations.GeneratorType
*
* @author Steve Ebersole
* @author Gavin King
*/
public interface ValueGenerationStrategy extends Serializable {
/**
* Specifies that the property value is generated:
* <ul>
* <li>{@linkplain GenerationTiming#INSERT when the entity is inserted},
* <li>{@linkplain GenerationTiming#UPDATE when the entity is updated},
* <li>{@linkplain GenerationTiming#ALWAYS whenever the entity is inserted or updated}, or
* <li>{@linkplain GenerationTiming#NEVER never}.
* </ul>
*
* @return The {@link GenerationTiming} specifying when the value is generated.
*/
GenerationTiming getGenerationTiming();
/**
* Determines if the property value is generated in Java, or by the database.
* @return {@code true} if the value is generated by the database, or false if it is
* generated in Java using a {@link ValueGenerator}.
*/
boolean generatedByDatabase();
}

View File

@ -40,13 +40,13 @@ import org.hibernate.mapping.Subclass;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.spi.PersisterCreationContext; import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
import org.hibernate.tuple.GenerationTiming; import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.IdentifierProperty; import org.hibernate.tuple.IdentifierProperty;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
import org.hibernate.tuple.InMemoryValueGenerationStrategy; import org.hibernate.tuple.InMemoryValueGenerationStrategy;
import org.hibernate.tuple.NonIdentifierAttribute; import org.hibernate.tuple.NonIdentifierAttribute;
import org.hibernate.tuple.PropertyFactory; import org.hibernate.tuple.PropertyFactory;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.ValueGenerator; import org.hibernate.tuple.ValueGenerator;
import org.hibernate.type.AssociationType; import org.hibernate.type.AssociationType;
import org.hibernate.type.CollectionType; import org.hibernate.type.CollectionType;
@ -458,28 +458,25 @@ public class EntityMetamodel implements Serializable {
private static GenerationStrategyPair buildGenerationStrategyPair( private static GenerationStrategyPair buildGenerationStrategyPair(
final SessionFactoryImplementor sessionFactory, final SessionFactoryImplementor sessionFactory,
final Property mappingProperty) { final Property mappingProperty) {
final ValueGeneration valueGeneration = mappingProperty.getValueGenerationStrategy(); final ValueGenerationStrategy valueGeneration = mappingProperty.getValueGenerationStrategy();
if ( valueGeneration != null && valueGeneration.getGenerationTiming() != GenerationTiming.NEVER ) { if ( valueGeneration != null && valueGeneration.getGenerationTiming() != GenerationTiming.NEVER ) {
// the property is generated in full. build the generation strategy pair. // the property is generated in full. build the generation strategy pair.
if ( !valueGeneration.generatedByDatabase() ) { if ( !valueGeneration.generatedByDatabase() ) {
// in-memory generation // in-memory generation
return new GenerationStrategyPair( return new GenerationStrategyPair(
FullInMemoryValueGenerationStrategy.create( valueGeneration ) FullInMemoryValueGenerationStrategy.create( (InMemoryValueGenerationStrategy) valueGeneration )
); );
} }
else { else {
// in-db generation // in-db generation
return new GenerationStrategyPair( return new GenerationStrategyPair( (InDatabaseValueGenerationStrategy) valueGeneration );
create(
sessionFactory,
mappingProperty,
valueGeneration
)
);
} }
} }
else if ( mappingProperty.getValue() instanceof Component ) { else if ( mappingProperty.getValue() instanceof Component ) {
final CompositeGenerationStrategyPairBuilder builder = new CompositeGenerationStrategyPairBuilder( mappingProperty ); final CompositeGenerationStrategyPairBuilder builder = new CompositeGenerationStrategyPairBuilder(
mappingProperty,
sessionFactory.getJdbcServices().getDialect()
);
interpretPartialCompositeValueGeneration( sessionFactory, (Component) mappingProperty.getValue(), builder ); interpretPartialCompositeValueGeneration( sessionFactory, (Component) mappingProperty.getValue(), builder );
return builder.buildPair(); return builder.buildPair();
} }
@ -498,36 +495,6 @@ public class EntityMetamodel implements Serializable {
} }
} }
public static InDatabaseValueGenerationStrategyImpl create(
SessionFactoryImplementor factory,
Property mappingProperty,
ValueGeneration valueGeneration) {
final int numberOfMappedColumns = mappingProperty.getType().getColumnSpan( factory );
final Dialect dialect = factory.getJdbcServices().getDialect();
if ( numberOfMappedColumns == 1 ) {
return new InDatabaseValueGenerationStrategyImpl(
valueGeneration.getGenerationTiming(),
valueGeneration.referenceColumnInSql(),
new String[] { valueGeneration.getDatabaseGeneratedReferencedColumnValue(dialect) }
);
}
else {
if ( valueGeneration.getDatabaseGeneratedReferencedColumnValue(dialect) != null ) {
LOG.debugf(
"Value generator specified column value in reference to multi-column attribute [%s -> %s]; ignoring",
mappingProperty.getPersistentClass(),
mappingProperty.getName()
);
}
return new InDatabaseValueGenerationStrategyImpl(
valueGeneration.getGenerationTiming(),
valueGeneration.referenceColumnInSql(),
new String[numberOfMappedColumns]
);
}
}
public static class GenerationStrategyPair { public static class GenerationStrategyPair {
private final InMemoryValueGenerationStrategy inMemoryStrategy; private final InMemoryValueGenerationStrategy inMemoryStrategy;
private final InDatabaseValueGenerationStrategy inDatabaseStrategy; private final InDatabaseValueGenerationStrategy inDatabaseStrategy;
@ -540,7 +507,7 @@ public class EntityMetamodel implements Serializable {
this( inMemoryStrategy, NoInDatabaseValueGenerationStrategy.INSTANCE ); this( inMemoryStrategy, NoInDatabaseValueGenerationStrategy.INSTANCE );
} }
public GenerationStrategyPair(InDatabaseValueGenerationStrategyImpl inDatabaseStrategy) { public GenerationStrategyPair(InDatabaseValueGenerationStrategy inDatabaseStrategy) {
this( NoInMemoryValueGenerationStrategy.INSTANCE, inDatabaseStrategy ); this( NoInMemoryValueGenerationStrategy.INSTANCE, inDatabaseStrategy );
} }
@ -583,14 +550,16 @@ public class EntityMetamodel implements Serializable {
private static class CompositeGenerationStrategyPairBuilder { private static class CompositeGenerationStrategyPairBuilder {
private final Property mappingProperty; private final Property mappingProperty;
private final Dialect dialect;
private boolean hadInMemoryGeneration; private boolean hadInMemoryGeneration;
private boolean hadInDatabaseGeneration; private boolean hadInDatabaseGeneration;
private List<InDatabaseValueGenerationStrategy> inDatabaseStrategies; private List<InDatabaseValueGenerationStrategy> inDatabaseStrategies;
public CompositeGenerationStrategyPairBuilder(Property mappingProperty) { public CompositeGenerationStrategyPairBuilder(Property mappingProperty, Dialect dialect) {
this.mappingProperty = mappingProperty; this.mappingProperty = mappingProperty;
this.dialect = dialect;
} }
public void addPair(GenerationStrategyPair generationStrategyPair) { public void addPair(GenerationStrategyPair generationStrategyPair) {
@ -675,8 +644,8 @@ public class EntityMetamodel implements Serializable {
// override base-line value // override base-line value
referenceColumns = true; referenceColumns = true;
} }
if ( subStrategy.getReferencedColumnValues() != null ) { if ( subStrategy.getReferencedColumnValues(dialect) != null ) {
if ( subStrategy.getReferencedColumnValues().length != property.getColumnSpan() ) { if ( subStrategy.getReferencedColumnValues(dialect).length != property.getColumnSpan() ) {
throw new ValueGenerationStrategyException( throw new ValueGenerationStrategyException(
"Internal error : mismatch between number of collected 'referenced column values'" + "Internal error : mismatch between number of collected 'referenced column values'" +
" and number of columns for composite attribute : " + mappingProperty.getName() + " and number of columns for composite attribute : " + mappingProperty.getName() +
@ -684,7 +653,7 @@ public class EntityMetamodel implements Serializable {
); );
} }
System.arraycopy( System.arraycopy(
subStrategy.getReferencedColumnValues(), subStrategy.getReferencedColumnValues(dialect),
0, 0,
columnValues, columnValues,
columnIndex, columnIndex,
@ -730,7 +699,7 @@ public class EntityMetamodel implements Serializable {
this.generator = generator; this.generator = generator;
} }
public static FullInMemoryValueGenerationStrategy create(ValueGeneration valueGeneration) { public static FullInMemoryValueGenerationStrategy create(InMemoryValueGenerationStrategy valueGeneration) {
return new FullInMemoryValueGenerationStrategy( return new FullInMemoryValueGenerationStrategy(
valueGeneration.getGenerationTiming(), valueGeneration.getGenerationTiming(),
valueGeneration.getValueGenerator() valueGeneration.getValueGenerator()
@ -765,9 +734,14 @@ public class EntityMetamodel implements Serializable {
} }
@Override @Override
public String[] getReferencedColumnValues() { public String[] getReferencedColumnValues(Dialect dialect) {
return null; return null;
} }
@Override
public boolean writePropertyValue() {
return true;
}
} }
private static class InDatabaseValueGenerationStrategyImpl implements InDatabaseValueGenerationStrategy { private static class InDatabaseValueGenerationStrategyImpl implements InDatabaseValueGenerationStrategy {
@ -795,9 +769,14 @@ public class EntityMetamodel implements Serializable {
} }
@Override @Override
public String[] getReferencedColumnValues() { public String[] getReferencedColumnValues(Dialect dialect) {
return referencedColumnValues; return referencedColumnValues;
} }
@Override
public boolean writePropertyValue() {
return false;
}
} }

View File

@ -35,6 +35,7 @@ import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.sqm.SqmExpressible; import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry; import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.PropertyFactory; import org.hibernate.tuple.PropertyFactory;
import org.hibernate.tuple.StandardProperty; import org.hibernate.tuple.StandardProperty;
import org.hibernate.tuple.ValueGeneration; import org.hibernate.tuple.ValueGeneration;
@ -52,7 +53,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
private final String[] propertyNames; private final String[] propertyNames;
private final Type[] propertyTypes; private final Type[] propertyTypes;
private final ValueGeneration[] propertyValueGenerationStrategies; private final ValueGenerationStrategy[] propertyValueGenerationStrategies;
private final boolean[] propertyNullability; private final boolean[] propertyNullability;
private final int[] originalPropertyOrder; private final int[] originalPropertyOrder;
protected final int propertySpan; protected final int propertySpan;
@ -437,7 +438,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
return propertyTypes; return propertyTypes;
} }
public ValueGeneration[] getPropertyValueGenerationStrategies() { public ValueGenerationStrategy[] getPropertyValueGenerationStrategies() {
return propertyValueGenerationStrategies; return propertyValueGenerationStrategies;
} }

View File

@ -33,9 +33,8 @@ import org.hibernate.envers.internal.entities.mapper.SubclassPropertyMapper;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.mapping.SyntheticProperty; import org.hibernate.mapping.SyntheticProperty;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.GeneratedValueGeneration; import org.hibernate.tuple.GeneratedValueGeneration;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.ValueGeneration;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
@ -120,7 +119,7 @@ public final class AuditMetadataGenerator extends AbstractMetadataGenerator {
private boolean isPropertyInsertable(Property property) { private boolean isPropertyInsertable(Property property) {
if ( !property.isInsertable() ) { if ( !property.isInsertable() ) {
final ValueGeneration generation = property.getValueGenerationStrategy(); final ValueGenerationStrategy generation = property.getValueGenerationStrategy();
if ( generation instanceof GeneratedValueGeneration ) { if ( generation instanceof GeneratedValueGeneration ) {
final GeneratedValueGeneration valueGeneration = (GeneratedValueGeneration) generation; final GeneratedValueGeneration valueGeneration = (GeneratedValueGeneration) generation;
if ( valueGeneration.getGenerationTiming().includesInsert() ) { if ( valueGeneration.getGenerationTiming().includesInsert() ) {