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