예제 #1
0
        protected virtual void PerformUpdate(SaveOrUpdateEvent @event, object entity, IEntityPersister persister)
        {
            if (!persister.IsMutable)
            {
                log.Debug("immutable instance passed to PerformUpdate(), locking");
            }

            if (log.IsDebugEnabled())
            {
                log.Debug("updating {0}", MessageHelper.InfoString(persister, @event.RequestedId, @event.Session.Factory));
            }

            IEventSource source = @event.Session;

            EntityKey key = source.GenerateEntityKey(@event.RequestedId, persister);

            source.PersistenceContext.CheckUniqueness(key, entity);

            if (InvokeUpdateLifecycle(entity, persister, source))
            {
                Reassociate(@event, @event.Entity, @event.RequestedId, persister);
                return;
            }

            // this is a transient object with existing persistent state not loaded by the session
            new OnUpdateVisitor(source, @event.RequestedId, entity).Process(entity, persister);

            //TODO: put this stuff back in to read snapshot from
            //      the second-level cache (needs some extra work)

            /*Object[] cachedState = null;
             *
             * if ( persister.hasCache() ) {
             * CacheEntry entry = (CacheEntry) persister.getCache()
             * .get( event.getRequestedId(), source.getTimestamp() );
             * cachedState = entry==null ?
             * null :
             * entry.getState(); //TODO: half-assemble this stuff
             * }*/

            source.PersistenceContext.AddEntity(
                entity,
                persister.IsMutable ? Status.Loaded : Status.ReadOnly,
                null,
                key,
                persister.GetVersion(entity),
                LockMode.None,
                true,
                persister,
                false);

            //persister.AfterReassociate(entity, source); TODO H3.2 not ported

            if (log.IsDebugEnabled())
            {
                log.Debug("updating {0}", MessageHelper.InfoString(persister, @event.RequestedId, source.Factory));
            }

            CascadeOnUpdate(@event, persister, entity);
        }
        /// <summary>
        /// The given save-update event named a detached entity.
        /// Here, we will perform the update processing.
        /// </summary>
        /// <param name="event">The update event to be handled. </param>
        /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
        protected virtual Task EntityIsDetachedAsync(SaveOrUpdateEvent @event, CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCanceled <object>(cancellationToken));
            }
            try
            {
                log.Debug("updating detached instance");

                if (@event.Session.PersistenceContext.IsEntryFor(@event.Entity))
                {
                    //TODO: assertion only, could be optimized away
                    return(Task.FromException <object>(new AssertionFailure("entity was persistent")));
                }

                object entity = @event.Entity;

                IEntityPersister persister = @event.Session.GetEntityPersister(@event.EntityName, entity);

                @event.RequestedId = GetUpdateId(entity, persister, @event.RequestedId);

                return(PerformUpdateAsync(@event, entity, persister, cancellationToken));
            }
            catch (Exception ex)
            {
                return(Task.FromException <object>(ex));
            }
        }
