protected AbstractEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache,
																			ISessionFactoryImplementor factory)
		{
			this.factory = factory;
			this.cache = cache;
			isLazyPropertiesCacheable = persistentClass.IsLazyPropertiesCacheable;
			cacheEntryStructure = factory.Settings.IsStructuredCacheEntriesEnabled
															? (ICacheEntryStructure)new StructuredCacheEntry(this)
															: (ICacheEntryStructure)new UnstructuredCacheEntry();

			entityMetamodel = new EntityMetamodel(persistentClass, factory);

			if (persistentClass.HasPocoRepresentation)
			{
				//TODO: this is currently specific to pojos, but need to be available for all entity-modes
				foreach (Subclass subclass in persistentClass.SubclassIterator)
				{
					entityNameBySubclass[subclass.MappedClass] = subclass.EntityName;
				}
			}

			batchSize = persistentClass.BatchSize.HasValue ? persistentClass.BatchSize.Value : factory.Settings.DefaultBatchFetchSize;
			hasSubselectLoadableCollections = persistentClass.HasSubselectLoadableCollections;

			propertyMapping = new BasicEntityPropertyMapping(this);

			#region IDENTIFIER

			identifierColumnSpan = persistentClass.Identifier.ColumnSpan;
			rootTableKeyColumnNames = new string[identifierColumnSpan];
			identifierAliases = new string[identifierColumnSpan];

			rowIdName = persistentClass.RootTable.RowId;

			loaderName = persistentClass.LoaderName;

			// TODO NH: Not safe cast to Column
			int i = 0;
			foreach (Column col in persistentClass.Identifier.ColumnIterator)
			{
				rootTableKeyColumnNames[i] = col.GetQuotedName(factory.Dialect);
				identifierAliases[i] = col.GetAlias(factory.Dialect, persistentClass.RootTable);
				i++;
			}

			#endregion

			#region VERSION

			if (persistentClass.IsVersioned)
			{
				foreach (Column col in persistentClass.Version.ColumnIterator)
				{
					versionColumnName = col.GetQuotedName(factory.Dialect);
					break; //only happens once
				}
			}
			else
			{
				versionColumnName = null;
			}

			#endregion

			#region WHERE STRING

			sqlWhereString = !string.IsNullOrEmpty(persistentClass.Where) ? "( " + persistentClass.Where + ") " : null;
			sqlWhereStringTemplate = sqlWhereString == null
																? null
																: Template.RenderWhereStringTemplate(sqlWhereString, factory.Dialect,
																																		 factory.SQLFunctionRegistry);

			#endregion

			#region PROPERTIES

			// NH: see consistence with the implementation on EntityMetamodel where we are disabling lazy-properties for no lazy entities
			bool lazyAvailable = IsInstrumented(EntityMode.Poco) && entityMetamodel.IsLazy;

			int hydrateSpan = entityMetamodel.PropertySpan;
			propertyColumnSpans = new int[hydrateSpan];
			propertySubclassNames = new string[hydrateSpan];
			propertyColumnAliases = new string[hydrateSpan][];
			propertyColumnNames = new string[hydrateSpan][];
			propertyColumnFormulaTemplates = new string[hydrateSpan][];
			propertyUniqueness = new bool[hydrateSpan];
			propertySelectable = new bool[hydrateSpan];
			propertyColumnUpdateable = new bool[hydrateSpan][];
			propertyColumnInsertable = new bool[hydrateSpan][];
			var thisClassProperties = new HashSet<Property>();

			lazyProperties = new HashedSet<string>();
			List<string> lazyNames = new List<string>();
			List<int> lazyNumbers = new List<int>();
			List<IType> lazyTypes = new List<IType>();
			List<string[]> lazyColAliases = new List<string[]>();

			i = 0;
			bool foundFormula = false;
			foreach (Property prop in persistentClass.PropertyClosureIterator)
			{
				thisClassProperties.Add(prop);

				int span = prop.ColumnSpan;
				propertyColumnSpans[i] = span;
				propertySubclassNames[i] = prop.PersistentClass.EntityName;
				string[] colNames = new string[span];
				string[] colAliases = new string[span];
				string[] templates = new string[span];
				int k = 0;
				foreach (ISelectable thing in prop.ColumnIterator)
				{
					colAliases[k] = thing.GetAlias(factory.Dialect, prop.Value.Table);
					if (thing.IsFormula)
					{
						foundFormula = true;
						templates[k] = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
					}
					else
					{
						colNames[k] = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
					}
					k++;
				}
				propertyColumnNames[i] = colNames;
				propertyColumnFormulaTemplates[i] = templates;
				propertyColumnAliases[i] = colAliases;

				if (lazyAvailable && prop.IsLazy)
				{
					lazyProperties.Add(prop.Name);
					lazyNames.Add(prop.Name);
					lazyNumbers.Add(i);
					lazyTypes.Add(prop.Value.Type);
					lazyColAliases.Add(colAliases);
				}

				propertyColumnUpdateable[i] = prop.Value.ColumnUpdateability;
				propertyColumnInsertable[i] = prop.Value.ColumnInsertability;

				propertySelectable[i] = prop.IsSelectable;

				propertyUniqueness[i] = prop.Value.IsAlternateUniqueKey;

				i++;
			}
			hasFormulaProperties = foundFormula;
			lazyPropertyColumnAliases = lazyColAliases.ToArray();
			lazyPropertyNames = lazyNames.ToArray();
			lazyPropertyNumbers = lazyNumbers.ToArray();
			lazyPropertyTypes = lazyTypes.ToArray();

			#endregion

			#region SUBCLASS PROPERTY CLOSURE

			List<string> columns = new List<string>();
			List<bool> columnsLazy = new List<bool>();
			List<string> aliases = new List<string>();
			List<string> formulas = new List<string>();
			List<string> formulaAliases = new List<string>();
			List<string> formulaTemplates = new List<string>();
			List<bool> formulasLazy = new List<bool>();
			List<IType> types = new List<IType>();
			List<string> names = new List<string>();
			List<string> classes = new List<string>();
			List<string[]> templates2 = new List<string[]>();
			List<string[]> propColumns = new List<string[]>();
			List<FetchMode> joinedFetchesList = new List<FetchMode>();
			List<CascadeStyle> cascades = new List<CascadeStyle>();
			List<bool> definedBySubclass = new List<bool>();
			List<int[]> propColumnNumbers = new List<int[]>();
			List<int[]> propFormulaNumbers = new List<int[]>();
			List<bool> columnSelectables = new List<bool>();
			List<bool> propNullables = new List<bool>();

			foreach (Property prop in persistentClass.SubclassPropertyClosureIterator)
			{
				names.Add(prop.Name);
				classes.Add(prop.PersistentClass.EntityName);
				bool isDefinedBySubclass = !thisClassProperties.Contains(prop);
				definedBySubclass.Add(isDefinedBySubclass);
				propNullables.Add(prop.IsOptional || isDefinedBySubclass); //TODO: is this completely correct?
				types.Add(prop.Type);

				string[] cols = new string[prop.ColumnSpan];
				string[] forms = new string[prop.ColumnSpan];
				int[] colnos = new int[prop.ColumnSpan];
				int[] formnos = new int[prop.ColumnSpan];
				int l = 0;
				bool lazy = prop.IsLazy && lazyAvailable;
				foreach (ISelectable thing in prop.ColumnIterator)
				{
					if (thing.IsFormula)
					{
						string template = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
						formnos[l] = formulaTemplates.Count;
						colnos[l] = -1;
						formulaTemplates.Add(template);
						forms[l] = template;
						formulas.Add(thing.GetText(factory.Dialect));
						formulaAliases.Add(thing.GetAlias(factory.Dialect));
						formulasLazy.Add(lazy);
					}
					else
					{
						string colName = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
						colnos[l] = columns.Count; //before add :-)
						formnos[l] = -1;
						columns.Add(colName);
						cols[l] = colName;
						aliases.Add(thing.GetAlias(factory.Dialect, prop.Value.Table));
						columnsLazy.Add(lazy);
						columnSelectables.Add(prop.IsSelectable);
					}
					l++;
				}
				propColumns.Add(cols);
				templates2.Add(forms);
				propColumnNumbers.Add(colnos);
				propFormulaNumbers.Add(formnos);

				joinedFetchesList.Add(prop.Value.FetchMode);
				cascades.Add(prop.CascadeStyle);
			}
			subclassColumnClosure = columns.ToArray();
			subclassColumnAliasClosure = aliases.ToArray();
			subclassColumnLazyClosure = columnsLazy.ToArray();
			subclassColumnSelectableClosure = columnSelectables.ToArray();

			subclassFormulaClosure = formulas.ToArray();
			subclassFormulaTemplateClosure = formulaTemplates.ToArray();
			subclassFormulaAliasClosure = formulaAliases.ToArray();
			subclassFormulaLazyClosure = formulasLazy.ToArray();

			subclassPropertyNameClosure = names.ToArray();
			subclassPropertySubclassNameClosure = classes.ToArray();
			subclassPropertyTypeClosure = types.ToArray();
			subclassPropertyNullabilityClosure = propNullables.ToArray();
			subclassPropertyFormulaTemplateClosure = templates2.ToArray();
			subclassPropertyColumnNameClosure = propColumns.ToArray();
			subclassPropertyColumnNumberClosure = propColumnNumbers.ToArray();
			subclassPropertyFormulaNumberClosure = propFormulaNumbers.ToArray();

			subclassPropertyCascadeStyleClosure = cascades.ToArray();
			subclassPropertyFetchModeClosure = joinedFetchesList.ToArray();

			propertyDefinedOnSubclass = definedBySubclass.ToArray();

			#endregion

			// Handle any filters applied to the class level
			filterHelper = new FilterHelper(persistentClass.FilterMap, factory.Dialect, factory.SQLFunctionRegistry);

			temporaryIdTableName = persistentClass.TemporaryIdTableName;
			temporaryIdTableDDL = persistentClass.TemporaryIdTableDDL;
		}
		public AbstractCollectionPersister(Mapping.Collection collection, ICacheConcurrencyStrategy cache,
		                                   ISessionFactoryImplementor factory)
		{
			this.factory = factory;
			dialect = factory.Dialect;
			this.cache = cache;
			//sqlExceptionConverter = factory.SQLExceptionConverter;
			collectionType = collection.CollectionType;
			role = collection.Role;
			ownerClass = collection.OwnerClass;
			ownerPersister = factory.GetEntityPersister(ownerClass);
			queryLoaderName = collection.LoaderName;
			Alias alias = new Alias("__");

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

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

			hasOrphanDelete = collection.OrphanDelete;

			batchSize = collection.BatchSize;
			isVersioned = collection.IsOptimisticLocked;

			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.GetAlias(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;
			subselectLoadable = collection.IsSubselectLoadable;

			IValue element = collection.Element;
			int elementSpan = element.ColumnSpan;
			Table table = collection.CollectionTable;
			fetchMode = element.FetchMode;
			elementType = element.Type;

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

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

			qualifiedTableName = table.GetQualifiedName(dialect, factory.DefaultSchema);
			elementColumnAliases = new string[elementSpan];
			elementColumnNames = new string[elementSpan];
			elementFormulaTemplates = new string[elementSpan];
			elementFormulas = new string[elementSpan];
			elementColumnIsSettable = new bool[elementSpan];
			elementColumnIsInPrimaryKey = new bool[elementSpan];
			int j = 0;
			foreach (ISelectable selectable in element.ColumnCollection)
			{
				elementColumnAliases[j] = selectable.GetAlias(dialect);
				if (selectable.IsFormula)
				{
					Formula form = (Formula) selectable;
					elementFormulaTemplates[j] = form.GetTemplate(dialect, factory.SQLFunctionRegistry);
					elementFormulas[j] = form.FormulaString;
				}
				else
				{
					Column col = (Column) selectable;
					elementColumnNames[j] = col.GetQuotedName(dialect);
					elementColumnIsSettable[j] = true;
					elementColumnIsInPrimaryKey[j] = !col.IsNullable;
				}
				j++;
			}

			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.GetAlias(dialect);
					indexColumnNames[i] = indexCol.GetQuotedName(dialect);
					i++;
				}
				indexColumnAliases = alias.ToAliasStrings(indexAliases, dialect);
				CheckColumnDuplication(distinctColumns, indexedCollection.Index.ColumnCollection);
			}
			else
			{
				indexType = null;
				indexColumnNames = null;
				indexColumnAliases = null;
			}

			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);
				identifierColumnAlias = alias.ToAliasString(col.GetAlias(dialect), dialect);
				identifierGenerator = idColl.Identifier.CreateIdentifierGenerator(dialect);
				CheckColumnDuplication(distinctColumns, idColl.Identifier.ColumnCollection);
			}
			else
			{
				identifierType = null;
				identifierColumnName = null;
				identifierColumnAlias = null;
				identifierGenerator = null;
			}

			sqlInsertRowString = GenerateInsertRowString();
			if (collection.CustomSQLInsert == null)
			{
				insertCallable = false;
				insertCheckStyle = ExecuteUpdateResultCheckStyle.Count;
			}
			else
			{
				sqlInsertRowString = new SqlCommandInfo(collection.CustomSQLInsert, sqlInsertRowString.ParameterTypes);
				insertCallable = collection.IsCustomInsertCallable;
				insertCheckStyle = collection.CustomSQLInsertCheckStyle == null
				                   	? ExecuteUpdateResultCheckStyle.DetermineDefault(collection.CustomSQLInsert, insertCallable)
				                   	: collection.CustomSQLInsertCheckStyle;
			}

			sqlUpdateRowString = GenerateUpdateRowString();
			if (collection.CustomSQLUpdate == null)
			{
				updateCallable = false;
				updateCheckStyle = ExecuteUpdateResultCheckStyle.Count;
			}
			else
			{
				sqlUpdateRowString = new SqlCommandInfo(collection.CustomSQLUpdate, sqlUpdateRowString.ParameterTypes);
				updateCallable = collection.IsCustomUpdateCallable;
				updateCheckStyle = collection.CustomSQLUpdateCheckStyle == null
				                   	? ExecuteUpdateResultCheckStyle.DetermineDefault(collection.CustomSQLUpdate, updateCallable)
				                   	: collection.CustomSQLUpdateCheckStyle;
			}

			sqlDeleteRowString = GenerateDeleteRowString();
			if (collection.CustomSQLDelete == null)
			{
				deleteCallable = false;
				deleteCheckStyle = ExecuteUpdateResultCheckStyle.None;
			}
			else
			{
				sqlDeleteRowString = new SqlCommandInfo(collection.CustomSQLDelete, sqlDeleteRowString.ParameterTypes);
				deleteCallable = collection.IsCustomDeleteCallable;
				deleteCheckStyle = ExecuteUpdateResultCheckStyle.None;
			}

			sqlDeleteString = GenerateDeleteString();
			if (collection.CustomSQLDeleteAll == null)
			{
				deleteAllCallable = false;
				deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.None;
			}
			else
			{
				sqlDeleteString = new SqlCommandInfo(collection.CustomSQLDeleteAll, sqlDeleteString.ParameterTypes);
				deleteAllCallable = collection.IsCustomDeleteAllCallable;
				deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.None;
			}

			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;
			}

			if (elementType.IsComponentType)
			{
				elementPropertyMapping = new CompositeElementPropertyMapping(
					elementColumnNames, elementFormulaTemplates,
					(IAbstractComponentType) elementType, factory);
			}
			else if (!elementType.IsEntityType)
			{
				elementPropertyMapping = new ElementPropertyMapping(elementColumnNames, elementType);
			}
			else
			{
				IEntityPersister persister = factory.GetEntityPersister(((EntityType) elementType).AssociatedClass);
				// Not all classpersisters implement IPropertyMapping!
				if (persister is IPropertyMapping)
				{
					elementPropertyMapping = (IPropertyMapping) persister;
				}
				else
				{
					elementPropertyMapping = new ElementPropertyMapping(elementColumnNames, elementType);
				}
			}

			// Handle any filters applied to this collection
			filterHelper = new FilterHelper(collection.FilterMap, dialect, factory.SQLFunctionRegistry);

			// Handle any filters applied to this collection for many-to-many
			manyToManyFilterHelper = new FilterHelper(collection.ManyToManyFilterMap, dialect, factory.SQLFunctionRegistry);
			manyToManyWhereString = StringHelper.IsNotEmpty(collection.ManyToManyWhere) ?
			                        "( " + collection.ManyToManyWhere + " )" :
			                        null;
			manyToManyWhereTemplate = manyToManyWhereString == null
			                          	?
			                          null
			                          	:
			                          Template.RenderWhereStringTemplate(manyToManyWhereString, factory.Dialect,
			                                                             factory.SQLFunctionRegistry);
				// , factory.getSqlFunctionRegistry() );
			manyToManyOrderByString = collection.ManyToManyOrdering;
			manyToManyOrderByTemplate = manyToManyOrderByString == null
			                            	? null
			                            	: Template.RenderOrderByStringTemplate(manyToManyOrderByString, factory.Dialect,
			                            	                                       factory.SQLFunctionRegistry);
				// , factory.getSqlFunctionRegistry() );

			InitCollectionPropertyMap();
		}
		public AbstractCollectionPersister(Mapping.Collection collection, ICacheConcurrencyStrategy cache, Configuration cfg,
		                                   ISessionFactoryImplementor factory)
		{
			this.factory = factory;
			this.cache = cache;
			if (factory.Settings.IsStructuredCacheEntriesEnabled)
			{
				cacheEntryStructure = collection.IsMap
				                      	? (ICacheEntryStructure) new StructuredMapCacheEntry()
				                      	: (ICacheEntryStructure) new StructuredCollectionCacheEntry();
			}
			else
			{
				cacheEntryStructure = new UnstructuredCacheEntry();
			}

			dialect = factory.Dialect;
			sqlExceptionConverter = factory.SQLExceptionConverter;
			collectionType = collection.CollectionType;
			role = collection.Role;
			entityName = collection.OwnerEntityName;
			ownerPersister = factory.GetEntityPersister(entityName);
			queryLoaderName = collection.LoaderName;
			nodeName = collection.NodeName;
			isMutable = collection.IsMutable;

			Table table = collection.CollectionTable;
			fetchMode = collection.Element.FetchMode;
			elementType = collection.Element.Type;
			isPrimitiveArray = collection.IsPrimitiveArray;
			isArray = collection.IsArray;
			subselectLoadable = collection.IsSubselectLoadable;
			qualifiedTableName = table.GetQualifiedName(dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName);

			int spacesSize = 1 + collection.SynchronizedTables.Count;
			spaces = new string[spacesSize];
			int ispa = 0;
			spaces[ispa++] = qualifiedTableName;
			foreach (string s in collection.SynchronizedTables)
			{
				spaces[ispa++] = s;
			}

			sqlOrderByString = collection.OrderBy;
			hasOrder = sqlOrderByString != null;
			sqlOrderByStringTemplate = hasOrder
			                           	? Template.RenderOrderByStringTemplate(sqlOrderByString, dialect,
			                           	                                       factory.SQLFunctionRegistry)
			                           	: null;
			sqlWhereString = !string.IsNullOrEmpty(collection.Where) ? '(' + collection.Where + ')' : null;
			hasWhere = sqlWhereString != null;
			sqlWhereStringTemplate = hasWhere
			                         	? Template.RenderWhereStringTemplate(sqlWhereString, dialect, factory.SQLFunctionRegistry)
			                         	: null;
			hasOrphanDelete = collection.HasOrphanDelete;
			int batch = collection.BatchSize;
			if (batch == -1)
			{
				batch = factory.Settings.DefaultBatchFetchSize;
			}
			batchSize = batch;

			isVersioned = collection.IsOptimisticLocked;

			keyType = collection.Key.Type;
			int keySpan = collection.Key.ColumnSpan;
			keyColumnNames = new string[keySpan];
			keyColumnAliases = new string[keySpan];
			int k = 0;
			foreach (Column col in collection.Key.ColumnIterator)
			{
				keyColumnNames[k] = col.GetQuotedName(dialect);
				keyColumnAliases[k] = col.GetAlias(dialect);
				k++;
			}
			ISet distinctColumns = new HashedSet();
			CheckColumnDuplication(distinctColumns, collection.Key.ColumnIterator);

			#region Element

			IValue element = collection.Element;
			if (!collection.IsOneToMany)
			{
				CheckColumnDuplication(distinctColumns, element.ColumnIterator);
			}

			string elemNode = collection.ElementNodeName;
			if (elementType.IsEntityType)
			{
				string _entityName = ((EntityType) elementType).GetAssociatedEntityName();
				elementPersister = factory.GetEntityPersister(_entityName);
				if (elemNode == null)
				{
					elemNode = cfg.GetClassMapping(_entityName).NodeName;
				}
				// NativeSQL: collect element column and auto-aliases
			}
			else
			{
				elementPersister = null;
			}
			elementNodeName = elemNode;

			int elementSpan = element.ColumnSpan;
			elementColumnAliases = new string[elementSpan];
			elementColumnNames = new string[elementSpan];
			elementFormulaTemplates = new string[elementSpan];
			elementFormulas = new string[elementSpan];
			elementColumnIsSettable = new bool[elementSpan];
			elementColumnIsInPrimaryKey = new bool[elementSpan];
			bool isPureFormula = true;
			bool hasNotNullableColumns = false;
			int j = 0;
			foreach (ISelectable selectable in element.ColumnIterator)
			{
				elementColumnAliases[j] = selectable.GetAlias(dialect);
				if (selectable.IsFormula)
				{
					Formula form = (Formula) selectable;
					elementFormulaTemplates[j] = form.GetTemplate(dialect, factory.SQLFunctionRegistry);
					elementFormulas[j] = form.FormulaString;
				}
				else
				{
					Column col = (Column) selectable;
					elementColumnNames[j] = col.GetQuotedName(dialect);
					elementColumnIsSettable[j] = true;
					elementColumnIsInPrimaryKey[j] = !col.IsNullable;
					if (!col.IsNullable)
					{
						hasNotNullableColumns = true;
					}

					isPureFormula = false;
				}
				j++;
			}
			elementIsPureFormula = isPureFormula;

			//workaround, for backward compatibility of sets with no
			//not-null columns, assume all columns are used in the
			//row locator SQL
			if (!hasNotNullableColumns)
			{
				ArrayHelper.Fill(elementColumnIsInPrimaryKey, true);
			}

			#endregion

			#region INDEX AND ROW SELECT

			hasIndex = collection.IsIndexed;
			if (hasIndex)
			{
				// NativeSQL: collect index column and auto-aliases
				IndexedCollection indexedCollection = (IndexedCollection) collection;
				indexType = indexedCollection.Index.Type;
				int indexSpan = indexedCollection.Index.ColumnSpan;
				indexColumnNames = new string[indexSpan];
				indexFormulaTemplates = new string[indexSpan];
				indexFormulas = new string[indexSpan];
				indexColumnIsSettable = new bool[indexSpan];
				indexColumnAliases = new string[indexSpan];
				bool hasFormula = false;
				int i = 0;
				foreach (ISelectable selectable in indexedCollection.Index.ColumnIterator)
				{
					indexColumnAliases[i] = selectable.GetAlias(dialect);
					if (selectable.IsFormula)
					{
						Formula indexForm = (Formula) selectable;
						indexFormulaTemplates[i] = indexForm.GetTemplate(dialect, factory.SQLFunctionRegistry);
						indexFormulas[i] = indexForm.FormulaString;
						hasFormula = true;
					}
					else
					{
						Column indexCol = (Column) selectable;
						indexColumnNames[i] = indexCol.GetQuotedName(dialect);
						indexColumnIsSettable[i] = true;
					}
					i++;
				}
				indexContainsFormula = hasFormula;
				baseIndex = indexedCollection.IsList ? ((List) indexedCollection).BaseIndex : 0;

				indexNodeName = indexedCollection.IndexNodeName;
				CheckColumnDuplication(distinctColumns, indexedCollection.Index.ColumnIterator);
			}
			else
			{
				indexContainsFormula = false;
				indexColumnIsSettable = null;
				indexFormulaTemplates = null;
				indexFormulas = null;
				indexType = null;
				indexColumnNames = null;
				indexColumnAliases = null;
				baseIndex = 0;
				indexNodeName = null;
			}

			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.ColumnIterator)
				{
					col = column;
					break;
				}

				identifierColumnName = col.GetQuotedName(dialect);
				identifierColumnAlias = col.GetAlias(dialect);
				identifierGenerator =
					idColl.Identifier.CreateIdentifierGenerator(factory.Dialect, factory.Settings.DefaultCatalogName,
					                                            factory.Settings.DefaultSchemaName, null);
				// NH see : identityDelegate declaration
				IPostInsertIdentifierGenerator pig = (identifierGenerator as IPostInsertIdentifierGenerator);
				if (pig != null)
				{
					identityDelegate = pig.GetInsertGeneratedIdentifierDelegate(this, Factory, UseGetGeneratedKeys());
				}
				else
				{
					identityDelegate = null;
				}

				CheckColumnDuplication(distinctColumns, idColl.Identifier.ColumnIterator);
			}
			else
			{
				identifierType = null;
				identifierColumnName = null;
				identifierColumnAlias = null;
				identifierGenerator = null;
				identityDelegate = null;
			}

			#endregion

			#region GENERATE THE SQL

			// NH Different behavior : for the Insert SQL we are managing isPostInsertIdentifier (not supported in H3.2.5) 
			if (collection.CustomSQLInsert == null)
			{
				if (!IsIdentifierAssignedByInsert)
				{
					sqlInsertRowString = GenerateInsertRowString();
				}
				else
				{
					sqlInsertRowString = GenerateIdentityInsertRowString();
				}
				insertCallable = false;
				insertCheckStyle = ExecuteUpdateResultCheckStyle.Count;
			}
			else
			{
				SqlType[] parmsTypes = GenerateInsertRowString().ParameterTypes;
				sqlInsertRowString = new SqlCommandInfo(collection.CustomSQLInsert, parmsTypes);
				insertCallable = collection.IsCustomInsertCallable;
				insertCheckStyle = collection.CustomSQLInsertCheckStyle
				                   ?? ExecuteUpdateResultCheckStyle.DetermineDefault(collection.CustomSQLInsert, insertCallable);
			}

			sqlUpdateRowString = GenerateUpdateRowString();
			if (collection.CustomSQLUpdate == null)
			{
				updateCallable = false;
				updateCheckStyle = ExecuteUpdateResultCheckStyle.Count;
			}
			else
			{
				sqlUpdateRowString = new SqlCommandInfo(collection.CustomSQLUpdate, sqlUpdateRowString.ParameterTypes);
				updateCallable = collection.IsCustomUpdateCallable;
				updateCheckStyle = collection.CustomSQLUpdateCheckStyle
				                   ?? ExecuteUpdateResultCheckStyle.DetermineDefault(collection.CustomSQLUpdate, updateCallable);
			}

			sqlDeleteRowString = GenerateDeleteRowString();
			if (collection.CustomSQLDelete == null)
			{
				deleteCallable = false;
				deleteCheckStyle = ExecuteUpdateResultCheckStyle.None;
			}
			else
			{
				sqlDeleteRowString = new SqlCommandInfo(collection.CustomSQLDelete, sqlDeleteRowString.ParameterTypes);
				deleteCallable = collection.IsCustomDeleteCallable;
				deleteCheckStyle = ExecuteUpdateResultCheckStyle.None;
			}

			sqlDeleteString = GenerateDeleteString();
			if (collection.CustomSQLDeleteAll == null)
			{
				deleteAllCallable = false;
				deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.None;
			}
			else
			{
				sqlDeleteString = new SqlCommandInfo(collection.CustomSQLDeleteAll, sqlDeleteString.ParameterTypes);
				deleteAllCallable = collection.IsCustomDeleteAllCallable;
				deleteAllCheckStyle = ExecuteUpdateResultCheckStyle.None;
			}

		    isCollectionIntegerIndex = collection.IsIndexed && !collection.IsMap;
			sqlDetectRowByIndexString = GenerateDetectRowByIndexString();
			sqlDetectRowByElementString = GenerateDetectRowByElementString();
			sqlSelectRowByIndexString = GenerateSelectRowByIndexString();

			LogStaticSQL();

			#endregion

			isLazy = collection.IsLazy;
			isExtraLazy = collection.ExtraLazy;
			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;
			}

			if (elementType.IsComponentType)
			{
				elementPropertyMapping =
					new CompositeElementPropertyMapping(elementColumnNames, elementFormulaTemplates,
					                                    (IAbstractComponentType) elementType, factory);
			}
			else if (!elementType.IsEntityType)
			{
				elementPropertyMapping = new ElementPropertyMapping(elementColumnNames, elementType);
			}
			else
			{
				elementPropertyMapping = elementPersister as IPropertyMapping;
				if (elementPropertyMapping == null)
				{
					elementPropertyMapping = new ElementPropertyMapping(elementColumnNames, elementType);
				}
			}

			// Handle any filters applied to this collection
			filterHelper = new FilterHelper(collection.FilterMap, dialect, factory.SQLFunctionRegistry);

			// Handle any filters applied to this collection for many-to-many
			manyToManyFilterHelper = new FilterHelper(collection.ManyToManyFilterMap, dialect, factory.SQLFunctionRegistry);
			manyToManyWhereString = !string.IsNullOrEmpty(collection.ManyToManyWhere)
			                        	? "( " + collection.ManyToManyWhere + " )"
			                        	: null;
			manyToManyWhereTemplate = manyToManyWhereString == null
			                          	? null
			                          	: Template.RenderWhereStringTemplate(manyToManyWhereString, factory.Dialect,
			                          	                                     factory.SQLFunctionRegistry);
			manyToManyOrderByString = collection.ManyToManyOrdering;
			manyToManyOrderByTemplate = manyToManyOrderByString == null
			                            	? null
			                            	: Template.RenderOrderByStringTemplate(manyToManyOrderByString, factory.Dialect,
			                            	                                       factory.SQLFunctionRegistry);
			InitCollectionPropertyMap();
		}
		protected AbstractEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache,
		                                  ISessionFactoryImplementor factory)
		{
			this.factory = factory;
			dialect = factory.Dialect;
			this.cache = cache;
			//sqlExceptionConverter = factory.SQLExceptionConverter;

			entityMetamodel = new EntityMetamodel(persistentClass, factory);

			// CLASS
			mappedClass = persistentClass.MappedClass;

			sqlWhereString = persistentClass.Where;
			sqlWhereStringTemplate = sqlWhereString == null
			                         	?
			                         null
			                         	:
			                         Template.RenderWhereStringTemplate(sqlWhereString, Dialect, factory.SQLFunctionRegistry);

			batchSize = persistentClass.BatchSize;
			hasSubselectLoadableCollections = persistentClass.HasSubselectLoadableCollections;
			constructor = ReflectHelper.GetDefaultConstructor(mappedClass);

			// verify that the class has a default constructor if it is not abstract - it is considered
			// a mapping exception if the default ctor is missing.
			if (!entityMetamodel.IsAbstract && constructor == null)
			{
				throw new MappingException("The mapped class " + mappedClass.FullName +
				                           " must declare a default (no-arg) constructor.");
			}

			// IDENTIFIER
			hasEmbeddedIdentifier = persistentClass.HasEmbeddedIdentifier;
			IValue idValue = persistentClass.Identifier;

			if (persistentClass.HasIdentifierProperty)
			{
				Mapping.Property idProperty = persistentClass.IdentifierProperty;
				identifierSetter = idProperty.GetSetter(mappedClass);
				identifierGetter = idProperty.GetGetter(mappedClass);
			}
			else
			{
				identifierGetter = null;
				identifierSetter = null;
			}

			System.Type prox = persistentClass.ProxyInterface;
			MethodInfo proxySetIdentifierMethod = null;
			MethodInfo proxyGetIdentifierMethod = null;

			if (persistentClass.HasIdentifierProperty && prox != null)
			{
				Mapping.Property idProperty = persistentClass.IdentifierProperty;
				proxyGetIdentifierMethod = idProperty.GetGetter(prox).Method;
				proxySetIdentifierMethod = idProperty.GetSetter(prox).Method;
			}

			// HYDRATE SPAN
			hydrateSpan = persistentClass.PropertyClosureCollection.Count;

			// IDENTIFIER 

			identifierColumnSpan = persistentClass.Identifier.ColumnSpan;
			rootTableKeyColumnNames = new string[identifierColumnSpan];
			identifierAliases = new string[identifierColumnSpan];

			loaderName = persistentClass.LoaderName;

			int i = 0;
			foreach (Column col in idValue.ColumnCollection)
			{
				rootTableKeyColumnNames[i] = col.GetQuotedName(factory.Dialect);
				identifierAliases[i] = col.GetAlias(Dialect, persistentClass.RootTable);
				i++;
			}

			// VERSION:

			if (persistentClass.IsVersioned)
			{
				foreach (Column col in persistentClass.Version.ColumnCollection)
				{
					versionColumnName = col.GetQuotedName(Dialect);
					break; //only happens once
				}
			}
			else
			{
				versionColumnName = null;
			}

			if (persistentClass.IsVersioned)
			{
				versionGetter = persistentClass.Version.GetGetter(mappedClass);
				versionType = (IVersionType) persistentClass.Version.Type;
			}
			else
			{
				versionGetter = null;
				versionType = null;
			}

			// PROPERTIES 

			getters = new IGetter[hydrateSpan];
			setters = new ISetter[hydrateSpan];
			string[] setterNames = new string[hydrateSpan];
			string[] getterNames = new string[hydrateSpan];
			System.Type[] classes = new System.Type[hydrateSpan];

			i = 0;

			// NH: reflection optimizer works with custom accessors
			//bool foundCustomAccessor = false;

			foreach (Mapping.Property prop in persistentClass.PropertyClosureCollection)
			{
				//if( !prop.IsBasicPropertyAccessor )
				//{
				//	foundCustomAccessor = true;
				//}

				getters[i] = prop.GetGetter(mappedClass);
				setters[i] = prop.GetSetter(mappedClass);
				getterNames[i] = getters[i].PropertyName;
				setterNames[i] = setters[i].PropertyName;
				classes[i] = getters[i].ReturnType;

				string propertyName = prop.Name;
				gettersByPropertyName[propertyName] = getters[i];
				settersByPropertyName[propertyName] = setters[i];

				i++;
			}

			// PROPERTIES (FROM ABSTRACTENTITYPERSISTER SUBCLASSES)
			propertyColumnNames = new string[HydrateSpan][];
			propertyColumnAliases = new string[HydrateSpan][];
			propertyColumnSpans = new int[HydrateSpan];
			propertyColumnFormulaTemplates = new string[HydrateSpan][];
			propertyColumnUpdateable = new bool[HydrateSpan][];
			propertyColumnInsertable = new bool[HydrateSpan][];
			propertyUniqueness = new bool[HydrateSpan];

			HashedSet thisClassProperties = new HashedSet();
			i = 0;
			bool foundFormula = false;

			foreach (Mapping.Property prop in persistentClass.PropertyClosureCollection)
			{
				thisClassProperties.Add(prop);

				int span = prop.ColumnSpan;
				propertyColumnSpans[i] = span;
				string[] colNames = new string[span];
				string[] colAliases = new string[span];
				string[] templates = new string[span];

				int k = 0;
				foreach (ISelectable thing in prop.ColumnCollection)
				{
					colAliases[k] = thing.GetAlias(factory.Dialect, prop.Value.Table);
					if (thing.IsFormula)
					{
						foundFormula = true;
						templates[k] = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
					}
					else
					{
						colNames[k] = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
					}
					k++;
				}
				propertyColumnNames[i] = colNames;
				propertyColumnFormulaTemplates[i] = templates;
				propertyColumnAliases[i] = colAliases;
				propertyColumnInsertable[i] = prop.Value.ColumnInsertability;
				propertyColumnUpdateable[i] = prop.Value.ColumnUpdateability;
				propertyUniqueness[i] = prop.Value.IsUnique;

				i++;
			}

			hasFormulaProperties = foundFormula;

			// NH: reflection optimizer works with custom accessors
			if (Environment.UseReflectionOptimizer)
			{
				optimizer = Environment.BytecodeProvider.GetReflectionOptimizer(MappedClass, Getters, Setters);
			}

			// SUBCLASS PROPERTY CLOSURE

			ArrayList columns = new ArrayList(); //this.subclassColumnClosure
			ArrayList aliases = new ArrayList();
			ArrayList formulaAliases = new ArrayList();
			ArrayList formulaTemplates = new ArrayList();
			ArrayList types = new ArrayList(); //this.subclassPropertyTypeClosure
			ArrayList names = new ArrayList(); //this.subclassPropertyNameClosure
			ArrayList subclassTemplates = new ArrayList();
			ArrayList propColumns = new ArrayList(); //this.subclassPropertyColumnNameClosure
			ArrayList joinedFetchesList = new ArrayList(); //this.subclassPropertyEnableJoinedFetch
			ArrayList cascades = new ArrayList();
			ArrayList definedBySubclass = new ArrayList(); // this.propertyDefinedOnSubclass
			ArrayList formulas = new ArrayList();
			ArrayList propNullables = new ArrayList();

			foreach (Mapping.Property prop in persistentClass.SubclassPropertyClosureCollection)
			{
				names.Add(prop.Name);
				bool isDefinedBySubclass = !thisClassProperties.Contains(prop);
				definedBySubclass.Add(isDefinedBySubclass);
				propNullables.Add(prop.IsOptional || isDefinedBySubclass); //TODO: is this completely correct?
				types.Add(prop.Type);

				string[] cols = new string[prop.ColumnSpan];
				string[] forms = new string[prop.ColumnSpan];
				int[] colnos = new int[prop.ColumnSpan];
				int[] formnos = new int[prop.ColumnSpan];
				int l = 0;

				foreach (ISelectable thing in prop.ColumnCollection)
				{
					if (thing.IsFormula)
					{
						string template = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
						formnos[l] = formulaTemplates.Count;
						colnos[l] = -1;
						formulaTemplates.Add(template);
						forms[l] = template;
						formulas.Add(thing.GetText(factory.Dialect));
						formulaAliases.Add(thing.GetAlias(factory.Dialect));
						// TODO H3: formulasLazy.add( lazy );
					}
					else
					{
						String colName = thing.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
						colnos[l] = columns.Count; //before add :-)
						formnos[l] = -1;
						columns.Add(colName);
						cols[l] = colName;
						aliases.Add(thing.GetAlias(factory.Dialect, prop.Value.Table));
						// TODO H3: columnsLazy.add( lazy );
						// TODO H3: columnSelectables.add( new Boolean( prop.isSelectable() ) );
					}
					l++;
				}

				propColumns.Add(cols);
				subclassTemplates.Add(forms);
				//propColumnNumbers.Add( colnos );
				//propFormulaNumbers.Add( formnos );

				joinedFetchesList.Add(prop.Value.FetchMode);
				cascades.Add(prop.CascadeStyle);
			}

			subclassColumnClosure = (string[]) columns.ToArray(typeof(string));
			subclassFormulaClosure = (string[]) formulas.ToArray(typeof(string));
			subclassFormulaTemplateClosure = (string[]) formulaTemplates.ToArray(typeof(string));
			subclassPropertyTypeClosure = (IType[]) types.ToArray(typeof(IType));
			subclassColumnAliasClosure = (string[]) aliases.ToArray(typeof(string));
			subclassFormulaAliasClosure = (string[]) formulaAliases.ToArray(typeof(string));
			subclassPropertyNameClosure = (string[]) names.ToArray(typeof(string));
			subclassPropertyNullabilityClosure = (bool[]) propNullables.ToArray(typeof(bool));
			subclassPropertyFormulaTemplateClosure = ArrayHelper.To2DStringArray(subclassTemplates);
			subclassPropertyColumnNameClosure = (string[][]) propColumns.ToArray(typeof(string[]));

			subclassPropertyCascadeStyleClosure = new Cascades.CascadeStyle[cascades.Count];
			int m = 0;
			foreach (Cascades.CascadeStyle cs in cascades)
			{
				subclassPropertyCascadeStyleClosure[m++] = cs;
			}

			subclassPropertyFetchModeClosure = new FetchMode[joinedFetchesList.Count];
			m = 0;
			foreach (FetchMode qq in joinedFetchesList)
			{
				subclassPropertyFetchModeClosure[m++] = qq;
			}

			propertyDefinedOnSubclass = new bool[definedBySubclass.Count];
			m = 0;
			foreach (bool val in definedBySubclass)
			{
				propertyDefinedOnSubclass[m++] = val;
			}

			// CALLBACK INTERFACES
			implementsLifecycle = typeof(ILifecycle).IsAssignableFrom(mappedClass);
			implementsValidatable = typeof(IValidatable).IsAssignableFrom(mappedClass);

			// PROXIES
			concreteProxyClass = persistentClass.ProxyInterface;
			bool hasProxy = concreteProxyClass != null;

			if (hasProxy)
			{
				HashedSet proxyInterfaces = new HashedSet();
				proxyInterfaces.Add(typeof(INHibernateProxy));

				if (!mappedClass.Equals(concreteProxyClass))
				{
					if (!concreteProxyClass.IsInterface)
					{
						throw new MappingException(
							"proxy must be either an interface, or the class itself: " +
							mappedClass.FullName);
					}

					proxyInterfaces.Add(concreteProxyClass);
				}

				if (mappedClass.IsInterface)
				{
					proxyInterfaces.Add(mappedClass);
				}

				if (HasProxy)
				{
					foreach (Subclass subclass in persistentClass.SubclassCollection)
					{
						System.Type subclassProxy = subclass.ProxyInterface;
						if (subclassProxy == null)
						{
							throw new MappingException("All subclasses must also have proxies: "
							                           + mappedClass.Name);
						}

						if (!subclass.MappedClass.Equals(subclassProxy))
						{
							proxyInterfaces.Add(subclassProxy);
						}
					}
				}

				if (HasProxy)
				{
					proxyFactory = CreateProxyFactory();
					proxyFactory.PostInstantiate(mappedClass, proxyInterfaces, proxyGetIdentifierMethod, proxySetIdentifierMethod);
				}
				else
				{
					proxyFactory = null;
				}
			}
			else
			{
				proxyFactory = null;
			}

			// Handle any filters applied to the class level
			filterHelper = new FilterHelper(persistentClass.FilterMap, factory.Dialect, factory.SQLFunctionRegistry);
		}