/// <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)); }
/// <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)); } }
/// <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)); } }
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 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)); } } } }