protected virtual async Task EntityIsPersistentAsync(PersistEvent @event, IDictionary createCache, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            log.Debug("ignoring persistent instance");
            IEventSource source = @event.Session;

            //TODO: check that entry.getIdentifier().equals(requestedId)
            object entity = source.PersistenceContext.Unproxy(@event.Entity);

            /* NH-2565: the UnProxy may return a "field interceptor proxy". When EntityName is null the session.GetEntityPersister will try to guess it.
             * Instead change a session's method I'll try to guess the EntityName here.
             * Because I'm using a session's method perhaps could be better if each session's method, which implementation forward to a method having the EntityName as parameter,
             * use the BestGuessEntityName directly instead do "70 turns" before call it.
             */
            if (@event.EntityName == null)
            {
                @event.EntityName = source.BestGuessEntityName(entity);
            }
            IEntityPersister persister = source.GetEntityPersister(@event.EntityName, entity);

            object tempObject;

            tempObject          = createCache[entity];
            createCache[entity] = entity;
            if (tempObject == null)
            {
                //TODO: merge into one method!
                await(CascadeBeforeSaveAsync(source, persister, entity, createCache, cancellationToken)).ConfigureAwait(false);
                await(CascadeAfterSaveAsync(source, persister, entity, createCache, cancellationToken)).ConfigureAwait(false);
            }
        }
Esempio n. 2
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));
                    }
                }
            }
        }
        public virtual void OnRefresh(RefreshEvent @event, IDictionary refreshedAlready)
        {
            IEventSource source = @event.Session;

            bool isTransient = !source.Contains(@event.Entity);

            if (source.PersistenceContext.ReassociateIfUninitializedProxy(@event.Entity))
            {
                if (isTransient)
                {
                    source.SetReadOnly(@event.Entity, source.DefaultReadOnly);
                }
                return;
            }

            object obj = source.PersistenceContext.UnproxyAndReassociate(@event.Entity);

            if (refreshedAlready.Contains(obj))
            {
                log.Debug("already refreshed");
                return;
            }

            EntityEntry      e = source.PersistenceContext.GetEntry(obj);
            IEntityPersister persister;
            object           id;

            if (e == null)
            {
                persister = source.GetEntityPersister(source.BestGuessEntityName(obj), obj);                 //refresh() does not pass an entityName
                id        = persister.GetIdentifier(obj);
                if (log.IsDebugEnabled())
                {
                    log.Debug("refreshing transient {0}", MessageHelper.InfoString(persister, id, source.Factory));
                }
                EntityKey key = source.GenerateEntityKey(id, persister);
                if (source.PersistenceContext.GetEntry(key) != null)
                {
                    throw new PersistentObjectException("attempted to refresh transient instance when persistent instance was already associated with the Session: " +
                                                        MessageHelper.InfoString(persister, id, source.Factory));
                }
            }
            else
            {
                if (log.IsDebugEnabled())
                {
                    log.Debug("refreshing {0}", MessageHelper.InfoString(e.Persister, e.Id, source.Factory));
                }
                if (!e.ExistsInDatabase)
                {
                    throw new HibernateException("this instance does not yet exist as a row in the database");
                }

                persister = e.Persister;
                id        = e.Id;
            }

            // cascade the refresh prior to refreshing this entity
            refreshedAlready[obj] = obj;
            new Cascade(CascadingAction.Refresh, CascadePoint.BeforeRefresh, source).CascadeOn(persister, obj, refreshedAlready);

            if (e != null)
            {
                EntityKey key = source.GenerateEntityKey(id, persister);
                source.PersistenceContext.RemoveEntity(key);
                if (persister.HasCollections)
                {
                    new EvictVisitor(source).Process(obj, persister);
                }
            }

            if (persister.HasCache)
            {
                CacheKey ck = source.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName);
                persister.Cache.Remove(ck);
            }

            EvictCachedCollections(persister, id, source.Factory);

            // NH Different behavior : NH-1601
            // At this point the entity need the real refresh, all elementes of collections are Refreshed,
            // the collection state was evicted, but the PersistentCollection (in the entity state)
            // is associated with a possible previous session.
            new WrapVisitor(source).Process(obj, persister);

            string previousFetchProfile = source.FetchProfile;

            source.FetchProfile = "refresh";
            object result = persister.Load(id, obj, @event.LockMode, source);

            if (result != null)
            {
                if (!persister.IsMutable)
                {
                    source.SetReadOnly(result, true);
                }
                else
                {
                    source.SetReadOnly(result, e == null ? source.DefaultReadOnly : !e.IsModifiableEntity());
                }
            }
            source.FetchProfile = previousFetchProfile;

            // NH Different behavior : we are ignoring transient entities without throw any kind of exception
            // because a transient entity is "self refreshed"
            if (!ForeignKeys.IsTransientFast(persister.EntityName, obj, @event.Session).GetValueOrDefault(result == null))
            {
                UnresolvableObjectException.ThrowIfNull(result, id, persister.EntityName);
            }
        }