예제 #3
0
        protected override object EntityIsTransient(SaveOrUpdateEvent e)
        {
            var trackable = e.Entity as ITrackable;

            if (trackable != null)
            {
                var time = DateTime.Now;
                var name = GetUsersName();

                _log.DebugFormat("Saving insert tracking information for entity of type '{0}'.", trackable.GetType());

                if (String.IsNullOrWhiteSpace(trackable.CreatedBy))
                {
                    trackable.CreatedBy = name;
                }
                if (trackable.CreatedOn == DateTime.MinValue)
                {
                    trackable.CreatedOn = time;
                }

                trackable.UpdatedBy = name;
                trackable.UpdatedOn = time;
            }

            return(base.EntityIsTransient(e));
        }
        public virtual async Task OnSaveOrUpdateAsync(SaveOrUpdateEvent @event, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            ISessionImplementor source = @event.Session;
            object obj         = @event.Entity;
            object requestedId = @event.RequestedId;

            if (requestedId != null)
            {
                //assign the requested id to the proxy, *before*
                //reassociating the proxy
                if (obj.IsProxy())
                {
                    ((INHibernateProxy)obj).HibernateLazyInitializer.Identifier = requestedId;
                }
            }

            if (ReassociateIfUninitializedProxy(obj, source))
            {
                log.Debug("reassociated uninitialized proxy");
                // an uninitialized proxy, noop, don't even need to
                // return an id, since it is never a save()
            }
            else
            {
                //initialize properties of the event:
                object entity = await(source.PersistenceContext.UnproxyAndReassociateAsync(obj, cancellationToken)).ConfigureAwait(false);
                @event.Entity = entity;
                @event.Entry  = source.PersistenceContext.GetEntry(entity);
                //return the id in the event object
                @event.ResultId = await(PerformSaveOrUpdateAsync(@event, cancellationToken)).ConfigureAwait(false);
            }
        }
		public virtual void OnSaveOrUpdate(SaveOrUpdateEvent @event)
		{
			ISessionImplementor source = @event.Session;
			object obj = @event.Entity;
			object requestedId = @event.RequestedId;

			if (requestedId != null)
			{
				//assign the requested id to the proxy, *before* 
				//reassociating the proxy
				if (obj.IsProxy())
				{
					((INHibernateProxy)obj).HibernateLazyInitializer.Identifier = requestedId;
				}
			}

			if (ReassociateIfUninitializedProxy(obj, source))
			{
				log.Debug("reassociated uninitialized proxy");
				// an uninitialized proxy, noop, don't even need to 
				// return an id, since it is never a save()
			}
			else
			{
				//initialize properties of the event:
				object entity = source.PersistenceContext.UnproxyAndReassociate(obj);
				@event.Entity = entity;
				@event.Entry = source.PersistenceContext.GetEntry(entity);
				//return the id in the event object
				@event.ResultId = PerformSaveOrUpdate(@event);
			}
		}
예제 #6
0
        protected override object EntityIsPersistent(SaveOrUpdateEvent e)
        {
            if (e.Entity is INHibernateProxy)
            {
                return(base.EntityIsPersistent(e));
            }

            var trackable = e.Entity as ITrackable;

            if (trackable != null)
            {
                // First make sure there are any dirty properties on object:
                // http://nhforge.org/wikis/howtonh/finding-dirty-properties-in-nhibernate.aspx
                var sessionImplementation = e.Session.GetSessionImplementation();
                var oldState     = e.Entry.LoadedState;
                var currentState = e.Entry.Persister.GetPropertyValues(e.Entity);

                if (oldState == null ||
                    e.Entry.Persister.FindDirty(currentState, oldState, e.Entity, sessionImplementation) != null)
                {
                    var time = DateTime.Now;
                    var name = GetUsersName();

                    _log.DebugFormat("Saving update tracking information for entity of type '{0}'.",
                                     trackable.GetType());

                    trackable.UpdatedBy = name;
                    trackable.UpdatedOn = time;
                }
            }

            return(base.EntityIsPersistent(e));
        }
예제 #7
0
 public void OnSaveOrUpdate(SaveOrUpdateEvent @event)
 {
     if (@event.Entity is IPersistentEntity)
     {
         (@event.Entity as IPersistentEntity).OnSave();
     }
 }
        /// <summary>
        /// The given save-update event named a transient entity.
        /// Here, we will perform the save processing.
        /// </summary>
        /// <param name="event">The save event to be handled. </param>
        /// <returns> The entity's identifier after saving. </returns>
        protected virtual object EntityIsTransient(SaveOrUpdateEvent @event)
        {
            log.Debug("saving transient instance");

            IEventSource source      = @event.Session;
            EntityEntry  entityEntry = @event.Entry;

            if (entityEntry != null)
            {
                if (entityEntry.Status == Status.Deleted)
                {
                    source.ForceFlush(entityEntry);
                }
                else
                {
                    throw new AssertionFailure("entity was persistent");
                }
            }

            object id = SaveWithGeneratedOrRequestedId(@event);

            source.PersistenceContext.ReassociateProxy(@event.Entity, id);

            return(id);
        }
        public virtual void OnSaveOrUpdate(SaveOrUpdateEvent @event)
        {
            ISessionImplementor source = @event.Session;
            object obj         = @event.Entity;
            object requestedId = @event.RequestedId;

            if (requestedId != null)
            {
                //assign the requested id to the proxy, *before*
                //reassociating the proxy
                if (obj.IsProxy())
                {
                    ((INHibernateProxy)obj).HibernateLazyInitializer.Identifier = requestedId;
                }
            }

            if (ReassociateIfUninitializedProxy(obj, source))
            {
                log.Debug("reassociated uninitialized proxy");
                // an uninitialized proxy, noop, don't even need to
                // return an id, since it is never a save()
            }
            else
            {
                //initialize properties of the event:
                object entity = source.PersistenceContext.UnproxyAndReassociate(obj);
                @event.Entity = entity;
                @event.Entry  = source.PersistenceContext.GetEntry(entity);
                //return the id in the event object
                @event.ResultId = PerformSaveOrUpdate(@event);
            }
        }
