use of org.hibernate.reactive.engine.impl.Cascade in project hibernate-reactive by hibernate.
the class DefaultReactiveMergeEventListener method fetchAndCopyValues.
private CompletionStage<Void> fetchAndCopyValues(final EntityPersister persister, final Object entity, final Object target, final SessionImplementor source, final MergeContext mergeContext) {
CompletionStage<Void> stage;
if (entity == target) {
// If entity == target, then nothing needs to be fetched.
stage = voidFuture();
} else {
ReactiveSession session = source.unwrap(ReactiveSession.class);
final Object[] mergeState = persister.getPropertyValues(entity);
final Object[] managedState = persister.getPropertyValues(target);
// Cascade-merge mappings do not determine what needs to be fetched.
// The value only needs to be fetched if the incoming value (mergeState[i])
// is initialized, but its corresponding managed state is not initialized.
// Initialization must be done before copyValues() executes.
stage = loop(0, mergeState.length, i -> Hibernate.isInitialized(mergeState[i]) && !Hibernate.isInitialized(managedState[i]), i -> session.reactiveFetch(managedState[i], true));
}
return stage.thenCompose(v -> copyValues(persister, entity, target, source, mergeContext));
}
use of org.hibernate.reactive.engine.impl.Cascade in project hibernate-reactive by hibernate.
the class AbstractReactiveSaveEventListener method reactivePerformSaveOrReplicate.
/**
* 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 context 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 CompletionStage<Void> reactivePerformSaveOrReplicate(Object entity, EntityKey key, EntityPersister persister, boolean useIdentityColumn, C context, EventSource source, boolean requiresImmediateIdAccess) {
Serializable id = key == null ? null : key.getIdentifier();
boolean inTransaction = source.isTransactionInProgress();
boolean shouldDelayIdentityInserts = !inTransaction && !requiresImmediateIdAccess;
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
// 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()?
EntityEntry original = persistenceContext.addEntry(entity, Status.SAVING, null, null, id, null, LockMode.WRITE, useIdentityColumn, persister, false);
return cascadeBeforeSave(source, persister, entity, context).thenCompose(v -> {
// We have to do this after cascadeBeforeSave completes,
// since it could result in generation of parent ids,
// which we will need as foreign keys in the insert
Object[] values = persister.getPropertyValuesToInsert(entity, getMergeMap(context), source);
Type[] types = persister.getPropertyTypes();
boolean substitute = substituteValuesIfNecessary(entity, id, values, persister, source);
if (persister.hasCollections()) {
boolean substituteBecauseOfCollections = visitCollectionsBeforeSave(entity, id, values, types, source);
substitute = substitute || substituteBecauseOfCollections;
}
if (substitute) {
persister.setPropertyValues(entity, values);
}
TypeHelper.deepCopy(values, types, persister.getPropertyUpdateability(), values, source);
CompletionStage<AbstractEntityInsertAction> insert = addInsertAction(values, id, entity, persister, useIdentityColumn, source, shouldDelayIdentityInserts);
EntityEntry newEntry = persistenceContext.getEntry(entity);
if (newEntry != original) {
EntityEntryExtraState extraState = newEntry.getExtraState(EntityEntryExtraState.class);
if (extraState == null) {
newEntry.addExtraState(original.getExtraState(EntityEntryExtraState.class));
}
}
return insert;
}).thenCompose(vv -> cascadeAfterSave(source, persister, entity, context));
// .thenAccept( v -> {
// postpone initializing id in case the insert has non-nullable transient dependencies
// that are not resolved until cascadeAfterSave() is executed
// Serializable newId = id;
// if ( useIdentityColumn && insert.isEarlyInsert() ) {
// if ( !EntityIdentityInsertAction.class.isInstance( insert ) ) {
// throw new IllegalStateException(
// "Insert should be using an identity column, but action is of unexpected type: " +
// insert.getClass().getName()
// );
// }
// newId = ( (EntityIdentityInsertAction) insert ).getGeneratedId();
//
// insert.handleNaturalIdPostSaveNotifications( newId );
// }
// return newId;
// } );
}
Aggregations