예제 #1
0
 public void Type(IDiscriminatorType persistentType)
 {
     Type(persistentType.GetType());
 }
		//INITIALIZATION:

		/// <summary>
		/// Constructs the NormalizedEntityPerister for the PersistentClass.
		/// </summary>
		/// <param name="model">The PeristentClass to create the EntityPersister for.</param>
		/// <param name="factory">The SessionFactory that this EntityPersister will be stored in.</param>
		public NormalizedEntityPersister( PersistentClass model, ISessionFactoryImplementor factory )
			: base( model, factory )
		{
			// I am am making heavy use of the "this." just to help me with debugging what is a local variable to the 
			// constructor versus what is an class scoped variable.  I am only doing this when we are using fields 
			// instead of properties because it is easy to tell properties by the Case.

			// CLASS + TABLE

			this.factory = factory;
			Table table = model.RootTable;
			this.qualifiedTableName = table.GetQualifiedName( Dialect, factory.DefaultSchema );

			// DISCRIMINATOR

			object discriminatorValue;
			if( model.IsPolymorphic )
			{
				// when we have a Polymorphic model then we are going to add a column "clazz_" to 
				// the sql statement that will be a large CASE statement where we will use the 
				// integer value to tell us which class to instantiate for the record.
				this.discriminatorColumnName = "clazz_";

				try
				{
					this.discriminatorType = ( IDiscriminatorType ) NHibernateUtil.Int32;
					discriminatorValue = 0;
					this.discriminatorSQLString = "0";
				}
				catch( Exception e )
				{
					throw new MappingException( "Could not format discriminator value '0' to sql string using the IType NHibernate.Types.Int32Type", e );
				}
			}
			else
			{
				this.discriminatorColumnName = null;
				this.discriminatorType = null;
				discriminatorValue = null;
				this.discriminatorSQLString = null;
			}

			if( OptimisticLockMode != OptimisticLockMode.Version )
			{
				throw new MappingException( "optimistic-lock attribute not supported for joined-subclass mappings: " + ClassName );
			}

			//MULTITABLES

			// these two will later be converted into arrays for the fields tableNames and tableKeyColumns
			ArrayList tables = new ArrayList();
			ArrayList keyColumns = new ArrayList();
			tables.Add( this.qualifiedTableName );
			keyColumns.Add( base.IdentifierColumnNames );

			// move through each table that contains the data for this entity.
			foreach( Table tab in model.TableClosureCollection )
			{
				string tabname = tab.GetQualifiedName( Dialect, factory.DefaultSchema );
				if( !tabname.Equals( qualifiedTableName ) )
				{
					tables.Add( tabname );
					string[ ] key = new string[tab.PrimaryKey.ColumnCollection.Count];
					int k = 0;
					foreach( Column col in tab.PrimaryKey.ColumnCollection )
					{
						key[ k++ ] = col.GetQuotedName( Dialect );
					}
					keyColumns.Add( key );
				}
			}

			this.naturalOrderTableNames = ( string[ ] ) tables.ToArray( typeof( string ) );
			this.naturalOrderTableKeyColumns = ( string[ ][ ] ) keyColumns.ToArray( typeof( string[ ] ) );

			// the description of these variables is the same as before
			ArrayList subtables = new ArrayList();
			keyColumns = new ArrayList();
			subtables.Add( this.qualifiedTableName );
			keyColumns.Add( base.IdentifierColumnNames );
			foreach( Table tab in model.SubclassTableClosureCollection )
			{
				string tabname = tab.GetQualifiedName( Dialect, factory.DefaultSchema );
				if( !tabname.Equals( qualifiedTableName ) )
				{
					subtables.Add( tabname );
					string[ ] key = new string[tab.PrimaryKey.ColumnCollection.Count];
					int k = 0;
					foreach( Column col in tab.PrimaryKey.ColumnCollection )
					{
						key[ k++ ] = col.GetQuotedName( Dialect );
					}
					keyColumns.Add( key );
				}
			}

			// convert the local ArrayList variables into arrays for the fields in the class
			this.subclassTableNameClosure = ( string[ ] ) subtables.ToArray( typeof( string ) );
			this.subclassTableKeyColumns = ( string[ ][ ] ) keyColumns.ToArray( typeof( string[ ] ) );
			this.isClassOrSuperclassTable = new bool[this.subclassTableNameClosure.Length];
			for( int j = 0; j < subclassTableNameClosure.Length; j++ )
			{
				this.isClassOrSuperclassTable[ j ] = tables.Contains( this.subclassTableNameClosure[ j ] );
			}

			int len = naturalOrderTableNames.Length;
			tableNames = Reverse( naturalOrderTableNames );
			tableKeyColumns = Reverse( naturalOrderTableKeyColumns );
			Array.Reverse( subclassTableNameClosure, 0, len );
			Array.Reverse( subclassTableKeyColumns, 0, len );

			// PROPERTIES

			// initialize the lengths of all of the Property related fields in the class
			this.propertyTables = new int[HydrateSpan];
			this.naturalOrderPropertyTables = new int[HydrateSpan];
			this.propertyColumnNames = new string[HydrateSpan][ ];
			this.propertyColumnNameAliases = new string[HydrateSpan][ ];
			this.propertyColumnSpans = new int[HydrateSpan];
			this.propertyFormulaTemplates = new string[ HydrateSpan ];

			HashedSet thisClassProperties = new HashedSet();

			int i = 0;
			bool foundFormula = false;
			foreach( Mapping.Property prop in model.PropertyClosureCollection )
			{
				thisClassProperties.Add( prop );
				Table tab = prop.Value.Table;
				string tabname = tab.GetQualifiedName( Dialect, factory.DefaultSchema );
				this.propertyTables[ i ] = GetTableId( tabname, this.tableNames );
				this.naturalOrderPropertyTables[ i ] = GetTableId( tabname, this.naturalOrderTableNames );

				if ( prop.IsFormula )
				{
					this.propertyColumnNameAliases[ i ] = new string[] { prop.Formula.Alias };
					this.propertyColumnSpans[ i ] = 1;
					this.propertyFormulaTemplates[ i ] = prop.Formula.GetTemplate( Dialect );
					foundFormula = true;
				}
				else
				{
					this.propertyColumnSpans[ i ] = prop.ColumnSpan;

					string[ ] propCols = new string[propertyColumnSpans[ i ]];
					string[ ] propAliases = new string[propertyColumnSpans[ i ]];

					int j = 0;
					foreach( Column col in prop.ColumnCollection )
					{
						string colname = col.GetQuotedName( Dialect );
						propCols[ j ] = colname;
						propAliases[ j ] = col.Alias( Dialect, tab.UniqueInteger.ToString() + StringHelper.Underscore );
						j++;
					}
					this.propertyColumnNames[ i ] = propCols;
					this.propertyColumnNameAliases[ i ] = propAliases;
				}

				i++;
			}

			this.hasFormulaProperties = foundFormula;

			// check distinctness of columns for this specific subclass only
			HashedSet distinctColumns = new HashedSet();
			CheckColumnDuplication( distinctColumns, model.Key.ColumnCollection );
			foreach( Mapping.Property prop in model.PropertyCollection )
			{
				if( prop.IsUpdateable || prop.IsInsertable )
				{
					CheckColumnDuplication( distinctColumns, prop.ColumnCollection );
				}
			}

			// subclass closure properties

			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 propColumns = new ArrayList(); //this.subclassPropertyColumnNameClosure
			ArrayList coltables = new ArrayList(); //this.subclassColumnTableNumberClosure
			ArrayList formtables = new ArrayList();
			ArrayList joinedFetchesList = new ArrayList(); //this.subclassPropertyEnableJoinedFetch
			ArrayList propTables = new ArrayList(); // this.subclassPropertyTableNameClosure
			ArrayList definedBySubclass = new ArrayList(); // this.propertyDefinedOnSubclass

			foreach( Mapping.Property prop in model.SubclassPropertyClosureCollection )
			{
				names.Add( prop.Name );
				definedBySubclass.Add( !thisClassProperties.Contains( prop ) );
				Table tab = prop.Value.Table;
				string tabname = tab.GetQualifiedName( Dialect, factory.DefaultSchema );
				int tabnum = GetTableId( tabname, subclassTableNameClosure );
				propTables.Add( tabnum );
				types.Add( prop.Type );

				if ( prop.IsFormula )
				{
					formulaTemplates.Add( prop.Formula.GetTemplate( Dialect ) );
					propColumns.Add( new string [] { } ) ;
					formulaAliases.Add( prop.Formula.Alias );
					formtables.Add( tabnum );
				}
				else
				{
					string[ ] cols = new string[prop.ColumnSpan];
					int l = 0;
					foreach( Column col in prop.ColumnCollection )
					{
						columns.Add( col.GetQuotedName( Dialect ) );
						coltables.Add( tabnum );
						cols[ l++ ] = col.GetQuotedName( Dialect );
						aliases.Add( col.Alias( Dialect, tab.UniqueInteger.ToString() + StringHelper.Underscore ) );
					}
					propColumns.Add( cols );
				}

				joinedFetchesList.Add( prop.Value.OuterJoinFetchSetting );
			}

			subclassColumnClosure = ( string[ ] ) columns.ToArray( typeof( string ) );
			subclassColumnClosureAliases = ( string[ ] ) aliases.ToArray( typeof( string ) );
			subclassColumnTableNumberClosure = ( int[ ] ) coltables.ToArray( typeof( int ) );
			subclassPropertyTypeClosure = ( IType[ ] ) types.ToArray( typeof( IType ) );
			subclassPropertyNameClosure = ( string[ ] ) names.ToArray( typeof( string ) );
			subclassPropertyTableNumberClosure = ( int[ ] ) propTables.ToArray( typeof( int ) );
			subclassFormulaAliasClosure = ( string[ ] ) formulaAliases.ToArray( typeof( string ) );
			subclassFormulaTemplateClosure = ( string[ ] ) formulaTemplates.ToArray( typeof( string ) );
			subclassFormulaTableNumberClosure = ( int[ ] ) formtables.ToArray( typeof( int ) );
			subclassPropertyColumnNameClosure = ( string[ ][ ] ) propColumns.ToArray( typeof( string[ ] ) );

			subclassPropertyEnableJoinedFetch = new OuterJoinFetchStrategy[ joinedFetchesList.Count ];
			int n = 0;
			foreach( OuterJoinFetchStrategy ojlType in joinedFetchesList )
			{
				subclassPropertyEnableJoinedFetch[ n++ ] = ojlType;
			}

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

			// ****** Moved the sql generation to PostIntantiate *****

			System.Type mappedClass = model.MappedClass;

			// SUBCLASSES

			// all of the classes spanned, so even though there might be 2 subclasses we need to 
			// add in the baseclass - so we add 1 to the Closure
			int subclassSpan = model.SubclassSpan + 1;
			this.subclassClosure = new System.Type[subclassSpan];

			// start with the mapped class as the last element in the subclassClosure
			this.subclassClosure[ subclassSpan - 1 ] = mappedClass;

			if( model.IsPolymorphic )
			{
				this.subclassesByDiscriminatorValue.Add( discriminatorValue, mappedClass );
				this.discriminatorValues = new string[subclassSpan];
				this.discriminatorValues[ subclassSpan - 1 ] = discriminatorSQLString;

				this.tableNumbers = new int[subclassSpan];
				int id = GetTableId(
					model.Table.GetQualifiedName( Dialect, factory.DefaultSchema ),
					this.subclassTableNameClosure );

				this.tableNumbers[ subclassSpan - 1 ] = id;
				this.notNullColumns = new string[subclassSpan];
				this.notNullColumns[ subclassSpan - 1 ] = subclassTableKeyColumns[ id ][ 0 ];
				/*
				foreach( Column col in model.Table.PrimaryKey.ColumnCollection )
				{
					notNullColumns[ subclassSpan - 1 ] = col.GetQuotedName( Dialect ); //only once
				}
				*/
			}
			else
			{
				discriminatorValues = null;
				tableNumbers = null;
				notNullColumns = null;
			}

			int p = 0;
			foreach( Subclass sc in model.SubclassCollection )
			{
				subclassClosure[ p ] = sc.MappedClass;
				try
				{
					if( model.IsPolymorphic )
					{
						int disc = p + 1;
						subclassesByDiscriminatorValue.Add( disc, sc.MappedClass );
						discriminatorValues[ p ] = disc.ToString();
						int id = GetTableId(
							sc.Table.GetQualifiedName( Dialect, factory.DefaultSchema ),
							this.subclassTableNameClosure );
						tableNumbers[ p ] = id;
						notNullColumns[ p ] = subclassTableKeyColumns[ id ][ 0 ];
						/*
						foreach( Column col in sc.Table.PrimaryKey.ColumnCollection )
						{
							notNullColumns[ p ] = col.GetQuotedName( Dialect ); //only once;
						}
						*/
					}
				}
				catch( Exception e )
				{
					throw new MappingException( "Error parsing discriminator value", e );
				}
				p++;
			}

			// moved the propertyHasColumns into PostInstantiate as it needs the SQL strings

			// needs identifier info so moved to PostInstatiate
			//InitLockers( );

			InitSubclassPropertyAliasesMap( model );
		}
        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);
        }
        //INITIALIZATION:

        public EntityPersister(PersistentClass model, ISessionFactoryImplementor factory)
            : base(model, factory)
        {
            // CLASS + TABLE

            System.Type mappedClass = model.MappedClass;
            this.factory = factory;
            Table table = model.RootTable;

            qualifiedTableName = table.GetQualifiedName(Dialect, factory.DefaultSchema);
            tableNames         = new string[] { qualifiedTableName };

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

            // DISCRIMINATOR
            object discriminatorValue;

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

                // the discriminator will have only one column
                foreach (Column discColumn in d.ColumnCollection)
                {
                    discriminatorColumnName = discColumn.GetQuotedName(Dialect);
                    discriminatorAlias      = discColumn.Alias(Dialect);
                }
                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;
                    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
            CheckColumnDuplication(distinctColumns, model.Key.ColumnCollection);

            propertyColumnNames      = new string[HydrateSpan][];
            propertyColumnAliases    = new string[HydrateSpan][];
            propertyColumnSpans      = new int[HydrateSpan];
            propertyFormulaTemplates = new string[HydrateSpan];
            ArrayList thisClassProperties = new ArrayList();

            int  i            = 0;
            bool foundColumn  = false;
            bool foundFormula = false;

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

                if (prop.IsFormula)
                {
                    propertyColumnAliases[i]    = new string[] { prop.Formula.Alias };
                    propertyColumnSpans[i]      = 1;
                    propertyFormulaTemplates[i] = prop.Formula.GetTemplate(Dialect);
                    foundFormula = true;
                }
                else
                {
                    int span = prop.ColumnSpan;
                    propertyColumnSpans[i] = span;

                    string[] colNames   = new string[span];
                    string[] colAliases = new string[span];
                    int      j          = 0;
                    foreach (Column col in prop.ColumnCollection)
                    {
                        colAliases[j] = col.Alias(Dialect);
                        colNames[j]   = col.GetQuotedName(Dialect);
                        j++;
                        if (prop.IsUpdateable)
                        {
                            foundColumn = true;
                        }
                    }
                    propertyColumnNames[i]   = colNames;
                    propertyColumnAliases[i] = colAliases;
                }
                i++;

                // columns must be unique across all subclasses
                if (prop.IsUpdateable || prop.IsInsertable)
                {
                    CheckColumnDuplication(distinctColumns, prop.ColumnCollection);
                }
            }

            hasFormulaProperties = foundFormula;
            hasUpdateableColumns = foundColumn;

            ArrayList columns           = new ArrayList();
            ArrayList aliases           = new ArrayList();
            ArrayList formulas          = new ArrayList();
            ArrayList formulaAliases    = new ArrayList();
            ArrayList formulaTemplates  = new ArrayList();
            ArrayList types             = new ArrayList();
            ArrayList names             = new ArrayList();
            ArrayList propColumns       = new ArrayList();
            ArrayList joinedFetchesList = new ArrayList();
            ArrayList definedBySubclass = new ArrayList();

            foreach (Mapping.Property prop in model.SubclassPropertyClosureCollection)
            {
                names.Add(prop.Name);
                definedBySubclass.Add(!thisClassProperties.Contains(prop));
                types.Add(prop.Type);

                if (prop.IsFormula)
                {
                    formulas.Add(prop.Formula.FormulaString);
                    formulaTemplates.Add(prop.Formula.GetTemplate(Dialect));
                    propColumns.Add(new string[0]);
                    formulaAliases.Add(prop.Formula.Alias);
                }
                else
                {
                    string[] cols = new string[prop.ColumnSpan];
                    int      l    = 0;
                    foreach (Column col in prop.ColumnCollection)
                    {
                        columns.Add(col.GetQuotedName(Dialect));
                        aliases.Add(col.Alias(Dialect));
                        cols[l++] = col.GetQuotedName(Dialect);
                    }
                    propColumns.Add(cols);
                }
                joinedFetchesList.Add(prop.Value.OuterJoinFetchSetting);
            }

            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));
            subclassPropertyColumnNameClosure = ( string[] [] )propColumns.ToArray(typeof(string[]));

            subclassPropertyEnableJoinedFetch = new OuterJoinFetchStrategy[joinedFetchesList.Count];
            int m = 0;

            foreach (OuterJoinFetchStrategy qq in joinedFetchesList)
            {
                subclassPropertyEnableJoinedFetch[m++] = qq;
            }

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

            // 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();

            InitSubclassPropertyAliasesMap(model);
        }