public static IExpectation AppropriateExpectation(ExecuteUpdateResultCheckStyle style)
		{
			if (style == ExecuteUpdateResultCheckStyle.None)
			{
				return None;
			}
			else if (style == ExecuteUpdateResultCheckStyle.Count)
			{
				return Basic;
			}
			else
			{
				throw new HibernateException("unknown check style : " + style);
			}
		}
Example #2
0
 public void SetCustomSQLUpdate(string sql, bool callable, ExecuteUpdateResultCheckStyle checkStyle)
 {
     customSQLUpdate = SqlString.Parse(sql);
     customUpdateCallable = callable;
     updateCheckStyle = checkStyle;
 }
Example #3
0
 public void SetCustomSQLInsert(string sql, bool callable, ExecuteUpdateResultCheckStyle checkStyle)
 {
     customSQLInsert = SqlString.Parse(sql);
     customInsertCallable = callable;
     insertCheckStyle = checkStyle;
 }
		public SingleTableEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache,
																			ISessionFactoryImplementor factory, IMapping mapping)
			: base(persistentClass, cache, factory)
		{
			#region CLASS + TABLE

			joinSpan = persistentClass.JoinClosureSpan + 1;
			qualifiedTableNames = new string[joinSpan];
			isInverseTable = new bool[joinSpan];
			isNullableTable = new bool[joinSpan];
			keyColumnNames = new string[joinSpan][];
			Table table = persistentClass.RootTable;
			qualifiedTableNames[0] =
				table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName);
			isInverseTable[0] = false;
			isNullableTable[0] = false;
			keyColumnNames[0] = IdentifierColumnNames;
			cascadeDeleteEnabled = new bool[joinSpan];

			// Custom sql
			customSQLInsert = new SqlString[joinSpan];
			customSQLUpdate = new SqlString[joinSpan];
			customSQLDelete = new SqlString[joinSpan];
			insertCallable = new bool[joinSpan];
			updateCallable = new bool[joinSpan];
			deleteCallable = new bool[joinSpan];
			insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
			updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
			deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];

			customSQLInsert[0] = persistentClass.CustomSQLInsert;
			insertCallable[0] = customSQLInsert[0] != null && persistentClass.IsCustomInsertCallable;
			insertResultCheckStyles[0] = persistentClass.CustomSQLInsertCheckStyle
																	 ?? ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLInsert[0], insertCallable[0]);
			customSQLUpdate[0] = persistentClass.CustomSQLUpdate;
			updateCallable[0] = customSQLUpdate[0] != null && persistentClass.IsCustomUpdateCallable;
			updateResultCheckStyles[0] = persistentClass.CustomSQLUpdateCheckStyle
																	 ?? ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLUpdate[0], updateCallable[0]);
			customSQLDelete[0] = persistentClass.CustomSQLDelete;
			deleteCallable[0] = customSQLDelete[0] != null && persistentClass.IsCustomDeleteCallable;
			deleteResultCheckStyles[0] = persistentClass.CustomSQLDeleteCheckStyle
																	 ?? ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLDelete[0], deleteCallable[0]);

			#endregion

			#region JOINS
			int j = 1;
			foreach (Join join in persistentClass.JoinClosureIterator)
			{
				qualifiedTableNames[j] = join.Table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName);
				isInverseTable[j] = join.IsInverse;
				isNullableTable[j] = join.IsOptional;
				cascadeDeleteEnabled[j] = join.Key.IsCascadeDeleteEnabled && factory.Dialect.SupportsCascadeDelete;

				customSQLInsert[j] = join.CustomSQLInsert;
				insertCallable[j] = customSQLInsert[j] != null && join.IsCustomInsertCallable;
				insertResultCheckStyles[j] = join.CustomSQLInsertCheckStyle
																		 ??
																		 ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLInsert[j], insertCallable[j]);
				customSQLUpdate[j] = join.CustomSQLUpdate;
				updateCallable[j] = customSQLUpdate[j] != null && join.IsCustomUpdateCallable;
				updateResultCheckStyles[j] = join.CustomSQLUpdateCheckStyle
																		 ??
																		 ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLUpdate[j], updateCallable[j]);
				customSQLDelete[j] = join.CustomSQLDelete;
				deleteCallable[j] = customSQLDelete[j] != null && join.IsCustomDeleteCallable;
				deleteResultCheckStyles[j] = join.CustomSQLDeleteCheckStyle
																		 ??
																		 ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLDelete[j], deleteCallable[j]);

				IEnumerable<Column> enumerableKeyCol = new SafetyEnumerable<Column>(join.Key.ColumnIterator);
				List<string> kcName = new List<string>(join.Key.ColumnSpan);
				foreach (Column col in enumerableKeyCol)
					kcName.Add(col.GetQuotedName(factory.Dialect));

				keyColumnNames[j] = kcName.ToArray();

				j++;
			}

			constraintOrderedTableNames = new string[qualifiedTableNames.Length];
			constraintOrderedKeyColumnNames = new string[qualifiedTableNames.Length][];
			for (int i = qualifiedTableNames.Length - 1, position = 0; i >= 0; i--, position++)
			{
				constraintOrderedTableNames[position] = qualifiedTableNames[i];
				constraintOrderedKeyColumnNames[position] = keyColumnNames[i];
			}

			spaces = ArrayHelper.Join(qualifiedTableNames, ArrayHelper.ToStringArray(persistentClass.SynchronizedTables));

			bool lazyAvailable = IsInstrumented(EntityMode.Poco);

			bool hasDeferred = false;
			List<string> subclassTables = new List<string>();
			List<string[]> joinKeyColumns = new List<string[]>();
			List<bool> isConcretes = new List<bool>();
			List<bool> isDeferreds = new List<bool>();
			List<bool> isInverses = new List<bool>();
			List<bool> isNullables = new List<bool>();
			List<bool> isLazies = new List<bool>();
			subclassTables.Add(qualifiedTableNames[0]);
			joinKeyColumns.Add(IdentifierColumnNames);
			isConcretes.Add(true);
			isDeferreds.Add(false);
			isInverses.Add(false);
			isNullables.Add(false);
			isLazies.Add(false);
			foreach (Join join in persistentClass.SubclassJoinClosureIterator)
			{
				isConcretes.Add(persistentClass.IsClassOrSuperclassJoin(join));
				isDeferreds.Add(join.IsSequentialSelect);
				isInverses.Add(join.IsInverse);
				isNullables.Add(join.IsOptional);
				isLazies.Add(lazyAvailable && join.IsLazy);
				if (join.IsSequentialSelect && !persistentClass.IsClassOrSuperclassJoin(join))
					hasDeferred = true;
				subclassTables.Add(join.Table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName));
				IEnumerable<Column> enumerableKeyCol = new SafetyEnumerable<Column>(join.Key.ColumnIterator);
				List<string> keyCols = new List<string>(join.Key.ColumnSpan);
				foreach (Column col in enumerableKeyCol)
					keyCols.Add(col.GetQuotedName(factory.Dialect));

				joinKeyColumns.Add(keyCols.ToArray());
			}

			subclassTableSequentialSelect = isDeferreds.ToArray();
			subclassTableNameClosure = subclassTables.ToArray();
			subclassTableIsLazyClosure = isLazies.ToArray();
			subclassTableKeyColumnClosure = joinKeyColumns.ToArray();
			isClassOrSuperclassTable = isConcretes.ToArray();
			isInverseSubclassTable = isInverses.ToArray();
			isNullableSubclassTable = isNullables.ToArray();
			hasSequentialSelects = hasDeferred;

			#endregion

			#region DISCRIMINATOR

			if (persistentClass.IsPolymorphic)
			{
				IValue discrimValue = persistentClass.Discriminator;
				if (discrimValue == null)
					throw new MappingException("Discriminator mapping required for single table polymorphic persistence");

				forceDiscriminator = persistentClass.IsForceDiscriminator;
				IEnumerator<ISelectable> iSel = discrimValue.ColumnIterator.GetEnumerator();
				iSel.MoveNext();
				ISelectable selectable = iSel.Current;
				if (discrimValue.HasFormula)
				{
					Formula formula = (Formula)selectable;
					discriminatorFormula = formula.FormulaString;
					discriminatorFormulaTemplate = formula.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
					discriminatorColumnName = null;
					discriminatorAlias = Discriminator_Alias;
				}
				else
				{
					Column column = (Column)selectable;
					discriminatorColumnName = column.GetQuotedName(factory.Dialect);
					discriminatorAlias = column.GetAlias(factory.Dialect, persistentClass.RootTable);
					discriminatorFormula = null;
					discriminatorFormulaTemplate = null;
				}
				discriminatorType = persistentClass.Discriminator.Type;
				if (persistentClass.IsDiscriminatorValueNull)
				{
					discriminatorValue = NullDiscriminator;
					discriminatorSQLValue = InFragment.Null;
					discriminatorInsertable = false;
				}
				else if (persistentClass.IsDiscriminatorValueNotNull)
				{
					discriminatorValue = NotNullDiscriminator;
					discriminatorSQLValue = InFragment.NotNull;
					discriminatorInsertable = false;
				}
				else
				{
					discriminatorInsertable = persistentClass.IsDiscriminatorInsertable && !discrimValue.HasFormula;
					try
					{
						IDiscriminatorType dtype = (IDiscriminatorType)discriminatorType;
						discriminatorValue = dtype.StringToObject(persistentClass.DiscriminatorValue);
						discriminatorSQLValue = dtype.ObjectToSQLString(discriminatorValue, factory.Dialect);
					}
					catch (InvalidCastException cce)
					{
						throw new MappingException(
							string.Format("Illegal discriminator type: {0} of entity {1}", discriminatorType.Name, persistentClass.EntityName), cce);
					}
					catch (Exception e)
					{
						throw new MappingException("Could not format discriminator value to SQL string of entity " + persistentClass.EntityName, e);
					}
				}
			}
			else
			{
				forceDiscriminator = false;
				discriminatorInsertable = false;
				discriminatorColumnName = null;
				discriminatorAlias = null;
				discriminatorType = null;
				discriminatorValue = null;
				discriminatorSQLValue = null;
				discriminatorFormula = null;
				discriminatorFormulaTemplate = null;
			}

			#endregion

			#region PROPERTIES

			propertyTableNumbers = new int[PropertySpan];
			int i2 = 0;
			foreach (Property prop in persistentClass.PropertyClosureIterator)
			{
				propertyTableNumbers[i2++] = persistentClass.GetJoinNumber(prop);
			}

			List<int> columnJoinNumbers = new List<int>();
			List<int> formulaJoinedNumbers = new List<int>();
			List<int> propertyJoinNumbers = new List<int>();
			foreach (Property prop in persistentClass.SubclassPropertyClosureIterator)
			{
				int join = persistentClass.GetJoinNumber(prop);
				propertyJoinNumbers.Add(join);

				//propertyTableNumbersByName.put( prop.getName(), join );
				propertyTableNumbersByNameAndSubclass[prop.PersistentClass.EntityName + '.' + prop.Name] = join;
				foreach (ISelectable thing in prop.ColumnIterator)
				{
					if (thing.IsFormula)
						formulaJoinedNumbers.Add(join);
					else
						columnJoinNumbers.Add(join);
				}
			}

			subclassColumnTableNumberClosure = columnJoinNumbers.ToArray();
			subclassFormulaTableNumberClosure = formulaJoinedNumbers.ToArray();
			subclassPropertyTableNumberClosure = propertyJoinNumbers.ToArray();

			int subclassSpan = persistentClass.SubclassSpan + 1;
			subclassClosure = new string[subclassSpan];
			subclassClosure[0] = EntityName;
			if (persistentClass.IsPolymorphic)
				subclassesByDiscriminatorValue[discriminatorValue] = EntityName;

			#endregion

			#region SUBCLASSES
			if (persistentClass.IsPolymorphic)
			{
				int k = 1;
				foreach (Subclass sc in persistentClass.SubclassIterator)
				{
					subclassClosure[k++] = sc.EntityName;
					if (sc.IsDiscriminatorValueNull)
					{
						subclassesByDiscriminatorValue[NullDiscriminator] = sc.EntityName;
					}
					else if (sc.IsDiscriminatorValueNotNull)
					{
						subclassesByDiscriminatorValue[NotNullDiscriminator] = sc.EntityName;
					}
					else
					{
						if (discriminatorType == null)
							throw new MappingException("Not available discriminator type of entity " + persistentClass.EntityName);
						try
						{
							IDiscriminatorType dtype = (IDiscriminatorType)discriminatorType;
							subclassesByDiscriminatorValue[dtype.StringToObject(sc.DiscriminatorValue)] = sc.EntityName;
						}
						catch (InvalidCastException cce)
						{
							throw new MappingException(
								string.Format("Illegal discriminator type: {0} of entity {1}", discriminatorType.Name, persistentClass.EntityName), cce);
						}
						catch (Exception e)
						{
							throw new MappingException("Error parsing discriminator value of entity " + persistentClass.EntityName, e);
						}
					}
				}
			}

			#endregion

			InitLockers();

			InitSubclassPropertyAliasesMap(persistentClass);

			PostConstruct(mapping);
		}