예제 #10
0
 protected override Task <object> PerformSaveOrUpdateAsync(SaveOrUpdateEvent @event, CancellationToken cancellationToken)
 {
     if (cancellationToken.IsCancellationRequested)
     {
         return(Task.FromCanceled <object>(cancellationToken));
     }
     try
     {
         // this implementation is supposed to tolerate incorrect unsaved-value
         // mappings, for the purpose of backward-compatibility
         EntityEntry entry = @event.Session.PersistenceContext.GetEntry(@event.Entity);
         if (entry != null && entry.Status != Status.Deleted)
         {
             return(Task.FromResult <object>(EntityIsPersistent(@event)));
         }
         else
         {
             return(EntityIsTransientAsync(@event, cancellationToken));
         }
     }
     catch (Exception ex)
     {
         return(Task.FromException <object>(ex));
     }
 }
        /// <summary>
        /// The given save-update event named a transient entity.
        /// Here, we will perform the save processing.
        /// </summary>
        /// <param name="event">The save event to be handled. </param>
        /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
        /// <returns> The entity's identifier after saving. </returns>
        protected virtual async Task <object> EntityIsTransientAsync(SaveOrUpdateEvent @event, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            log.Debug("saving transient instance");

            IEventSource source      = @event.Session;
            EntityEntry  entityEntry = @event.Entry;

            if (entityEntry != null)
            {
                if (entityEntry.Status == Status.Deleted)
                {
                    await(source.ForceFlushAsync(entityEntry, cancellationToken)).ConfigureAwait(false);
                }
                else
                {
                    throw new AssertionFailure("entity was persistent");
                }
            }

            object id = await(SaveWithGeneratedOrRequestedIdAsync(@event, cancellationToken)).ConfigureAwait(false);

            source.PersistenceContext.ReassociateProxy(@event.Entity, id);

            return(id);
        }
예제 #12
0
 protected override Task <object> SaveWithGeneratedOrRequestedIdAsync(SaveOrUpdateEvent @event, CancellationToken cancellationToken)
 {
     if (cancellationToken.IsCancellationRequested)
     {
         return(Task.FromCanceled <object>(cancellationToken));
     }
     return(SaveWithGeneratedIdAsync(@event.Entity, @event.EntityName, null, @event.Session, true, cancellationToken));
 }
예제 #13
0
        public void OnSaveOrUpdate(SaveOrUpdateEvent @event)
        {
            IAuditable auditable = @event.Entity as IAuditable;

            if (auditable.CreatedAt == DateTime.MinValue)
            {
                this.ExplicitUpdateCall(auditable);
            }
        }
예제 #14
0
        /// <summary>
        /// Performs the update.
        /// </summary>
        /// <param name="evt">The event.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="persister">The persister.</param>
        protected override void PerformUpdate(SaveOrUpdateEvent evt, object entity, NHibernate.Persister.Entity.IEntityPersister persister)
        {
            if (evt.Session.IsDirtyEntity(entity))
            {
                eventListenerHelper.OnModify(entity);
            }

            base.PerformUpdate(evt, entity, persister);
        }
