📄 abstractsaveeventlistener.java
字号:
//$Id: AbstractSaveEventListener.java 10948 2006-12-07 21:53:10Z steve.ebersole@jboss.com $package org.hibernate.event.def;import java.io.Serializable;import java.util.Map;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.hibernate.LockMode;import org.hibernate.NonUniqueObjectException;import org.hibernate.action.EntityIdentityInsertAction;import org.hibernate.action.EntityInsertAction;import org.hibernate.classic.Lifecycle;import org.hibernate.classic.Validatable;import org.hibernate.engine.Cascade;import org.hibernate.engine.CascadingAction;import org.hibernate.engine.EntityEntry;import org.hibernate.engine.EntityKey;import org.hibernate.engine.ForeignKeys;import org.hibernate.engine.Nullability;import org.hibernate.engine.SessionImplementor;import org.hibernate.engine.Status;import org.hibernate.engine.Versioning;import org.hibernate.event.EventSource;import org.hibernate.id.IdentifierGenerationException;import org.hibernate.id.IdentifierGeneratorFactory;import org.hibernate.intercept.FieldInterceptionHelper;import org.hibernate.intercept.FieldInterceptor;import org.hibernate.persister.entity.EntityPersister;import org.hibernate.pretty.MessageHelper;import org.hibernate.type.Type;import org.hibernate.type.TypeFactory;/** * A convenience bas class for listeners responding to save events. * * @author Steve Ebersole. */public abstract class AbstractSaveEventListener extends AbstractReassociateEventListener { protected static final int PERSISTENT = 0; protected static final int TRANSIENT = 1; protected static final int DETACHED = 2; protected static final int DELETED = 3; private static final Logger log = LoggerFactory.getLogger( AbstractSaveEventListener.class ); /** * Prepares the save call using the given requested id. * * @param entity The entity to be saved. * @param requestedId The id to which to associate the entity. * @param entityName The name of the entity being saved. * @param anything Generally cascade-specific information. * @param source The session which is the source of this save event. * * @return The id used to save the entity. */ protected Serializable saveWithRequestedId( Object entity, Serializable requestedId, String entityName, Object anything, EventSource source) { return performSave( entity, requestedId, source.getEntityPersister( entityName, entity ), false, anything, source, true ); } /** * Prepares the save call using a newly generated id. * * @param entity The entity to be saved * @param entityName The entity-name for the entity to be saved * @param anything Generally cascade-specific information. * @param source The session which is the source of this save event. * @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 saveWithGeneratedId( Object entity, String entityName, Object anything, EventSource source, boolean requiresImmediateIdAccess) { EntityPersister persister = source.getEntityPersister( entityName, entity ); Serializable generatedId = persister.getIdentifierGenerator().generate( source, entity ); if ( generatedId == null ) { throw new IdentifierGenerationException( "null id generated for:" + entity.getClass() ); } else if ( generatedId == IdentifierGeneratorFactory.SHORT_CIRCUIT_INDICATOR ) { return source.getIdentifier( entity ); } else if ( generatedId == IdentifierGeneratorFactory.POST_INSERT_INDICATOR ) { return performSave( entity, null, persister, true, anything, source, requiresImmediateIdAccess ); } else { if ( log.isDebugEnabled() ) { log.debug( "generated identifier: " + persister.getIdentifierType().toLoggableString( generatedId, source.getFactory() ) + ", using strategy: " + persister.getIdentifierGenerator().getClass().getName() //TODO: define toString()s for generators ); } return performSave( entity, generatedId, persister, false, anything, source, true ); } } /** * Ppepares 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.trace( "saving " + MessageHelper.infoString( persister, id, source.getFactory() ) ); } EntityKey key; if ( !useIdentityColumn ) { key = new EntityKey( id, persister, source.getEntityMode() ); 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.getEntityMode() ); } else { key = null; } if ( invokeSaveLifecycle( entity, persister, source ) ) { return id; //EARLY EXIT } return performSaveOrReplicate( entity, key, persister, useIdentityColumn, anything, source, requiresImmediateIdAccess ); } protected boolean invokeSaveLifecycle(Object entity, EntityPersister persister, EventSource source) { // Sub-insertions should occur before containing insertion so // Try to do the callback now if ( persister.implementsLifecycle( source.getEntityMode() ) ) { log.debug( "calling onSave()" ); if ( ( ( Lifecycle ) entity ).onSave( source ) ) { log.debug( "insertion vetoed by onSave()" ); return true; } } return false; } protected void validate(Object entity, EntityPersister persister, EventSource source) { if ( persister.implementsValidatable( source.getEntityMode() ) ) { ( ( Validatable ) entity ).validate(); } } /** * Performs all the actual work needed to save an entity (well to get the save moved to * the execution queue). * * @param entity The entity to be saved * @param key The id to be used for saving the entity (or null, in the case of identity columns) * @param persister The entity's persister instance. * @param useIdentityColumn Should an identity column be used for id generation? * @param anything Generally cascade-specific information. * @param source The session which is the source of the current event. * @param requiresImmediateIdAccess Is access to the identifier required immediately * after the completion of the save? persist(), for example, does not require this... * * @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 performSaveOrReplicate( Object entity, EntityKey key, EntityPersister persister, boolean useIdentityColumn, Object anything, EventSource source, boolean requiresImmediateIdAccess) { validate( entity, persister, source ); Serializable id = key == null ? null : key.getIdentifier(); boolean inTxn = source.getJDBCContext().isTransactionInProgress(); boolean shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess; if ( useIdentityColumn && !shouldDelayIdentityInserts ) { log.trace( "executing insertions" ); source.getActionQueue().executeInserts(); } // Put a placeholder in entries, so we don't recurse back and try to save() the // same object again. QUESTION: should this be done before onSave() is called? // likewise, should it be done before onUpdate()? source.getPersistenceContext().addEntry( entity, Status.SAVING, null, null, id, null, LockMode.WRITE, useIdentityColumn, persister, false, false ); cascadeBeforeSave( source, persister, entity, anything ); Object[] values = persister.getPropertyValuesToInsert( entity, getMergeMap( anything ), source ); Type[] types = persister.getPropertyTypes(); boolean substitute = substituteValuesIfNecessary( entity, id, values, persister, source ); if ( persister.hasCollections() ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -