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.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.property.access.spi.PropertyAccessStrategy;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.AnnotationValueGeneration;
import org.hibernate.tuple.AttributeBinder;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.ValueGenerator;
@ -383,19 +385,17 @@ public class PropertyBinder {
}
}
private ValueGeneration determineValueGenerationStrategy(XProperty property) {
ValueGeneration valueGeneration = getValueGenerationFromAnnotations( property );
private ValueGenerationStrategy determineValueGenerationStrategy(XProperty property) {
ValueGenerationStrategy valueGeneration = getValueGenerationFromAnnotations( property );
if ( valueGeneration == null ) {
return NoValueGeneration.INSTANCE;
}
if ( !valueGeneration.writePropertyValue() ) {
if ( valueGeneration instanceof InDatabaseValueGenerationStrategy) {
// if we have an in-db generator, mark it as not insertable nor updatable
insertable = false;
updatable = false;
final boolean writable = ( (InDatabaseValueGenerationStrategy) valueGeneration ).writePropertyValue();
insertable = writable;
updatable = writable;
}
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.Setter;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;
@ -45,7 +45,7 @@ public class Property implements Serializable, MetaAttributable {
private boolean insertable = true;
private boolean selectable = true;
private boolean optimisticLocked = true;
private ValueGeneration valueGenerationStrategy;
private ValueGenerationStrategy valueGenerationStrategy;
private String propertyAccessorName;
private PropertyAccessStrategy propertyAccessStrategy;
private boolean lazy;
@ -216,11 +216,11 @@ public class Property implements Serializable, MetaAttributable {
return insertable && value.hasAnyInsertableColumns();
}
public ValueGeneration getValueGenerationStrategy() {
public ValueGenerationStrategy getValueGenerationStrategy() {
return valueGenerationStrategy;
}
public void setValueGenerationStrategy(ValueGeneration valueGenerationStrategy) {
public void setValueGenerationStrategy(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.sql.results.graph.DatabaseSnapshotContributor;
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.MutabilityPlan;
import org.hibernate.type.descriptor.java.MutabilityPlanExposer;
@ -70,7 +70,7 @@ public interface AttributeMapping
*
* @apiNote Only relevant for non-id attributes
*/
ValueGeneration getValueGeneration();
ValueGenerationStrategy getValueGeneration();
@Override
default EntityMappingType findContainingEntityMapping() {

View File

@ -9,8 +9,9 @@ package org.hibernate.metamodel.mapping;
import org.hibernate.Incubating;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.internal.NoGeneratedValueResolver;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.InMemoryValueGenerationStrategy;
/**
* Generalized contract covering an attribute's generation handling
@ -20,7 +21,7 @@ import org.hibernate.tuple.ValueGeneration;
@Incubating
public interface GeneratedValueResolver {
static GeneratedValueResolver from(
ValueGeneration valueGeneration,
ValueGenerationStrategy valueGeneration,
GenerationTiming requestedTiming,
int dbSelectionPosition) {
assert requestedTiming != GenerationTiming.NEVER;
@ -38,7 +39,8 @@ public interface GeneratedValueResolver {
return new InDatabaseGeneratedValueResolver( requestedTiming, dbSelectionPosition );
}
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.property.access.spi.PropertyAccess;
import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.ValueGenerationStrategy;
/**
* @author Steve Ebersole
@ -23,7 +23,7 @@ public abstract class AbstractSingularAttributeMapping
implements SingularAttributeMapping {
private final PropertyAccess propertyAccess;
private final ValueGeneration valueGeneration;
private final ValueGenerationStrategy valueGeneration;
public AbstractSingularAttributeMapping(
String name,
@ -32,7 +32,7 @@ public abstract class AbstractSingularAttributeMapping
FetchOptions mappedFetchOptions,
ManagedMappingType declaringType,
PropertyAccess propertyAccess,
ValueGeneration valueGeneration) {
ValueGenerationStrategy valueGeneration) {
super( name, attributeMetadataAccess, mappedFetchOptions, stateArrayPosition, declaringType );
this.propertyAccess = propertyAccess;
this.valueGeneration = valueGeneration != null
@ -48,7 +48,7 @@ public abstract class AbstractSingularAttributeMapping
FetchStyle fetchStyle,
ManagedMappingType declaringType,
PropertyAccess propertyAccess,
ValueGeneration valueGeneration) {
ValueGenerationStrategy valueGeneration) {
super( name, attributeMetadataAccess, fetchTiming, fetchStyle, stateArrayPosition, declaringType );
this.propertyAccess = propertyAccess;
this.valueGeneration = valueGeneration != null
@ -62,7 +62,7 @@ public abstract class AbstractSingularAttributeMapping
}
@Override
public ValueGeneration getValueGeneration() {
public ValueGenerationStrategy getValueGeneration() {
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.basic.BasicFetch;
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;
/**
@ -87,7 +87,7 @@ public class BasicAttributeMapping
JdbcMapping jdbcMapping,
ManagedMappingType declaringType,
PropertyAccess propertyAccess,
ValueGeneration valueGeneration) {
ValueGenerationStrategy valueGeneration) {
super(
attributeName,
stateArrayPosition,
@ -126,7 +126,7 @@ public class BasicAttributeMapping
ManagedMappingType declaringType,
BasicValuedModelPart original,
PropertyAccess propertyAccess,
ValueGeneration valueGeneration,
ValueGenerationStrategy valueGeneration,
boolean insertable,
boolean updateable,
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.internal.EmbeddableFetchImpl;
import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.ValueGenerationStrategy;
/**
* @author Steve Ebersole
@ -80,7 +80,7 @@ public class EmbeddedAttributeMapping
EmbeddableMappingType embeddableMappingType,
ManagedMappingType declaringType,
PropertyAccess propertyAccess,
ValueGeneration valueGeneration) {
ValueGenerationStrategy valueGeneration) {
this(
name,
navigableRole,
@ -109,7 +109,7 @@ public class EmbeddedAttributeMapping
EmbeddableMappingType embeddableMappingType,
ManagedMappingType declaringType,
PropertyAccess propertyAccess,
ValueGeneration valueGeneration) {
ValueGenerationStrategy valueGeneration) {
super(
name,
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.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.type.AssociationType;
import org.hibernate.type.BasicType;
import org.hibernate.type.ComponentType;
@ -266,7 +265,6 @@ public class MappingModelCreationHelper {
fetchTiming = bootProperty.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE;
fetchStyle = bootProperty.isLazy() ? FetchStyle.SELECT : FetchStyle.JOIN;
}
final ValueGeneration valueGeneration = bootProperty.getValueGenerationStrategy();
return new BasicAttributeMapping(
attrName,
@ -290,7 +288,7 @@ public class MappingModelCreationHelper {
attrType,
declaringType,
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.property.access.spi.PropertyAccess;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.ValueGenerationStrategy;
/**
* @author Christian Beikov
@ -35,7 +35,8 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
FetchStyle mappedFetchStyle,
EmbeddableMappingType embeddableMappingType,
ManagedMappingType declaringType,
PropertyAccess propertyAccess, ValueGeneration valueGeneration) {
PropertyAccess propertyAccess,
ValueGenerationStrategy valueGeneration) {
super(
name,
navigableRole,
@ -63,7 +64,8 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im
FetchStyle mappedFetchStyle,
EmbeddableMappingType embeddableMappingType,
ManagedMappingType declaringType,
PropertyAccess propertyAccess, ValueGeneration valueGeneration) {
PropertyAccess propertyAccess,
ValueGenerationStrategy valueGeneration) {
super(
name,
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.internal.SqlSelectionImpl;
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.NonIdentifierAttribute;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.entity.EntityBasedAssociationAttribute;
import org.hibernate.tuple.entity.EntityMetamodel;
import org.hibernate.type.AnyType;
@ -2758,15 +2759,16 @@ public abstract class AbstractEntityPersister
hasColumns = true;
}
else {
final ValueGeneration valueGeneration = attributeMapping.getValueGeneration();
final ValueGenerationStrategy valueGeneration = attributeMapping.getValueGeneration();
if ( valueGeneration.getGenerationTiming().includesUpdate()
&& valueGeneration.generatedByDatabase()
&& valueGeneration.referenceColumnInSql() ) {
&& valueGeneration.generatedByDatabase() ) {
final InDatabaseValueGenerationStrategy generation = (InDatabaseValueGenerationStrategy) valueGeneration;
if ( generation.referenceColumnsInSql() ) {
final Dialect dialect = getFactory().getJdbcServices().getDialect();
update.addColumns(
getPropertyColumnNames( index ),
getPropertyColumnNames(index),
SINGLE_TRUE,
new String[] { valueGeneration.getDatabaseGeneratedReferencedColumnValue(dialect) }
generation.getReferencedColumnValues(dialect)
);
hasColumns = true;
}
@ -2774,6 +2776,7 @@ public abstract class AbstractEntityPersister
}
}
}
}
// HHH-4635
// 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 org.hibernate.Internal;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.sql.model.ModelMutationLogging;
import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.MutationOperationGroup;
import org.hibernate.sql.model.ValuesAnalysis;
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.MutationOperationGroupSingle;
import org.hibernate.sql.model.internal.MutationOperationGroupStandard;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
/**
* 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.Session;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
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.BasicEntityIdentifierMapping;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.sql.model.MutationOperationGroup;
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.TableInsertBuilder;
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.ValueGeneration;
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) {
final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values );
final TableInclusionChecker tableInclusionChecker = (tableMapping) -> {
if ( tableMapping.isOptional() ) {
return insertValuesAnalysis.hasNonNullBindings( tableMapping );
}
return true;
};
final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis );
final MutationExecutorService mutationExecutorService = session.getSessionFactory()
.getServiceRegistry()
@ -278,13 +270,7 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
final InsertValuesAnalysis insertValuesAnalysis = new InsertValuesAnalysis( entityPersister(), values );
final TableInclusionChecker tableInclusionChecker = (tableMapping) -> {
if ( tableMapping.isOptional() ) {
return insertValuesAnalysis.hasNonNullBindings( tableMapping );
}
return true;
};
final TableInclusionChecker tableInclusionChecker = getTableInclusionChecker( insertValuesAnalysis );
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,
@ -387,8 +377,6 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
MutationGroupBuilder insertGroupBuilder,
boolean[] attributeInclusions) {
final List<AttributeMapping> attributeMappings = entityPersister().getAttributeMappings();
//noinspection resource
final Dialect dialect = factory().getJdbcServices().getDialect();
insertGroupBuilder.forEachTableMutationBuilder( (builder) -> {
final EntityTableMapping tableMapping = (EntityTableMapping) builder.getMutatingTable().getTableMapping();
@ -402,18 +390,12 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
final AttributeMapping attributeMapping = attributeMappings.get( attributeIndex );
if ( !attributeInclusions[ attributeIndex ] ) {
final ValueGeneration valueGeneration = attributeMapping.getValueGeneration();
if ( valueGeneration.getGenerationTiming().includesInsert()
&& valueGeneration.getValueGenerator() == null
&& valueGeneration.referenceColumnInSql() ) {
// value-generation is only valid for basic attributes
final BasicAttributeMapping basicAttributeMapping = (BasicAttributeMapping) attributeMapping;
final String tableNameForMutation = entityPersister().physicalTableNameForMutation( basicAttributeMapping );
final TableInsertBuilder tableInsertBuilder = insertGroupBuilder.findTableDetailsBuilder( tableNameForMutation );
tableInsertBuilder.addValueColumn(
basicAttributeMapping.getSelectionExpression(),
valueGeneration.getDatabaseGeneratedReferencedColumnValue( dialect ),
basicAttributeMapping.getJdbcMapping()
final ValueGenerationStrategy valueGeneration = attributeMapping.getValueGeneration();
if ( isValueGenerationInSql( valueGeneration ) ) {
handleValueGeneration(
attributeMapping,
insertGroupBuilder,
(InDatabaseValueGenerationStrategy) valueGeneration
);
}
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.Session;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey;
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.EntityVersionMapping;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.sql.ast.SqlAstTranslator;
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.internal.MutationOperationGroupSingle;
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.ValueGeneration;
import org.hibernate.tuple.entity.EntityMetamodel;
import static org.hibernate.engine.OptimisticLockStyle.ALL;
@ -213,10 +212,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
}
final InclusionChecker updateabilityChecker = (position, attribute) -> {
final ValueGeneration valueGeneration = attribute.getValueGeneration();
if ( valueGeneration.getGenerationTiming().includesUpdate()
&& valueGeneration.getValueGenerator() == null
&& valueGeneration.referenceColumnInSql() ) {
if ( isValueGenerationInSql( attribute.getValueGeneration() ) ) {
return true;
}
@ -253,8 +249,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
if ( optimisticLockStyle == VERSION ) {
return versionMapping != null
&& versionMapping.getVersionAttribute() == attribute
;
&& versionMapping.getVersionAttribute() == attribute;
// && 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?
* (Initialized, updateable ones!)
@ -657,16 +658,14 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
}
final IncludedAttributeAnalysis attributeAnalysis = (IncludedAttributeAnalysis) attributeAnalysisRef;
final ValueGeneration valueGeneration = attributeMapping.getValueGeneration();
if ( attributeAnalysis.includeInSet() ) {
// apply the new values
final boolean includeInSet;
if ( valueGeneration.getGenerationTiming().includesUpdate()
&& valueGeneration.getValueGenerator() == null
&& valueGeneration.referenceColumnInSql()
&& valueGeneration.getDatabaseGeneratedReferencedColumnValue() != null ) {
final ValueGenerationStrategy valueGeneration = attributeMapping.getValueGeneration();
if ( isValueGenerationInSql( valueGeneration )
&& !( (InDatabaseValueGenerationStrategy) valueGeneration ).writePropertyValue() ) {
// we applied `#getDatabaseGeneratedReferencedColumnValue` earlier
includeInSet = false;
}
@ -881,7 +880,6 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
final List<AttributeMapping> attributeMappings = entityPersister().getAttributeMappings();
final boolean[] versionability = entityPersister().getPropertyVersionability();
final OptimisticLockStyle optimisticLockStyle = entityPersister().optimisticLockStyle();
final Dialect dialect = factory().getJdbcServices().getDialect();
updateGroupBuilder.forEachTableMutationBuilder( (builder) -> {
final EntityTableMapping tableMapping = (EntityTableMapping) builder.getMutatingTable().getTableMapping();
@ -898,21 +896,12 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
if ( attributeAnalysis.includeInSet() ) {
assert updateValuesAnalysis.tablesNeedingUpdate.contains( tableMapping );
final ValueGeneration valueGeneration = attributeMapping.getValueGeneration();
if ( valueGeneration.getGenerationTiming().includesUpdate()
&& valueGeneration.getValueGenerator() == null
&& valueGeneration.referenceColumnInSql() ) {
// value-generation is only valid for basic attributes
final BasicAttributeMapping basicAttributeMapping = (BasicAttributeMapping) attributeMapping;
final String databaseGeneratedValue = valueGeneration.getDatabaseGeneratedReferencedColumnValue(
dialect
);
tableUpdateBuilder.addValueColumn(
basicAttributeMapping.getSelectionExpression(),
databaseGeneratedValue == null
? "?"
: databaseGeneratedValue,
basicAttributeMapping.getJdbcMapping()
final ValueGenerationStrategy valueGeneration = attributeMapping.getValueGeneration();
if ( isValueGenerationInSql( valueGeneration ) ) {
handleValueGeneration(
attributeMapping,
updateGroupBuilder,
(InDatabaseValueGenerationStrategy) valueGeneration
);
}
else if ( versionMapping != null
@ -1014,7 +1003,6 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
} );
}
/**
* Contains the aggregated analysis of the update values to determine
* what SQL UPDATE statement(s) should be used to update the entity
@ -1344,10 +1332,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
null,
null,
(index,attribute) -> {
final ValueGeneration valueGeneration = attribute.getValueGeneration();
if ( valueGeneration.getGenerationTiming().includesUpdate()
&& valueGeneration.getValueGenerator() == null
&& valueGeneration.referenceColumnInSql() ) {
if ( isValueGenerationInSql( attribute.getValueGeneration() ) ) {
return true;
}

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.sql.ast.spi;
import java.util.Objects;
import java.util.function.Function;
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;
/**
* Specialized TableMutationBuilder implementation for building mutations
* which define a where-clause
* Specialized {@link TableMutationBuilder} implementation for building mutations
* which have a {@code where} clause.
*
* Common operations of {@link TableUpdateBuilder} and {@link TableDeleteBuilder}.
*
* @author Steve Ebersole
*/

View File

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

View File

@ -6,45 +6,13 @@
*/
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;
/**
* TableMutationBuilder implementation for insert statements
* {@link TableMutationBuilder} implementation for {@code insert} statements.
*
* @author Steve Ebersole
*/
public interface TableInsertBuilder extends TableMutationBuilder<TableInsert> {
/**
* Add a column as part of the values list
*/
default void addValueColumn(SelectableMapping selectableMapping) {
addValueColumn(
selectableMapping.getSelectionExpression(),
selectableMapping.getWriteExpression(),
selectableMapping.getJdbcMapping()
);
}
public interface TableInsertBuilder extends TableMutationBuilder<TableInsert>, ColumnValuesTableMutationBuilder {
/**
* 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;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.sql.model.MutationOperation;
import org.hibernate.sql.model.ast.RestrictedTableMutation;
/**
* {@link TableMutationBuilder} implementation for {@code update} statements.
*
* @author Steve Ebersole
*/
public interface TableUpdateBuilder<O extends MutationOperation>
extends RestrictedTableMutationBuilder<O, RestrictedTableMutation<O>> {
/**
* Add a column as part of the values list
*/
default void addValueColumn(SelectableMapping selectableMapping) {
addValueColumn(
selectableMapping.getSelectionExpression(),
selectableMapping.getWriteExpression(),
selectableMapping.getJdbcMapping()
);
}
extends RestrictedTableMutationBuilder<O, RestrictedTableMutation<O>>, ColumnValuesTableMutationBuilder {
/**
* Convenience form of {@link #addValueColumn(SelectableMapping)} matching the
@ -42,26 +32,5 @@ public interface TableUpdateBuilder<O extends MutationOperation>
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);
}

View File

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

View File

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

View File

@ -6,37 +6,63 @@
*/
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
*/
public interface InDatabaseValueGenerationStrategy {
/**
* When is this value generated : NEVER, INSERT, ALWAYS (INSERT+UPDATE)
*
* @return When the value is generated.
*/
GenerationTiming getGenerationTiming();
public interface InDatabaseValueGenerationStrategy extends ValueGenerationStrategy {
/**
* Should the column(s) be referenced in the INSERT / UPDATE SQL?
* <p>
* This will be {@code false} most often to have a DDL-defined DEFAULT value be applied on INSERT. For
* trigger-generated values this could be {@code true} or {@code false} depending on whether the user wants
* the trigger to have access to some value for the column passed in.
* Determines if the columns whose values are generated are included in the column list of
* the SQL {@code insert} or {@code update} statement, in the case where the value is
* generated by the database. For example, this method should return:
* <ul>
* <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();
/**
* For columns that will be referenced in the SQL (per {@link #referenceColumnsInSql()}), what value
* should be used in the SQL as the column value.
*
* @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}).
* Determines if the property values are written to JDBC as the argument of a JDBC {@code ?}
* parameter.
*/
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;
/**
* 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
*/
public interface InMemoryValueGenerationStrategy {
/**
* When is this value generated : NEVER, INSERT, ALWAYS (INSERT+UPDATE)
*
* @return When the value is generated.
*/
GenerationTiming getGenerationTiming();
public interface InMemoryValueGenerationStrategy extends ValueGenerationStrategy {
/**
* Obtain the in-VM value generator.
* <p>
* 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
* 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 strategy for performing in-VM value generation
* @return The value generator
*/
ValueGenerator<?> getValueGenerator();
default boolean generatedByDatabase() {
return false;
}
}

View File

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

View File

@ -6,24 +6,16 @@
*/
package org.hibernate.tuple;
import java.lang.reflect.Constructor;
import org.hibernate.HibernateException;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Property;
import org.hibernate.metamodel.RepresentationMode;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
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.EntityBasedBasicAttribute;
import org.hibernate.tuple.entity.EntityBasedCompositionAttribute;

View File

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

View File

@ -8,50 +8,14 @@ package org.hibernate.tuple;
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
* 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
* A value generator that can adapt to both Java value generation and database value
* generation.
*
* @author Steve Ebersole
* @author Gavin King
*/
public interface ValueGeneration 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();
/**
* 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();
public interface ValueGeneration extends InMemoryValueGenerationStrategy, InDatabaseValueGenerationStrategy {
/**
* 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
@ -110,6 +74,17 @@ public interface ValueGeneration extends Serializable {
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.
* <p>
@ -137,6 +112,6 @@ public interface ValueGeneration extends Serializable {
default boolean writePropertyValue() {
return !generatedByDatabase() // value generated in memory and then written 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.persister.entity.EntityPersister;
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.IdentifierProperty;
import org.hibernate.tuple.InDatabaseValueGenerationStrategy;
import org.hibernate.tuple.InMemoryValueGenerationStrategy;
import org.hibernate.tuple.NonIdentifierAttribute;
import org.hibernate.tuple.PropertyFactory;
import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.ValueGenerator;
import org.hibernate.type.AssociationType;
import org.hibernate.type.CollectionType;
@ -458,28 +458,25 @@ public class EntityMetamodel implements Serializable {
private static GenerationStrategyPair buildGenerationStrategyPair(
final SessionFactoryImplementor sessionFactory,
final Property mappingProperty) {
final ValueGeneration valueGeneration = mappingProperty.getValueGenerationStrategy();
final ValueGenerationStrategy valueGeneration = mappingProperty.getValueGenerationStrategy();
if ( valueGeneration != null && valueGeneration.getGenerationTiming() != GenerationTiming.NEVER ) {
// the property is generated in full. build the generation strategy pair.
if ( !valueGeneration.generatedByDatabase() ) {
// in-memory generation
return new GenerationStrategyPair(
FullInMemoryValueGenerationStrategy.create( valueGeneration )
FullInMemoryValueGenerationStrategy.create( (InMemoryValueGenerationStrategy) valueGeneration )
);
}
else {
// in-db generation
return new GenerationStrategyPair(
create(
sessionFactory,
mappingProperty,
valueGeneration
)
);
return new GenerationStrategyPair( (InDatabaseValueGenerationStrategy) valueGeneration );
}
}
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 );
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 {
private final InMemoryValueGenerationStrategy inMemoryStrategy;
private final InDatabaseValueGenerationStrategy inDatabaseStrategy;
@ -540,7 +507,7 @@ public class EntityMetamodel implements Serializable {
this( inMemoryStrategy, NoInDatabaseValueGenerationStrategy.INSTANCE );
}
public GenerationStrategyPair(InDatabaseValueGenerationStrategyImpl inDatabaseStrategy) {
public GenerationStrategyPair(InDatabaseValueGenerationStrategy inDatabaseStrategy) {
this( NoInMemoryValueGenerationStrategy.INSTANCE, inDatabaseStrategy );
}
@ -583,14 +550,16 @@ public class EntityMetamodel implements Serializable {
private static class CompositeGenerationStrategyPairBuilder {
private final Property mappingProperty;
private final Dialect dialect;
private boolean hadInMemoryGeneration;
private boolean hadInDatabaseGeneration;
private List<InDatabaseValueGenerationStrategy> inDatabaseStrategies;
public CompositeGenerationStrategyPairBuilder(Property mappingProperty) {
public CompositeGenerationStrategyPairBuilder(Property mappingProperty, Dialect dialect) {
this.mappingProperty = mappingProperty;
this.dialect = dialect;
}
public void addPair(GenerationStrategyPair generationStrategyPair) {
@ -675,8 +644,8 @@ public class EntityMetamodel implements Serializable {
// override base-line value
referenceColumns = true;
}
if ( subStrategy.getReferencedColumnValues() != null ) {
if ( subStrategy.getReferencedColumnValues().length != property.getColumnSpan() ) {
if ( subStrategy.getReferencedColumnValues(dialect) != null ) {
if ( subStrategy.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() +
@ -684,7 +653,7 @@ public class EntityMetamodel implements Serializable {
);
}
System.arraycopy(
subStrategy.getReferencedColumnValues(),
subStrategy.getReferencedColumnValues(dialect),
0,
columnValues,
columnIndex,
@ -730,7 +699,7 @@ public class EntityMetamodel implements Serializable {
this.generator = generator;
}
public static FullInMemoryValueGenerationStrategy create(ValueGeneration valueGeneration) {
public static FullInMemoryValueGenerationStrategy create(InMemoryValueGenerationStrategy valueGeneration) {
return new FullInMemoryValueGenerationStrategy(
valueGeneration.getGenerationTiming(),
valueGeneration.getValueGenerator()
@ -765,9 +734,14 @@ public class EntityMetamodel implements Serializable {
}
@Override
public String[] getReferencedColumnValues() {
public String[] getReferencedColumnValues(Dialect dialect) {
return null;
}
@Override
public boolean writePropertyValue() {
return true;
}
}
private static class InDatabaseValueGenerationStrategyImpl implements InDatabaseValueGenerationStrategy {
@ -795,9 +769,14 @@ public class EntityMetamodel implements Serializable {
}
@Override
public String[] getReferencedColumnValues() {
public String[] getReferencedColumnValues(Dialect dialect) {
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.query.sqm.SqmExpressible;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.PropertyFactory;
import org.hibernate.tuple.StandardProperty;
import org.hibernate.tuple.ValueGeneration;
@ -52,7 +53,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
private final String[] propertyNames;
private final Type[] propertyTypes;
private final ValueGeneration[] propertyValueGenerationStrategies;
private final ValueGenerationStrategy[] propertyValueGenerationStrategies;
private final boolean[] propertyNullability;
private final int[] originalPropertyOrder;
protected final int propertySpan;
@ -437,7 +438,7 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
return propertyTypes;
}
public ValueGeneration[] getPropertyValueGenerationStrategies() {
public ValueGenerationStrategy[] getPropertyValueGenerationStrategies() {
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.Property;
import org.hibernate.mapping.SyntheticProperty;
import org.hibernate.tuple.ValueGenerationStrategy;
import org.hibernate.tuple.GeneratedValueGeneration;
import org.hibernate.tuple.GenerationTiming;
import org.hibernate.tuple.ValueGeneration;
import org.jboss.logging.Logger;
@ -120,7 +119,7 @@ public final class AuditMetadataGenerator extends AbstractMetadataGenerator {
private boolean isPropertyInsertable(Property property) {
if ( !property.isInsertable() ) {
final ValueGeneration generation = property.getValueGenerationStrategy();
final ValueGenerationStrategy generation = property.getValueGenerationStrategy();
if ( generation instanceof GeneratedValueGeneration ) {
final GeneratedValueGeneration valueGeneration = (GeneratedValueGeneration) generation;
if ( valueGeneration.getGenerationTiming().includesInsert() ) {