HHH-15782 use a Generator for seeding/incrementing versions
add javadoc for version generation
This commit is contained in:
parent
0228c3d185
commit
239dfa30fa
|
@ -11,13 +11,11 @@ import org.hibernate.collection.spi.PersistentCollection;
|
|||
import org.hibernate.engine.internal.ForeignKeys;
|
||||
import org.hibernate.engine.internal.NonNullableTransientDependencies;
|
||||
import org.hibernate.engine.internal.Nullability;
|
||||
import org.hibernate.engine.internal.Versioning;
|
||||
import org.hibernate.engine.spi.CachedNaturalIdValueSource;
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.Status;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.metamodel.mapping.NaturalIdMapping;
|
||||
|
@ -26,6 +24,8 @@ import org.hibernate.persister.collection.CollectionPersister;
|
|||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
import static org.hibernate.engine.internal.Versioning.getVersion;
|
||||
|
||||
/**
|
||||
* A base class for entity insert actions.
|
||||
*
|
||||
|
@ -127,7 +127,7 @@ public abstract class AbstractEntityInsertAction extends EntityAction {
|
|||
*/
|
||||
public final void makeEntityManaged() {
|
||||
nullifyTransientReferencesIfNotAlready();
|
||||
final Object version = Versioning.getVersion( getState(), getPersister() );
|
||||
final Object version = getVersion( getState(), getPersister() );
|
||||
final PersistenceContext persistenceContextInternal = getSession().getPersistenceContextInternal();
|
||||
persistenceContextInternal.addEntity(
|
||||
getInstance(),
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.hibernate.cache.CacheException;
|
|||
import org.hibernate.cache.spi.access.EntityDataAccess;
|
||||
import org.hibernate.cache.spi.access.SoftLock;
|
||||
import org.hibernate.cache.spi.entry.CacheEntry;
|
||||
import org.hibernate.engine.internal.Versioning;
|
||||
import org.hibernate.engine.spi.CachedNaturalIdValueSource;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.SessionEventListenerManager;
|
||||
|
@ -33,6 +32,8 @@ import org.hibernate.stat.spi.StatisticsImplementor;
|
|||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
import org.hibernate.type.TypeHelper;
|
||||
|
||||
import static org.hibernate.engine.internal.Versioning.getVersion;
|
||||
|
||||
/**
|
||||
* The action for performing entity updates.
|
||||
*/
|
||||
|
@ -239,7 +240,7 @@ public class EntityUpdateAction extends EntityAction {
|
|||
// have the entity entry doAfterTransactionCompletion post-update processing, passing it the
|
||||
// update state and the new version (if one).
|
||||
if ( persister.isVersionPropertyGenerated() ) {
|
||||
nextVersion = Versioning.getVersion( state, persister );
|
||||
nextVersion = getVersion( state, persister );
|
||||
}
|
||||
entry.postUpdate( instance, state, nextVersion );
|
||||
}
|
||||
|
|
|
@ -47,14 +47,13 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
* property to be generated when any SQL statement to {@code insert} or
|
||||
* {@code update} the entity is executed.
|
||||
* <p>
|
||||
* Every generator annotation type has an {@link Generator}
|
||||
* implementation which is responsible for generating values. It must be either:
|
||||
* Every generator annotation type has an {@link Generator} implementation which
|
||||
* is responsible for generating values. It must be either:
|
||||
* <ul>
|
||||
* <li>an {@link InMemoryGenerator}, for
|
||||
* values that are generated in Java code, using a
|
||||
* {@link org.hibernate.tuple.ValueGenerator}, or
|
||||
* <li>an {@link InDatabaseGenerator}, for
|
||||
* values which are generated by the database.
|
||||
* <li>an {@link InMemoryGenerator}, for values that are generated in Java code,
|
||||
* using a {@link org.hibernate.tuple.ValueGenerator}, or
|
||||
* <li>an {@link InDatabaseGenerator}, for values which are generated by the
|
||||
* database.
|
||||
* </ul>
|
||||
* A generator annotation may have members, which are used to configure the
|
||||
* generation strategy, when the strategy instance in initialized via
|
||||
|
|
|
@ -23,6 +23,8 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
|||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
|
||||
/**
|
||||
* An {@code IdentifierBag} implements "bag" semantics more efficiently than
|
||||
* a regular {@code Bag} by adding a synthetic identifier column to the
|
||||
|
@ -368,7 +370,7 @@ public class PersistentIdentifierBag<E> extends AbstractPersistentCollection<E>
|
|||
final Integer loc = i++;
|
||||
if ( !identifiers.containsKey( loc ) ) {
|
||||
//TODO: native ids
|
||||
final Object id = persister.getGenerator().generate( getSession(), entry, null );
|
||||
final Object id = persister.getGenerator().generate( getSession(), entry, null, INSERT );
|
||||
identifiers.put( loc, id );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.engine.internal;
|
||||
|
||||
import org.hibernate.Remove;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.metamodel.mapping.EntityVersionMapping;
|
||||
|
@ -14,6 +15,9 @@ import org.hibernate.type.descriptor.java.VersionJavaType;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
import static org.hibernate.generator.EventType.UPDATE;
|
||||
|
||||
/**
|
||||
* Utilities for dealing with optimistic locking values.
|
||||
*
|
||||
|
@ -39,7 +43,7 @@ public final class Versioning {
|
|||
* @param session The originating session
|
||||
* @return The initial optimistic locking value
|
||||
*/
|
||||
private static Object seed(EntityVersionMapping versionMapping, SharedSessionContractImplementor session) {
|
||||
public static Object seed(EntityVersionMapping versionMapping, SharedSessionContractImplementor session) {
|
||||
final Object seed = versionMapping.getJavaType().seed(
|
||||
versionMapping.getLength(),
|
||||
versionMapping.getPrecision(),
|
||||
|
@ -50,10 +54,40 @@ public final class Versioning {
|
|||
return seed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create an initial optimistic locking value using the for the version property
|
||||
* <em>if required</em> using the {@link org.hibernate.generator.Generator} contract
|
||||
* and inject it into the snapshot state.
|
||||
*
|
||||
* @param fields The current snapshot state
|
||||
* @param persister The persister of the versioned entity
|
||||
* @param entity The entity instance
|
||||
* @param session The originating session
|
||||
* @return True if we injected a new version value into the fields array; false
|
||||
* otherwise.
|
||||
*/
|
||||
public static boolean seedVersion(
|
||||
Object entity,
|
||||
Object[] fields,
|
||||
EntityPersister persister,
|
||||
SharedSessionContractImplementor session) {
|
||||
final int versionProperty = persister.getVersionProperty();
|
||||
final Object initialVersion = fields[versionProperty];
|
||||
if ( isNullInitialVersion( initialVersion ) ) {
|
||||
fields[versionProperty] = persister.getVersionGenerator().generate( session, entity, initialVersion, INSERT );
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
LOG.tracev( "Using initial version: {0}", initialVersion );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an initial optimistic locking value according the {@link VersionJavaType}
|
||||
* contract for the version property <b>if required</b> and inject it into
|
||||
* the snapshot state.
|
||||
* contract for the version property <em>if required</em> and inject it into the
|
||||
* snapshot state.
|
||||
*
|
||||
* @param fields The current snapshot state
|
||||
* @param versionProperty The index of the version property
|
||||
|
@ -61,28 +95,60 @@ public final class Versioning {
|
|||
* @param session The originating session
|
||||
* @return True if we injected a new version value into the fields array; false
|
||||
* otherwise.
|
||||
*
|
||||
* @deprecated Use {@link #seedVersion(Object, Object[], EntityPersister, SharedSessionContractImplementor)}
|
||||
*/
|
||||
@Deprecated(since = "6.2") @Remove
|
||||
public static boolean seedVersion(
|
||||
Object[] fields,
|
||||
int versionProperty,
|
||||
EntityVersionMapping versionMapping,
|
||||
SharedSessionContractImplementor session) {
|
||||
final Object initialVersion = fields[versionProperty];
|
||||
if (
|
||||
initialVersion==null ||
|
||||
// This next bit is to allow for both unsaved-value="negative"
|
||||
// and for "older" behavior where version number did not get
|
||||
// seeded if it was already set in the object
|
||||
// TODO: shift it into unsaved-value strategy
|
||||
( (initialVersion instanceof Number) && ( (Number) initialVersion ).longValue()<0 )
|
||||
) {
|
||||
if ( isNullInitialVersion( initialVersion ) ) {
|
||||
fields[versionProperty] = seed( versionMapping, session );
|
||||
return true;
|
||||
}
|
||||
LOG.tracev( "Using initial version: {0}", initialVersion );
|
||||
return false;
|
||||
else {
|
||||
LOG.tracev( "Using initial version: {0}", initialVersion );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the value of the assigned version property should be considered
|
||||
* a "null" value, that is, if it is literally {@code null}, or if it is a negative
|
||||
* integer.
|
||||
*
|
||||
* @param initialVersion The value initially assigned to a version property
|
||||
* @return {@code} if the value shoudl be considered null for this purpose
|
||||
*/
|
||||
public static boolean isNullInitialVersion(Object initialVersion) {
|
||||
return initialVersion == null
|
||||
|| // This next bit is to allow for both unsaved-value="negative"
|
||||
// and for "older" behavior where version number did not get
|
||||
// seeded if it was already set in the object
|
||||
// TODO: shift it into unsaved-value strategy
|
||||
initialVersion instanceof Number && ((Number) initialVersion).longValue() < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the next increment in the optimistic locking value according the
|
||||
* {@link org.hibernate.generator.Generator} contract for the version property.
|
||||
*
|
||||
* @param entity The entity instance
|
||||
* @param currentVersion The current version
|
||||
* @param persister The persister of the versioned entity
|
||||
* @param session The originating session
|
||||
* @return The incremented optimistic locking value.
|
||||
*/
|
||||
public static Object incrementVersion(
|
||||
Object entity,
|
||||
Object currentVersion,
|
||||
EntityPersister persister,
|
||||
SharedSessionContractImplementor session) {
|
||||
return persister.getVersionGenerator().generate( session, entity, currentVersion, UPDATE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the next increment in the optimistic locking value according
|
||||
|
@ -121,10 +187,9 @@ public final class Versioning {
|
|||
* @param persister The entity persister
|
||||
*/
|
||||
public static void setVersion(Object[] fields, Object version, EntityPersister persister) {
|
||||
if ( !persister.isVersioned() ) {
|
||||
return;
|
||||
if ( persister.isVersioned() ) {
|
||||
fields[ persister.getVersionProperty() ] = version;
|
||||
}
|
||||
fields[ persister.getVersionProperty() ] = version;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -135,10 +200,7 @@ public final class Versioning {
|
|||
* @return The extracted optimistic locking value
|
||||
*/
|
||||
public static Object getVersion(Object[] fields, EntityPersister persister) {
|
||||
if ( !persister.isVersioned() ) {
|
||||
return null;
|
||||
}
|
||||
return fields[ persister.getVersionProperty() ];
|
||||
return persister.isVersioned() ? fields[persister.getVersionProperty()] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.event.internal;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.internal.Versioning;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
|
@ -21,6 +20,8 @@ import org.hibernate.type.TypeHelper;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.engine.internal.Versioning.getVersion;
|
||||
|
||||
/**
|
||||
* A convenience base class for listeners that respond to requests to reassociate an entity
|
||||
* to a session ( such as through lock() or update() ).
|
||||
|
@ -65,7 +66,7 @@ public abstract class AbstractReassociateEventListener {
|
|||
values,
|
||||
source
|
||||
);
|
||||
Object version = Versioning.getVersion( values, persister );
|
||||
Object version = getVersion( values, persister );
|
||||
|
||||
EntityEntry newEntry = persistenceContext.addEntity(
|
||||
object,
|
||||
|
|
|
@ -16,7 +16,6 @@ import org.hibernate.action.internal.EntityInsertAction;
|
|||
import org.hibernate.classic.Lifecycle;
|
||||
import org.hibernate.engine.internal.Cascade;
|
||||
import org.hibernate.engine.internal.CascadePoint;
|
||||
import org.hibernate.engine.internal.Versioning;
|
||||
import org.hibernate.engine.spi.CascadingAction;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityEntryExtraState;
|
||||
|
@ -27,7 +26,6 @@ import org.hibernate.engine.spi.SessionImplementor;
|
|||
import org.hibernate.engine.spi.Status;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.id.IdentifierGenerationException;
|
||||
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.jpa.event.spi.CallbackRegistry;
|
||||
|
@ -40,6 +38,10 @@ import org.hibernate.type.Type;
|
|||
import org.hibernate.type.TypeHelper;
|
||||
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.processIfSelfDirtinessTracker;
|
||||
import static org.hibernate.engine.internal.Versioning.getVersion;
|
||||
import static org.hibernate.engine.internal.Versioning.seedVersion;
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
import static org.hibernate.id.IdentifierGeneratorHelper.SHORT_CIRCUIT_INDICATOR;
|
||||
|
||||
/**
|
||||
* A convenience base class for listeners responding to save events.
|
||||
|
@ -115,11 +117,11 @@ public abstract class AbstractSaveEventListener<C>
|
|||
final EntityPersister persister = source.getEntityPersister( entityName, entity );
|
||||
Generator generator = persister.getGenerator();
|
||||
if ( !generator.generatedByDatabase() ) {
|
||||
Object generatedId = ( (InMemoryGenerator) generator ).generate( source, entity, null );
|
||||
final Object generatedId = ( (InMemoryGenerator) generator ).generate( source, entity, null, INSERT );
|
||||
if ( generatedId == null ) {
|
||||
throw new IdentifierGenerationException( "null id generated for: " + entity.getClass() );
|
||||
}
|
||||
else if ( generatedId == IdentifierGeneratorHelper.SHORT_CIRCUIT_INDICATOR ) {
|
||||
else if ( generatedId == SHORT_CIRCUIT_INDICATOR ) {
|
||||
return source.getIdentifier( entity );
|
||||
}
|
||||
else {
|
||||
|
@ -188,7 +190,7 @@ public abstract class AbstractSaveEventListener<C>
|
|||
}
|
||||
|
||||
private static EntityKey entityKey(Object entity, Object id, EntityPersister persister, boolean useIdentityColumn, EventSource source) {
|
||||
if ( !useIdentityColumn) {
|
||||
if ( !useIdentityColumn ) {
|
||||
final EntityKey key = source.generateEntityKey( id, persister );
|
||||
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
|
||||
final Object old = persistenceContext.getEntity( key );
|
||||
|
@ -316,16 +318,16 @@ public abstract class AbstractSaveEventListener<C>
|
|||
}
|
||||
|
||||
private Object[] cloneAndSubstituteValues(Object entity, EntityPersister persister, C context, EventSource source, Object id) {
|
||||
Object[] values = persister.getPropertyValuesToInsert(entity, getMergeMap(context), source);
|
||||
Object[] values = persister.getPropertyValuesToInsert( entity, getMergeMap(context), source );
|
||||
Type[] types = persister.getPropertyTypes();
|
||||
|
||||
boolean substitute = substituteValuesIfNecessary(entity, id, values, persister, source);
|
||||
boolean substitute = substituteValuesIfNecessary( entity, id, values, persister, source );
|
||||
if ( persister.hasCollections() ) {
|
||||
substitute = visitCollectionsBeforeSave(entity, id, values, types, source) || substitute;
|
||||
substitute = visitCollectionsBeforeSave( entity, id, values, types, source ) || substitute;
|
||||
}
|
||||
|
||||
if ( substitute ) {
|
||||
persister.setValues(entity, values );
|
||||
persister.setValues( entity, values );
|
||||
}
|
||||
|
||||
TypeHelper.deepCopy(
|
||||
|
@ -363,7 +365,7 @@ public abstract class AbstractSaveEventListener<C>
|
|||
id,
|
||||
values,
|
||||
entity,
|
||||
Versioning.getVersion( values, persister ),
|
||||
getVersion( values, persister ),
|
||||
persister,
|
||||
isVersionIncrementDisabled(),
|
||||
source
|
||||
|
@ -429,12 +431,7 @@ public abstract class AbstractSaveEventListener<C>
|
|||
|
||||
//keep the existing version number in the case of replicate!
|
||||
if ( persister.isVersioned() ) {
|
||||
substitute = Versioning.seedVersion(
|
||||
values,
|
||||
persister.getVersionProperty(),
|
||||
persister.getVersionMapping(),
|
||||
source
|
||||
) || substitute;
|
||||
substitute = seedVersion( entity, values, persister, source ) || substitute;
|
||||
}
|
||||
return substitute;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,9 @@ import static org.hibernate.engine.internal.ManagedTypeHelper.asSelfDirtinessTra
|
|||
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isSelfDirtinessTracker;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.processIfSelfDirtinessTracker;
|
||||
import static org.hibernate.engine.internal.Versioning.getVersion;
|
||||
import static org.hibernate.engine.internal.Versioning.incrementVersion;
|
||||
import static org.hibernate.engine.internal.Versioning.setVersion;
|
||||
|
||||
/**
|
||||
* An event that occurs for each entity instance at flush time
|
||||
|
@ -381,13 +384,13 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
|
|||
if ( persister.isVersioned() ) {
|
||||
Object[] values = event.getPropertyValues();
|
||||
if ( entry.isBeingReplicated() ) {
|
||||
return Versioning.getVersion( values, persister );
|
||||
return getVersion( values, persister );
|
||||
}
|
||||
else {
|
||||
final Object nextVersion = isVersionIncrementRequired( event, entry )
|
||||
? Versioning.increment( entry.getVersion(), persister.getVersionMapping(), event.getSession() )
|
||||
? incrementVersion( event.getEntity(), entry.getVersion(), persister, event.getSession() )
|
||||
: entry.getVersion(); //use the current version
|
||||
Versioning.setVersion( values, nextVersion, persister );
|
||||
setVersion( values, nextVersion, persister );
|
||||
return nextVersion;
|
||||
}
|
||||
}
|
||||
|
@ -397,7 +400,7 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
|
|||
|
||||
}
|
||||
|
||||
private boolean isVersionIncrementRequired(FlushEntityEvent event, EntityEntry entry) {
|
||||
private static boolean isVersionIncrementRequired(FlushEntityEvent event, EntityEntry entry) {
|
||||
if ( entry.getStatus() == Status.DELETED ) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,18 @@ package org.hibernate.generator;
|
|||
* @see EventTypeSets
|
||||
*/
|
||||
public enum EventType {
|
||||
/**
|
||||
* An event that occurs when any {@code insert} statements needed
|
||||
* to persist a new entity instance are executed. This indicates,
|
||||
* for example, that a surrogate primary key should be generated,
|
||||
* or initial that an initial version number should be seeded.
|
||||
*/
|
||||
INSERT,
|
||||
/**
|
||||
* An event that occurs when any {@code update} statements needed
|
||||
* to persist changes to a dirty entity instance are executed.
|
||||
* This indicates, for example, that a version number should be
|
||||
* incremented.
|
||||
*/
|
||||
UPDATE;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import static org.hibernate.generator.EventType.UPDATE;
|
|||
* generated in Java code, or by the database.
|
||||
* <ul>
|
||||
* <li>Value generation via arbitrary code written in Java is the responsibility of the method
|
||||
* {@link InMemoryGenerator#generate(SharedSessionContractImplementor, Object, Object)}.
|
||||
* {@link InMemoryGenerator#generate(SharedSessionContractImplementor, Object, Object, EventType)}.
|
||||
* 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
|
||||
|
@ -45,11 +45,20 @@ import static org.hibernate.generator.EventType.UPDATE;
|
|||
* A generator must implement {@link #getEventTypes()} to specify the events for which it should be
|
||||
* called to produce a new value. {@link EventTypeSets} provides a convenient list of possibilities.
|
||||
* <p>
|
||||
* There are two especially important applications of this machinery:
|
||||
* <ul>
|
||||
* <li>
|
||||
* An {@linkplain jakarta.persistence.Id identifier} generator is a generator capable of producing
|
||||
* surrogate primary key values. An identifier generator must respond to insert events only. That
|
||||
* is, {@link #getEventTypes()} must return {@link EventTypeSets#INSERT_ONLY}. It may be integrated
|
||||
* using the {@link org.hibernate.annotations.IdGeneratorType} meta-annotation or the older-style
|
||||
* {@link org.hibernate.annotations.GenericGenerator} annotation.
|
||||
* <li>
|
||||
* A {@linkplain jakarta.persistence.Version version} generator is a generator capable of seeding
|
||||
* and incrementing version numbers. A version generator must respond to both insert and update
|
||||
* events. That is, {@link #getEventTypes()} must return {@link EventTypeSets#INSERT_AND_UPDATE}.
|
||||
* It may be integrated using {@link org.hibernate.annotations.ValueGenerationType} meta-annotation.
|
||||
* </ul>
|
||||
*
|
||||
* @see org.hibernate.annotations.ValueGenerationType
|
||||
* @see org.hibernate.annotations.IdGeneratorType
|
||||
|
|
|
@ -37,13 +37,13 @@ public interface InMemoryGenerator extends Generator {
|
|||
/**
|
||||
* Generate a value.
|
||||
*
|
||||
* @param session The session from which the request originates.
|
||||
* @param owner The instance of the object owning the attribute for which we are generating a value.
|
||||
* @param session The session from which the request originates.
|
||||
* @param owner The instance of the object owning the attribute for which we are generating a value.
|
||||
* @param currentValue The current value assigned to the property, or {@code null}
|
||||
*
|
||||
* @param eventType The type of event that has triggered generation of a new value
|
||||
* @return The generated value
|
||||
*/
|
||||
Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue);
|
||||
Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType);
|
||||
|
||||
default boolean generatedByDatabase() {
|
||||
return false;
|
||||
|
|
|
@ -91,7 +91,7 @@ public class CurrentTimestampGeneration implements InMemoryGenerator, InDatabase
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue) {
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||
return generator.generateValue( (Session) session, owner, currentValue );
|
||||
}
|
||||
|
||||
|
|
|
@ -89,7 +89,7 @@ public class SourceGeneration implements InMemoryGenerator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue) {
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||
return valueGenerator.generateValue( (Session) session, owner, currentValue );
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ public class TenantIdGeneration implements InMemoryGenerator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue) {
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||
SessionFactoryImplementor sessionFactory = session.getSessionFactory();
|
||||
JavaType<Object> descriptor = sessionFactory.getTypeConfiguration().getJavaTypeRegistry()
|
||||
.findDescriptor(propertyType);
|
||||
|
|
|
@ -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.generator.internal;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.generator.EventType;
|
||||
import org.hibernate.generator.InMemoryGenerator;
|
||||
import org.hibernate.metamodel.mapping.EntityVersionMapping;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import static org.hibernate.engine.internal.Versioning.increment;
|
||||
import static org.hibernate.engine.internal.Versioning.seed;
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
import static org.hibernate.generator.EventTypeSets.INSERT_AND_UPDATE;
|
||||
|
||||
/**
|
||||
* A default {@link org.hibernate.generator.Generator} for {@link jakarta.persistence.Version @Version}
|
||||
* properties. This implementation simply delegates back to:
|
||||
* <ul>
|
||||
* <li>{@link org.hibernate.type.descriptor.java.VersionJavaType#seed} to seed an initial version, and
|
||||
* <li>{@link org.hibernate.type.descriptor.java.VersionJavaType#next} to increment a version.
|
||||
* </ul>
|
||||
* Thus, this implementation reproduces the "classic" behavior of Hibernate. A custom generator specified
|
||||
* using a {@linkplain org.hibernate.annotations.ValueGenerationType generator annotation} will override
|
||||
* this implementation, allowing customized versioning.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class VersionGeneration implements InMemoryGenerator {
|
||||
private final EntityVersionMapping versionMapping;
|
||||
|
||||
public VersionGeneration(EntityVersionMapping versionMapping) {
|
||||
this.versionMapping = versionMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<EventType> getEventTypes() {
|
||||
return INSERT_AND_UPDATE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object current, EventType eventType) {
|
||||
return eventType == INSERT
|
||||
? seed( versionMapping, session )
|
||||
: increment( current, versionMapping, session );
|
||||
}
|
||||
}
|
|
@ -142,7 +142,7 @@ public interface IdentifierGenerator extends InMemoryGenerator, ExportableProduc
|
|||
* The {@code currentValue} is usually null for id generation.
|
||||
*/
|
||||
@Override
|
||||
default Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue) {
|
||||
default Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||
return generate( session, owner );
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ public class UuidGenerator implements InMemoryGenerator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue) {
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||
return valueTransformer.transform( generator.generateUuid( session ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
|
|||
import org.hibernate.cache.spi.access.EntityDataAccess;
|
||||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.internal.StatefulPersistenceContext;
|
||||
import org.hibernate.engine.internal.Versioning;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
|
@ -41,6 +40,10 @@ import jakarta.transaction.SystemException;
|
|||
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
|
||||
import static org.hibernate.engine.internal.Versioning.incrementVersion;
|
||||
import static org.hibernate.engine.internal.Versioning.seedVersion;
|
||||
import static org.hibernate.engine.internal.Versioning.setVersion;
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
|
||||
/**
|
||||
* Concrete implementation of the {@link StatelessSession} API.
|
||||
|
@ -97,17 +100,11 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
final EntityPersister persister = getEntityPersister( entityName, entity );
|
||||
final Object id;
|
||||
final Object[] state = persister.getValues( entity );
|
||||
Generator generator = persister.getGenerator();
|
||||
final Generator generator = persister.getGenerator();
|
||||
if ( !generator.generatedByDatabase() ) {
|
||||
id = ( (InMemoryGenerator) generator).generate( this, entity, null );
|
||||
id = ( (InMemoryGenerator) generator).generate( this, entity, null, INSERT );
|
||||
if ( persister.isVersioned() ) {
|
||||
boolean substitute = Versioning.seedVersion(
|
||||
state,
|
||||
persister.getVersionProperty(),
|
||||
persister.getVersionMapping(),
|
||||
this
|
||||
);
|
||||
if ( substitute ) {
|
||||
if ( seedVersion( entity, state, persister, this ) ) {
|
||||
persister.setValues( entity, state );
|
||||
}
|
||||
}
|
||||
|
@ -156,8 +153,8 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
|
|||
Object oldVersion;
|
||||
if ( persister.isVersioned() ) {
|
||||
oldVersion = persister.getVersion( entity );
|
||||
Object newVersion = Versioning.increment( oldVersion, persister.getVersionMapping(), this );
|
||||
Versioning.setVersion( state, newVersion, persister );
|
||||
Object newVersion = incrementVersion( entity, oldVersion, persister, this );
|
||||
setVersion( state, newVersion, persister );
|
||||
persister.setValues( entity, state );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -18,7 +18,6 @@ import org.hibernate.cache.spi.entry.StandardCacheEntryImpl;
|
|||
import org.hibernate.engine.internal.CacheHelper;
|
||||
import org.hibernate.engine.internal.StatefulPersistenceContext;
|
||||
import org.hibernate.engine.internal.TwoPhaseLoad;
|
||||
import org.hibernate.engine.internal.Versioning;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
|
@ -45,6 +44,7 @@ import org.hibernate.type.TypeHelper;
|
|||
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isManagedEntity;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
|
||||
import static org.hibernate.engine.internal.Versioning.getVersion;
|
||||
import static org.hibernate.loader.ast.internal.LoaderHelper.upgradeLock;
|
||||
|
||||
/**
|
||||
|
@ -424,7 +424,7 @@ public class CacheEntityLoaderHelper {
|
|||
source
|
||||
);
|
||||
}
|
||||
version = Versioning.getVersion( values, subclassPersister );
|
||||
version = getVersion( values, subclassPersister );
|
||||
LOG.tracef( "Cached Version : %s", version );
|
||||
|
||||
final Object proxy = persistenceContext.getProxy( entityKey );
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.hibernate.dialect.Dialect;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.id.CompositeNestedGeneratedValueGenerator;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.IdentifierGeneratorHelper;
|
||||
import org.hibernate.id.factory.IdentifierGeneratorFactory;
|
||||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
|
@ -41,6 +40,9 @@ import org.hibernate.type.ComponentType;
|
|||
import org.hibernate.type.EmbeddedComponentType;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
import static org.hibernate.id.IdentifierGeneratorHelper.POST_INSERT_INDICATOR;
|
||||
|
||||
/**
|
||||
* A mapping model object that represents an {@linkplain jakarta.persistence.Embeddable embeddable class}.
|
||||
* <p>
|
||||
|
@ -508,38 +510,36 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
|
|||
}
|
||||
|
||||
public static class ValueGenerationPlan implements CompositeNestedGeneratedValueGenerator.GenerationPlan {
|
||||
private final Generator subGenerator;
|
||||
private final Generator subgenerator;
|
||||
private final Setter injector;
|
||||
|
||||
public ValueGenerationPlan(
|
||||
Generator subGenerator,
|
||||
Setter injector) {
|
||||
this.subGenerator = subGenerator;
|
||||
public ValueGenerationPlan(Generator subgenerator, Setter injector) {
|
||||
this.subgenerator = subgenerator;
|
||||
this.injector = injector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(SharedSessionContractImplementor session, Object incomingObject, Object injectionContext) {
|
||||
if ( !subGenerator.generatedByDatabase() ) {
|
||||
Object generatedId = ( (InMemoryGenerator) subGenerator ).generate( session, incomingObject, null );
|
||||
if ( !subgenerator.generatedByDatabase() ) {
|
||||
Object generatedId = ( (InMemoryGenerator) subgenerator).generate( session, incomingObject, null, INSERT );
|
||||
injector.set( injectionContext, generatedId );
|
||||
}
|
||||
else {
|
||||
injector.set( injectionContext, IdentifierGeneratorHelper.POST_INSERT_INDICATOR );
|
||||
injector.set( injectionContext, POST_INSERT_INDICATOR );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerExportables(Database database) {
|
||||
if ( subGenerator instanceof ExportableProducer ) {
|
||||
( (ExportableProducer) subGenerator ).registerExportables( database );
|
||||
if ( subgenerator instanceof ExportableProducer ) {
|
||||
( (ExportableProducer) subgenerator).registerExportables( database );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(SqlStringGenerationContext context) {
|
||||
if ( subGenerator instanceof IdentifierGenerator ) {
|
||||
( (IdentifierGenerator) subGenerator ).initialize( context );
|
||||
if ( subgenerator instanceof IdentifierGenerator ) {
|
||||
( (IdentifierGenerator) subgenerator).initialize( context );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ package org.hibernate.metamodel.mapping;
|
|||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.generator.EventType;
|
||||
|
||||
/**
|
||||
* GeneratedValueResolver impl for in-db generation. It extracts the generated value
|
||||
|
@ -18,11 +18,11 @@ import org.hibernate.tuple.GenerationTiming;
|
|||
*/
|
||||
@Internal
|
||||
public class InDatabaseGeneratedValueResolver implements GeneratedValueResolver {
|
||||
// private final GenerationTiming timing;
|
||||
private final EventType eventType;
|
||||
private final int resultPosition;
|
||||
|
||||
public InDatabaseGeneratedValueResolver(GenerationTiming timing, int resultPosition) {
|
||||
// this.timing = timing;
|
||||
public InDatabaseGeneratedValueResolver(EventType eventType, int resultPosition) {
|
||||
this.eventType = eventType;
|
||||
this.resultPosition = resultPosition;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ package org.hibernate.metamodel.mapping;
|
|||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.generator.EventType;
|
||||
import org.hibernate.generator.InMemoryGenerator;
|
||||
|
||||
/**
|
||||
|
@ -18,12 +18,12 @@ import org.hibernate.generator.InMemoryGenerator;
|
|||
*/
|
||||
@Internal
|
||||
public class InMemoryGeneratedValueResolver implements GeneratedValueResolver {
|
||||
// private final GenerationTiming generationTiming;
|
||||
private final InMemoryGenerator valueGenerator;
|
||||
private final EventType eventType;
|
||||
private final InMemoryGenerator generator;
|
||||
|
||||
public InMemoryGeneratedValueResolver(InMemoryGenerator valueGenerator, GenerationTiming generationTiming) {
|
||||
this.valueGenerator = valueGenerator;
|
||||
// this.generationTiming = generationTiming;
|
||||
public InMemoryGeneratedValueResolver(InMemoryGenerator generator, EventType eventType) {
|
||||
this.generator = generator;
|
||||
this.eventType = eventType;
|
||||
}
|
||||
|
||||
// @Override
|
||||
|
@ -33,6 +33,6 @@ public class InMemoryGeneratedValueResolver implements GeneratedValueResolver {
|
|||
|
||||
@Override
|
||||
public Object resolveGeneratedValue(Object[] row, Object entity, SharedSessionContractImplementor session, Object currentValue) {
|
||||
return valueGenerator.generate( session, entity, currentValue );
|
||||
return generator.generate( session, entity, currentValue, eventType );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import org.hibernate.LockOptions;
|
|||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.generator.EventType;
|
||||
import org.hibernate.generator.InDatabaseGenerator;
|
||||
import org.hibernate.loader.ast.internal.LoaderSelectBuilder;
|
||||
import org.hibernate.metamodel.UnsupportedMappingException;
|
||||
|
@ -31,7 +32,6 @@ import org.hibernate.sql.exec.spi.Callback;
|
|||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.generator.Generator;
|
||||
|
||||
import static org.hibernate.sql.results.spi.ListResultsConsumer.UniqueSemantic.FILTER;
|
||||
|
@ -59,7 +59,7 @@ public class GeneratedValuesProcessor {
|
|||
|
||||
public GeneratedValuesProcessor(
|
||||
EntityMappingType entityDescriptor,
|
||||
GenerationTiming timing,
|
||||
EventType timing,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.entityDescriptor = entityDescriptor;
|
||||
this.sessionFactory = sessionFactory;
|
||||
|
@ -88,7 +88,7 @@ public class GeneratedValuesProcessor {
|
|||
* populate the list of {@link GeneratedValueDescriptor}s by side effect, and
|
||||
* return a list of {@link AttributeMapping}s.
|
||||
*/
|
||||
private List<AttributeMapping> getGeneratedAttributes(EntityMappingType entityDescriptor, GenerationTiming timing) {
|
||||
private List<AttributeMapping> getGeneratedAttributes(EntityMappingType entityDescriptor, EventType timing) {
|
||||
// todo (6.0): For now, we rely on the entity metamodel as composite attributes report
|
||||
// GenerationTiming.NEVER even if they have attributes that would need generation
|
||||
final Generator[] generators = entityDescriptor.getEntityPersister().getEntityMetamodel().getGenerators();
|
||||
|
|
|
@ -93,6 +93,9 @@ import org.hibernate.engine.spi.SessionImplementor;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.event.spi.LoadEvent;
|
||||
import org.hibernate.generator.EventType;
|
||||
import org.hibernate.generator.InMemoryGenerator;
|
||||
import org.hibernate.generator.internal.VersionGeneration;
|
||||
import org.hibernate.id.Assigned;
|
||||
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
|
@ -259,7 +262,6 @@ import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
|||
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||
import org.hibernate.generator.Generator;
|
||||
import org.hibernate.generator.InDatabaseGenerator;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.tuple.NonIdentifierAttribute;
|
||||
import org.hibernate.tuple.entity.EntityBasedAssociationAttribute;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
|
@ -278,6 +280,8 @@ import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttrib
|
|||
import static org.hibernate.engine.internal.ManagedTypeHelper.processIfPersistentAttributeInterceptable;
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.processIfSelfDirtinessTracker;
|
||||
import static org.hibernate.engine.internal.Versioning.isVersionIncrementRequired;
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
import static org.hibernate.generator.EventType.UPDATE;
|
||||
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
|
||||
|
||||
/**
|
||||
|
@ -414,7 +418,6 @@ public abstract class AbstractEntityPersister
|
|||
private final Map<String,String[]> subclassPropertyAliases = new HashMap<>();
|
||||
private final Map<String,String[]> subclassPropertyColumnNames = new HashMap<>();
|
||||
|
||||
|
||||
private final JavaType<?> javaType;
|
||||
private final EntityRepresentationStrategy representationStrategy;
|
||||
|
||||
|
@ -431,6 +434,8 @@ public abstract class AbstractEntityPersister
|
|||
protected Map<String, AttributeMapping> declaredAttributeMappings = new LinkedHashMap<>();
|
||||
protected List<Fetchable> staticFetchableList;
|
||||
|
||||
private InMemoryGenerator versionGenerator;
|
||||
|
||||
protected ReflectionOptimizer.AccessOptimizer accessOptimizer;
|
||||
|
||||
/**
|
||||
|
@ -490,10 +495,10 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
this.representationStrategy = creationContext.getBootstrapContext().getRepresentationStrategySelector()
|
||||
representationStrategy = creationContext.getBootstrapContext().getRepresentationStrategySelector()
|
||||
.resolveStrategy( bootDescriptor, this, creationContext );
|
||||
|
||||
this.javaType = representationStrategy.getLoadJavaType();
|
||||
javaType = representationStrategy.getLoadJavaType();
|
||||
assert javaType != null;
|
||||
|
||||
final JdbcServices jdbcServices = factory.getServiceRegistry().getService( JdbcServices.class );
|
||||
|
@ -1933,7 +1938,7 @@ public abstract class AbstractEntityPersister
|
|||
return select.addCondition( rootTableKeyColumnNames, "=?" ).toStatementString();
|
||||
}
|
||||
|
||||
private GeneratedValuesProcessor createGeneratedValuesProcessor(GenerationTiming timing) {
|
||||
private GeneratedValuesProcessor createGeneratedValuesProcessor(EventType timing) {
|
||||
return new GeneratedValuesProcessor( this, timing, getFactory() );
|
||||
}
|
||||
|
||||
|
@ -3992,6 +3997,11 @@ public abstract class AbstractEntityPersister
|
|||
return entityMetamodel.getIdentifierProperty().getGenerator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InMemoryGenerator getVersionGenerator() {
|
||||
return versionGenerator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRootEntityName() {
|
||||
return entityMetamodel.getRootName();
|
||||
|
@ -4771,11 +4781,11 @@ public abstract class AbstractEntityPersister
|
|||
if ( superMappingType != null ) {
|
||||
( (InFlightEntityMappingType) superMappingType ).prepareMappingModel( creationProcess );
|
||||
if ( shouldProcessSuperMapping() ) {
|
||||
this.discriminatorMapping = superMappingType.getDiscriminatorMapping();
|
||||
this.identifierMapping = superMappingType.getIdentifierMapping();
|
||||
this.naturalIdMapping = superMappingType.getNaturalIdMapping();
|
||||
this.versionMapping = superMappingType.getVersionMapping();
|
||||
this.rowIdMapping = superMappingType.getRowIdMapping();
|
||||
discriminatorMapping = superMappingType.getDiscriminatorMapping();
|
||||
identifierMapping = superMappingType.getIdentifierMapping();
|
||||
naturalIdMapping = superMappingType.getNaturalIdMapping();
|
||||
versionMapping = superMappingType.getVersionMapping();
|
||||
rowIdMapping = superMappingType.getRowIdMapping();
|
||||
}
|
||||
else {
|
||||
prepareMappingModel( creationProcess, bootEntityDescriptor );
|
||||
|
@ -4787,10 +4797,17 @@ public abstract class AbstractEntityPersister
|
|||
// rootEntityDescriptor = this;
|
||||
}
|
||||
|
||||
final EntityMetamodel currentEntityMetamodel = this.getEntityMetamodel();
|
||||
final EntityMetamodel currentEntityMetamodel = getEntityMetamodel();
|
||||
|
||||
if ( currentEntityMetamodel.isVersioned() ) {
|
||||
final InMemoryGenerator generator = currentEntityMetamodel.getVersionGenerator();
|
||||
// need to do this here because EntityMetamodel doesn't have the EntityVersionMapping :-(
|
||||
versionGenerator = generator == null ? new VersionGeneration( versionMapping ) : generator;
|
||||
}
|
||||
|
||||
int stateArrayPosition = getStateArrayInitialPosition( creationProcess );
|
||||
|
||||
NonIdentifierAttribute[] properties = currentEntityMetamodel.getProperties();
|
||||
final NonIdentifierAttribute[] properties = currentEntityMetamodel.getProperties();
|
||||
for ( int i = 0; i < currentEntityMetamodel.getPropertySpan(); i++ ) {
|
||||
final NonIdentifierAttribute runtimeAttrDefinition = properties[i];
|
||||
final Property bootProperty = bootEntityDescriptor.getProperty( runtimeAttrDefinition.getName() );
|
||||
|
@ -4826,7 +4843,6 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
|
||||
|
||||
|
||||
// register a callback for after all `#prepareMappingModel` calls have finished. here we want to delay the
|
||||
// generation of `staticFetchableList` because we need to wait until after all sub-classes have had their
|
||||
// `#prepareMappingModel` called (and their declared attribute mappings resolved)
|
||||
|
@ -4834,10 +4850,10 @@ public abstract class AbstractEntityPersister
|
|||
"Entity(" + getEntityName() + ") `staticFetchableList` generator",
|
||||
() -> {
|
||||
if ( hasInsertGeneratedProperties() ) {
|
||||
insertGeneratedValuesProcessor = createGeneratedValuesProcessor( GenerationTiming.INSERT );
|
||||
insertGeneratedValuesProcessor = createGeneratedValuesProcessor( INSERT );
|
||||
}
|
||||
if ( hasUpdateGeneratedProperties() ) {
|
||||
updateGeneratedValuesProcessor = createGeneratedValuesProcessor( GenerationTiming.UPDATE );
|
||||
updateGeneratedValuesProcessor = createGeneratedValuesProcessor( UPDATE );
|
||||
}
|
||||
staticFetchableList = new ArrayList<>( attributeMappings.size() );
|
||||
visitSubTypeAttributeMappings( attributeMapping -> staticFetchableList.add( attributeMapping ) );
|
||||
|
@ -4921,8 +4937,7 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
identifierMapping = creationProcess.processSubPart(
|
||||
EntityIdentifierMapping.ROLE_LOCAL_NAME,
|
||||
(role, process) ->
|
||||
generateIdentifierMapping( templateInstanceCreator, bootEntityDescriptor, process )
|
||||
(role, process) -> generateIdentifierMapping( templateInstanceCreator, bootEntityDescriptor, process )
|
||||
);
|
||||
|
||||
versionMapping = generateVersionMapping( templateInstanceCreator, bootEntityDescriptor, creationProcess );
|
||||
|
|
|
@ -27,6 +27,8 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.generator.InMemoryGenerator;
|
||||
import org.hibernate.generator.internal.VersionGeneration;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
import org.hibernate.internal.FilterAliasGenerator;
|
||||
|
@ -464,6 +466,10 @@ public interface EntityPersister
|
|||
return getIdentifierGenerator();
|
||||
}
|
||||
|
||||
default InMemoryGenerator getVersionGenerator() {
|
||||
return new VersionGeneration( getVersionMapping() );
|
||||
}
|
||||
|
||||
@Override
|
||||
default AttributeMapping getAttributeMapping(int position) {
|
||||
return getAttributeMappings().get( position );
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.engine.jdbc.mutation.TableInclusionChecker;
|
|||
import org.hibernate.engine.jdbc.mutation.spi.MutationExecutorService;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.generator.EventType;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
|
@ -103,11 +104,11 @@ public class InsertCoordinator extends AbstractMutationCoordinator {
|
|||
if ( entityMetamodel.hasPreInsertGeneratedValues() ) {
|
||||
final Generator[] generators = entityMetamodel.getGenerators();
|
||||
for ( int i = 0; i < generators.length; i++ ) {
|
||||
Generator generator = generators[i];
|
||||
final Generator generator = generators[i];
|
||||
if ( generator != null
|
||||
&& !generator.generatedByDatabase()
|
||||
&& generator.generatesOnInsert() ) {
|
||||
values[i] = ( (InMemoryGenerator) generator ).generate( session, entity, values[i] );
|
||||
values[i] = ( (InMemoryGenerator) generator ).generate( session, entity, values[i], EventType.INSERT );
|
||||
entityPersister().setPropertyValue( entity, i, values[i] );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ import static org.hibernate.engine.OptimisticLockStyle.DIRTY;
|
|||
import static org.hibernate.engine.OptimisticLockStyle.NONE;
|
||||
import static org.hibernate.engine.OptimisticLockStyle.VERSION;
|
||||
import static org.hibernate.engine.internal.Versioning.isVersionIncrementRequired;
|
||||
import static org.hibernate.generator.EventType.UPDATE;
|
||||
import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_INT_ARRAY;
|
||||
|
||||
/**
|
||||
|
@ -452,7 +453,7 @@ public class UpdateCoordinatorStandard extends AbstractMutationCoordinator imple
|
|||
if ( generator != null
|
||||
&& !generator.generatedByDatabase()
|
||||
&& generator.generatesOnUpdate() ) {
|
||||
newValues[i] = ( (InMemoryGenerator) generator ).generate( session, object, newValues[i] );
|
||||
newValues[i] = ( (InMemoryGenerator) generator ).generate( session, object, newValues[i], UPDATE );
|
||||
entityPersister().setPropertyValue( object, i, newValues[i] );
|
||||
fieldsPreUpdateNeeded[count++] = i;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.hibernate.engine.FetchTiming;
|
|||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.generator.EventType;
|
||||
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
|
||||
import org.hibernate.id.OptimizableGenerator;
|
||||
import org.hibernate.id.enhanced.Optimizer;
|
||||
|
@ -508,7 +509,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
|||
rootIdentity,
|
||||
new JdbcParameterBindingImpl(
|
||||
identifierMapping.getJdbcMapping(),
|
||||
( (InMemoryGenerator) generator ).generate( executionContext.getSession(), null, null )
|
||||
( (InMemoryGenerator) generator ).generate( executionContext.getSession(), null, null, EventType.INSERT )
|
||||
)
|
||||
);
|
||||
jdbcServices.getJdbcMutationExecutor().execute(
|
||||
|
|
|
@ -404,6 +404,7 @@ import jakarta.persistence.TemporalType;
|
|||
import jakarta.persistence.metamodel.SingularAttribute;
|
||||
import jakarta.persistence.metamodel.Type;
|
||||
|
||||
import static org.hibernate.generator.EventType.INSERT;
|
||||
import static org.hibernate.internal.util.NullnessHelper.coalesceSuppliedValues;
|
||||
import static org.hibernate.query.sqm.BinaryArithmeticOperator.ADD;
|
||||
import static org.hibernate.query.sqm.BinaryArithmeticOperator.MULTIPLY;
|
||||
|
@ -1464,7 +1465,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
ExecutionContext executionContext) throws SQLException {
|
||||
getJdbcMapping().getJdbcValueBinder().bind(
|
||||
statement,
|
||||
generator.generate( executionContext.getSession(), null, null ),
|
||||
generator.generate( executionContext.getSession(), null, null, INSERT ),
|
||||
startPosition,
|
||||
executionContext.getSession()
|
||||
);
|
||||
|
|
|
@ -55,7 +55,7 @@ public interface ValueGeneration extends InMemoryGenerator, InDatabaseGenerator
|
|||
ValueGenerator<?> getValueGenerator();
|
||||
|
||||
@Override
|
||||
default Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue) {
|
||||
default Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||
return getValueGenerator().generateValue( (Session) session, owner, currentValue );
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ public class VmValueGeneration implements InMemoryGenerator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue) {
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||
return generator.generateValue( (Session) session, owner, currentValue );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -139,6 +139,8 @@ public class EntityMetamodel implements Serializable {
|
|||
private final Set<String> subclassEntityNames;
|
||||
private final Map<Class<?>,String> entityNameByInheritanceClassMap;
|
||||
|
||||
private final InMemoryGenerator versionGenerator;
|
||||
|
||||
private final BytecodeEnhancementMetadata bytecodeEnhancementMetadata;
|
||||
|
||||
@Deprecated(since = "6.0")
|
||||
|
@ -217,7 +219,7 @@ public class EntityMetamodel implements Serializable {
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// generated value strategies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
this.generators = new Generator[propertySpan];
|
||||
generators = new Generator[propertySpan];
|
||||
|
||||
boolean foundPreInsertGeneratedValues = false;
|
||||
boolean foundPreUpdateGeneratedValues = false;
|
||||
|
@ -233,6 +235,7 @@ public class EntityMetamodel implements Serializable {
|
|||
BitSet mutableIndexes = new BitSet();
|
||||
boolean foundNonIdentifierPropertyNamedId = false;
|
||||
boolean foundUpdateableNaturalIdProperty = false;
|
||||
InMemoryGenerator tempVersionGenerator = null;
|
||||
|
||||
List<Property> props = persistentClass.getPropertyClosure();
|
||||
for ( int i=0; i<props.size(); i++ ) {
|
||||
|
@ -298,34 +301,43 @@ public class EntityMetamodel implements Serializable {
|
|||
propertyInsertability[i] = attribute.isInsertable();
|
||||
propertyVersionability[i] = attribute.isVersionable();
|
||||
nonlazyPropertyUpdateability[i] = attribute.isUpdateable() && !lazy;
|
||||
propertyCheckability[i] = propertyUpdateability[i] ||
|
||||
( propertyType.isAssociationType() && ( (AssociationType) propertyType ).isAlwaysDirtyChecked() );
|
||||
propertyCheckability[i] = propertyUpdateability[i]
|
||||
|| propertyType.isAssociationType() && ( (AssociationType) propertyType ).isAlwaysDirtyChecked();
|
||||
|
||||
cascadeStyles[i] = attribute.getCascadeStyle();
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// generated value strategies ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
final Generator generator = buildGenerator( property, creationContext );
|
||||
generators[i] = generator;
|
||||
if ( generator != null ) {
|
||||
if ( generatedWithNoParameter( generator ) ) {
|
||||
propertyInsertability[i] = false;
|
||||
propertyUpdateability[i] = false;
|
||||
if ( i == tempVersionProperty && !generator.generatedByDatabase() ) {
|
||||
// when we have an in-memory generator for the version, we
|
||||
// want to plug it in to the older infrastructure specific
|
||||
// to version generation, instead of treating it like a
|
||||
// plain "value" generator for a regular attribute
|
||||
tempVersionGenerator = (InMemoryGenerator) generator;
|
||||
}
|
||||
if ( generator.generatesOnInsert() ) {
|
||||
if ( generator.generatedByDatabase() ) {
|
||||
foundPostInsertGeneratedValues = true;
|
||||
else {
|
||||
generators[i] = generator;
|
||||
if ( generatedWithNoParameter( generator ) ) {
|
||||
propertyInsertability[i] = false;
|
||||
propertyUpdateability[i] = false;
|
||||
}
|
||||
else {
|
||||
foundPreInsertGeneratedValues = true;
|
||||
if ( generator.generatesOnInsert() ) {
|
||||
if ( generator.generatedByDatabase() ) {
|
||||
foundPostInsertGeneratedValues = true;
|
||||
}
|
||||
else {
|
||||
foundPreInsertGeneratedValues = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( generator.generatesOnUpdate() ) {
|
||||
if ( generator.generatedByDatabase() ) {
|
||||
foundPostUpdateGeneratedValues = true;
|
||||
}
|
||||
else {
|
||||
foundPreUpdateGeneratedValues = true;
|
||||
if ( generator.generatesOnUpdate() ) {
|
||||
if ( generator.generatedByDatabase() ) {
|
||||
foundPostUpdateGeneratedValues = true;
|
||||
}
|
||||
else {
|
||||
foundPreUpdateGeneratedValues = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -369,17 +381,19 @@ public class EntityMetamodel implements Serializable {
|
|||
hasCacheableNaturalId = persistentClass.getNaturalIdCacheRegionName() != null;
|
||||
}
|
||||
|
||||
this.hasPreInsertGeneratedValues = foundPreInsertGeneratedValues;
|
||||
this.hasPreUpdateGeneratedValues = foundPreUpdateGeneratedValues;
|
||||
this.hasInsertGeneratedValues = foundPostInsertGeneratedValues;
|
||||
this.hasUpdateGeneratedValues = foundPostUpdateGeneratedValues;
|
||||
hasPreInsertGeneratedValues = foundPreInsertGeneratedValues;
|
||||
hasPreUpdateGeneratedValues = foundPreUpdateGeneratedValues;
|
||||
hasInsertGeneratedValues = foundPostInsertGeneratedValues;
|
||||
hasUpdateGeneratedValues = foundPostUpdateGeneratedValues;
|
||||
|
||||
versionGenerator = tempVersionGenerator;
|
||||
|
||||
hasCascades = foundCascade;
|
||||
hasCascadeDelete = foundCascadeDelete;
|
||||
hasNonIdentifierPropertyNamedId = foundNonIdentifierPropertyNamedId;
|
||||
versionPropertyIndex = tempVersionProperty;
|
||||
hasLazyProperties = hasLazy;
|
||||
if (hasLazyProperties) {
|
||||
if ( hasLazyProperties ) {
|
||||
LOG.lazyPropertyFetchingAvailable(name);
|
||||
}
|
||||
|
||||
|
@ -405,7 +419,8 @@ public class EntityMetamodel implements Serializable {
|
|||
selectBeforeUpdate = persistentClass.hasSelectBeforeUpdate();
|
||||
|
||||
dynamicUpdate = persistentClass.useDynamicUpdate()
|
||||
|| ( getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() && getBytecodeEnhancementMetadata().getLazyAttributesMetadata().getFetchGroupNames().size() > 1 );
|
||||
|| ( getBytecodeEnhancementMetadata().isEnhancedForLazyLoading()
|
||||
&& getBytecodeEnhancementMetadata().getLazyAttributesMetadata().getFetchGroupNames().size() > 1 );
|
||||
dynamicInsert = persistentClass.useDynamicInsert();
|
||||
|
||||
polymorphic = persistentClass.isPolymorphic();
|
||||
|
@ -477,6 +492,10 @@ public class EntityMetamodel implements Serializable {
|
|||
return generators;
|
||||
}
|
||||
|
||||
public InMemoryGenerator getVersionGenerator() {
|
||||
return versionGenerator;
|
||||
}
|
||||
|
||||
public static class ValueGenerationStrategyException extends HibernateException {
|
||||
public ValueGenerationStrategyException(String message) {
|
||||
super( message );
|
||||
|
|
|
@ -98,7 +98,7 @@ public class GeneratedUuidTests {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue) {
|
||||
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||
return UUID.randomUUID();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue