/// <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 void InitializeEntity(object entity, bool readOnly, ISessionImplementor session, PreLoadEvent preLoadEvent, PostLoadEvent postLoadEvent, Action <IEntityPersister, CachePutData> cacheBatchingHandler) { //TODO: Should this be an InitializeEntityEventListener??? (watch out for performance!) bool statsEnabled = session.Factory.Statistics.IsStatisticsEnabled; var stopWath = new Stopwatch(); if (statsEnabled) { stopWath.Start(); } 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] = types[i].ResolveIdentifier(value, session, entity); } } foreach (var i in collectionToResolveIndexes) { hydratedState[i] = types[i].ResolveIdentifier(hydratedState[i], session, entity); } //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++) { listeners[i].OnPreLoad(preLoadEvent); } } 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 = CacheEntry.Create(hydratedState, persister, version, session, entity); 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 = persister.Cache.Put(cacheKey, persister.CacheEntryStructure.Structure(entry), session.Timestamp, version, persister.IsVersioned ? persister.VersionType.Comparator : null, UseMinimalPuts(session, entityEntry)); 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 (statsEnabled) { stopWath.Stop(); factory.StatisticsImplementor.LoadEntity(persister.EntityName, stopWath.Elapsed); } }
public override void Execute() { 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 = PreUpdate(); 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 = persister.Cache.Lock(ck, previousVersion); } if (!veto) { persister.Update(id, state, dirtyFields, hasDirtyCollection, previousState, previousVersion, instance, null, session); } 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... persister.ProcessUpdateGeneratedProperties(id, instance, state, Session); 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) { persister.Cache.Evict(ck); } else { CacheEntry ce = CacheEntry.Create(state, persister, nextVersion, Session, instance); cacheEntry = persister.CacheEntryStructure.Structure(ce); bool put = persister.Cache.Update(ck, cacheEntry, nextVersion, previousVersion); if (put && factory.Statistics.IsStatisticsEnabled) { factory.StatisticsImplementor.SecondLevelCachePut(Persister.Cache.RegionName); } } } PostUpdate(); if (statsEnabled && !veto) { stopwatch.Stop(); factory.StatisticsImplementor.UpdateEntity(Persister.EntityName, stopwatch.Elapsed); } }
public void PutCloneToCache(AggregateRoot aggregateRootInfo) { // don't waste cycles add/trimming if (IsEffectivelyDisabled) { return; } var aggregateRootId = aggregateRootInfo.Id; var entriesForThisRoot = _cacheEntries.GetOrAdd(aggregateRootId, id => new ConcurrentDictionary <long, CacheEntry>()); var entrySuccessfullyAdded = entriesForThisRoot.TryAdd(aggregateRootInfo.GlobalSequenceNumberCutoff, CacheEntry.Create(aggregateRootInfo)); if (entrySuccessfullyAdded) { Interlocked.Increment(ref _currentNumberOfCacheEntries); } PossiblyTrimCache(); }
public override void Execute() { 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 = PreInsert(); // Don't need to lock the cache here, since if someone // else inserted the same pk first, the insert would fail if (!veto) { persister.Insert(id, State, instance, Session); EntityEntry entry = Session.PersistenceContext.GetEntry(instance); if (entry == null) { throw new AssertionFailure("Possible nonthreadsafe access to session"); } entry.PostInsert(); if (persister.HasInsertGeneratedProperties) { persister.ProcessInsertGeneratedProperties(id, instance, State, Session); if (persister.IsVersionPropertyGenerated) { version = Versioning.GetVersion(State, persister); } entry.PostUpdate(instance, State, version); } } ISessionFactoryImplementor factory = Session.Factory; if (IsCachePutEnabled(persister)) { CacheEntry ce = CacheEntry.Create(State, persister, persister.HasUninitializedLazyProperties(instance), version, session, instance); 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); } } PostInsert(); if (statsEnabled && !veto) { stopwatch.Stop(); factory.StatisticsImplementor.InsertEntity(Persister.EntityName, stopwatch.Elapsed); } }
public override void Execute() { 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 = PreInsert(); 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}"); } persister.Insert(id, State, instance, Session); 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) { persister.ProcessInsertGeneratedProperties(id, instance, State, Session); if (persister.IsVersionPropertyGenerated) { version = Versioning.GetVersion(State, persister); } entry.PostUpdate(instance, State, version); } } ISessionFactoryImplementor factory = Session.Factory; if (IsCachePutEnabled(persister)) { CacheEntry ce = CacheEntry.Create(State, persister, version, session, instance); 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); } } PostInsert(); if (statsEnabled && !veto) { stopwatch.Stop(); factory.StatisticsImplementor.InsertEntity(Persister.EntityName, stopwatch.Elapsed); } }