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