protected int getEntityState(Object entity,
String entityName,
EntityEntry entry,
SessionImplementor source) {
if ( entry != null ) { // the object is persistent
//the entity is associated with the session, so check its status
if ( entry.getStatus() != Status.DELETED ) {
// do nothing for persistent instances
if ( log.isTraceEnabled() ) {
log.trace(
"persistent instance of: " +
getLoggableName( entityName, entity )
);
}
return PERSISTENT;
}
else {
//ie. e.status==DELETED
if ( log.isTraceEnabled() ) {
log.trace(
"deleted instance of: " +
getLoggableName( entityName, entity )
);
}
return DELETED;
}
}
else { // the object is transient or detached
//the entity is not associated with the session, so
//try interceptor and unsaved-value
if ( ForeignKeys.isTransient( entityName, entity, getAssumedUnsaved(), source ) ) {
if ( log.isTraceEnabled() ) {
log.trace(
"transient instance of: " +
getLoggableName( entityName, entity )
);
}
return TRANSIENT;
}
else {
if ( log.isTraceEnabled() ) {
log.trace(
"detached instance of: " +
getLoggableName( entityName, entity )
);
}
return DETACHED;
}
}
}
Determine whether the entity is persistent, detached, or transient |
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
);
}
Ppepares the save call by checking the session caches for a pre-existing
entity and performing any lifecycle callbacks. |
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() ) {
substitute = substitute || visitCollectionsBeforeSave( entity, id, values, types, source );
}
if ( substitute ) {
persister.setPropertyValues( entity, values, source.getEntityMode() );
}
TypeFactory.deepCopy(
values,
types,
persister.getPropertyUpdateability(),
values,
source
);
new ForeignKeys.Nullifier( entity, false, useIdentityColumn, source )
.nullifyTransientReferences( values, types );
new Nullability( source ).checkNullability( values, persister, false );
if ( useIdentityColumn ) {
EntityIdentityInsertAction insert = new EntityIdentityInsertAction(
values, entity, persister, source, shouldDelayIdentityInserts
);
if ( !shouldDelayIdentityInserts ) {
log.debug( "executing identity-insert immediately" );
source.getActionQueue().execute( insert );
id = insert.getGeneratedId();
//now done in EntityIdentityInsertAction
//persister.setIdentifier( entity, id, source.getEntityMode() );
key = new EntityKey( id, persister, source.getEntityMode() );
source.getPersistenceContext().checkUniqueness( key, entity );
//source.getBatcher().executeBatch(); //found another way to ensure that all batched joined inserts have been executed
}
else {
log.debug( "delaying identity-insert due to no transaction in progress" );
source.getActionQueue().addAction( insert );
key = insert.getDelayedEntityKey();
}
}
Object version = Versioning.getVersion( values, persister );
source.getPersistenceContext().addEntity(
entity,
Status.MANAGED,
values,
key,
version,
LockMode.WRITE,
useIdentityColumn,
persister,
isVersionIncrementDisabled(),
false
);
//source.getPersistenceContext().removeNonExist( new EntityKey( id, persister, source.getEntityMode() ) );
if ( !useIdentityColumn ) {
source.getActionQueue().addAction(
new EntityInsertAction( id, values, entity, version, persister, source )
);
}
cascadeAfterSave( source, persister, entity, anything );
markInterceptorDirty( entity, persister, source );
return id;
}
Performs all the actual work needed to save an entity (well to get the save moved to
the execution queue). |
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 == IdentifierGeneratorHelper.SHORT_CIRCUIT_INDICATOR ) {
return source.getIdentifier( entity );
}
else if ( generatedId == IdentifierGeneratorHelper.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 );
}
}
Prepares the save call using a newly generated id. |