use of org.hibernate.event.internal.MergeContext in project hibernate-reactive by hibernate.
the class DefaultReactiveMergeEventListener method entityIsTransient.
protected CompletionStage<Void> entityIsTransient(MergeEvent event, MergeContext copyCache) {
LOG.trace("Merging transient instance");
final Object entity = event.getEntity();
final EventSource session = event.getSession();
final String entityName = event.getEntityName();
final EntityPersister persister = session.getEntityPersister(entityName, entity);
final Serializable id = persister.hasIdentifierProperty() ? persister.getIdentifier(entity, session) : null;
final Object copy;
final Object existingCopy = copyCache.get(entity);
if (existingCopy != null) {
persister.setIdentifier(copyCache.get(entity), id, session);
copy = existingCopy;
} else {
copy = session.instantiate(persister, id);
// before cascade!
copyCache.put(entity, copy, true);
}
// cascadeOnMerge(event, persister, entity, copyCache, Cascades.CASCADE_BEFORE_MERGE);
return super.cascadeBeforeSave(session, persister, entity, copyCache).thenCompose(v -> copyValues(persister, entity, copy, session, copyCache, FROM_PARENT)).thenCompose(v -> saveTransientEntity(copy, entityName, event.getRequestedId(), session, copyCache)).thenCompose(v -> super.cascadeAfterSave(session, persister, entity, copyCache)).thenCompose(v -> copyValues(persister, entity, copy, session, copyCache, TO_PARENT)).thenAccept(v -> {
event.setResult(copy);
if (copy instanceof PersistentAttributeInterceptable) {
final PersistentAttributeInterceptable interceptable = (PersistentAttributeInterceptable) copy;
final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor();
if (interceptor == null) {
persister.getBytecodeEnhancementMetadata().injectInterceptor(copy, id, session);
}
}
});
}
use of org.hibernate.event.internal.MergeContext in project hibernate-reactive by hibernate.
the class DefaultReactiveMergeEventListener method entityIsDetached.
protected CompletionStage<Void> entityIsDetached(MergeEvent event, MergeContext copyCache) {
LOG.trace("Merging detached instance");
final Object entity = event.getEntity();
final EventSource source = event.getSession();
final EntityPersister persister = source.getEntityPersister(event.getEntityName(), entity);
final String entityName = persister.getEntityName();
Serializable requestedId = event.getRequestedId();
Serializable id;
if (requestedId == null) {
id = persister.getIdentifier(entity, source);
} else {
id = requestedId;
// check that entity id = requestedId
Serializable entityId = persister.getIdentifier(entity, source);
if (!persister.getIdentifierType().isEqual(id, entityId, source.getFactory())) {
throw LOG.mergeRequestedIdNotMatchingIdOfPassedEntity();
}
}
String previousFetchProfile = source.getLoadQueryInfluencers().getInternalFetchProfile();
source.getLoadQueryInfluencers().setInternalFetchProfile("merge");
// we must clone embedded composite identifiers, or
// we will get back the same instance that we pass in
final Serializable clonedIdentifier = (Serializable) persister.getIdentifierType().deepCopy(id, source.getFactory());
return source.unwrap(ReactiveSession.class).reactiveGet((Class<?>) persister.getMappedClass(), clonedIdentifier).thenCompose(result -> {
if (result != null) {
// before cascade!
copyCache.put(entity, result, true);
Object target = unproxyManagedForDetachedMerging(entity, result, persister, source);
if (target == entity) {
throw new AssertionFailure("entity was not detached");
} else if (!source.getEntityName(target).equals(entityName)) {
throw new WrongClassException("class of the given object did not match class of persistent copy", event.getRequestedId(), entityName);
} else if (isVersionChanged(entity, source, persister, target)) {
final StatisticsImplementor statistics = source.getFactory().getStatistics();
if (statistics.isStatisticsEnabled()) {
statistics.optimisticFailure(entityName);
}
throw new StaleObjectStateException(entityName, id);
}
// copy created before we actually copy
return cascadeOnMerge(source, persister, entity, copyCache).thenCompose(v -> fetchAndCopyValues(persister, entity, target, source, copyCache)).thenAccept(v -> {
// copyValues() (called by fetchAndCopyValues) works by reflection,
// so explicitly mark the entity instance dirty
markInterceptorDirty(entity, target, persister);
event.setResult(result);
});
} else {
// really persistent
return entityIsTransient(event, copyCache);
}
}).whenComplete((v, e) -> source.getLoadQueryInfluencers().setInternalFetchProfile(previousFetchProfile));
}
use of org.hibernate.event.internal.MergeContext in project hibernate-reactive by hibernate.
the class DefaultReactiveMergeEventListener method reactiveOnMerge.
/**
* Handle the given merge event.
*
* @param event The merge event to be handled.
*/
@Override
public CompletionStage<Void> reactiveOnMerge(MergeEvent event) throws HibernateException {
final EntityCopyObserver entityCopyObserver = createEntityCopyObserver(event.getSession().getFactory());
final MergeContext mergeContext = new MergeContext(event.getSession(), entityCopyObserver);
return reactiveOnMerge(event, mergeContext).thenAccept(v -> entityCopyObserver.topLevelMergeComplete(event.getSession())).whenComplete((v, e) -> {
entityCopyObserver.clear();
mergeContext.clear();
});
}
use of org.hibernate.event.internal.MergeContext in project hibernate-reactive by hibernate.
the class DefaultReactiveMergeEventListener method entityIsPersistent.
protected CompletionStage<Void> entityIsPersistent(MergeEvent event, MergeContext copyCache) {
LOG.trace("Ignoring persistent instance");
// TODO: check that entry.getIdentifier().equals(requestedId)
final Object entity = event.getEntity();
final EventSource source = event.getSession();
final EntityPersister persister = source.getEntityPersister(event.getEntityName(), entity);
// before cascade!
copyCache.put(entity, entity, true);
return cascadeOnMerge(source, persister, entity, copyCache).thenCompose(v -> fetchAndCopyValues(persister, entity, entity, source, copyCache)).thenAccept(v -> event.setResult(entity));
}
use of org.hibernate.event.internal.MergeContext 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));
}
Aggregations