예제 #15
0
        /// <summary>
        /// Performs the save or update.
        /// </summary>
        /// <param name="evt">The evt.</param>
        /// <returns>
        /// The id used to save the entity; may be null depending on the
        /// type of id generator used and the requiresImmediateIdAccess value
        /// </returns>
        protected override object PerformSaveOrUpdate(SaveOrUpdateEvent evt)
        {
            if (evt.Session.IsDirtyEntity(evt.Entity))
            {
                eventListenerHelper.OnModify(evt.Entity);
            }

            return(base.PerformSaveOrUpdate(evt));
        }
예제 #16
0
    private static bool IsDirty(SaveOrUpdateEvent @event)
    {
        IEntityPersister persister = @event.Entry.Persister;

        object[] oldState     = @event.Entry.LoadedState;
        object[] currentState = persister.GetPropertyValues(@event.Entity, @event.Session.EntityMode);
        Int32[]  dirtyProps   = persister.FindDirty(currentState, oldState, @event.Entity, @event.Session);
        return(dirtyProps != null);
    }
예제 #17
0
        public void OnSaveOrUpdate(SaveOrUpdateEvent @event)
        {
            Debug.WriteLine(string.Format("OnSaveOrUpdate - {0}", @event.Entity));

            if (@event.Entity is IDataObject)
            {
                ServiceDataAuthorizationConnector.Check((IDataObject)@event.Entity,
                                                        DataOperation.Retreive);
            }
        }
예제 #18
0
        public void OnSaveOrUpdate(SaveOrUpdateEvent @event)
        {
            var res = @event.Entity;

            if (res.GetType() == typeof(Movie))
            {
                var m = (Movie)res;
                Console.WriteLine("%%%% Save or update:", m.Title);
            }
        }
예제 #19
0
        private void HandleCreated(IVersionedEntity entity, SaveOrUpdateEvent @event)
        {
            entity.SetMemberValue(x => x.CreatedDate, DateTime.UtcNow);

            if (IsVersionedEntityWithUser(entity))
            {
                var user = GetCurrentUser(@event.Session);

                entity.SetMemberValue(PropertyName((IVersionedEntityWithUser <TUser> x) => x.CreatedBy), user);
            }
        }
예제 #20
0
 protected override object SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent @event)
 {
     if (@event.RequestedId == null)
     {
         return(base.SaveWithGeneratedOrRequestedId(@event));
     }
     else
     {
         return(SaveWithRequestedId(@event.Entity, @event.RequestedId, @event.EntityName, null, @event.Session));
     }
 }
 /// <summary>
 /// Save the transient instance, assigning the right identifier
 /// </summary>
 /// <param name="event">The initiating event. </param>
 /// <returns> The entity's identifier value after saving.</returns>
 protected virtual object SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent @event)
 {
     if (@event.RequestedId == null)
     {
         return(SaveWithGeneratedId(@event.Entity, @event.EntityName, null, @event.Session, true));
     }
     else
     {
         return(SaveWithRequestedId(@event.Entity, @event.RequestedId, @event.EntityName, null, @event.Session));
     }
 }
		protected override object SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent @event)
		{
			if (@event.RequestedId == null)
			{
				return base.SaveWithGeneratedOrRequestedId(@event);
			}
			else
			{
				return SaveWithRequestedId(@event.Entity, @event.RequestedId, @event.EntityName, null, @event.Session);
			}
		}
        protected override object PerformSaveOrUpdate(SaveOrUpdateEvent evt)
        {
            var entity = evt.Entity as Entity;

            if (entity != null)
            {
                ProcessEntityBeforeInsert(entity, evt.Session);
            }

            return(base.PerformSaveOrUpdate(evt));
        }
