public override async Task ExecuteAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); ISessionImplementor session = Session; object id = Id; IEntityPersister persister = Persister; object instance = Instance; bool statsEnabled = Session.Factory.Statistics.IsStatisticsEnabled; Stopwatch stopwatch = null; if (statsEnabled) { stopwatch = Stopwatch.StartNew(); } bool veto = await(PreUpdateAsync(cancellationToken)).ConfigureAwait(false); ISessionFactoryImplementor factory = Session.Factory; if (persister.IsVersionPropertyGenerated) { // we need to grab the version value from the entity, otherwise // we have issues with generated-version entities that may have // multiple actions queued during the same flush previousVersion = persister.GetVersion(instance); } CacheKey ck = null; if (persister.HasCache) { ck = session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName); slock = await(persister.Cache.LockAsync(ck, previousVersion, cancellationToken)).ConfigureAwait(false); } if (!veto) { await(persister.UpdateAsync(id, state, dirtyFields, hasDirtyCollection, previousState, previousVersion, instance, null, session, cancellationToken)).ConfigureAwait(false); } EntityEntry entry = Session.PersistenceContext.GetEntry(instance); if (entry == null) { throw new AssertionFailure("Possible nonthreadsafe access to session"); } if (entry.Status == Status.Loaded || persister.IsVersionPropertyGenerated) { // get the updated snapshot of the entity state by cloning current state; // it is safe to copy in place, since by this time no-one else (should have) // has a reference to the array TypeHelper.DeepCopy(state, persister.PropertyTypes, persister.PropertyCheckability, state, Session); if (persister.HasUpdateGeneratedProperties) { // this entity defines property generation, so process those generated // values... await(persister.ProcessUpdateGeneratedPropertiesAsync(id, instance, state, Session, cancellationToken)).ConfigureAwait(false); if (persister.IsVersionPropertyGenerated) { nextVersion = Versioning.GetVersion(state, persister); } } // have the entity entry perform post-update processing, passing it the // update state and the new version (if one). entry.PostUpdate(instance, state, nextVersion); } if (persister.HasCache) { if (persister.IsCacheInvalidationRequired || entry.Status != Status.Loaded) { await(persister.Cache.EvictAsync(ck, cancellationToken)).ConfigureAwait(false); } else { CacheEntry ce = await(CacheEntry.CreateAsync(state, persister, nextVersion, Session, instance, cancellationToken)).ConfigureAwait(false); cacheEntry = persister.CacheEntryStructure.Structure(ce); bool put = await(persister.Cache.UpdateAsync(ck, cacheEntry, nextVersion, previousVersion, cancellationToken)).ConfigureAwait(false); if (put && factory.Statistics.IsStatisticsEnabled) { factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName); } } } await(PostUpdateAsync(cancellationToken)).ConfigureAwait(false); if (statsEnabled && !veto) { stopwatch.Stop(); factory.StatisticsImplementor.UpdateEntity(Persister.EntityName, stopwatch.Elapsed); } }
public override async Task ExecuteAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); IEntityPersister persister = Persister; ISessionImplementor session = Session; object instance = Instance; object id = Id; bool statsEnabled = Session.Factory.Statistics.IsStatisticsEnabled; Stopwatch stopwatch = null; if (statsEnabled) { stopwatch = Stopwatch.StartNew(); } bool veto = await(PreInsertAsync(cancellationToken)).ConfigureAwait(false); // Don't need to lock the cache here, since if someone // else inserted the same pk first, the insert would fail if (!veto) { await(persister.InsertAsync(id, State, instance, Session, cancellationToken)).ConfigureAwait(false); EntityEntry entry = Session.PersistenceContext.GetEntry(instance); if (entry == null) { throw new AssertionFailure("Possible nonthreadsafe access to session"); } entry.PostInsert(); if (persister.HasInsertGeneratedProperties) { await(persister.ProcessInsertGeneratedPropertiesAsync(id, instance, State, Session, cancellationToken)).ConfigureAwait(false); if (persister.IsVersionPropertyGenerated) { version = Versioning.GetVersion(State, persister); } entry.PostUpdate(instance, State, version); } } ISessionFactoryImplementor factory = Session.Factory; if (IsCachePutEnabled(persister)) { CacheEntry ce = await(CacheEntry.CreateAsync(State, persister, persister.HasUninitializedLazyProperties(instance), version, session, instance, cancellationToken)).ConfigureAwait(false); cacheEntry = persister.CacheEntryStructure.Structure(ce); CacheKey ck = Session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName); bool put = persister.Cache.Insert(ck, cacheEntry, version); if (put && factory.Statistics.IsStatisticsEnabled) { factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName); } } await(PostInsertAsync(cancellationToken)).ConfigureAwait(false); if (statsEnabled && !veto) { stopwatch.Stop(); factory.StatisticsImplementor.InsertEntity(Persister.EntityName, stopwatch.Elapsed); } }
/// <summary> /// Perform the second step of 2-phase load. Fully initialize the entity instance. /// After processing a JDBC result set, we "resolve" all the associations /// between the entities which were instantiated and had their state /// "hydrated" into an array /// </summary> internal static async Task InitializeEntityAsync(object entity, bool readOnly, ISessionImplementor session, PreLoadEvent preLoadEvent, PostLoadEvent postLoadEvent, Action <IEntityPersister, CachePutData> cacheBatchingHandler, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); //TODO: Should this be an InitializeEntityEventListener??? (watch out for performance!) Stopwatch stopWatch = null; if (session.Factory.Statistics.IsStatisticsEnabled) { stopWatch = Stopwatch.StartNew(); } IPersistenceContext persistenceContext = session.PersistenceContext; EntityEntry entityEntry = persistenceContext.GetEntry(entity); if (entityEntry == null) { throw new AssertionFailure("possible non-threadsafe access to the session"); } IEntityPersister persister = entityEntry.Persister; object id = entityEntry.Id; object[] hydratedState = entityEntry.LoadedState; if (log.IsDebugEnabled()) { log.Debug("resolving associations for {0}", MessageHelper.InfoString(persister, id, session.Factory)); } IType[] types = persister.PropertyTypes; var collectionToResolveIndexes = new List <int>(hydratedState.Length); for (int i = 0; i < hydratedState.Length; i++) { object value = hydratedState[i]; if (!Equals(LazyPropertyInitializer.UnfetchedProperty, value) && !(Equals(BackrefPropertyAccessor.Unknown, value))) { if (types[i].IsCollectionType) { // Resolve them last, because they may depend on other properties if they use a property-ref collectionToResolveIndexes.Add(i); continue; } hydratedState[i] = await(CustomEntityTypeMapper.Map(types[i]).ResolveIdentifierAsync(value, session, entity, cancellationToken)).ConfigureAwait(false); } } foreach (var i in collectionToResolveIndexes) { hydratedState[i] = await(CustomEntityTypeMapper.Map(types[i]).ResolveIdentifierAsync(hydratedState[i], session, entity, cancellationToken)).ConfigureAwait(false); } //Must occur after resolving identifiers! if (session.IsEventSource) { preLoadEvent.Entity = entity; preLoadEvent.State = hydratedState; preLoadEvent.Id = id; preLoadEvent.Persister = persister; IPreLoadEventListener[] listeners = session.Listeners.PreLoadEventListeners; for (int i = 0; i < listeners.Length; i++) { await(listeners[i].OnPreLoadAsync(preLoadEvent, cancellationToken)).ConfigureAwait(false); } } persister.SetPropertyValues(entity, hydratedState); ISessionFactoryImplementor factory = session.Factory; if (persister.HasCache && session.CacheMode.HasFlag(CacheMode.Put)) { if (log.IsDebugEnabled()) { log.Debug("adding entity to second-level cache: {0}", MessageHelper.InfoString(persister, id, session.Factory)); } object version = Versioning.GetVersion(hydratedState, persister); CacheEntry entry = await(CacheEntry.CreateAsync(hydratedState, persister, version, session, entity, cancellationToken)).ConfigureAwait(false); CacheKey cacheKey = session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName); if (cacheBatchingHandler != null && persister.IsBatchLoadable) { cacheBatchingHandler( persister, new CachePutData( cacheKey, persister.CacheEntryStructure.Structure(entry), version, persister.IsVersioned ? persister.VersionType.Comparator : null, UseMinimalPuts(session, entityEntry))); } else { bool put = await(persister.Cache.PutAsync(cacheKey, persister.CacheEntryStructure.Structure(entry), session.Timestamp, version, persister.IsVersioned ? persister.VersionType.Comparator : null, UseMinimalPuts(session, entityEntry), cancellationToken)).ConfigureAwait(false); if (put && factory.Statistics.IsStatisticsEnabled) { factory.StatisticsImplementor.SecondLevelCachePut(persister.Cache.RegionName); } } } bool isReallyReadOnly = readOnly; if (!persister.IsMutable) { isReallyReadOnly = true; } else { object proxy = persistenceContext.GetProxy(entityEntry.EntityKey); if (proxy != null) { // there is already a proxy for this impl // only set the status to read-only if the proxy is read-only isReallyReadOnly = ((INHibernateProxy)proxy).HibernateLazyInitializer.ReadOnly; } } if (isReallyReadOnly) { //no need to take a snapshot - this is a //performance optimization, but not really //important, except for entities with huge //mutable property values persistenceContext.SetEntryStatus(entityEntry, Status.ReadOnly); } else { //take a snapshot TypeHelper.DeepCopy(hydratedState, persister.PropertyTypes, persister.PropertyUpdateability, hydratedState, session); persistenceContext.SetEntryStatus(entityEntry, Status.Loaded); } persister.AfterInitialize(entity, session); if (session.IsEventSource) { postLoadEvent.Entity = entity; postLoadEvent.Id = id; postLoadEvent.Persister = persister; IPostLoadEventListener[] listeners = session.Listeners.PostLoadEventListeners; for (int i = 0; i < listeners.Length; i++) { listeners[i].OnPostLoad(postLoadEvent); } } if (log.IsDebugEnabled()) { log.Debug("done materializing entity {0}", MessageHelper.InfoString(persister, id, session.Factory)); } if (stopWatch != null) { stopWatch.Stop(); factory.StatisticsImplementor.LoadEntity(persister.EntityName, stopWatch.Elapsed); } }
public override async Task ExecuteAsync(CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); IEntityPersister persister = Persister; ISessionImplementor session = Session; object instance = Instance; object id = Id; bool statsEnabled = Session.Factory.Statistics.IsStatisticsEnabled; Stopwatch stopwatch = null; if (statsEnabled) { stopwatch = Stopwatch.StartNew(); } bool veto = await(PreInsertAsync(cancellationToken)).ConfigureAwait(false); var wasDelayed = false; // Don't need to lock the cache here, since if someone // else inserted the same pk first, the insert would fail if (!veto) { // The identifier may be a foreign delayed identifier, which at this point should have been resolved. if (id is DelayedPostInsertIdentifier delayed) { wasDelayed = true; id = delayed.ActualId ?? throw new InvalidOperationException( $"The delayed foreign identifier {delayed} has not been resolved before insertion of a {instance}"); } await(persister.InsertAsync(id, State, instance, Session, cancellationToken)).ConfigureAwait(false); EntityEntry entry = Session.PersistenceContext.GetEntry(instance); if (entry == null) { throw new AssertionFailure("Possible nonthreadsafe access to session"); } entry.PostInsert(); if (wasDelayed) { Session.PersistenceContext.ReplaceDelayedEntityIdentityInsertKeys(entry.EntityKey, id); } if (persister.HasInsertGeneratedProperties) { await(persister.ProcessInsertGeneratedPropertiesAsync(id, instance, State, Session, cancellationToken)).ConfigureAwait(false); if (persister.IsVersionPropertyGenerated) { version = Versioning.GetVersion(State, persister); } entry.PostUpdate(instance, State, version); } } ISessionFactoryImplementor factory = Session.Factory; if (IsCachePutEnabled(persister)) { CacheEntry ce = await(CacheEntry.CreateAsync(State, persister, version, session, instance, cancellationToken)).ConfigureAwait(false); cacheEntry = persister.CacheEntryStructure.Structure(ce); CacheKey ck = Session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName); bool put = persister.Cache.Insert(ck, cacheEntry, version); if (put && factory.Statistics.IsStatisticsEnabled) { factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName); } } await(PostInsertAsync(cancellationToken)).ConfigureAwait(false); if (statsEnabled && !veto) { stopwatch.Stop(); factory.StatisticsImplementor.InsertEntity(Persister.EntityName, stopwatch.Elapsed); } }