Esempio n. 1
0
 public override void Process(object obj, IClassPersister persister)
 {
     object[] values = persister.GetPropertyValues(obj);
     IType[]  types  = persister.PropertyTypes;
     ProcessValues(values, types);
     if (IsSubstitutionRequired)
     {
         persister.SetPropertyValues(obj, values);
     }
 }
Esempio n. 2
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="obj"></param>
 /// <param name="persister"></param>
 /// <param name="session"></param>
 /// <returns></returns>
 private static object[] Disassemble(object obj, IClassPersister persister, ISessionImplementor session)
 {
     object[] values        = persister.GetPropertyValues(obj);
     IType[]  propertyTypes = persister.PropertyTypes;
     for (int i = 0; i < values.Length; i++)
     {
         values[i] = propertyTypes[i].Disassemble(values[i], session);
     }
     return(values);
 }
		/// <summary>
		/// 
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="persister"></param>
		/// <param name="session"></param>
		/// <returns></returns>
		private static object[ ] Disassemble( object obj, IClassPersister persister, ISessionImplementor session )
		{
			object[ ] values = persister.GetPropertyValues( obj );
			IType[ ] propertyTypes = persister.PropertyTypes;
			for( int i = 0; i < values.Length; i++ )
			{
				values[ i ] = propertyTypes[ i ].Disassemble( values[ i ], session );
			}
			return values;
		}
		public override void Process(object obj, IClassPersister persister)
		{
			object[] values = persister.GetPropertyValues( obj );
			IType[] types = persister.PropertyTypes;
			ProcessValues( values, types );
			if( IsSubstitutionRequired )
			{
				persister.SetPropertyValues( obj, values );
			}
		}
 /// <summary>
 /// Walk the tree starting from the given entity.
 /// </summary>
 /// <param name="obj"></param>
 /// <param name="persister"></param>
 public virtual void Process(object obj, IClassPersister persister)
 {
     ProcessValues(
         persister.GetPropertyValues(obj),
         persister.PropertyTypes);
 }
		/// <summary>
		/// Walk the tree starting from the given entity.
		/// </summary>
		/// <param name="obj"></param>
		/// <param name="persister"></param>
		public virtual void Process(object obj, IClassPersister persister)
		{
			ProcessValues(
				persister.GetPropertyValues( obj ),
				persister.PropertyTypes );
		}
		private object DoSave(
			object theObj,
			Key key,
			IClassPersister persister,
			bool replicate,
			bool useIdentityColumn,
			Cascades.CascadingAction cascadeAction,
			object anything )
		{
			if( persister.ImplementsValidatable )
			{
				( ( IValidatable ) theObj ).Validate();
			}

			object id;
			if( useIdentityColumn )
			{
				id = null;
				ExecuteInserts();
			}
			else
			{
				id = key.Identifier;
			}

			// Put a placeholder in entries, so we don't recurse back to try and Save() the
			// same object again. QUESTION: Should this be done before OnSave() is called?
			// likewise, should it be done before OnUpdate()?
			AddEntry( theObj, Status.Saving, null, id, null, LockMode.Write, useIdentityColumn, persister, false ); // okay if id is null here

			// cascade-save to many-to-one BEFORE the parent is saved
			cascading++;
			try
			{
				Cascades.Cascade( this, persister, theObj, cascadeAction, CascadePoint.CascadeBeforeInsertAfterDelete, anything );
			}
			finally
			{
				cascading--;
			}

			object[ ] values = persister.GetPropertyValues( theObj );
			IType[ ] types = persister.PropertyTypes;

			bool substitute = false;
			if( !replicate )
			{
				substitute = interceptor.OnSave( theObj, id, values, persister.PropertyNames, types );

				// Keep the existing version number in the case of replicate!
				if( persister.IsVersioned )
				{
					// IsUnsavedVersion bit below is NHibernate-specific
					substitute = Versioning.SeedVersion(
						values, persister.VersionProperty, persister.VersionType, persister.IsUnsavedVersion( values )
						) || substitute;
				}
			}

			if( persister.HasCollections )
			{
				// TODO: make OnReplicateVisitor extend WrapVisitor
				if( replicate )
				{
					OnReplicateVisitor visitor = new OnReplicateVisitor( this, id );
					visitor.ProcessValues( values, types );
				}
				WrapVisitor visitor2 = new WrapVisitor( this );
				// substitutes into values by side-effect
				visitor2.ProcessValues( values, types );
				substitute = substitute || visitor2.IsSubstitutionRequired;
			}

			if( substitute )
			{
				persister.SetPropertyValues( theObj, values );
			}

			TypeFactory.DeepCopy( values, types, persister.PropertyUpdateability, values );
			NullifyTransientReferences( values, types, useIdentityColumn, theObj );
			CheckNullability( values, persister, false );

			if( useIdentityColumn )
			{
				ScheduledIdentityInsertion insert = new ScheduledIdentityInsertion( values, theObj, persister, this );
				Execute( insert );
				id = insert.GeneratedId;
				persister.SetIdentifier( theObj, id );
				key = new Key( id, persister );
				CheckUniqueness( key, theObj );
			}

			object version = Versioning.GetVersion( values, persister );
			AddEntity( key, theObj );
			AddEntry( theObj, Status.Loaded, values, id, version, LockMode.Write, useIdentityColumn, persister, replicate );
			nonExists.Remove( key );

			if( !useIdentityColumn )
			{
				insertions.Add( new ScheduledInsertion( id, values, theObj, version, persister, this ) );
			}

			// cascade-save to collections AFTER the collection owner was saved
			cascading++;
			try
			{
				Cascades.Cascade( this, persister, theObj, cascadeAction, CascadePoint.CascadeAfterInsertBeforeDelete, anything );
			}
			finally
			{
				cascading--;
			}

			return id;
		}
		private EntityEntry Reassociate( object obj, object id, IClassPersister persister )
		{
			if( log.IsDebugEnabled )
			{
				log.Debug( "reassociating transient instance: " + MessageHelper.InfoString( persister, id ) );
			}
			Key key = new Key( id, persister );
			CheckUniqueness( key, obj );
			AddEntity( key, obj );
			Object[ ] values = persister.GetPropertyValues( obj );
			TypeFactory.DeepCopy( values, persister.PropertyTypes, persister.PropertyUpdateability, values );
			object version = Versioning.GetVersion( values, persister );
			EntityEntry newEntry = AddEntry( obj, Status.Loaded, values, id, version, LockMode.None, true, persister, false );
			new OnLockVisitor( this, id ).Process( obj, persister );
			return newEntry;
		}
		private void DoDelete( object obj, EntityEntry entry, IClassPersister persister )
		{
			if( log.IsDebugEnabled )
			{
				log.Debug( "deleting " + MessageHelper.InfoString( persister, entry.Id ) );
			}

			IType[ ] propTypes = persister.PropertyTypes;

			object version = entry.Version;

			object[ ] loadedState;
			if( entry.LoadedState == null )
			{
				//ie the object came in from Update()
				loadedState = persister.GetPropertyValues( obj );
			}
			else
			{
				loadedState = entry.LoadedState;
			}
			entry.DeletedState = new object[loadedState.Length];
			TypeFactory.DeepCopy( loadedState, propTypes, persister.PropertyUpdateability, entry.DeletedState );

			interceptor.OnDelete( obj, entry.Id, entry.DeletedState, persister.PropertyNames, propTypes );

			entry.Status = Status.Deleted; // before cascade and Lifecycle callback, so we are circular-reference safe
			Key key = new Key( entry.Id, persister );

			IList deletionsByOnDelete = null;
			ISet nullifiablesAfterOnDelete = null;

			// do Lifecycle callback before cascades, since this can veto
			if( persister.ImplementsLifecycle )
			{
				ISet oldNullifiables = ( ISet ) nullifiables.Clone();
				ArrayList oldDeletions = ( ArrayList ) deletions.Clone();

				nullifiables.Add( key ); //the deletion of the parent is actually executed BEFORE any deletion from onDelete()

				try
				{
					log.Debug( "calling onDelete()" );
					if( ( ( ILifecycle ) obj ).OnDelete( this ) == LifecycleVeto.Veto )
					{
						//rollback deletion
						entry.Status = Status.Loaded;
						entry.DeletedState = null;
						nullifiables = oldNullifiables;
						log.Debug( "deletion vetoed by OnDelete()" );
						return; // don't let it cascade
					}
				}
				catch( Exception )
				{
					//rollback deletion
					entry.Status = Status.Loaded;
					entry.DeletedState = null;
					nullifiables = oldNullifiables;
					throw;
				}

				//note, the following assumes that onDelete() didn't cause the session to be flushed! 
				// TODO: add a better check that it doesn't
				if( oldDeletions.Count > deletions.Count )
				{
					throw new HibernateException( "session was flushed during onDelete()" );
				}
				deletionsByOnDelete = Sublist( deletions, oldDeletions.Count, deletions.Count );
				deletions = oldDeletions;
				nullifiablesAfterOnDelete = nullifiables;
				nullifiables = oldNullifiables;
			}

			cascading++;
			try
			{
				// cascade-delete to collections "BEFORE" the collection owner is deleted
				Cascades.Cascade( this, persister, obj, Cascades.CascadingAction.ActionDelete, CascadePoint.CascadeAfterInsertBeforeDelete, null );
			}
			finally
			{
				cascading--;
			}

			NullifyTransientReferences( entry.DeletedState, propTypes, false, obj );
			// NH: commented out, seems illogical to check for nulls here
			//CheckNullability( entry.DeletedState, persister, true );
			nullifiables.Add( key );

			ScheduledDeletion delete = new ScheduledDeletion( entry.Id, version, obj, persister, this );
			deletions.Add( delete ); // Ensures that containing deletions happen before sub-deletions

			if( persister.ImplementsLifecycle )
			{
				// after nullify, because we don't want to nullify references to subdeletions
				nullifiables.AddAll( nullifiablesAfterOnDelete );
				// after deletions.add(), to respect foreign key constraints
				deletions.AddRange( deletionsByOnDelete );
			}

			cascading++;
			try
			{
				// cascade-delete to many-to-one AFTER the parent was deleted
				Cascades.Cascade( this, persister, obj, Cascades.CascadingAction.ActionDelete, CascadePoint.CascadeBeforeInsertAfterDelete );
			}
			finally
			{
				cascading--;
			}
		}