예제 #24
0
    protected override object EntityIsTransient(SaveOrUpdateEvent @event)
    {
        Pony ent = @event.Entity as Pony;

        if (ent == null)
        {
            return(base.EntityIsTransient(@event));
        }
        ent.RevisionValidFrom = Host.NextRevision;
        ent.RevisionValidTo   = null;
        return(base.EntityIsTransient(@event));
    }
        /// <summary>
        /// Handles the calls needed to perform cascades as part of an update request
        /// for the given entity.
        /// </summary>
        /// <param name="event">The event currently being processed. </param>
        /// <param name="persister">The defined persister for the entity being updated. </param>
        /// <param name="entity">The entity being updated. </param>
        private void CascadeOnUpdate(SaveOrUpdateEvent @event, IEntityPersister persister, object entity)
        {
            IEventSource source = @event.Session;

            source.PersistenceContext.IncrementCascadeLevel();
            try
            {
                new Cascade(CascadingAction.SaveUpdate, CascadePoint.AfterUpdate, source).CascadeOn(persister, entity);
            }
            finally
            {
                source.PersistenceContext.DecrementCascadeLevel();
            }
        }
		protected override object PerformSaveOrUpdate(SaveOrUpdateEvent @event)
		{
			// this implementation is supposed to tolerate incorrect unsaved-value
			// mappings, for the purpose of backward-compatibility
			EntityEntry entry = @event.Session.PersistenceContext.GetEntry(@event.Entity);
			if (entry != null && entry.Status != Status.Deleted)
			{
				return EntityIsPersistent(@event);
			}
			else
			{
				return EntityIsTransient(@event);
			}
		}
예제 #27
0
        /// <summary>
        /// Performs the save or update.
        /// </summary>
        /// <param name="evt">The save or update event.</param>
        /// <returns>
        /// The id used to save the entity; may be null depending on the
        /// type of id generator used and the requiresImmediateIdAccess value
        /// </returns>
        protected override object PerformSaveOrUpdate(SaveOrUpdateEvent evt)
        {
            if (evt.Entity is IEntity)
            {
                Events.CoreEvents.Instance.OnEntitySaving((IEntity)evt.Entity, evt.Session);
            }

            if (evt.Session.IsDirtyEntity(evt.Entity))
            {
                eventListenerHelper.OnModify(evt.Entity);
            }

            return(base.PerformSaveOrUpdate(evt));
        }
예제 #28
0
        /// <summary>
        /// Performs the update.
        /// </summary>
        /// <param name="evt">The event.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="persister">The entity's persister.</param>
        protected override void PerformUpdate(SaveOrUpdateEvent evt, object entity, IEntityPersister persister)
        {
            if (entity is IEntity)
            {
                Events.CoreEvents.Instance.OnEntitySaving((IEntity)entity, evt.Session);
            }

            if (evt.Session.IsDirtyEntity(entity))
            {
                eventListenerHelper.OnModify(entity);
            }

            base.PerformUpdate(evt, entity, persister);
        }
예제 #29
0
    public override void OnSaveOrUpdate(SaveOrUpdateEvent @event)
    {
        Auditable a = @event.Entity as Auditable;

        if (a != null)
        {
            if (this.GetEntityState(@event.Entity, @event.EntityName, @event.Entry, @event.Session) == EntityState.Transient)
            {
                a.create_dt = DateTime.Now;
                a.create_by = @event.Session.Load <Staff>(CurrentStaff.Id);
            }
        }

        base.OnSaveOrUpdate(@event);
    }
예제 #30
0
        protected override object EntityIsTransient(SaveOrUpdateEvent @event)
        {
            if (@event.Entry == null)
            {
                var entity = @event.Entity as IVersionedEntity;
                if (entity != null && entity.IsTransient())
                {
                    HandleCreated(entity, @event);
                }

                PublishEventAsync(@event.Entity, @event.Session).GetAwaiter().GetResult();
            }

            return(base.EntityIsTransient(@event));
        }
