Example #1
0
        /// <summary>
        /// A non null propertyHolder means than we process the Pk creation without delay
        /// </summary>
        /// <param name="secondaryTable"></param>
        /// <param name="joinTable"></param>
        /// <param name="propertyHolder"></param>
        /// <param name="noDelayInPkColumnCreation"></param>
        /// <returns></returns>
        private Join AddJoin(SecondaryTableAttribute secondaryTable,
                             JoinTableAttribute joinTable,
                             IPropertyHolder propertyHolder,
                             bool noDelayInPkColumnCreation)
        {
            Join join = new Join();

            join.PersistentClass = persistentClass;
            string schema;
            string catalog;
            string table;
            string realTable;

            System.Persistence.UniqueConstraintAttribute[] uniqueConstraintsAnn;
            if (secondaryTable != null)
            {
                schema               = secondaryTable.Schema;
                catalog              = secondaryTable.Catalog;
                table                = secondaryTable.Name;
                realTable            = mappings.NamingStrategy.TableName(table);      //always an explicit table name
                uniqueConstraintsAnn = secondaryTable.UniqueConstraints;
            }
            else if (joinTable != null)
            {
                schema               = joinTable.Schema;
                catalog              = joinTable.Catalog;
                table                = joinTable.Name;
                realTable            = mappings.NamingStrategy.TableName(table);      //always an explicit table name
                uniqueConstraintsAnn = joinTable.UniqueConstraints;
            }
            else
            {
                throw new AssertionFailure("Both JoinTable and SecondaryTable are null");
            }

            var uniqueConstraints = new List <string[]>(uniqueConstraintsAnn == null ? 0 : uniqueConstraintsAnn.Length);

            if (uniqueConstraintsAnn != null && uniqueConstraintsAnn.Length != 0)
            {
                foreach (UniqueConstraintAttribute uc in uniqueConstraintsAnn)
                {
                    uniqueConstraints.Add(uc.ColumnNames);
                }
            }
            Table tableMapping = TableBinder.FillTable(
                schema,
                catalog,
                realTable,
                table, false, uniqueConstraints, null, null, mappings);

            //no check constraints available on joins
            join.Table = tableMapping;

            //somehow keep joins() for later.
            //Has to do the work later because it needs persistentClass id!
            object joinColumns = null;

            //get the appropriate pk columns
            if (secondaryTable != null)
            {
                joinColumns = secondaryTable.PkJoinColumns;
            }
            else if (joinTable != null)
            {
                joinColumns = joinTable.JoinColumns;
            }
            log.InfoFormat("Adding secondary table to entity {0} -> {1}", persistentClass.EntityName, join.Table.Name);

            TableAttribute matchingTable = FindMatchingComplimentTableAnnotation(join);

            if (matchingTable != null)
            {
                join.IsSequentialSelect = FetchMode.Join != matchingTable.Fetch;
                join.IsInverse          = matchingTable.IsInverse;
                join.IsOptional         = matchingTable.IsOptional;
                if (!BinderHelper.IsDefault(matchingTable.SqlInsert.Sql))
                {
                    join.SetCustomSQLInsert(matchingTable.SqlInsert.Sql.Trim(),
                                            matchingTable.SqlInsert.Callable,
                                            ExecuteUpdateResultCheckStyle.Parse(matchingTable.SqlInsert.Check.ToString().ToLower()));
                }
                if (!BinderHelper.IsDefault(matchingTable.SqlUpdate.Sql))
                {
                    join.SetCustomSQLUpdate(matchingTable.SqlUpdate.Sql.Trim(),
                                            matchingTable.SqlUpdate.Callable,
                                            ExecuteUpdateResultCheckStyle.Parse(matchingTable.SqlUpdate.Check.ToString().ToLower())
                                            );
                }
                if (!BinderHelper.IsDefault(matchingTable.SqlDelete.Sql))
                {
                    join.SetCustomSQLDelete(matchingTable.SqlDelete.Sql.Trim(),
                                            matchingTable.SqlDelete.Callable,
                                            ExecuteUpdateResultCheckStyle.Parse(matchingTable.SqlDelete.Check.ToString().ToLower())
                                            );
                }
            }
            else
            {
                //default
                join.IsSequentialSelect = false;
                join.IsInverse          = false;
                join.IsOptional         = false;         //perhaps not quite per-spec, but a Good Thing anyway
            }

            if (noDelayInPkColumnCreation)
            {
                CreatePrimaryColumnsToSecondaryTable(joinColumns, propertyHolder, join);
            }
            else
            {
                secondaryTables.Add(table, join);
                secondaryTableJoins.Add(table, joinColumns);
            }
            return(join);
        }
Example #2
0
 public void SetCustomSQLInsert(string sql, bool callable, ExecuteUpdateResultCheckStyle checkStyle)
 {
     customSQLInsert      = SqlString.Parse(sql);
     customInsertCallable = callable;
     insertCheckStyle     = checkStyle;
 }
Example #3
0
        /// <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);
        }