/// <summary> /// Refresh the entity instance state from the database. /// </summary> /// <param name="entityName">The entityName for the entity to be refreshed. </param> /// <param name="entity">The entity to be refreshed. </param> /// <param name="lockMode">The LockMode to be applied. </param> /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param> public async Task RefreshAsync(string entityName, object entity, LockMode lockMode, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); using (BeginProcess()) { // We need to flush the batcher. Otherwise it may have pending operations which will not already have reached the database, // and the query may yield stale data. await(FlushAsync(cancellationToken)).ConfigureAwait(false); IEntityPersister persister = GetEntityPersister(entityName, entity); object id = persister.GetIdentifier(entity); if (log.IsDebugEnabled()) { log.Debug("refreshing transient {0}", MessageHelper.InfoString(persister, id, Factory)); } //from H3.2 TODO : can this ever happen??? // EntityKey key = new EntityKey( id, persister, source.getEntityMode() ); // if ( source.getPersistenceContext().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.getFactory() ) // ); // } if (persister.HasCache) { CacheKey ck = GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName); await(persister.Cache.RemoveAsync(ck, cancellationToken)).ConfigureAwait(false); } string previousFetchProfile = FetchProfile; object result; try { FetchProfile = "refresh"; result = await(persister.LoadAsync(id, entity, lockMode, this, cancellationToken)).ConfigureAwait(false); } finally { FetchProfile = previousFetchProfile; } UnresolvableObjectException.ThrowIfNull(result, id, persister.EntityName); } }
/// <summary> /// Refresh the entity instance state from the database. /// </summary> /// <param name="entityName">The entityName for the entity to be refreshed. </param> /// <param name="entity">The entity to be refreshed. </param> /// <param name="lockMode">The LockMode to be applied. </param> public void Refresh(string entityName, object entity, LockMode lockMode) { using (new SessionIdLoggingContext(SessionId)) { IEntityPersister persister = GetEntityPersister(entityName, entity); object id = persister.GetIdentifier(entity); if (log.IsDebugEnabled) { log.Debug("refreshing transient " + MessageHelper.InfoString(persister, id, Factory)); } //from H3.2 TODO : can this ever happen??? // EntityKey key = new EntityKey( id, persister, source.getEntityMode() ); // if ( source.getPersistenceContext().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.getFactory() ) // ); // } if (persister.HasCache) { CacheKey ck = GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName); persister.Cache.Remove(ck); } string previousFetchProfile = FetchProfile; object result; try { FetchProfile = "refresh"; result = persister.Load(id, entity, lockMode, this); } finally { FetchProfile = previousFetchProfile; } UnresolvableObjectException.ThrowIfNull(result, id, persister.EntityName); } }
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(null, 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); } }
public virtual void OnRefresh(RefreshEvent @event, IDictionary refreshedAlready) { IEventSource source = @event.Session; if (source.PersistenceContext.ReassociateIfUninitializedProxy(@event.Entity)) { 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(null, obj); //refresh() does not pass an entityName id = persister.GetIdentifier(obj, source.EntityMode); if (log.IsDebugEnabled) { log.Debug("refreshing transient " + MessageHelper.InfoString(persister, id, source.Factory)); } EntityKey key = new EntityKey(id, persister, source.EntityMode); 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 " + 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 = new EntityKey(id, persister, source.EntityMode); source.PersistenceContext.RemoveEntity(key); if (persister.HasCollections) { new EvictVisitor(source).Process(obj, persister); } } if (persister.HasCache) { CacheKey ck = new CacheKey(id, persister.IdentifierType, persister.RootEntityName, source.EntityMode, source.Factory); 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); // NH-3253: Forcing simple load to prevent the redundante instance //on session: //Ocurre when: // -there is a 'one-to-many' 'Parent-Child' relationship; // -AND the 'Parent' 'many-to-one' association is ' fetch="select" '; // -AND 'Child' is using a 'composite-id' and 'key-many-to-one' to the //'Parent'. object result; if (this.IsReferencedByCompositeId(persister)) { result = persister.Load(id, obj, @event.LockMode, source); } string previousFetchProfile = source.FetchProfile; source.FetchProfile = "refresh"; result = persister.Load(id, obj, @event.LockMode, source); 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.IsTransient(persister.EntityName, obj, result == null, @event.Session)) { UnresolvableObjectException.ThrowIfNull(result, id, persister.EntityName); } }