예제 #31
0
        protected override object PerformSaveOrUpdate(SaveOrUpdateEvent @event)
        {
            // this implementation is supposed to tolerate incorrect unsaved-value
            // mappings, for the purpose of backward-compatibility
            EntityEntry entry = @event.Session.PersistenceContext.GetEntry(@event.Entity);

            if (entry != null && entry.Status != Status.Deleted)
            {
                return(EntityIsPersistent(@event));
            }
            else
            {
                return(EntityIsTransient(@event));
            }
        }
        /// <summary>
        /// Handles the calls needed to perform cascades as part of an update request
        /// for the given entity.
        /// </summary>
        /// <param name="event">The event currently being processed. </param>
        /// <param name="persister">The defined persister for the entity being updated. </param>
        /// <param name="entity">The entity being updated. </param>
        /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
        private async Task CascadeOnUpdateAsync(SaveOrUpdateEvent @event, IEntityPersister persister, object entity, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();
            IEventSource source = @event.Session;

            source.PersistenceContext.IncrementCascadeLevel();
            try
            {
                await(new Cascade(CascadingAction.SaveUpdate, CascadePoint.AfterUpdate, source).CascadeOnAsync(persister, entity, cancellationToken)).ConfigureAwait(false);
            }
            finally
            {
                source.PersistenceContext.DecrementCascadeLevel();
            }
        }
