protected override object ProcessCollection( object collection, PersistentCollectionType type )
		{
			SessionImpl session = Session;
			object key = Key;
			ICollectionPersister persister = session.GetCollectionPersister( type.Role );

			session.RemoveCollection( persister, key );

			if ( collection != null && ( collection is PersistentCollection ) )
			{
				PersistentCollection wrapper = collection as PersistentCollection;
				wrapper.SetCurrentSession( session );
				if ( wrapper.WasInitialized )
				{
					session.AddNewCollection( wrapper, persister );
				}
				else
				{
					session.ReattachCollection( wrapper, wrapper.CollectionSnapshot ) ;
				}
			}
			else
			{
				// otherwise a null or brand new collection 
				// this will also (inefficiently) handle arrays, which 
				// have no snapshot, so we can't do any better
				//processArrayOrNewCollection(collection, type);
			}

			return null;
		}
		protected override object ProcessCollection(object collection, PersistentCollectionType type)
		{
			if( collection != null )
			{
				SessionImpl session = Session;
				PersistentCollection coll;

				if( type.IsArrayType )
				{
					coll = session.GetArrayHolder( collection );
					// if no array holder we found an unwrappered array (this can't occur,
					// because we now always call wrap() before getting to here)
					// return (ah==null) ? true : searchForDirtyCollections(ah, type);
				}
				else
				{
					// if not wrappered yet, its dirty (this can't occur, because 
					// we now always call wrap() before getting to here) 
					// return ( ! (obj is PersistentCollection) ) ?
					//	true : SearchForDirtyCollections( (PersistentCollection) obj, type );
					coll = (PersistentCollection)collection;
				}

				if( session.CollectionIsDirty( coll ) )
				{
					_dirty = true;
					return null; // NOTE: early exit
				}
			}
			return null;
		}
		private object ProcessArrayOrNewCollection(object collection, PersistentCollectionType collectionType)
		{
			if( collection == null )
			{
				return null;
			}

			ICollectionPersister persister = Session.GetCollectionPersister( collectionType.Role );

			if( collectionType.IsArrayType )
			{
				ArrayHolder ah = Session.GetArrayHolder( collection );
				if( ah == null )
				{
					ah = new ArrayHolder( Session, collection );
					Session.AddNewCollection( ah, persister );
					Session.AddArrayHolder( ah );
				}
				return null;
			}
			else
			{
				PersistentCollection persistentCollection = collectionType.Wrap( Session, collection );
				Session.AddNewCollection( persistentCollection, persister );

				if( log.IsDebugEnabled )
				{
					log.Debug( "Wrapped collection in role: " + collectionType.Role );
				}

				return persistentCollection; //Force a substitution!
			}
		}
		protected override object ProcessCollection(object collection, PersistentCollectionType type)
		{
			if( collection != null )
			{
				Session.EvictCollection( collection, type );
			}

			return null;
		}
		protected override object ProcessCollection(object collection, PersistentCollectionType collectionType)
		{
			if( collection != null && (collection is PersistentCollection) )
			{
				PersistentCollection coll = collection as PersistentCollection;
				if( coll.SetCurrentSession( Session ) )
				{
					Session.ReattachCollection( coll, coll.CollectionSnapshot );
				}
				return null;
			}
			else
			{
				return ProcessArrayOrNewCollection( collection, collectionType );
			}
		}
		protected override object ProcessCollection(object collection, PersistentCollectionType type)
		{
			ICollectionPersister persister = Session.GetCollectionPersister( type.Role );

			if( collection is PersistentCollection )
			{
				PersistentCollection wrapper = (PersistentCollection)collection;

				if( wrapper.SetCurrentSession( Session ) )
				{
					//a "detached" collection!
					ICollectionSnapshot snapshot = wrapper.CollectionSnapshot;

					if( !SessionImpl.IsOwnerUnchanged( snapshot, persister, Key ) )
					{
						// if the collection belonged to a different entity,
						// clean up the existing state of the collection
						Session.RemoveCollection( persister, Key );
					}

					Session.ReattachCollection( wrapper, snapshot );
				}
				else
				{
					// a collection loaded in the current session
					// can not possibly be the collection belonging
					// to the entity passed to update()
					Session.RemoveCollection( persister, Key );
				}
			}
			else
			{
				// null or brand new collection
				// this will also (inefficiently) handle arrays, which have
				// no snapshot, so we can't do any better
				Session.RemoveCollection( persister, Key );
				//processArrayOrNewCollection(collection, type);
			}

			return null;
		}
		protected override object ProcessCollection(object collection, PersistentCollectionType type)
		{
			if( log.IsDebugEnabled )
			{
				log.Debug( string.Format( "Processing collection for role {0}", type.Role ) );
			}

			if( collection != null )
			{
				PersistentCollection coll;
				if( type.IsArrayType )
				{
					coll = Session.GetArrayHolder( collection );
				}
				else
				{
					coll = (PersistentCollection)collection;
				}
				Session.UpdateReachableCollection( coll, type, _owner );
			}
			return null;
		}
		public AbstractCollectionPersister( Mapping.Collection collection, ISessionFactoryImplementor factory )
		{
			this.factory = factory;
			dialect = factory.Dialect;
			//sqlExceptionConverter = factory.SQLExceptionConverter;
			collectionType = collection.CollectionType;
			role = collection.Role;
			ownerClass = collection.OwnerClass;
			Alias alias = new Alias( "__" );

			sqlOrderByString = collection.OrderBy;
			hasOrder = sqlOrderByString != null;
			sqlOrderByStringTemplate = hasOrder ? Template.RenderOrderByStringTemplate( sqlOrderByString, dialect ) : null;

			sqlWhereString = collection.Where;
			hasWhere = sqlWhereString != null;
			sqlWhereStringTemplate = hasWhere ? Template.RenderWhereStringTemplate( sqlWhereString, dialect ) : null;

			hasOrphanDelete = collection.OrphanDelete;

			batchSize = collection.BatchSize;

			cache = collection.Cache;

			keyType = collection.Key.Type;
			int keySpan = collection.Key.ColumnSpan;
			keyColumnNames = new string[keySpan];
			string[ ] keyAliases = new string[keySpan];
			int k = 0;
			foreach( Column col in collection.Key.ColumnCollection )
			{
				keyColumnNames[ k ] = col.GetQuotedName( dialect );
				keyAliases[ k ] = col.Alias( dialect );
				k++;
			}
			keyColumnAliases = alias.ToAliasStrings( keyAliases, dialect );
			//unquotedKeyColumnNames = StringHelper.Unquote( keyColumnAliases );
			ISet distinctColumns = new HashedSet();
			CheckColumnDuplication( distinctColumns, collection.Key.ColumnCollection );

			//isSet = collection.IsSet;
			//isSorted = collection.IsSorted;
			primitiveArray = collection.IsPrimitiveArray;
			array = collection.IsArray;

			IValue element = collection.Element;
			int elementSpan = element.ColumnSpan;
			ICollection iter = element.ColumnCollection;
			Table table = collection.CollectionTable;
			enableJoinedFetch = element.OuterJoinFetchSetting;
			elementType = element.Type;

			if( !collection.IsOneToMany )
			{
				CheckColumnDuplication( distinctColumns, element.ColumnCollection );
			}

			if( elementType.IsEntityType )
			{
				elementPersister = factory.GetPersister( ( ( EntityType ) elementType ).AssociatedClass );
			}
			else
			{
				elementPersister = null;
			}

			qualifiedTableName = table.GetQualifiedName( dialect, factory.DefaultSchema );
			string[ ] aliases = new string[elementSpan];
			elementColumnNames = new string[elementSpan];
			int j = 0;
			foreach( Column col in iter )
			{
				elementColumnNames[ j ] = col.GetQuotedName( dialect );
				aliases[ j ] = col.Alias( dialect );
				j++;
			}

			elementColumnAliases = alias.ToAliasStrings( aliases, dialect );

			IType selectColumns;
			string[ ] selectType;

			hasIndex = collection.IsIndexed;

			if( hasIndex )
			{
				IndexedCollection indexedCollection = ( IndexedCollection ) collection;

				indexType = indexedCollection.Index.Type;
				int indexSpan = indexedCollection.Index.ColumnSpan;
				indexColumnNames = new string[indexSpan];

				string[ ] indexAliases = new string[indexSpan];
				int i = 0;
				foreach( Column indexCol in indexedCollection.Index.ColumnCollection )
				{
					indexAliases[ i ] = indexCol.Alias( dialect );
					indexColumnNames[ i ] = indexCol.GetQuotedName( dialect );
					i++;
				}
				selectType = indexColumnNames;
				selectColumns = indexType;
				indexColumnAliases = alias.ToAliasStrings( indexAliases, dialect );
				CheckColumnDuplication( distinctColumns, indexedCollection.Index.ColumnCollection );
			}
			else
			{
				indexType = null;
				indexColumnNames = null;
				indexColumnAliases = null;
				selectType = elementColumnNames;
				selectColumns = elementType;
			}

			hasIdentifier = collection.IsIdentified;

			if( hasIdentifier )
			{
				if( collection.IsOneToMany )
				{
					throw new MappingException( "one-to-many collections with identifiers are not supported." );
				}
				IdentifierCollection idColl = ( IdentifierCollection ) collection;
				identifierType = idColl.Identifier.Type;

				Column col = null;
				foreach( Column column in idColl.Identifier.ColumnCollection )
				{
					col = column;
					break;
				}

				identifierColumnName = col.GetQuotedName( dialect );
				selectType = new string[ ] {identifierColumnName};
				selectColumns = identifierType;
				identifierColumnAlias = alias.ToAliasString( col.Alias( dialect ), dialect );
				unquotedIdentifierColumnName = identifierColumnAlias;
				identifierGenerator = idColl.Identifier.CreateIdentifierGenerator( dialect );
				CheckColumnDuplication( distinctColumns, idColl.Identifier.ColumnCollection );
			}
			else
			{
				identifierType = null;
				identifierColumnName = null;
				identifierColumnAlias = null;
				unquotedIdentifierColumnName = null;
				identifierGenerator = null;
			}

			rowSelectColumnNames = selectType;
			rowSelectType = selectColumns;

			sqlDeleteString = GenerateDeleteString();
			sqlInsertRowString = GenerateInsertRowString();
			sqlUpdateRowString = GenerateUpdateRowString();
			sqlDeleteRowString = GenerateDeleteRowString();
			isLazy = collection.IsLazy;

			isInverse = collection.IsInverse;

			if( collection.IsArray )
			{
				elementClass = ( ( Array ) collection ).ElementClass;
			}
			else
			{
				// for non-arrays, we don't need to know the element class
				elementClass = null;
			}

			initializer = CreateCollectionInitializer( factory );

			if( elementType.IsComponentType )
			{
				elementPropertyMapping = new CompositeElementPropertyMapping( elementColumnNames, ( IAbstractComponentType ) elementType, factory );
			}
			else if( !elementType.IsEntityType )
			{
				elementPropertyMapping = new ElementPropertyMapping( elementColumnNames, elementType );
			}
			else
			{
				IClassPersister persister = factory.GetPersister( ( ( EntityType ) elementType ).AssociatedClass );
				// Not all classpersisters implement IPropertyMapping!
				if( persister is IPropertyMapping )
				{
					elementPropertyMapping = ( IPropertyMapping ) persister;
				}
				else
				{
					elementPropertyMapping = new ElementPropertyMapping( elementColumnNames, elementType );
				}
			}
		}
			/// <summary>
			/// The children to whom we should cascade.
			/// </summary>
			public abstract ICollection CascadableChildrenCollection( PersistentCollectionType collectionType, object collection );
		internal static ICollection GetAllElementsCollection( PersistentCollectionType collectionType, object collection )
		{
			return collectionType.GetElementsCollection( collection );
		}
		internal static ICollection GetLoadedElementsCollection( PersistentCollectionType collectionType, object collection )
		{
			if ( CollectionIsInitialized( collection ) )
			{
				// handles arrays and newly instantiated collections
				return collectionType.GetElementsCollection( collection );
			}
			else
			{
				// does not handle arrays (that's ok, cos they can't be lazy)
				// or newly instantiated collections so we can do the cast
				return ( (PersistentCollection) collection).QueuedAddsCollection;
			}
		}
		/// <summary>
		/// Cascade to the collection elements
		/// </summary>
		/// <param name="action"></param>
		/// <param name="style"></param>
		/// <param name="collectionType"></param>
		/// <param name="elemType"></param>
		/// <param name="child"></param>
		/// <param name="cascadeVia"></param>
		/// <param name="session"></param>
		/// <param name="anything"></param>
		private static void CascadeCollection(
			CascadingAction action,
			CascadeStyle style,
			PersistentCollectionType collectionType,
			IType elemType,
			object child,
			CascadePoint cascadeVia, 
			ISessionImplementor session,
			object anything )
		{
			// cascade to current collection elements
			if( log.IsDebugEnabled )
			{
				log.Debug( "cascading to collection: " + collectionType.Role );
			}
			ICollection iter = action.CascadableChildrenCollection( collectionType, child );
			foreach( object obj in iter )
			{
				Cascade( session, obj, elemType, action, style, cascadeVia, anything );
			}

			// handle oprhaned entities!!
			if( style.HasOrphanDelete && action.DeleteOrphans() && child is PersistentCollection )
			{
				// We can do the cast since orphan-delete does not apply to:
				// 1. newly instatiated collections
				// 2. arrays ( we can't track orphans for detached arrays)
				DeleteOrphans( child as PersistentCollection, session );
			}
		}
				public override ICollection CascadableChildrenCollection( PersistentCollectionType collectionType, object collection )
				{
					return Cascades.GetLoadedElementsCollection( collectionType, collection );
				}
				public override ICollection CascadableChildrenCollection( PersistentCollectionType collectionType, object collection )
				{
					// saves / updates don't cascade to uninitialized collections
					return Cascades.GetLoadedElementsCollection( collectionType, collection );
				}
		/// <summary>
		/// Visit a collection. Default superclass implementation is a no-op.
		/// </summary>
		/// <param name="collection"></param>
		/// <param name="type"></param>
		/// <returns></returns>
		protected virtual object ProcessCollection(object collection, PersistentCollectionType type)
		{
			return null;
		}
		internal void EvictCollection( object value, PersistentCollectionType type )
		{
			object pc;
			if( type.IsArrayType )
			{
				pc = arrayHolders[ value ];
				arrayHolders.Remove( value );
			}
			else if( value is PersistentCollection )
			{
				pc = value;
			}
			else
			{
				return; //EARLY EXIT!
			}

			PersistentCollection collection = pc as PersistentCollection;
			if( collection.UnsetSession( this ) )
			{
				EvictCollection( collection );
			}

		}