context: using System.Collections.Generic;
  using System.Text;
  using NHibernate.Cache;
  using NHibernate.Cfg;
  using NHibernate.Engine;
  using NHibernate.Id;
  using NHibernate.Mapping;
  using NHibernate.SqlCommand;
  using NHibernate.SqlTypes;
  using NHibernate.Util;
  using System.Linq;
  
  namespace NHibernate.Persister.Entity
  {
  	public class UnionSubclassEntityPersister : AbstractEntityPersister
  	{
  		private readonly string subquery;
  		private readonly string tableName;
  		private readonly string[] subclassClosure;
  		private readonly string[] spaces;
  		private readonly string[] subclassSpaces;
  		private readonly string discriminatorSQLValue;
  		private readonly object discriminatorValue;
  		private readonly Dictionary<int, string> subclassByDiscriminatorValue = new Dictionary<int, string>();
  		private readonly string[] constraintOrderedTableNames;
  		private readonly string[][] constraintOrderedKeyColumnNames;
  
  		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
  
  			var dialect = factory.Dialect;
  			var defaultCatalogName = factory.Settings.DefaultCatalogName;
  			var defaultSchemaName = factory.Settings.DefaultSchemaName;
  			tableName = persistentClass.Table.GetQualifiedName(dialect, defaultCatalogName, 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;
  			}
  
  			subclassSpaces = persistentClass.SubclassTableClosureIterator
  				.Select(table =>
  					table.GetQualifiedName(dialect, defaultCatalogName, defaultSchemaName))
  				.Distinct().ToArray();
  
  			subquery = GenerateSubquery(persistentClass, mapping);
  
  			if (IsMultiTable)
  			{
  				var tableNames = new List<string>();
  				var keyColumns = new List<string[]>();
  				if (!IsAbstract)
  				{
  					tableNames.Add(tableName);
  					keyColumns.Add(IdentifierColumnNames);
  				}
  				foreach (var tab in persistentClass.SubclassTableClosureIterator)
  				{
  					if (!tab.IsAbstractUnionTable)
  					{
  						string _tableName =
  							tab.GetQualifiedName(dialect, defaultCatalogName, defaultSchemaName);
  						tableNames.Add(_tableName);
  
  						var names = tab.PrimaryKey.ColumnIterator
  									   .Select(column => column.GetQuotedName(dialect))
  									   .ToArray();
  
  						keyColumns.Add(names);
  					}
  				}
  
  				constraintOrderedTableNames = tableNames.ToArray();
  				constraintOrderedKeyColumnNames = keyColumns.ToArray();
  			}
  			else
  			{
  				constraintOrderedTableNames = new string[] { tableName };
  				constraintOrderedKeyColumnNames = new string[][] { IdentifierColumnNames };
  			}
  			#endregion
  
  			InitLockers();
  
  			InitSubclassPropertyAliasesMap(persistentClass);
  
  			PostConstruct(mapping);
  		}
  
  		public override string[] QuerySpaces
  		{
  			get { return subclassSpaces; }
  		}
  
  		public override Type.IType DiscriminatorType
  		{
  			get { return NHibernateUtil.Int32; }
  		}
  
  		public override string DiscriminatorSQLValue
  		{
  			get { return discriminatorSQLValue;}
  		}
  
  		public override object DiscriminatorValue
  		{
  			get { return discriminatorValue; }
  		}
  
  		public override string[] SubclassClosure
  		{
  			get { return subclassClosure; }
  		}
  
  		public override string[] PropertySpaces
  		{
  			get { return spaces; }
  		}
  
  		protected internal override int[] PropertyTableNumbersInSelect
  		{
  			get { return new int[PropertySpan]; }
  		}
  
  		public override bool IsMultiTable
  		{
  			get
  			{
  				// This could also just be true all the time...
  				return IsAbstract || HasSubclasses;
  			}
  		}
  
  		protected override int[] SubclassColumnTableNumberClosure
  		{
  			get { return new int[SubclassColumnClosure.Length]; }
  		}
  
  		protected override int[] SubclassFormulaTableNumberClosure
  		{
  
gt: 			get { return new int[SubclassFormulaClosure.Length]; }