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:
parent
94e2b599e4
commit
3e6fcdeda3
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ public abstract class AbstractNonIdentifierAttribute extends AbstractAttribute i
|
|||
}
|
||||
|
||||
@Override
|
||||
public ValueGeneration getValueGenerationStrategy() {
|
||||
public ValueGenerationStrategy getValueGenerationStrategy() {
|
||||
return attributeInformation.getValueGenerationStrategy();
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ public interface NonIdentifierAttribute extends Attribute {
|
|||
|
||||
boolean isUpdateable();
|
||||
|
||||
ValueGeneration getValueGenerationStrategy();
|
||||
ValueGenerationStrategy getValueGenerationStrategy();
|
||||
|
||||
boolean isNullable();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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() ) {
|
||||
|
|
Loading…
Reference in New Issue