예제 #1
0
        /// <summary>
        /// Possibly unproxy the given reference and reassociate it with the current session.
        /// </summary>
        /// <param name="maybeProxy">The reference to be unproxied if it currently represents a proxy. </param>
        /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
        /// <returns> The unproxied instance. </returns>
        public Task <object> UnproxyAndReassociateAsync(object maybeProxy, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCanceled <object>(cancellationToken));
            }
            try
            {
                // TODO H3.2 Not ported
                //ElementWrapper wrapper = maybeProxy as ElementWrapper;
                //if (wrapper != null)
                //{
                //  maybeProxy = wrapper.Element;
                //}
                if (maybeProxy.IsProxy())
                {
                    var proxy = maybeProxy as INHibernateProxy;

                    ILazyInitializer li = proxy.HibernateLazyInitializer;
                    ReassociateProxy(li, proxy);
                    return(li.GetImplementationAsync(cancellationToken));                    //initialize + unwrap the object
                }
                return(Task.FromResult <object>(maybeProxy));
            }
            catch (Exception ex)
            {
                return(Task.FromException <object>(ex));
            }
        }
예제 #2
0
        /// <summary>
        /// Given that there is a pre-existing proxy.
        /// Initialize it if necessary; narrow if necessary.
        /// </summary>
        private object ReturnNarrowedProxy(LoadEvent @event, IEntityPersister persister, EntityKey keyToLoad, LoadType options, IPersistenceContext persistenceContext, object proxy)
        {
            log.Debug("entity proxy found in session cache");
            var castedProxy     = (INHibernateProxy)proxy;
            ILazyInitializer li = castedProxy.HibernateLazyInitializer;

            if (li.Unwrap)
            {
                return(li.GetImplementation());
            }
            object impl = null;

            if (!options.IsAllowProxyCreation)
            {
                impl = Load(@event, persister, keyToLoad, options);
                // NH Different behavior : NH-1252
                if (impl == null && !options.IsAllowNulls)
                {
                    @event.Session.Factory.EntityNotFoundDelegate.HandleEntityNotFound(persister.EntityName, keyToLoad.Identifier);
                }
            }
            if (impl == null && !options.IsAllowProxyCreation && options.ExactPersister)
            {
                // NH Different behavior : NH-1252
                return(null);
            }
            return(persistenceContext.NarrowProxy(castedProxy, persister, keyToLoad, impl));
        }
예제 #3
0
        public virtual bool Contains(object collection, object childObject, ISessionImplementor session)
        {
            // we do not have to worry about queued additions to uninitialized
            // collections, since they can only occur for inverse collections!
            IEnumerable elems = GetElementsIterator(collection, session);

            foreach (object elem in elems)
            {
                object element = elem;
                // worrying about proxies is perhaps a little bit of overkill here...

                if (element.IsProxy())
                {
                    INHibernateProxy proxy = element as INHibernateProxy;

                    ILazyInitializer li = proxy.HibernateLazyInitializer;
                    if (!li.IsUninitialized)
                    {
                        element = li.GetImplementation();
                    }
                }

                if (element == childObject)
                {
                    return(true);
                }
            }
            return(false);
        }
예제 #4
0
        /// <summary>
        /// Given that there is a pre-existing proxy.
        /// Initialize it if necessary; narrow if necessary.
        /// </summary>
        private async Task <object> ReturnNarrowedProxyAsync(LoadEvent @event, IEntityPersister persister, EntityKey keyToLoad, LoadType options, IPersistenceContext persistenceContext, object proxy, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            log.Debug("entity proxy found in session cache");
            var castedProxy     = (INHibernateProxy)proxy;
            ILazyInitializer li = castedProxy.HibernateLazyInitializer;

            if (li.Unwrap)
            {
                return(await(li.GetImplementationAsync(cancellationToken)).ConfigureAwait(false));
            }
            object impl = null;

            if (!options.IsAllowProxyCreation)
            {
                impl = await(LoadAsync(@event, persister, keyToLoad, options, cancellationToken)).ConfigureAwait(false);
                // NH Different behavior : NH-1252
                if (impl == null && !options.IsAllowNulls)
                {
                    @event.Session.Factory.EntityNotFoundDelegate.HandleEntityNotFound(persister.EntityName, keyToLoad.Identifier);
                }
            }
            if (impl == null && !options.IsAllowProxyCreation && options.ExactPersister)
            {
                // NH Different behavior : NH-1252
                return(null);
            }
            return(persistenceContext.NarrowProxy(castedProxy, persister, keyToLoad, impl));
        }
예제 #5
0
        /// <summary>
        /// Check if the property is initialized. If the named property does not exist
        /// or is not persistent, this method always returns <tt>true</tt>.
        /// </summary>
        /// <param name="proxy">The potential proxy </param>
        /// <param name="propertyName">the name of a persistent attribute of the object </param>
        /// <returns>
        /// true if the named property of the object is not listed as uninitialized;
        /// false if the object is an uninitialized proxy, or the named property is uninitialized
        /// </returns>
        public static bool IsPropertyInitialized(object proxy, string propertyName)
        {
            object entity;

            if (proxy.IsProxy())
            {
                ILazyInitializer li = ((INHibernateProxy)proxy).HibernateLazyInitializer;
                if (li.IsUninitialized)
                {
                    return(false);
                }
                else
                {
                    entity = li.GetImplementation();
                }
            }
            else
            {
                entity = proxy;
            }

            if (entity is IFieldInterceptorAccessor interceptorAccessor)
            {
                var interceptor = interceptorAccessor.FieldInterceptor;
                return(interceptor == null || interceptor.IsInitializedField(propertyName));
            }
            else
            {
                return(true);
            }
        }
예제 #6
0
        /// <summary>
        /// Get the true, underlying class of a proxied persistent class. This operation
        /// will NOT initialize the proxy and thus may return an incorrect result.
        /// </summary>
        /// <param name="entity">a persistable object or proxy</param>
        /// <returns>guessed class of the instance</returns>
        /// <remarks>
        /// This method is approximate match for Session.bestGuessEntityName in H3.2
        /// </remarks>
        public static System.Type GuessClass(object entity)
        {
            var proxy = entity as INHibernateProxy;

            //todo 修改源码
            if (entity.IsProxy() && proxy != null)
            {
                ILazyInitializer li = proxy.HibernateLazyInitializer;
                if (li.IsUninitialized || li.GetImplementation().GetType().Name.Contains("Proxy"))
                {
                    return(li.PersistentClass);
                }
                return(li.GetImplementation().GetType());
            }
            var propInfo = entity.GetType().GetProperty("EntityType");

            if (propInfo != null)
            {
                var entityType = propInfo.GetValue(entity, null) as System.Type;
                if (entityType != null)
                {
                    return(entityType);
                }
            }

            var fieldInterceptorAccessor = entity as IFieldInterceptorAccessor;

            if (fieldInterceptorAccessor != null)
            {
                var fieldInterceptor = fieldInterceptorAccessor.FieldInterceptor;
                return(fieldInterceptor.MappedClass);
            }
            return(entity.GetType());
        }
예제 #7
0
        /// <summary>
        /// Check if the property is initialized. If the named property does not exist
        /// or is not persistent, this method always returns <tt>true</tt>.
        /// </summary>
        /// <param name="proxy">The potential proxy </param>
        /// <param name="propertyName">the name of a persistent attribute of the object </param>
        /// <returns>
        /// true if the named property of the object is not listed as uninitialized;
        /// false if the object is an uninitialized proxy, or the named property is uninitialized
        /// </returns>
        public static bool IsPropertyInitialized(object proxy, string propertyName)
        {
            object entity;

            if (proxy is INHibernateProxy)
            {
                ILazyInitializer li = ((INHibernateProxy)proxy).HibernateLazyInitializer;
                if (li.IsUninitialized)
                {
                    return(false);
                }
                else
                {
                    entity = li.GetImplementation();
                }
            }
            else
            {
                entity = proxy;
            }

            if (FieldInterceptionHelper.IsInstrumented(entity))
            {
                IFieldInterceptor interceptor = FieldInterceptionHelper.ExtractFieldInterceptor(entity);
                return(interceptor == null || interceptor.IsInitializedField(propertyName));
            }
            else
            {
                return(true);
            }
        }
예제 #8
0
            /// <summary>
            /// Determine if the object already exists in the database, using a "best guess"
            /// </summary>
            private async Task <bool> IsNullifiableAsync(string entityName, object obj, CancellationToken cancellationToken)
            {
                cancellationToken.ThrowIfCancellationRequested();

                //if (obj == org.hibernate.intercept.LazyPropertyInitializer_Fields.UNFETCHED_PROPERTY)
                //  return false; //this is kinda the best we can do...

                if (obj.IsProxy())
                {
                    INHibernateProxy proxy = obj as INHibernateProxy;

                    // if its an uninitialized proxy it can't be transient
                    ILazyInitializer li = proxy.HibernateLazyInitializer;
                    if (li.GetImplementation(session) == null)
                    {
                        return(false);
                        // ie. we never have to null out a reference to
                        // an uninitialized proxy
                    }
                    else
                    {
                        //unwrap it
                        obj = await(li.GetImplementationAsync(cancellationToken)).ConfigureAwait(false);
                    }
                }

                // if it was a reference to self, don't need to nullify
                // unless we are using native id generation, in which
                // case we definitely need to nullify
                if (obj == self)
                {
                    // TODO H3.2: Different behaviour
                    //return isEarlyInsert || (isDelete && session.Factory.Dialect.HasSelfReferentialForeignKeyBug);
                    return(isEarlyInsert || isDelete);
                }

                // See if the entity is already bound to this session, if not look at the
                // entity identifier and assume that the entity is persistent if the
                // id is not "unsaved" (that is, we rely on foreign keys to keep
                // database integrity)
                EntityEntry entityEntry = session.PersistenceContext.GetEntry(obj);

                if (entityEntry == null)
                {
                    return(await(IsTransientSlowAsync(entityName, obj, session, cancellationToken)).ConfigureAwait(false));
                }
                else
                {
                    return(entityEntry.IsNullifiable(isEarlyInsert, session));
                }
            }
예제 #9
0
        /// <summary>
        /// Get the identifier value of an instance or proxy.
        /// <p/>
        /// Intended only for loggin purposes!!!
        /// </summary>
        /// <param name="obj">The object from which to extract the identifier.</param>
        /// <param name="persister">The entity persister </param>
        /// <returns> The extracted identifier. </returns>
        private static object GetIdentifier(object obj, IEntityPersister persister)
        {
            if (obj.IsProxy())
            {
                INHibernateProxy proxy = obj as INHibernateProxy;
                ILazyInitializer li    = proxy.HibernateLazyInitializer;

                return(li.Identifier);
            }
            else
            {
                return(persister.GetIdentifier(obj));
            }
        }
예제 #10
0
        /// <summary>
        /// Get the identifier value of an instance or proxy.
        /// <p/>
        /// Intended only for loggin purposes!!!
        /// </summary>
        /// <param name="obj">The object from which to extract the identifier.</param>
        /// <param name="persister">The entity persister </param>
        /// <param name="entityMode">The entity mode </param>
        /// <returns> The extracted identifier. </returns>
        private static object GetIdentifier(object obj, IEntityPersister persister, EntityMode entityMode)
        {
            INHibernateProxy proxy = obj as INHibernateProxy;

            if (proxy != null)
            {
                ILazyInitializer li = proxy.HibernateLazyInitializer;
                return(li.Identifier);
            }
            else
            {
                return(persister.GetIdentifier(obj, entityMode));
            }
        }
예제 #11
0
        public virtual async Task OnPersistAsync(PersistEvent @event, IDictionary createdAlready, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            ISessionImplementor source = @event.Session;
            object obj = @event.Entity;

            object entity;

            if (obj.IsProxy())
            {
                ILazyInitializer li = ((INHibernateProxy)obj).HibernateLazyInitializer;
                if (li.IsUninitialized)
                {
                    if (li.Session == source)
                    {
                        return;                         //NOTE EARLY EXIT!
                    }
                    else
                    {
                        throw new PersistentObjectException("uninitialized proxy passed to persist()");
                    }
                }
                entity = await(li.GetImplementationAsync(cancellationToken)).ConfigureAwait(false);
            }
            else
            {
                entity = obj;
            }

            EntityState entityState = await(GetEntityStateAsync(entity, @event.EntityName, source.PersistenceContext.GetEntry(entity), source, cancellationToken)).ConfigureAwait(false);

            switch (entityState)
            {
            case EntityState.Persistent:
                await(EntityIsPersistentAsync(@event, createdAlready, cancellationToken)).ConfigureAwait(false);
                break;

            case EntityState.Transient:
                await(EntityIsTransientAsync(@event, createdAlready, cancellationToken)).ConfigureAwait(false);
                break;

            case EntityState.Detached:
                throw new PersistentObjectException("detached entity passed to persist: " + GetLoggableName(@event.EntityName, entity));

            default:
                throw new ObjectDeletedException("deleted instance passed to merge", null, GetLoggableName(@event.EntityName, entity));
            }
        }
        public virtual void OnPersist(PersistEvent @event, IDictionary createdAlready)
        {
            ISessionImplementor source = @event.Session;
            object obj = @event.Entity;

            object entity;

            if (obj is INHibernateProxy)
            {
                ILazyInitializer li = ((INHibernateProxy)obj).HibernateLazyInitializer;
                if (li.IsUninitialized)
                {
                    if (li.Session == source)
                    {
                        return;                         //NOTE EARLY EXIT!
                    }
                    else
                    {
                        throw new PersistentObjectException("uninitialized proxy passed to persist()");
                    }
                }
                entity = li.GetImplementation();
            }
            else
            {
                entity = obj;
            }

            EntityState entityState = GetEntityState(entity, @event.EntityName, source.PersistenceContext.GetEntry(entity), source);

            switch (entityState)
            {
            case EntityState.Persistent:
                EntityIsPersistent(@event, createdAlready);
                break;

            case EntityState.Transient:
                EntityIsTransient(@event, createdAlready);
                break;

            case EntityState.Detached:
                throw new PersistentObjectException("detached entity passed to persist: " + GetLoggableName(@event.EntityName, entity));

            default:
                throw new ObjectDeletedException("deleted instance passed to merge", null, GetLoggableName(@event.EntityName, entity));
            }
        }
예제 #13
0
        /// <summary>
        /// Get the true, underlying class of a proxied persistent class. This operation
        /// will NOT initialize the proxy and thus may return an incorrect result.
        /// </summary>
        /// <param name="entity">a persistable object or proxy</param>
        /// <returns>guessed class of the instance</returns>
        /// <remarks>
        /// This method is approximate match for Session.bestGuessEntityName in H3.2
        /// </remarks>
        public static System.Type GuessClass(object entity)
        {
            if (entity.IsProxy())
            {
                var proxy           = entity as INHibernateProxy;
                ILazyInitializer li = proxy.HibernateLazyInitializer;
                if (li.IsUninitialized)
                {
                    return(li.PersistentClass);
                }
                return(li.GetImplementation().GetType());
            }
            var fieldInterceptorAccessor = entity as IFieldInterceptorAccessor;

            if (fieldInterceptorAccessor != null)
            {
                var fieldInterceptor = fieldInterceptorAccessor.FieldInterceptor;
                return(fieldInterceptor.MappedClass);
            }
            return(entity.GetType());
        }
예제 #14
0
        public TEspecializado InicializarLazyLoad <TEspecializado>(object paraInicializar)
        {
            if (null == paraInicializar)
            {
                throw new ArgumentNullException("paraInicializar");
            }

            if (typeof(TEspecializado) == paraInicializar.GetType())
            {
                return((TEspecializado)paraInicializar);
            }

            if (false == typeof(INHibernateProxy).IsAssignableFrom(paraInicializar.GetType()))
            {
                throw new Exception(string.Format("{0} nao implementa INHibernateProxy", paraInicializar.GetType().FullName));
            }

            ILazyInitializer lazyInitializer = ((INHibernateProxy)paraInicializar).HibernateLazyInitializer;

            return((TEspecializado)lazyInitializer.GetImplementation());
        }
        /// <summary>
        /// Get the true, underlying class of a proxied persistent class. This operation
        /// will NOT initialize the proxy and thus may return an incorrect result.
        /// </summary>
        /// <param name="entity">a persistable object or proxy</param>
        /// <returns>guessed class of the instance</returns>
        /// <remarks>
        /// This method is approximate match for Session.bestGuessEntityName in H3.2
        /// </remarks>
        public static System.Type GuessClass(object entity)
        {
            INHibernateProxy proxy = entity as INHibernateProxy;

            if (proxy != null)
            {
                ILazyInitializer li = proxy.HibernateLazyInitializer;
                if (li.IsUninitialized)
                {
                    return(li.PersistentClass);
                }
                else
                {
                    return(li.GetImplementation().GetType());
                }
            }
            else
            {
                return(entity.GetType());
            }
        }
        public virtual async Task OnEvictAsync(EvictEvent @event, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            IEventSource        source             = @event.Session;
            object              obj                = @event.Entity;
            IPersistenceContext persistenceContext = source.PersistenceContext;

            if (obj.IsProxy())
            {
                ILazyInitializer li        = ((INHibernateProxy)obj).HibernateLazyInitializer;
                object           id        = li.Identifier;
                IEntityPersister persister = source.Factory.GetEntityPersister(li.EntityName);
                if (id == null)
                {
                    throw new ArgumentException("null identifier");
                }
                EntityKey key = source.GenerateEntityKey(id, persister);
                persistenceContext.RemoveProxy(key);
                if (!li.IsUninitialized)
                {
                    object entity = persistenceContext.RemoveEntity(key);
                    if (entity != null)
                    {
                        EntityEntry e = @event.Session.PersistenceContext.RemoveEntry(entity);
                        await(DoEvictAsync(entity, key, e.Persister, @event.Session, cancellationToken)).ConfigureAwait(false);
                    }
                }
                li.UnsetSession();
            }
            else
            {
                EntityEntry e = persistenceContext.RemoveEntry(obj);
                if (e != null)
                {
                    persistenceContext.RemoveEntity(e.EntityKey);
                    await(DoEvictAsync(obj, e.EntityKey, e.Persister, source, cancellationToken)).ConfigureAwait(false);
                }
            }
        }
        public virtual void OnEvict(EvictEvent @event)
        {
            IEventSource        source             = @event.Session;
            object              obj                = @event.Entity;
            IPersistenceContext persistenceContext = source.PersistenceContext;

            if (obj is INHibernateProxy)
            {
                ILazyInitializer li        = ((INHibernateProxy)obj).HibernateLazyInitializer;
                object           id        = li.Identifier;
                IEntityPersister persister = source.Factory.GetEntityPersister(li.EntityName);
                if (id == null)
                {
                    throw new ArgumentException("null identifier");
                }
                EntityKey key = new EntityKey(id, persister, source.EntityMode);
                persistenceContext.RemoveProxy(key);
                if (!li.IsUninitialized)
                {
                    object entity = persistenceContext.RemoveEntity(key);
                    if (entity != null)
                    {
                        EntityEntry e = @event.Session.PersistenceContext.RemoveEntry(entity);
                        DoEvict(entity, key, e.Persister, @event.Session);
                    }
                }
                li.Session = null;
            }
            else
            {
                EntityEntry e = persistenceContext.RemoveEntry(obj);
                if (e != null)
                {
                    EntityKey key = new EntityKey(e.Id, e.Persister, source.EntityMode);
                    persistenceContext.RemoveEntity(key);
                    DoEvict(obj, key, e.Persister, source);
                }
            }
        }
예제 #18
0
        public static bool IsPropertyInitialized(object proxy, string propertyName)
        {
            object entity;

            if (!IsProxyFactoryConfigurated())
            {
                //if the proxy provider it's not configurated, can't be a proxy neither an instrumented field.
                return(true);
            }

            if (proxy.IsProxy())
            {
                ILazyInitializer li = ((INHibernateProxy)proxy).HibernateLazyInitializer;
                if (li.IsUninitialized)
                {
                    return(false);
                }
                else
                {
                    entity = li.GetImplementation();
                }
            }
            else
            {
                entity = proxy;
            }

            if (FieldInterceptionHelper.IsInstrumented(entity))
            {
                IFieldInterceptor interceptor = FieldInterceptionHelper.ExtractFieldInterceptor(entity);
                return(interceptor == null || interceptor.IsInitializedField(propertyName));
            }
            else
            {
                return(true);
            }
        }
		/// <summary> 
		/// Associate a proxy that was instantiated by another session with this session
		/// </summary>
		/// <param name="li">The proxy initializer. </param>
		/// <param name="proxy">The proxy to reassociate. </param>
		private void ReassociateProxy(ILazyInitializer li, INHibernateProxy proxy)
		{
			if (li.Session != Session)
			{
				IEntityPersister persister = session.Factory.GetEntityPersister(li.EntityName);
				EntityKey key = new EntityKey(li.Identifier, persister, session.EntityMode);
				// any earlier proxy takes precedence
				if (!proxiesByKey.ContainsKey(key))
				{
					proxiesByKey[key] = proxy;
				}
				proxy.HibernateLazyInitializer.Session = Session;
			}
		}
        public virtual void OnMerge(MergeEvent @event, IDictionary copyCache)
        {
            IEventSource source   = @event.Session;
            object       original = @event.Original;

            if (original != null)
            {
                object entity;
                if (original is INHibernateProxy)
                {
                    ILazyInitializer li = ((INHibernateProxy)original).HibernateLazyInitializer;
                    if (li.IsUninitialized)
                    {
                        log.Debug("ignoring uninitialized proxy");
                        @event.Result = source.Load(li.PersistentClass, li.Identifier);
                        return;                         //EARLY EXIT!
                    }
                    else
                    {
                        entity = li.GetImplementation();
                    }
                }
                else
                {
                    entity = original;
                }

                if (copyCache.Contains(entity))
                {
                    log.Debug("already merged");
                    @event.Result = entity;
                }
                else
                {
                    @event.Entity = entity;
                    EntityState entityState = EntityState.Undefined;

                    // Check the persistence context for an entry relating to this
                    // entity to be merged...
                    EntityEntry entry = source.PersistenceContext.GetEntry(entity);
                    if (entry == null)
                    {
                        IEntityPersister persister = source.GetEntityPersister(@event.EntityName, entity);
                        object           id        = persister.GetIdentifier(entity, source.EntityMode);
                        if (id != null)
                        {
                            EntityKey key           = new EntityKey(id, persister, source.EntityMode);
                            object    managedEntity = source.PersistenceContext.GetEntity(key);
                            entry = source.PersistenceContext.GetEntry(managedEntity);
                            if (entry != null)
                            {
                                // we have specialized case of a detached entity from the
                                // perspective of the merge operation.  Specifically, we
                                // have an incoming entity instance which has a corresponding
                                // entry in the current persistence context, but registered
                                // under a different entity instance
                                entityState = EntityState.Detached;
                            }
                        }
                    }

                    if (entityState == EntityState.Undefined)
                    {
                        entityState = GetEntityState(entity, @event.EntityName, entry, source);
                    }

                    switch (entityState)
                    {
                    case EntityState.Persistent:
                        EntityIsPersistent(@event, copyCache);
                        break;

                    case EntityState.Transient:
                        EntityIsTransient(@event, copyCache);
                        break;

                    case EntityState.Detached:
                        EntityIsDetached(@event, copyCache);
                        break;

                    default:
                        throw new ObjectDeletedException("deleted instance passed to merge", null, GetLoggableName(@event.EntityName, entity));
                    }
                }
            }
        }
예제 #21
0
        public virtual async Task OnMergeAsync(MergeEvent @event, IDictionary copiedAlready, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            EventCache   copyCache = (EventCache)copiedAlready;
            IEventSource source    = @event.Session;
            object       original  = @event.Original;

            if (original != null)
            {
                object entity;
                if (original.IsProxy())
                {
                    ILazyInitializer li = ((INHibernateProxy)original).HibernateLazyInitializer;
                    if (li.IsUninitialized)
                    {
                        log.Debug("ignoring uninitialized proxy");
                        @event.Result = await(source.LoadAsync(li.EntityName, li.Identifier, cancellationToken)).ConfigureAwait(false);
                        return;                         //EARLY EXIT!
                    }
                    else
                    {
                        entity = await(li.GetImplementationAsync(cancellationToken)).ConfigureAwait(false);
                    }
                }
                else
                {
                    entity = original;
                }

                if (copyCache.Contains(entity) && copyCache.IsOperatedOn(entity))
                {
                    log.Debug("already in merge process");
                    @event.Result = entity;
                }
                else
                {
                    if (copyCache.Contains(entity))
                    {
                        log.Info("already in copyCache; setting in merge process");
                        copyCache.SetOperatedOn(entity, true);
                    }

                    @event.Entity = entity;
                    EntityState entityState = EntityState.Undefined;
                    if (ReferenceEquals(null, @event.EntityName))
                    {
                        @event.EntityName = source.BestGuessEntityName(entity);
                    }

                    // Check the persistence context for an entry relating to this
                    // entity to be merged...
                    EntityEntry entry = source.PersistenceContext.GetEntry(entity);
                    if (entry == null)
                    {
                        IEntityPersister persister = source.GetEntityPersister(@event.EntityName, entity);
                        object           id        = persister.GetIdentifier(entity);
                        if (id != null)
                        {
                            EntityKey key           = source.GenerateEntityKey(id, persister);
                            object    managedEntity = source.PersistenceContext.GetEntity(key);
                            entry = source.PersistenceContext.GetEntry(managedEntity);
                            if (entry != null)
                            {
                                // we have specialized case of a detached entity from the
                                // perspective of the merge operation.  Specifically, we
                                // have an incoming entity instance which has a corresponding
                                // entry in the current persistence context, but registered
                                // under a different entity instance
                                entityState = EntityState.Detached;
                            }
                        }
                    }

                    if (entityState == EntityState.Undefined)
                    {
                        entityState = await(GetEntityStateAsync(entity, @event.EntityName, entry, source, cancellationToken)).ConfigureAwait(false);
                    }

                    switch (entityState)
                    {
                    case EntityState.Persistent:
                        await(EntityIsPersistentAsync(@event, copyCache, cancellationToken)).ConfigureAwait(false);
                        break;

                    case EntityState.Transient:
                        await(EntityIsTransientAsync(@event, copyCache, cancellationToken)).ConfigureAwait(false);
                        break;

                    case EntityState.Detached:
                        await(EntityIsDetachedAsync(@event, copyCache, cancellationToken)).ConfigureAwait(false);
                        break;

                    default:
                        throw new ObjectDeletedException("deleted instance passed to merge", null, GetLoggableName(@event.EntityName, entity));
                    }
                }
            }
        }