Example #5
0
		public void SetCustomSQLDeleteAll(string sql, bool callable, ExecuteUpdateResultCheckStyle checkStyle)
		{
			customSQLDeleteAll = SqlString.Parse(sql);
			customDeleteAllCallable = callable;
			deleteAllCheckStyle = checkStyle;
		}
		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();
		}
		/// <summary>
		/// Constructs the NormalizedEntityPerister for the PersistentClass.
		/// </summary>
		/// <param name="persistentClass">The PersistentClass to create the EntityPersister for.</param>
		/// <param name="cache">The configured <see cref="ICacheConcurrencyStrategy" />.</param>
		/// <param name="factory">The SessionFactory that this EntityPersister will be stored in.</param>
		/// <param name="mapping">The mapping used to retrieve type information.</param>
		public JoinedSubclassEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache,
											 ISessionFactoryImplementor factory, IMapping mapping)
			: base(persistentClass, cache, factory)
		{
			#region DISCRIMINATOR

			if (persistentClass.IsPolymorphic)
			{
				try
				{
					discriminatorValue = persistentClass.SubclassId;
					discriminatorSQLString = discriminatorValue.ToString();
				}
				catch (Exception e)
				{
					throw new MappingException("Could not format discriminator value to SQL string", e);
				}
			}
			else
			{
				discriminatorValue = null;
				discriminatorSQLString = null;
			}

			if (OptimisticLockMode > Versioning.OptimisticLock.Version)
				throw new MappingException(string.Format("optimistic-lock=all|dirty not supported for joined-subclass mappings [{0}]", EntityName));

			#endregion

			#region MULTITABLES
			int idColumnSpan = IdentifierColumnSpan;

			List<string> tables = new List<string>();
			List<string[]> keyColumns = new List<string[]>();
			List<bool> cascadeDeletes = new List<bool>();
			IEnumerator<IKeyValue> kiter = persistentClass.KeyClosureIterator.GetEnumerator();
			foreach (Table tab in persistentClass.TableClosureIterator)
			{
				kiter.MoveNext();
				IKeyValue key = kiter.Current;
				string tabname = tab.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName);
				tables.Add(tabname);

				List<string> keyCols = new List<string>(idColumnSpan);
				IEnumerable<Column> enumerableKCols = new SafetyEnumerable<Column>(key.ColumnIterator);
				foreach (Column kcol in enumerableKCols)
					keyCols.Add(kcol.GetQuotedName(factory.Dialect));

				keyColumns.Add(keyCols.ToArray());
				cascadeDeletes.Add(key.IsCascadeDeleteEnabled && factory.Dialect.SupportsCascadeDelete);				
			}
			naturalOrderTableNames = tables.ToArray();
			naturalOrderTableKeyColumns = keyColumns.ToArray();
			naturalOrderCascadeDeleteEnabled = cascadeDeletes.ToArray();

			List<string> subtables = new List<string>();
			List<bool> isConcretes = new List<bool>();
			keyColumns = new List<string[]>();
			foreach (Table tab in persistentClass.SubclassTableClosureIterator)
			{
				isConcretes.Add(persistentClass.IsClassOrSuperclassTable(tab));
				string tabname = tab.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName);
				subtables.Add(tabname);
				List<string> key = new List<string>(idColumnSpan);
				foreach (Column column in tab.PrimaryKey.ColumnIterator)
					key.Add(column.GetQuotedName(factory.Dialect));

				keyColumns.Add(key.ToArray());				
			}
			subclassTableNameClosure = subtables.ToArray();
			subclassTableKeyColumnClosure = keyColumns.ToArray();
			isClassOrSuperclassTable = isConcretes.ToArray();

			constraintOrderedTableNames = new string[subclassTableNameClosure.Length];
			constraintOrderedKeyColumnNames = new string[subclassTableNameClosure.Length][];
			int currentPosition = 0;
			for (int i = subclassTableNameClosure.Length - 1; i >= 0; i--, currentPosition++)
			{
				constraintOrderedTableNames[currentPosition] = subclassTableNameClosure[i];
				constraintOrderedKeyColumnNames[currentPosition] = subclassTableKeyColumnClosure[i];
			}

			tableSpan = naturalOrderTableNames.Length;
			tableNames = Reverse(naturalOrderTableNames);
			tableKeyColumns = Reverse(naturalOrderTableKeyColumns);
			Reverse(subclassTableNameClosure, tableSpan);
			Reverse(subclassTableKeyColumnClosure, tableSpan);

			spaces = ArrayHelper.Join(tableNames, persistentClass.SynchronizedTables.ToArray());

			// Custom sql
			customSQLInsert = new SqlString[tableSpan];
			customSQLUpdate = new SqlString[tableSpan];
			customSQLDelete = new SqlString[tableSpan];
			insertCallable = new bool[tableSpan];
			updateCallable = new bool[tableSpan];
			deleteCallable = new bool[tableSpan];
			insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
			updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];
			deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[tableSpan];

			PersistentClass pc = persistentClass;
			int jk = tableSpan - 1;
			while (pc != null)
			{
				customSQLInsert[jk] = pc.CustomSQLInsert;
				insertCallable[jk] = customSQLInsert[jk] != null && pc.IsCustomInsertCallable;
				insertResultCheckStyles[jk] = pc.CustomSQLInsertCheckStyle
											  ??
											  ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLInsert[jk], insertCallable[jk]);
				customSQLUpdate[jk] = pc.CustomSQLUpdate;
				updateCallable[jk] = customSQLUpdate[jk] != null && pc.IsCustomUpdateCallable;
				updateResultCheckStyles[jk] = pc.CustomSQLUpdateCheckStyle
											  ??
											  ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLUpdate[jk], updateCallable[jk]);
				customSQLDelete[jk] = pc.CustomSQLDelete;
				deleteCallable[jk] = customSQLDelete[jk] != null && pc.IsCustomDeleteCallable;
				deleteResultCheckStyles[jk] = pc.CustomSQLDeleteCheckStyle
											  ??
											  ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLDelete[jk], deleteCallable[jk]);
				jk--;
				pc = pc.Superclass;
			}
			if (jk != -1)
			{
				throw new AssertionFailure("Tablespan does not match height of joined-subclass hierarchy.");
			}

			#endregion

			#region PROPERTIES

			int hydrateSpan = PropertySpan;
			naturalOrderPropertyTableNumbers = new int[hydrateSpan];
			propertyTableNumbers = new int[hydrateSpan];
			int i2 = 0;
			foreach (Property prop in persistentClass.PropertyClosureIterator)
			{
				string tabname = prop.Value.Table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName);
				propertyTableNumbers[i2] = GetTableId(tabname, tableNames);
				naturalOrderPropertyTableNumbers[i2] = GetTableId(tabname, naturalOrderTableNames);
				i2++;
			}

			// subclass closure properties
			List<int> columnTableNumbers = new List<int>();
			List<int> formulaTableNumbers = new List<int>();
			List<int> propTableNumbers = new List<int>();
			foreach (Property prop in persistentClass.SubclassPropertyClosureIterator)
			{
				Table tab = prop.Value.Table;
				string tabname = tab.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName);
				int tabnum = GetTableId(tabname, subclassTableNameClosure);
				propTableNumbers.Add(tabnum);

				foreach (ISelectable thing in prop.ColumnIterator)
				{
					if (thing.IsFormula)
						formulaTableNumbers.Add(tabnum);
					else
						columnTableNumbers.Add(tabnum);
				}
			}

			subclassColumnTableNumberClosure = columnTableNumbers.ToArray();
			subclassPropertyTableNumberClosure = propTableNumbers.ToArray();
			subclassFormulaTableNumberClosure = formulaTableNumbers.ToArray();
			#endregion

			#region SUBCLASSES

			int subclassSpan = persistentClass.SubclassSpan + 1;
			subclassClosure = new string[subclassSpan];
			subclassClosure[subclassSpan - 1] = EntityName;
			if (persistentClass.IsPolymorphic)
			{
				subclassesByDiscriminatorValue[discriminatorValue] = EntityName;
				discriminatorValues = new string[subclassSpan];
				discriminatorValues[subclassSpan - 1] = discriminatorSQLString;
				notNullColumnTableNumbers = new int[subclassSpan];
				int id =
					GetTableId(
						persistentClass.Table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName,
															   factory.Settings.DefaultSchemaName), subclassTableNameClosure);
				notNullColumnTableNumbers[subclassSpan - 1] = id;
				notNullColumnNames = new string[subclassSpan];
				notNullColumnNames[subclassSpan - 1] = subclassTableKeyColumnClosure[id][0]; 
				//( (Column) model.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
			}
			else
			{
				discriminatorValues = null;
				notNullColumnTableNumbers = null;
				notNullColumnNames = null;
			}

			int k2 = 0;
			foreach (Subclass sc in persistentClass.SubclassIterator)
			{
				subclassClosure[k2] = sc.EntityName;
				try
				{
					if (persistentClass.IsPolymorphic)
					{
						// we now use subclass ids that are consistent across all
						// persisters for a class hierarchy, so that the use of 
						// "foo.class = Bar" works in HQL
						int subclassId = sc.SubclassId; //new Integer(k+1);
						subclassesByDiscriminatorValue[subclassId] = sc.EntityName;
						discriminatorValues[k2] = subclassId.ToString();
						int id =
							GetTableId(
								sc.Table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName,
														  factory.Settings.DefaultSchemaName), subclassTableNameClosure);
						notNullColumnTableNumbers[k2] = id;
						notNullColumnNames[k2] = subclassTableKeyColumnClosure[id][0]; 
						//( (Column) sc.getTable().getPrimaryKey().getColumnIterator().next() ).getName();
					}
				}
				catch (Exception e)
				{
					throw new MappingException("Error parsing discriminator value", e);
				}
				k2++;				
			}

			#endregion

			InitLockers();

			InitSubclassPropertyAliasesMap(persistentClass);

			PostConstruct(mapping);
		}
		public UnionSubclassEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache, 
			ISessionFactoryImplementor factory, IMapping mapping):base(persistentClass, cache, factory)
		{
			if (IdentifierGenerator is IdentityGenerator)
			{
				throw new MappingException("Cannot use identity column key generation with <union-subclass> mapping for: " + EntityName);
			}

			// TABLE

			tableName =
				persistentClass.Table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName,
				                                       factory.Settings.DefaultSchemaName);

			#region Custom SQL

			SqlString sql;
			bool callable;
			ExecuteUpdateResultCheckStyle checkStyle;

			sql = persistentClass.CustomSQLInsert;
			callable = sql != null && persistentClass.IsCustomInsertCallable;
			checkStyle = sql == null
			             	? ExecuteUpdateResultCheckStyle.Count
			             	: (persistentClass.CustomSQLInsertCheckStyle
			             	   ?? ExecuteUpdateResultCheckStyle.DetermineDefault(sql, callable));
			customSQLInsert = new SqlString[] { sql };
			insertCallable = new bool[] { callable };
			insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };

			sql = persistentClass.CustomSQLUpdate;
			callable = sql != null && persistentClass.IsCustomUpdateCallable;
			checkStyle = sql == null
			             	? ExecuteUpdateResultCheckStyle.Count
			             	: (persistentClass.CustomSQLUpdateCheckStyle
			             	   ?? ExecuteUpdateResultCheckStyle.DetermineDefault(sql, callable));
			customSQLUpdate = new SqlString[] { sql };
			updateCallable = new bool[] { callable };
			updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };

			sql = persistentClass.CustomSQLDelete;
			callable = sql != null && persistentClass.IsCustomDeleteCallable;
			checkStyle = sql == null
			             	? ExecuteUpdateResultCheckStyle.Count
			             	: (persistentClass.CustomSQLDeleteCheckStyle
			             	   ?? ExecuteUpdateResultCheckStyle.DetermineDefault(sql, callable));
			customSQLDelete = new SqlString[] { sql };
			deleteCallable = new bool[] { callable };
			deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[] { checkStyle };

			#endregion

			discriminatorValue = persistentClass.SubclassId;
			discriminatorSQLValue = persistentClass.SubclassId.ToString();

			#region PROPERTIES

			int subclassSpan = persistentClass.SubclassSpan + 1;
			subclassClosure = new string[subclassSpan];
			subclassClosure[0] = EntityName;

			#endregion

			#region SUBCLASSES

			subclassByDiscriminatorValue[persistentClass.SubclassId] = persistentClass.EntityName;
			if (persistentClass.IsPolymorphic)
			{
				int k = 1;
				foreach (Subclass sc in persistentClass.SubclassIterator)
				{
					subclassClosure[k++] = sc.EntityName;
					subclassByDiscriminatorValue[sc.SubclassId] = sc.EntityName;
				}
			}

			#endregion

			#region SPACES
			//TODO: i'm not sure, but perhaps we should exclude abstract denormalized tables?

			int spacesSize = 1 + persistentClass.SynchronizedTables.Count;
			spaces = new string[spacesSize];
			spaces[0] = tableName;
			IEnumerator<string> iSyncTab = persistentClass.SynchronizedTables.GetEnumerator();
			for (int i = 1; i < spacesSize; i++)
			{
				iSyncTab.MoveNext();
				spaces[i] = iSyncTab.Current;
			}

			HashedSet<string> subclassTables = new HashedSet<string>();
			foreach (Table table in persistentClass.SubclassTableClosureIterator)
			{
				subclassTables.Add(
					table.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName));
			}
			subclassSpaces = new string[subclassTables.Count];
			subclassTables.CopyTo(subclassSpaces, 0);

			subquery = GenerateSubquery(persistentClass, mapping);

			if (IsMultiTable)
			{
				int idColumnSpan = IdentifierColumnSpan;
				List<string> tableNames = new List<string>();
				List<string[]> keyColumns = new List<string[]>();
				if (!IsAbstract)
				{
					tableNames.Add(tableName);
					keyColumns.Add(IdentifierColumnNames);
				}
				foreach (Table tab in persistentClass.SubclassTableClosureIterator)
				{
					if (!tab.IsAbstractUnionTable)
					{
						string _tableName =
							tab.GetQualifiedName(factory.Dialect, factory.Settings.DefaultCatalogName, factory.Settings.DefaultSchemaName);
						tableNames.Add(_tableName);

						List<string> key = new List<string>(idColumnSpan);
						foreach (Column column in tab.PrimaryKey.ColumnIterator)
							key.Add(column.GetQuotedName(factory.Dialect));

						keyColumns.Add(key.ToArray());
					}					
				}

				constraintOrderedTableNames = tableNames.ToArray();
				constraintOrderedKeyColumnNames = keyColumns.ToArray();
			}
			else
			{
				constraintOrderedTableNames = new string[] { tableName };
				constraintOrderedKeyColumnNames = new string[][] { IdentifierColumnNames };
			}
			#endregion

			InitLockers();

			InitSubclassPropertyAliasesMap(persistentClass);

			PostConstruct(mapping);
		}
		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();
		}
		//INITIALIZATION:

		public SingleTableEntityPersister(PersistentClass model, ICacheConcurrencyStrategy cache,
		                                  ISessionFactoryImplementor factory, IMapping mapping)
			: base(model, cache, factory)
		{
			// CLASS + TABLE

			System.Type mappedClass = model.MappedClass;
			Table table = model.RootTable;
			qualifiedTableName = table.GetQualifiedName(Dialect, factory.DefaultSchema);
			tableNames = new string[] {qualifiedTableName};

			// Custom sql
			customSQLInsert = new SqlString[1];
			customSQLUpdate = new SqlString[1];
			customSQLDelete = new SqlString[1];
			insertCallable = new bool[1];
			updateCallable = new bool[1];
			deleteCallable = new bool[1];
			insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[1];
			updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[1];
			deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[1];

			customSQLInsert[0] = model.CustomSQLInsert;
			insertCallable[0] = customSQLInsert[0] != null && model.IsCustomInsertCallable;
			insertResultCheckStyles[0] = model.CustomSQLInsertCheckStyle == null
			                             	?
			                             ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLInsert[0], insertCallable[0])
			                             	: model.CustomSQLInsertCheckStyle;
			customSQLUpdate[0] = model.CustomSQLUpdate;
			updateCallable[0] = customSQLUpdate[0] != null && model.IsCustomUpdateCallable;
			updateResultCheckStyles[0] = model.CustomSQLUpdateCheckStyle == null
			                             	?
			                             ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLUpdate[0], updateCallable[0])
			                             	: model.CustomSQLUpdateCheckStyle;
			customSQLDelete[0] = model.CustomSQLDelete;
			deleteCallable[0] = customSQLDelete[0] != null && model.IsCustomDeleteCallable;
			deleteResultCheckStyles[0] = model.CustomSQLDeleteCheckStyle == null
			                             	?
			                             ExecuteUpdateResultCheckStyle.DetermineDefault(customSQLDelete[0], deleteCallable[0])
			                             	: model.CustomSQLDeleteCheckStyle;

			// detect mapping errors
			HashedSet distinctColumns = new HashedSet();

			// DISCRIMINATOR
			if (model.IsPolymorphic)
			{
				IValue d = model.Discriminator;
				if (d == null)
				{
					throw new MappingException("A discriminator mapping required for polymorphic persistence of " + model.Name);
				}
				forceDiscriminator = model.IsForceDiscriminator;

				// the discriminator will have only one column 
				foreach (ISelectable selectable in d.ColumnCollection)
				{
					if (d.HasFormula)
					{
						Formula formula = (Formula) selectable;
						discriminatorFormula = formula.FormulaString;
						discriminatorFormulaTemplate = formula.GetTemplate(factory.Dialect, factory.SQLFunctionRegistry);
						discriminatorColumnName = null;
						discriminatorAlias = "clazz_";
					}
					else
					{
						Column column = (Column) selectable;
						discriminatorColumnName = column.GetQuotedName(Dialect);
						discriminatorAlias = column.GetAlias(Dialect);
						discriminatorFormula = null;
						discriminatorFormulaTemplate = null;
					}
				}
				discriminatorType = model.Discriminator.Type;

				if (model.IsDiscriminatorValueNull)
				{
					discriminatorValue = NullDiscriminator;
					discriminatorSQLValue = InFragment.Null;
					discriminatorInsertable = false;
				}
				else if (model.IsDiscriminatorValueNotNull)
				{
					discriminatorValue = NotNullDiscriminator;
					discriminatorSQLValue = InFragment.NotNull;
					discriminatorInsertable = false;
				}
				else
				{
					discriminatorInsertable = model.IsDiscriminatorInsertable && !d.HasFormula;
					try
					{
						IDiscriminatorType dtype = (IDiscriminatorType) discriminatorType;
						discriminatorValue = dtype.StringToObject(model.DiscriminatorValue);
						discriminatorSQLValue = dtype.ObjectToSQLString(discriminatorValue);
					}
					catch (InvalidCastException)
					{
						throw new MappingException(string.Format("Illegal discriminator type: {0}", discriminatorType.Name));
					}
					catch (Exception e)
					{
						string msg = String.Format("Could not format discriminator value '{0}' to sql string using the IType {1}",
						                           model.DiscriminatorValue,
						                           model.Discriminator.Type.ToString());

						throw new MappingException(msg, e);
					}

					if (discriminatorInsertable)
					{
						distinctColumns.Add(discriminatorColumnName);
					}
				}
			}
			else
			{
				forceDiscriminator = false;
				discriminatorInsertable = false;
				discriminatorColumnName = null;
				discriminatorAlias = null;
				discriminatorType = null;
				discriminatorValue = null;
				discriminatorSQLValue = null;
			}

			// PROPERTIES
			HashedSet thisClassProperties = new HashedSet();

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

			// SQL string generation moved to PostInstantiate

			int subclassSpan = model.SubclassSpan + 1;
			subclassClosure = new System.Type[subclassSpan];
			subclassClosure[0] = mappedClass;
			if (model.IsPolymorphic)
			{
				subclassesByDiscriminatorValue.Add(discriminatorValue, mappedClass);
			}

			// SUBCLASSES
			if (model.IsPolymorphic)
			{
				int k = 1;
				foreach (Subclass sc in model.SubclassCollection)
				{
					subclassClosure[k++] = sc.MappedClass;
					if (sc.IsDiscriminatorValueNull)
					{
						subclassesByDiscriminatorValue.Add(NullDiscriminator, sc.MappedClass);
					}
					else if (sc.IsDiscriminatorValueNotNull)
					{
						subclassesByDiscriminatorValue.Add(NotNullDiscriminator, sc.MappedClass);
					}
					else
					{
						try
						{
							IDiscriminatorType dtype = discriminatorType as IDiscriminatorType;
							subclassesByDiscriminatorValue.Add(
								dtype.StringToObject(sc.DiscriminatorValue),
								sc.MappedClass);
						}
						catch (InvalidCastException)
						{
							throw new MappingException(string.Format("Illegal discriminator type: {0}", discriminatorType.Name));
						}
						catch (Exception e)
						{
							throw new MappingException(string.Format("Error parsing discriminator value: '{0}'", sc.DiscriminatorValue), e);
						}
					}
				}
			}

			// This is in PostInstatiate as it needs identifier info
			//InitLockers();

			propertyTableNumbers = new int[EntityMetamodel.PropertySpan];
			for (int i = 0; i < propertyTableNumbers.Length; i++)
			{
				propertyTableNumbers[i] = 0;
			}

			InitSubclassPropertyAliasesMap(model);
			PostConstruct(mapping);
		}