protected override void DeleteEntity(IEventSource session, object entity, EntityEntry entityEntry, bool isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities) { if (entity is IPermanent) { var e = (IPermanent)entity; e.IsDeleted = true; CascadeBeforeDelete(session, persister, entity, entityEntry, transientEntities); CascadeAfterDelete(session, persister, entity, transientEntities); } else { base.DeleteEntity(session, entity, entityEntry, isCascadeDeleteEnabled, persister, transientEntities); } }
protected override void DeleteEntity(IEventSource session, object entity, EntityEntry entityEntry, bool isCascadeDeleteEnabled, IEntityPersister persister, ISet<object> transientEntities) { var entityValue = entity as EntityBase; if (entityValue != null) { entityValue.Deactive = true; entityValue.UpdatedBy = EntityConstant.UpdatedBy; entityValue.UpdatedOn = DateTime.Now; } base.DeleteEntity(session, entity, entityEntry, isCascadeDeleteEnabled, persister, transientEntities); }
protected override void DeleteEntity(IEventSource session, object entity, EntityEntry entityEntry, bool isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities) { //need to implement the condition check if (entity is DomainEntity) { ((DomainEntity)entity).IsDeleted = true; this.CascadeBeforeDelete(session, persister, entity, entityEntry, transientEntities); this.CascadeAfterDelete(session, persister, entity, transientEntities); } else { base.DeleteEntity(session, entity, entityEntry, isCascadeDeleteEnabled, persister, transientEntities); } }
/// <summary> /// Perform the entity deletion. Well, as with most operations, does not /// really perform it; just schedules an action/execution with the /// <see cref="T:NHibernate.Engine.ActionQueue" /> for execution during flush. /// </summary> /// <param name="session">The originating session</param> /// <param name="entity">The entity to delete</param> /// <param name="entityEntry">The entity's entry in the <see cref="T:NHibernate.ISession" /></param> /// <param name="isCascadeDeleteEnabled">Is delete cascading enabled?</param> /// <param name="persister">The entity persister.</param> /// <param name="transientEntities">A cache of already deleted entities.</param> protected override void DeleteEntity(IEventSource session, object entity, EntityEntry entityEntry, bool isCascadeDeleteEnabled, IEntityPersister persister, ISet transientEntities) { if (entity is IPersistentEntity) { eventListenerHelper.OnDelete(entity); CascadeBeforeDelete(session, persister, entity, entityEntry, transientEntities); CascadeAfterDelete(session, persister, entity, transientEntities); } else { base.DeleteEntity(session, entity, entityEntry, isCascadeDeleteEnabled, persister, transientEntities); } }
protected override void DeleteEntity(IEventSource session, object entity, EntityEntry entityEntry, bool isCascadeDeleteEnabled, IEntityPersister persister, ISet<object> transientEntities) { var systemEntity = entity as SystemEntity; HttpContextBase context = CurrentRequestData.CurrentContext; if (systemEntity != null && !(context != null && context.IsSoftDeleteDisabled())) { systemEntity.IsDeleted = true; CascadeBeforeDelete(session, persister, systemEntity, entityEntry, transientEntities); CascadeAfterDelete(session, persister, systemEntity, transientEntities); } else { base.DeleteEntity(session, entity, entityEntry, isCascadeDeleteEnabled, persister, transientEntities); } }
public FlushEntityEvent(IEventSource source, object entity, EntityEntry entry) : base(source) { this.entity = entity; entityEntry = entry; }
protected override void DeleteEntity(IEventSource session, object entity, EntityEntry entityEntry, bool isCascadeDeleteEnabled, NHibernate.Persister.Entity.IEntityPersister persister, Iesi.Collections.ISet transientEntities) { var entityBase = entity as EntityBase; if (entityBase != null) entityBase.IsDeleted = true; }
private static Task ProcessDereferencedCollectionAsync(IPersistentCollection coll, ISessionImplementor session, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { return(Task.FromCanceled <object>(cancellationToken)); } try { IPersistenceContext persistenceContext = session.PersistenceContext; CollectionEntry entry = persistenceContext.GetCollectionEntry(coll); ICollectionPersister loadedPersister = entry.LoadedPersister; if (log.IsDebugEnabled() && loadedPersister != null) { log.Debug("Collection dereferenced: {0}", MessageHelper.CollectionInfoString(loadedPersister, coll, entry.LoadedKey, session)); } // do a check bool hasOrphanDelete = loadedPersister != null && loadedPersister.HasOrphanDelete; if (hasOrphanDelete) { object ownerId = loadedPersister.OwnerEntityPersister.GetIdentifier(coll.Owner); // TODO NH Different behavior //if (ownerId == null) //{ // // the owning entity may have been deleted and its identifier unset due to // // identifier-rollback; in which case, try to look up its identifier from // // the persistence context // if (session.Factory.Settings.IsIdentifierRollbackEnabled) // { // EntityEntry ownerEntry = persistenceContext.GetEntry(coll.Owner); // if (ownerEntry != null) // { // ownerId = ownerEntry.Id; // } // } // if (ownerId == null) // { // throw new AssertionFailure("Unable to determine collection owner identifier for orphan-delete processing"); // } //} EntityKey key = session.GenerateEntityKey(ownerId, loadedPersister.OwnerEntityPersister); object owner = persistenceContext.GetEntity(key); if (owner == null) { return(Task.FromException <object>(new AssertionFailure("collection owner not associated with session: " + loadedPersister.Role))); } EntityEntry e = persistenceContext.GetEntry(owner); //only collections belonging to deleted entities are allowed to be dereferenced in the case of orphan delete if (e != null && e.Status != Status.Deleted && e.Status != Status.Gone) { return(Task.FromException <object>(new HibernateException("A collection with cascade=\"all-delete-orphan\" was no longer referenced by the owning entity instance: " + loadedPersister.Role))); } } // do the work entry.CurrentPersister = null; entry.CurrentKey = null; return(PrepareCollectionForUpdateAsync(coll, entry, session.Factory, cancellationToken)); } catch (System.Exception ex) { return(Task.FromException <object>(ex)); } }
/// <summary> Cascade an action to the child or children</summary> private void CascadeProperty(object parent, object child, IType type, CascadeStyle style, string propertyName, object anything, bool isCascadeDeleteEnabled) { if (child != null) { if (type.IsAssociationType) { IAssociationType associationType = (IAssociationType)type; if (CascadeAssociationNow(associationType)) { CascadeAssociation(parent, child, type, style, anything, isCascadeDeleteEnabled); } } else if (type.IsComponentType) { CascadeComponent(parent, child, (IAbstractComponentType)type, propertyName, anything); } } else { // potentially we need to handle orphan deletes for one-to-ones here... if (type.IsEntityType && ((EntityType)type).IsLogicalOneToOne()) { // We have a physical or logical one-to-one and from previous checks we know we // have a null value. See if the attribute cascade settings and action-type require // orphan checking if (style.HasOrphanDelete && action.DeleteOrphans) { // value is orphaned if loaded state for this property shows not null // because it is currently null. EntityEntry entry = eventSource.PersistenceContext.GetEntry(parent); if (entry != null && entry.Status != Status.Saving) { EntityType entityType = (EntityType)type; object loadedValue; if (componentPathStack.Count == 0) { // association defined on entity loadedValue = entry.GetLoadedValue(propertyName); } else { // association defined on component // todo : this is currently unsupported because of the fact that // we do not know the loaded state of this value properly // and doing so would be very difficult given how components and // entities are loaded (and how 'loaded state' is put into the // EntityEntry). Solutions here are to either: // 1) properly account for components as a 2-phase load construct // 2) just assume the association was just now orphaned and // issue the orphan delete. This would require a special // set of SQL statements though since we do not know the // orphaned value, something a delete with a subquery to // match the owner. loadedValue = null; } if (loadedValue != null) { eventSource.Delete(entry.Persister.EntityName, loadedValue, false, null); } } } } } }
/// <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(types[i].ResolveIdentifierAsync(value, session, entity, cancellationToken)).ConfigureAwait(false); } } foreach (var i in collectionToResolveIndexes) { hydratedState[i] = await(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); } }
/// <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> public static void InitializeEntity(object entity, bool readOnly, ISessionImplementor session, PreLoadEvent preLoadEvent, PostLoadEvent postLoadEvent) { //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 " + MessageHelper.InfoString(persister, id, session.Factory)); } IType[] types = persister.PropertyTypes; for (int i = 0; i < hydratedState.Length; i++) { object value = hydratedState[i]; if (value != LazyPropertyInitializer.UnfetchedProperty && value != BackrefPropertyAccessor.Unknown) { hydratedState[i] = types[i].ResolveIdentifier(value, 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, session.EntityMode); ISessionFactoryImplementor factory = session.Factory; if (persister.HasCache && ((session.CacheMode & CacheMode.Put) == CacheMode.Put)) { if (log.IsDebugEnabled) { log.Debug("adding entity to second-level cache: " + MessageHelper.InfoString(persister, id, session.Factory)); } object version = Versioning.GetVersion(hydratedState, persister); CacheEntry entry = new CacheEntry(hydratedState, persister, entityEntry.LoadedWithLazyPropertiesUnfetched, version, session, entity); CacheKey cacheKey = new CacheKey(id, persister.IdentifierType, persister.RootEntityName, session.EntityMode, session.Factory); 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); } } if (readOnly || !persister.IsMutable) { //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 TypeFactory.DeepCopy(hydratedState, persister.PropertyTypes, persister.PropertyUpdateability, hydratedState, session); persistenceContext.SetEntryStatus(entityEntry, Status.Loaded); } persister.AfterInitialize(entity, entityEntry.LoadedWithLazyPropertiesUnfetched, 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 " + MessageHelper.InfoString(persister, id, session.Factory)); } if (statsEnabled) { stopWath.Stop(); factory.StatisticsImplementor.LoadEntity(persister.EntityName, stopWath.Elapsed); } }
private static bool UseMinimalPuts(ISessionImplementor session, EntityEntry entityEntry) { return((session.Factory.Settings.IsMinimalPutsEnabled && session.CacheMode != CacheMode.Refresh) || (entityEntry.Persister.HasLazyProperties && entityEntry.LoadedWithLazyPropertiesUnfetched && entityEntry.Persister.IsLazyPropertiesCacheable)); }
private bool IsInManagedState(object child, IEventSource session) { EntityEntry entry = session.PersistenceContext.GetEntry(child); return(entry != null && (entry.Status == Status.Loaded || entry.Status == Status.ReadOnly)); }