Example #1
0
        protected virtual async Task EntityIsDetachedAsync(MergeEvent @event, IDictionary copyCache, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            log.Debug("merging detached instance");

            object       entity = @event.Entity;
            IEventSource source = @event.Session;

            IEntityPersister persister  = source.GetEntityPersister(@event.EntityName, entity);
            string           entityName = persister.EntityName;

            object id = @event.RequestedId;

            if (id == null)
            {
                id = persister.GetIdentifier(entity);
            }
            else
            {
                // check that entity id = requestedId
                object entityId = persister.GetIdentifier(entity);
                if (!persister.IdentifierType.IsEqual(id, entityId, source.Factory))
                {
                    throw new HibernateException("merge requested with id not matching id of passed entity");
                }
            }

            string previousFetchProfile = source.FetchProfile;

            source.FetchProfile = "merge";

            //we must clone embedded composite identifiers, or
            //we will get back the same instance that we pass in
            object clonedIdentifier = persister.IdentifierType.DeepCopy(id, source.Factory);
            object result           = await(source.GetAsync(persister.EntityName, clonedIdentifier, cancellationToken)).ConfigureAwait(false);

            source.FetchProfile = previousFetchProfile;

            if (result == null)
            {
                //TODO: we should throw an exception if we really *know* for sure
                //      that this is a detached instance, rather than just assuming
                //throw new StaleObjectStateException(entityName, id);

                // we got here because we assumed that an instance
                // with an assigned id was detached, when it was
                // really persistent
                await(EntityIsTransientAsync(@event, copyCache, cancellationToken)).ConfigureAwait(false);
            }
            else
            {
                // NH different behavior : NH-1517
                if (InvokeUpdateLifecycle(entity, persister, source))
                {
                    return;
                }

                ((EventCache)copyCache).Add(entity, result, true);                 //before cascade!

                object target = source.PersistenceContext.Unproxy(result);
                if (target == entity)
                {
                    throw new AssertionFailure("entity was not detached");
                }
                else if (!(await(source.GetEntityNameAsync(target, cancellationToken)).ConfigureAwait(false)).Equals(entityName))
                {
                    throw new WrongClassException("class of the given object did not match class of persistent copy",
                                                  @event.RequestedId, persister.EntityName);
                }
                else if (IsVersionChanged(entity, source, persister, target))
                {
                    if (source.Factory.Statistics.IsStatisticsEnabled)
                    {
                        source.Factory.StatisticsImplementor.OptimisticFailure(entityName);
                    }
                    throw new StaleObjectStateException(persister.EntityName, id);
                }

                // cascade first, so that all unsaved objects get their
                // copy created before we actually copy
                await(CascadeOnMergeAsync(source, persister, entity, copyCache, cancellationToken)).ConfigureAwait(false);
                await(CopyValuesAsync(persister, entity, target, source, copyCache, cancellationToken)).ConfigureAwait(false);

                //copyValues works by reflection, so explicitly mark the entity instance dirty
                MarkInterceptorDirty(entity, target);

                @event.Result = result;
            }
        }