예제 #33
0
        protected override async Task <object> EntityIsTransientAsync(SaveOrUpdateEvent @event, CancellationToken cancellationToken)
        {
            if (@event.Entry == null)
            {
                var entity = @event.Entity as IVersionedEntity;
                if (entity != null && entity.IsTransient())
                {
                    HandleCreated(entity, @event);
                }

                await PublishEventAsync(@event.Entity, @event.Session);
            }

            return(await base.EntityIsTransientAsync(@event, cancellationToken));
        }
		protected virtual object PerformSaveOrUpdate(SaveOrUpdateEvent @event)
		{
			EntityState entityState = GetEntityState(@event.Entity, @event.EntityName, @event.Entry, @event.Session);

			switch (entityState)
			{
				case EntityState.Detached:
					EntityIsDetached(@event);
					return null;

				case EntityState.Persistent:
					return EntityIsPersistent(@event);

				default:  //TRANSIENT or DELETED
					return EntityIsTransient(@event);
			}
		}
        /// <summary> 
        /// The given save-update event named a detached entity.
        /// Here, we will perform the update processing. 
        /// </summary>
        /// <param name="event">The update event to be handled. </param>
        protected virtual void EntityIsDetached(SaveOrUpdateEvent @event)
        {
            log.Debug("updating detached instance");

            if (@event.Session.PersistenceContext.IsEntryFor(@event.Entity))
            {
                //TODO: assertion only, could be optimized away
                throw new AssertionFailure("entity was persistent");
            }

            object entity = @event.Entity;

            IEntityPersister persister = @event.Session.GetEntityPersister(entity);

            @event.RequestedId = GetUpdateId(entity, persister, @event.RequestedId, @event.Session.EntityMode);

            PerformUpdate(@event, entity, persister);
        }
		protected virtual object EntityIsPersistent(SaveOrUpdateEvent @event)
		{
			log.Debug("ignoring persistent instance");

			EntityEntry entityEntry = @event.Entry;
			if (entityEntry == null)
			{
				throw new AssertionFailure("entity was transient or detached");
			}
			else
			{
				if (entityEntry.Status == Status.Deleted)
				{
					throw new AssertionFailure("entity was deleted");
				}

				ISessionFactoryImplementor factory = @event.Session.Factory;

				object requestedId = @event.RequestedId;
				object savedId;
				if (requestedId == null)
				{
					savedId = entityEntry.Id;
				}
				else
				{
					if (!entityEntry.Persister.IdentifierType.IsEqual(requestedId, entityEntry.Id, EntityMode.Poco))
					{
						throw new PersistentObjectException("object passed to save() was already persistent: " + 
							MessageHelper.InfoString(entityEntry.Persister, requestedId, factory));
					}
					savedId = requestedId;
				}

				if (log.IsDebugEnabled)
				{
					log.Debug("object already associated with session: " + 
						MessageHelper.InfoString(entityEntry.Persister, savedId, factory));
				}

				return savedId;
			}
		}
		protected override object PerformSaveOrUpdate(SaveOrUpdateEvent @event)
		{
			// this implementation is supposed to tolerate incorrect unsaved-value
			// mappings, for the purpose of backward-compatibility
			EntityEntry entry = @event.Session.PersistenceContext.GetEntry(@event.Entity);
			if (entry != null)
			{
				if (entry.Status == Status.Deleted)
				{
					throw new ObjectDeletedException("deleted instance passed to update()", null, @event.EntityName);
				}
				else
				{
					return EntityIsPersistent(@event);
				}
			}
			else
			{
				EntityIsDetached(@event);
				return null;
			}
		}
		/// <summary> 
		/// The given save-update event named a transient entity.
		/// Here, we will perform the save processing. 
		/// </summary>
		/// <param name="event">The save event to be handled. </param>
		/// <returns> The entity's identifier after saving. </returns>
		protected virtual object EntityIsTransient(SaveOrUpdateEvent @event)
		{
			log.Debug("saving transient instance");

			IEventSource source = @event.Session;
			EntityEntry entityEntry = @event.Entry;
			if (entityEntry != null)
			{
				if (entityEntry.Status == Status.Deleted)
				{
					source.ForceFlush(entityEntry);
				}
				else
				{
					throw new AssertionFailure("entity was persistent");
				}
			}

			object id = SaveWithGeneratedOrRequestedId(@event);

			source.PersistenceContext.ReassociateProxy(@event.Entity, id);

			return id;
		}
		/// <summary> 
		/// Save the transient instance, assigning the right identifier 
		/// </summary>
		/// <param name="event">The initiating event. </param>
		/// <returns> The entity's identifier value after saving.</returns>
		protected virtual object SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent @event)
		{
			return SaveWithGeneratedId(@event.Entity, @event.EntityName, null, @event.Session, true);
		}
		protected virtual void PerformUpdate(SaveOrUpdateEvent @event, object entity, IEntityPersister persister)
		{
			if (!persister.IsMutable)
			{
				log.Debug("immutable instance passed to PerformUpdate(), locking");
			}

			if (log.IsDebugEnabled)
			{
				log.Debug("updating " + MessageHelper.InfoString(persister, @event.RequestedId, @event.Session.Factory));
			}

			IEventSource source = @event.Session;

			EntityKey key = new EntityKey(@event.RequestedId, persister, source.EntityMode);

			source.PersistenceContext.CheckUniqueness(key, entity);

			if (InvokeUpdateLifecycle(entity, persister, source))
			{
				Reassociate(@event, @event.Entity, @event.RequestedId, persister);
				return;
			}

			// this is a transient object with existing persistent state not loaded by the session
			new OnUpdateVisitor(source, @event.RequestedId, entity).Process(entity, persister);

			//TODO: put this stuff back in to read snapshot from
			//      the second-level cache (needs some extra work)
			/*Object[] cachedState = null;
			
			if ( persister.hasCache() ) {
			CacheEntry entry = (CacheEntry) persister.getCache()
			.get( event.getRequestedId(), source.getTimestamp() );
			cachedState = entry==null ? 
			null : 
			entry.getState(); //TODO: half-assemble this stuff
			}*/

			source.PersistenceContext.AddEntity(
				entity, 
				persister.IsMutable ? Status.Loaded : Status.ReadOnly,
				null, 
				key,
				persister.GetVersion(entity, source.EntityMode), 
				LockMode.None, 
				true, 
				persister,
				false,
				true);

			//persister.AfterReassociate(entity, source); TODO H3.2 not ported

			if (log.IsDebugEnabled)
			{
				log.Debug("updating " + MessageHelper.InfoString(persister, @event.RequestedId, source.Factory));
			}

			CascadeOnUpdate(@event, persister, entity);
		}
		/// <summary> 
		/// Handles the calls needed to perform cascades as part of an update request
		/// for the given entity. 
		/// </summary>
		/// <param name="event">The event currently being processed. </param>
		/// <param name="persister">The defined persister for the entity being updated. </param>
		/// <param name="entity">The entity being updated. </param>
		private void CascadeOnUpdate(SaveOrUpdateEvent @event, IEntityPersister persister, object entity)
		{
			IEventSource source = @event.Session;
			source.PersistenceContext.IncrementCascadeLevel();
			try
			{
				new Cascade(CascadingAction.SaveUpdate, CascadePoint.AfterUpdate, source).CascadeOn(persister, entity);
			}
			finally
			{
				source.PersistenceContext.DecrementCascadeLevel();
			}
		}