下面列出了org.hibernate.event.spi.EventSource#generateEntityKey ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
private CompletionStage<Object> doOnLoad(
final EntityPersister persister,
final LoadEvent event,
final LoadEventListener.LoadType loadType) {
final EventSource session = event.getSession();
final EntityKey keyToLoad = session.generateEntityKey( event.getEntityId(), persister );
if ( loadType.isNakedEntityReturned() ) {
//do not return a proxy!
//(this option indicates we are initializing a proxy)
return load( event, persister, keyToLoad, loadType );
}
//return a proxy if appropriate
else if ( event.getLockMode() == LockMode.NONE ) {
return proxyOrLoad( event, persister, keyToLoad, loadType );
}
else {
return lockAndLoad( event, persister, keyToLoad, loadType, session );
}
}
private CompletionStage<Void> loadByDerivedIdentitySimplePkValue(LoadEvent event, LoadEventListener.LoadType options,
EntityPersister dependentPersister, EmbeddedComponentType dependentIdType, EntityPersister parentPersister) {
EventSource session = event.getSession();
final EntityKey parentEntityKey = session.generateEntityKey( event.getEntityId(), parentPersister );
return doLoad( event, parentPersister, parentEntityKey, options )
.thenApply( checkEntityFound( session, parentEntityKey.getEntityName(), parentEntityKey ) )
.thenApply( parent -> {
final Serializable dependent = (Serializable) dependentIdType.instantiate( parent, session );
dependentIdType.setPropertyValues( dependent, new Object[] {parent}, dependentPersister.getEntityMode() );
event.setEntityId( dependent );
return session.generateEntityKey( dependent, dependentPersister );
} )
.thenCompose( dependentEntityKey -> doLoad( event, dependentPersister, dependentEntityKey, options ) )
.thenAccept( event::setResult );
}
private boolean existsInDatabase(Object entity, EventSource source, EntityPersister persister) {
EntityEntry entry = source.getPersistenceContext().getEntry( entity );
if ( entry == null ) {
Serializable id = persister.getIdentifier( entity, source );
if ( id != null ) {
final EntityKey key = source.generateEntityKey( id, persister );
final Object managedEntity = source.getPersistenceContext().getEntity( key );
entry = source.getPersistenceContext().getEntry( managedEntity );
}
}
return entry != null && entry.isExistsInDatabase();
}
/**
* Prepares the save call by checking the session caches for a pre-existing
* entity and performing any lifecycle callbacks.
*
* @param entity The entity to be saved.
* @param id The id by which to save the entity.
* @param persister The entity's persister instance.
* @param useIdentityColumn Is an identity column being used?
* @param context Generally cascade-specific information.
* @param source The session from which the event originated.
* @param requiresImmediateIdAccess does the event context require
* access to the identifier immediately after execution of this method (if
* not, post-insert style id generators may be postponed if we are outside
* a transaction).
*
* @return The id used to save the entity; may be null depending on the
* type of id generator used and the requiresImmediateIdAccess value
*/
protected CompletionStage<Void> reactivePerformSave(
Object entity,
Serializable id,
EntityPersister persister,
boolean useIdentityColumn,
C context,
EventSource source,
boolean requiresImmediateIdAccess) {
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Saving {0}", MessageHelper.infoString( persister, id, source.getFactory() ) );
}
final EntityKey key;
if ( !useIdentityColumn ) {
key = source.generateEntityKey( id, persister );
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
Object old = persistenceContext.getEntity( key );
if ( old != null ) {
if ( persistenceContext.getEntry( old ).getStatus() == Status.DELETED ) {
source.forceFlush( persistenceContext.getEntry( old ) );
}
else {
return CompletionStages.failedFuture( new NonUniqueObjectException( id, persister.getEntityName() ) );
}
}
persister.setIdentifier( entity, id, source );
}
else {
key = null;
}
return reactivePerformSaveOrReplicate(
entity,
key,
persister,
useIdentityColumn,
context,
source,
requiresImmediateIdAccess
);
}
/**
* Handle the given delete event. This is the cascaded form.
*
* @param event The delete event.
* @param transientEntities The cache of entities already deleted
*
* @throws HibernateException
*/
public void onDelete(DeleteEvent event, Set transientEntities) throws HibernateException {
final EventSource source = event.getSession();
final PersistenceContext persistenceContext = source.getPersistenceContext();
Object entity = persistenceContext.unproxyAndReassociate( event.getObject() );
EntityEntry entityEntry = persistenceContext.getEntry( entity );
final EntityPersister persister;
final Serializable id;
final Object version;
if ( entityEntry == null ) {
LOG.trace( "Entity was not persistent in delete processing" );
persister = source.getEntityPersister( event.getEntityName(), entity );
if ( ForeignKeys.isTransient( persister.getEntityName(), entity, null, source ) ) {
deleteTransientEntity( source, entity, event.isCascadeDeleteEnabled(), persister, transientEntities );
// EARLY EXIT!!!
return;
}
performDetachedEntityDeletionCheck( event );
id = persister.getIdentifier( entity, source );
if ( id == null ) {
throw new TransientObjectException(
"the detached instance passed to delete() had a null identifier"
);
}
final EntityKey key = source.generateEntityKey( id, persister );
persistenceContext.checkUniqueness( key, entity );
new OnUpdateVisitor( source, id, entity ).process( entity, persister );
version = persister.getVersion( entity );
entityEntry = persistenceContext.addEntity(
entity,
(persister.isMutable() ? Status.MANAGED : Status.READ_ONLY),
persister.getPropertyValues( entity ),
key,
version,
LockMode.NONE,
true,
persister,
false
);
}
else {
LOG.trace( "Deleting a persistent instance" );
if ( entityEntry.getStatus() == Status.DELETED || entityEntry.getStatus() == Status.GONE ) {
LOG.trace( "Object was already deleted" );
return;
}
persister = entityEntry.getPersister();
id = entityEntry.getId();
version = entityEntry.getVersion();
}
/*if ( !persister.isMutable() ) {
throw new HibernateException(
"attempted to delete an object of immutable class: " +
MessageHelper.infoString(persister)
);
}*/
if ( invokeDeleteLifecycle( source, entity, persister ) ) {
return;
}
deleteEntity(
source,
entity,
entityEntry,
event.isCascadeDeleteEnabled(),
event.isOrphanRemovalBeforeUpdates(),
persister,
transientEntities
);
if ( source.getFactory().getSettings().isIdentifierRollbackEnabled() ) {
persister.resetIdentifier( entity, id, version, source );
}
}
/**
* Perform the entity deletion. Well, as with most operations, does not
* really perform it; just schedules an action/execution with the
* {@link org.hibernate.engine.spi.ActionQueue} for execution during flush.
*
* @param session The originating session
* @param entity The entity to delete
* @param entityEntry The entity's entry in the {@link PersistenceContext}
* @param isCascadeDeleteEnabled Is delete cascading enabled?
* @param persister The entity persister.
* @param transientEntities A cache of already deleted entities.
*/
protected final void deleteEntity(
final EventSource session,
final Object entity,
final EntityEntry entityEntry,
final boolean isCascadeDeleteEnabled,
final boolean isOrphanRemovalBeforeUpdates,
final EntityPersister persister,
final Set transientEntities) {
if ( LOG.isTraceEnabled() ) {
LOG.tracev(
"Deleting {0}",
MessageHelper.infoString( persister, entityEntry.getId(), session.getFactory() )
);
}
final PersistenceContext persistenceContext = session.getPersistenceContext();
final Type[] propTypes = persister.getPropertyTypes();
final Object version = entityEntry.getVersion();
final Object[] currentState;
if ( entityEntry.getLoadedState() == null ) {
//ie. the entity came in from update()
currentState = persister.getPropertyValues( entity );
}
else {
currentState = entityEntry.getLoadedState();
}
final Object[] deletedState = createDeletedState( persister, currentState, session );
entityEntry.setDeletedState( deletedState );
session.getInterceptor().onDelete(
entity,
entityEntry.getId(),
deletedState,
persister.getPropertyNames(),
propTypes
);
// before any callbacks, etc, so subdeletions see that this deletion happened first
persistenceContext.setEntryStatus( entityEntry, Status.DELETED );
final EntityKey key = session.generateEntityKey( entityEntry.getId(), persister );
cascadeBeforeDelete( session, persister, entity, entityEntry, transientEntities );
new ForeignKeys.Nullifier( entity, true, false, session )
.nullifyTransientReferences( entityEntry.getDeletedState(), propTypes );
new Nullability( session ).checkNullability( entityEntry.getDeletedState(), persister, Nullability.NullabilityCheckType.DELETE );
persistenceContext.getNullifiableEntityKeys().add( key );
if ( isOrphanRemovalBeforeUpdates ) {
// TODO: The removeOrphan concept is a temporary "hack" for HHH-6484. This should be removed once action/task
// ordering is improved.
session.getActionQueue().addAction(
new OrphanRemovalAction(
entityEntry.getId(),
deletedState,
version,
entity,
persister,
isCascadeDeleteEnabled,
session
)
);
}
else {
// Ensures that containing deletions happen before sub-deletions
session.getActionQueue().addAction(
new EntityDeleteAction(
entityEntry.getId(),
deletedState,
version,
entity,
persister,
isCascadeDeleteEnabled,
session
)
);
}
cascadeAfterDelete( session, persister, entity, transientEntities );
// the entry will be removed after the flush, and will no longer
// override the stale snapshot
// This is now handled by removeEntity() in EntityDeleteAction
//persistenceContext.removeDatabaseSnapshot(key);
}
protected void performUpdate(
SaveOrUpdateEvent event,
Object entity,
EntityPersister persister) throws HibernateException {
final boolean traceEnabled = LOG.isTraceEnabled();
if ( traceEnabled && !persister.isMutable() ) {
LOG.trace( "Immutable instance passed to performUpdate()" );
}
if ( traceEnabled ) {
LOG.tracev(
"Updating {0}",
MessageHelper.infoString( persister, event.getRequestedId(), event.getSession().getFactory() )
);
}
final EventSource source = event.getSession();
final EntityKey key = source.generateEntityKey( event.getRequestedId(), persister );
source.getPersistenceContext().checkUniqueness( key, entity );
if ( invokeUpdateLifecycle( entity, persister, source ) ) {
reassociate( event, event.getObject(), event.getRequestedId(), persister );
return;
}
// this is a transient object with existing persistent state not loaded by the session
new OnUpdateVisitor( source, event.getRequestedId(), entity ).process( entity, persister );
// TODO: put this stuff back in to read snapshot from
// the second-level cache (needs some extra work)
/*Object[] cachedState = null;
if ( persister.hasCache() ) {
CacheEntry entry = (CacheEntry) persister.getCache()
.get( event.getRequestedId(), source.getTimestamp() );
cachedState = entry==null ?
null :
entry.getState(); //TODO: half-assemble this stuff
}*/
source.getPersistenceContext().addEntity(
entity,
( persister.isMutable() ? Status.MANAGED : Status.READ_ONLY ),
null, // cachedState,
key,
persister.getVersion( entity ),
LockMode.NONE,
true,
persister,
false
);
persister.afterReassociate( entity, source );
if ( traceEnabled ) {
LOG.tracev(
"Updating {0}", MessageHelper.infoString(
persister,
event.getRequestedId(),
source.getFactory()
)
);
}
cascadeOnUpdate( event, persister, entity );
}
/**
* Associates a given entity (either transient or associated with another session) to
* the given session.
*
* @param event The event triggering the re-association
* @param object The entity to be associated
* @param id The id of the entity.
* @param persister The entity's persister instance.
*
* @return An EntityEntry representing the entity within this session.
*/
protected final EntityEntry reassociate(AbstractEvent event, Object object, Serializable id, EntityPersister persister) {
if ( log.isTraceEnabled() ) {
log.tracev(
"Reassociating transient instance: {0}",
MessageHelper.infoString( persister, id, event.getSession().getFactory() )
);
}
final EventSource source = event.getSession();
final EntityKey key = source.generateEntityKey( id, persister );
source.getPersistenceContext().checkUniqueness( key, object );
//get a snapshot
Object[] values = persister.getPropertyValues( object );
TypeHelper.deepCopy(
values,
persister.getPropertyTypes(),
persister.getPropertyUpdateability(),
values,
source
);
Object version = Versioning.getVersion( values, persister );
EntityEntry newEntry = source.getPersistenceContext().addEntity(
object,
( persister.isMutable() ? Status.MANAGED : Status.READ_ONLY ),
values,
key,
version,
LockMode.NONE,
true,
persister,
false
);
new OnLockVisitor( source, id, object ).process( object, persister );
persister.afterReassociate( object, source );
return newEntry;
}
/**
* Handle the given merge event.
*
* @param event The merge event to be handled.
*
* @throws HibernateException
*/
public void onMerge(MergeEvent event, Map copiedAlready) throws HibernateException {
final MergeContext copyCache = (MergeContext) copiedAlready;
final EventSource source = event.getSession();
final Object original = event.getOriginal();
if ( original != null ) {
final Object entity;
if ( original instanceof HibernateProxy ) {
LazyInitializer li = ( (HibernateProxy) original ).getHibernateLazyInitializer();
if ( li.isUninitialized() ) {
LOG.trace( "Ignoring uninitialized proxy" );
event.setResult( source.load( li.getEntityName(), li.getIdentifier() ) );
return; //EARLY EXIT!
}
else {
entity = li.getImplementation();
}
}
else {
entity = original;
}
if ( copyCache.containsKey( entity ) &&
( copyCache.isOperatedOn( entity ) ) ) {
LOG.trace( "Already in merge process" );
event.setResult( entity );
}
else {
if ( copyCache.containsKey( entity ) ) {
LOG.trace( "Already in copyCache; setting in merge process" );
copyCache.setOperatedOn( entity, true );
}
event.setEntity( entity );
EntityState entityState = null;
// Check the persistence context for an entry relating to this
// entity to be merged...
EntityEntry entry = source.getPersistenceContext().getEntry( entity );
if ( entry == null ) {
EntityPersister persister = source.getEntityPersister( event.getEntityName(), entity );
Serializable id = persister.getIdentifier( entity, source );
if ( id != null ) {
final EntityKey key = source.generateEntityKey( id, persister );
final Object managedEntity = source.getPersistenceContext().getEntity( key );
entry = source.getPersistenceContext().getEntry( managedEntity );
if ( entry != null ) {
// we have specialized case of a detached entity from the
// perspective of the merge operation. Specifically, we
// have an incoming entity instance which has a corresponding
// entry in the current persistence context, but registered
// under a different entity instance
entityState = EntityState.DETACHED;
}
}
}
if ( entityState == null ) {
entityState = getEntityState( entity, event.getEntityName(), entry, source );
}
switch ( entityState ) {
case DETACHED:
entityIsDetached( event, copyCache );
break;
case TRANSIENT:
entityIsTransient( event, copyCache );
break;
case PERSISTENT:
entityIsPersistent( event, copyCache );
break;
default: //DELETED
throw new ObjectDeletedException(
"deleted instance passed to merge",
null,
getLoggableName( event.getEntityName(), entity )
);
}
}
}
}
/**
* Prepares the save call by checking the session caches for a pre-existing
* entity and performing any lifecycle callbacks.
*
* @param entity The entity to be saved.
* @param id The id by which to save the entity.
* @param persister The entity's persister instance.
* @param useIdentityColumn Is an identity column being used?
* @param anything Generally cascade-specific information.
* @param source The session from which the event originated.
* @param requiresImmediateIdAccess does the event context require
* access to the identifier immediately after execution of this method (if
* not, post-insert style id generators may be postponed if we are outside
* a transaction).
*
* @return The id used to save the entity; may be null depending on the
* type of id generator used and the requiresImmediateIdAccess value
*/
protected Serializable performSave(
Object entity,
Serializable id,
EntityPersister persister,
boolean useIdentityColumn,
Object anything,
EventSource source,
boolean requiresImmediateIdAccess) {
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Saving {0}", MessageHelper.infoString( persister, id, source.getFactory() ) );
}
final EntityKey key;
if ( !useIdentityColumn ) {
key = source.generateEntityKey( id, persister );
Object old = source.getPersistenceContext().getEntity( key );
if ( old != null ) {
if ( source.getPersistenceContext().getEntry( old ).getStatus() == Status.DELETED ) {
source.forceFlush( source.getPersistenceContext().getEntry( old ) );
}
else {
throw new NonUniqueObjectException( id, persister.getEntityName() );
}
}
persister.setIdentifier( entity, id, source );
}
else {
key = null;
}
if ( invokeSaveLifecycle( entity, persister, source ) ) {
return id; //EARLY EXIT
}
return performSaveOrReplicate(
entity,
key,
persister,
useIdentityColumn,
anything,
source,
requiresImmediateIdAccess
);
}