Combine() public static method

public static Combine ( Spacing spacing ) : SqlPreCommand
spacing Spacing
return SqlPreCommand
コード例 #1
0
        private static SqlPreCommand AlterTableAddColumnDefault(ITable table, IColumn column, Replacements rep)
        {
            bool temporalDefault = !column.Nullable && !column.Identity && column.Default == null;

            if (!temporalDefault)
            {
                return(SqlBuilder.AlterTableAddColumn(table, column));
            }

            try
            {
                var defaultValue = GetDefaultValue(table, column, rep);
                if (defaultValue == "force")
                {
                    return(SqlBuilder.AlterTableAddColumn(table, column));
                }

                column.Default = defaultValue;

                return(SqlPreCommand.Combine(Spacing.Simple,
                                             SqlBuilder.AlterTableAddColumn(table, column),
                                             SqlBuilder.DropDefaultConstraint(table.Name, column.Name)));
            }
            finally
            {
                column.Default = null;
            }
        }
コード例 #2
0
        public static SqlPreCommand?CreateTablesScript()
        {
            var           sqlBuilder = Connector.Current.SqlBuilder;
            Schema        s          = Schema.Current;
            List <ITable> tables     = s.GetDatabaseTables().Where(t => !s.IsExternalDatabase(t.Name.Schema.Database)).ToList();

            SqlPreCommand?createTables = tables.Select(t => sqlBuilder.CreateTableSql(t)).Combine(Spacing.Double)?.PlainSqlCommand();

            SqlPreCommand?foreignKeys = tables.Select(sqlBuilder.AlterTableForeignKeys).Combine(Spacing.Double)?.PlainSqlCommand();

            SqlPreCommand?indices = tables.Select(t =>
            {
                var allIndexes = t.GeneratAllIndexes().Where(a => !(a is PrimaryKeyIndex));;

                var mainIndices = allIndexes.Select(ix => sqlBuilder.CreateIndex(ix, checkUnique: null)).Combine(Spacing.Simple);

                var historyIndices = t.SystemVersioned == null ? null :
                                     allIndexes.Where(a => a.GetType() == typeof(TableIndex)).Select(mix => sqlBuilder.CreateIndexBasic(mix, forHistoryTable: true)).Combine(Spacing.Simple);

                return(SqlPreCommand.Combine(Spacing.Double, mainIndices, historyIndices));
            }).NotNull().Combine(Spacing.Double)?.PlainSqlCommand();


            return(SqlPreCommand.Combine(Spacing.Triple, createTables, foreignKeys, indices));
        }
コード例 #3
0
        public static SqlPreCommand SnapshotIsolation(Replacements replacements)
        {
            if (replacements.SchemaOnly)
            {
                return(null);
            }

            var list = Schema.Current.DatabaseNames().Select(a => a?.ToString()).ToList();

            if (list.Contains(null))
            {
                list.Remove(null);
                list.Add(Connector.Current.DatabaseName());
            }

            var results = Database.View <SysDatabases>()
                          .Where(d => list.Contains(d.name))
                          .Select(d => new { d.name, d.snapshot_isolation_state, d.is_read_committed_snapshot_on }).ToList();

            var cmd = replacements.WithReplacedDatabaseName().Using(_ => results.Select((a, i) =>
                                                                                        SqlPreCommand.Combine(Spacing.Simple,
                                                                                                              !a.snapshot_isolation_state || !a.is_read_committed_snapshot_on ? DisconnectUsers(a.name, "SPID" + i) : null,
                                                                                                              !a.snapshot_isolation_state ? SqlBuilder.SetSnapshotIsolation(a.name, true) : null,
                                                                                                              !a.is_read_committed_snapshot_on ? SqlBuilder.MakeSnapshotIsolationDefault(a.name, true) : null)).Combine(Spacing.Double));

            if (cmd == null)
            {
                return(null);
            }

            return(SqlPreCommand.Combine(Spacing.Double,
                                         new SqlPreCommandSimple("use master -- Start Snapshot"),
                                         cmd,
                                         new SqlPreCommandSimple("use {0} -- Stop Snapshot".FormatWith(Connector.Current.DatabaseName()))));
        }
コード例 #4
0
        public static SqlPreCommand SnapshotIsolation()
        {
            if (!Connector.Current.AllowsSetSnapshotIsolation)
            {
                return(null);
            }

            var list = Schema.Current.DatabaseNames().Select(a => a?.ToString()).ToList();

            if (list.Contains(null))
            {
                list.Remove(null);
                list.Add(Connector.Current.DatabaseName());
            }

            var cmd = list.Select(a =>
                                  SqlPreCommand.Combine(Spacing.Simple,
                                                        //DisconnectUsers(a.name, "SPID" + i) : null,
                                                        SqlBuilder.SetSingleUser(a),
                                                        SqlBuilder.SetSnapshotIsolation(a, true),
                                                        SqlBuilder.MakeSnapshotIsolationDefault(a, true),
                                                        SqlBuilder.SetMultiUser(a))
                                  ).Combine(Spacing.Double);

            return(cmd);
        }
コード例 #5
0
        public static SqlPreCommand CreateIndex(Index index)
        {
            string columns = index.Columns.ToString(c => c.Name.SqlEscape(), ", ");

            if (index is PrimaryClusteredIndex)
            {
                return(new SqlPreCommandSimple("ALTER TABLE {0} ADD CONSTRAINT {1} PRIMARY KEY CLUSTERED({2})".FormatWith(
                                                   index.Table.Name,
                                                   index.IndexName,
                                                   columns)));
            }

            if (index is UniqueIndex uIndex && uIndex.ViewName != null)
            {
                ObjectName viewName = new ObjectName(uIndex.Table.Name.Schema, uIndex.ViewName);

                SqlPreCommandSimple viewSql = new SqlPreCommandSimple(@"CREATE VIEW {0} WITH SCHEMABINDING AS SELECT {1} FROM {2} WHERE {3}"
                                                                      .FormatWith(viewName, columns, uIndex.Table.Name.ToString(), uIndex.Where))
                {
                    GoBefore = true, GoAfter = true
                };

                SqlPreCommandSimple indexSql = new SqlPreCommandSimple(@"CREATE UNIQUE CLUSTERED INDEX {0} ON {1}({2})"
                                                                       .FormatWith(uIndex.IndexName, viewName, uIndex.Columns.ToString(c => c.Name.SqlEscape(), ", ")));

                return(SqlPreCommand.Combine(Spacing.Simple, viewSql, indexSql));
            }
コード例 #6
0
        public static SqlPreCommand?SnapshotIsolation()
        {
            if (!Connector.Current.AllowsSetSnapshotIsolation)
            {
                return(null);
            }


            var list = Schema.Current.DatabaseNames().Select(a => a?.ToString()).ToList();

            if (list.Contains(null))
            {
                list.Remove(null);
                list.Add(Connector.Current.DatabaseName());
            }

            var cmd = list.NotNull()
                      .Where(db => !SnapshotIsolationEnabled(db))
                      .Select(db => SqlPreCommand.Combine(Spacing.Simple,
                                                          SqlBuilder.SetSingleUser(db),
                                                          SqlBuilder.SetSnapshotIsolation(db, true),
                                                          SqlBuilder.MakeSnapshotIsolationDefault(db, true),
                                                          SqlBuilder.SetMultiUser(db))
                              ).Combine(Spacing.Double);

            return(cmd);
        }
コード例 #7
0
        public static SqlPreCommand?SnapshotIsolation()
        {
            var connector = Connector.Current;

            if (!connector.AllowsSetSnapshotIsolation)
            {
                return(null);
            }


            var list = connector.Schema.DatabaseNames().Select(a => a?.ToString()).ToList();

            if (list.Contains(null))
            {
                list.Remove(null);
                list.Add(connector.DatabaseName());
            }

            var sqlBuilder = connector.SqlBuilder;

            var cmd = list.NotNull()
                      .Select(dbn => new DatabaseName(null, dbn, connector.Schema.Settings.IsPostgres))
                      .Where(db => !SnapshotIsolationEnabled(db))
                      .Select(db => SqlPreCommand.Combine(Spacing.Simple,
                                                          sqlBuilder.SetSingleUser(db),
                                                          sqlBuilder.SetSnapshotIsolation(db, true),
                                                          sqlBuilder.MakeSnapshotIsolationDefault(db, true),
                                                          sqlBuilder.SetMultiUser(db))
                              ).Combine(Spacing.Double);

            return(cmd);
        }
コード例 #8
0
        public static SqlPreCommand RemoveAllScript(DatabaseName databaseName)
        {
            var schemas = SqlBuilder.SystemSchemas.ToString(a => "'" + a + "'", ", ");

            return(SqlPreCommand.Combine(Spacing.Double,
                                         new SqlPreCommandSimple(Use(databaseName, RemoveAllProceduresScript)),
                                         new SqlPreCommandSimple(Use(databaseName, RemoveAllViewsScript)),
                                         new SqlPreCommandSimple(Use(databaseName, RemoveAllConstraintsScript)),
                                         new SqlPreCommandSimple(Use(databaseName, RemoveAllTablesScript)),
                                         new SqlPreCommandSimple(Use(databaseName, RemoveAllSchemasScript.FormatWith(schemas)))
                                         ));
        }
コード例 #9
0
        public static SqlPreCommand RenameOrMove(DiffTable oldTable, ITable newTable)
        {
            if (object.Equals(oldTable.Name.Schema.Database, newTable.Name.Schema.Database))
            {
                return(RenameOrChangeSchema(oldTable.Name, newTable.Name));
            }

            return(SqlPreCommand.Combine(Spacing.Simple,
                                         CreateTableSql(newTable),
                                         MoveRows(oldTable.Name, newTable.Name, newTable.Columns.Keys),
                                         DropTable(oldTable)) !);
        }
コード例 #10
0
        public static SqlPreCommand CreateTablesScript()
        {
            List <ITable> tables = Schema.Current.GetDatabaseTables().ToList();

            SqlPreCommand createTables = tables.Select(SqlBuilder.CreateTableSql).Combine(Spacing.Double).PlainSqlCommand();

            SqlPreCommand foreignKeys = tables.Select(SqlBuilder.AlterTableForeignKeys).Combine(Spacing.Double).PlainSqlCommand();

            SqlPreCommand indices = tables.Select(SqlBuilder.CreateAllIndices).NotNull().Combine(Spacing.Double).PlainSqlCommand();

            return(SqlPreCommand.Combine(Spacing.Triple, createTables, foreignKeys, indices));
        }
コード例 #11
0
        public static SqlPreCommand RemoveAllScript(DatabaseName databaseName)
        {
            var schemas = SqlBuilder.SystemSchemas.ToString(a => "'" + a + "'", ", ");

            return(SqlPreCommand.Combine(Spacing.Double,
                                         new SqlPreCommandSimple(Use(databaseName, RemoveAllProceduresScript)),
                                         new SqlPreCommandSimple(Use(databaseName, RemoveAllViewsScript)),
                                         new SqlPreCommandSimple(Use(databaseName, RemoveAllConstraintsScript)),
                                         Connector.Current.SupportsTemporalTables ? new SqlPreCommandSimple(Use(databaseName, StopSystemVersioning)) : null,
                                         new SqlPreCommandSimple(Use(databaseName, RemoveAllTablesScript)),
                                         new SqlPreCommandSimple(Use(databaseName, RemoveAllSchemasScript.FormatWith(schemas)))
                                         ));
        }
コード例 #12
0
        public static SqlPreCommand?RemoveDuplicatedIndices()
        {
            var isPostgres = Schema.Current.Settings.IsPostgres;
            var sqlBuilder = Connector.Current.SqlBuilder;
            var plainData  = (from s in Database.View <SysSchemas>()
                              from t in s.Tables()
                              from ix in t.Indices()
                              from ic in ix.IndexColumns()
                              from c in t.Columns()
                              where ic.column_id == c.column_id
                              select new
            {
                table = new ObjectName(new SchemaName(null, s.name, isPostgres), t.name, isPostgres),
                index = ix.name,
                ix.is_unique,
                column = c.name,
                ic.is_descending_key,
                ic.is_included_column,
                ic.index_column_id
            }).ToList();

            var tables = plainData.AgGroupToDictionary(a => a.table,
                                                       gr => gr.AgGroupToDictionary(a => new { a.index, a.is_unique },
                                                                                    gr2 => gr2.OrderBy(a => a.index_column_id)
                                                                                    .Select(a => a.column + (a.is_included_column ? "(K)" : "(I)") + (a.is_descending_key ? "(D)" : "(A)"))
                                                                                    .ToString("|")));

            var result = tables.SelectMany(t =>
                                           t.Value.GroupBy(a => a.Value, a => a.Key)
                                           .Where(gr => gr.Count() > 1)
                                           .Select(gr =>
            {
                var best = gr.OrderByDescending(a => a.is_unique).ThenByDescending(a => a.index !/*CSBUG*/.StartsWith("IX")).ThenByDescending(a => a.index).First();

                return(gr.Where(g => g != best)
                       .Select(g => sqlBuilder.DropIndex(t.Key !, g.index !))
                       .PreAnd(new SqlPreCommandSimple("-- DUPLICATIONS OF {0}".FormatWith(best.index))).Combine(Spacing.Simple));
            })
                                           ).Combine(Spacing.Double);

            if (result == null)
            {
                return(null);
            }

            return(SqlPreCommand.Combine(Spacing.Double,
                                         new SqlPreCommandSimple("use {0}".FormatWith(Connector.Current.DatabaseName())),
                                         result));
        }
コード例 #13
0
        public static SqlPreCommand CreateIndex(Index index)
        {
            string columns = index.Columns.ToString(c => c.Name.SqlEscape(), ", ");

            if (!(index is UniqueIndex))
            {
                return(new SqlPreCommandSimple("CREATE INDEX {0} ON {1}({2})".FormatWith(
                                                   index.IndexName,
                                                   index.Table.Name,
                                                   columns)));
            }
            else
            {
                var uIndex = (UniqueIndex)index;

                if (string.IsNullOrEmpty(uIndex.Where))
                {
                    return(new SqlPreCommandSimple("CREATE {0}INDEX {1} ON {2}({3})".FormatWith(
                                                       uIndex is UniqueIndex ? "UNIQUE " : null,
                                                       uIndex.IndexName,
                                                       uIndex.Table.Name,
                                                       columns)));
                }

                if (uIndex.ViewName != null)
                {
                    ObjectName viewName = new ObjectName(uIndex.Table.Name.Schema, uIndex.ViewName);

                    SqlPreCommandSimple viewSql = new SqlPreCommandSimple(@"CREATE VIEW {0} WITH SCHEMABINDING AS SELECT {1} FROM {2} WHERE {3}"
                                                                          .FormatWith(viewName, columns, uIndex.Table.Name.ToString(), uIndex.Where))
                    {
                        GoBefore = true, GoAfter = true
                    };

                    SqlPreCommandSimple indexSql = new SqlPreCommandSimple(@"CREATE UNIQUE CLUSTERED INDEX {0} ON {1}({2})"
                                                                           .FormatWith(uIndex.IndexName, viewName, uIndex.Columns.ToString(c => c.Name.SqlEscape(), ", ")));

                    return(SqlPreCommand.Combine(Spacing.Simple, viewSql, indexSql));
                }
                else
                {
                    return(new SqlPreCommandSimple("CREATE UNIQUE INDEX {0} ON {1}({2}) WHERE {3}".FormatWith(
                                                       uIndex.IndexName,
                                                       uIndex.Table.Name,
                                                       columns, uIndex.Where)));
                }
            }
        }
コード例 #14
0
        public static SqlPreCommand TotalSynchronizeScript(bool interactive = true, bool schemaOnly = false)
        {
            var command = Schema.Current.SynchronizationScript(interactive, schemaOnly);

            if (command == null)
            {
                return(null);
            }

            return(SqlPreCommand.Combine(Spacing.Double,
                                         new SqlPreCommandSimple(SynchronizerMessage.StartOfSyncScriptGeneratedOn0.NiceToString().FormatWith(DateTime.Now)),

                                         new SqlPreCommandSimple("use {0}".FormatWith(Connector.Current.DatabaseName())),
                                         command,
                                         new SqlPreCommandSimple(SynchronizerMessage.EndOfSyncScript.NiceToString())));
        }
コード例 #15
0
ファイル: SqlBuilder.cs プロジェクト: hua7073/framework
        public static SqlPreCommand MoveRows(ObjectName oldTable, ObjectName newTable, IEnumerable <string> columnNames)
        {
            SqlPreCommandSimple command = new SqlPreCommandSimple(
                @"INSERT INTO {0} ({2})
SELECT {3}
FROM {1} as [table]".FormatWith(
                    newTable,
                    oldTable,
                    columnNames.ToString(a => a.SqlEscape(), ", "),
                    columnNames.ToString(a => "[table]." + a.SqlEscape(), ", ")));

            return(SqlPreCommand.Combine(Spacing.Simple,
                                         new SqlPreCommandSimple("SET IDENTITY_INSERT {0} ON".FormatWith(newTable)),
                                         command,
                                         new SqlPreCommandSimple("SET IDENTITY_INSERT {0} OFF".FormatWith(newTable))));
        }
コード例 #16
0
        public static SqlPreCommand AlterTableAlterColumn(ITable table, IColumn column, string?defaultConstraintName = null, ObjectName?forceTableName = null)
        {
            var alterColumn = new SqlPreCommandSimple("ALTER TABLE {0} ALTER COLUMN {1}".FormatWith(forceTableName ?? table.Name, CreateColumn(column, null, isChange: true)));

            if (column.Default == null)
            {
                return(alterColumn);
            }

            var defCons = GetDefaultConstaint(table, column) !;

            return(SqlPreCommand.Combine(Spacing.Simple,
                                         AlterTableDropConstraint(table.Name, defaultConstraintName ?? defCons.Name),
                                         alterColumn,
                                         AlterTableAddDefaultConstraint(table.Name, defCons)
                                         ) !);
        }
コード例 #17
0
        public static SqlPreCommand RenameOrChangeSchema(ObjectName oldTableName, ObjectName newTableName)
        {
            if (!object.Equals(oldTableName.Schema.Database, newTableName.Schema.Database))
            {
                throw new InvalidOperationException("Different database");
            }

            if (object.Equals(oldTableName.Schema, newTableName.Schema))
            {
                return(RenameTable(oldTableName, newTableName.Name));
            }

            var oldNewSchema = oldTableName.OnSchema(newTableName.Schema);

            return(SqlPreCommand.Combine(Spacing.Simple,
                                         AlterSchema(oldTableName, newTableName.Schema),
                                         oldNewSchema.Equals(newTableName) ? null : RenameTable(oldNewSchema, newTableName.Name)) !);
        }
コード例 #18
0
        private static SqlPreCommand SyncEnums(Schema schema, Table table, Dictionary <string, Entity> current, Dictionary <string, Entity> should)
        {
            var deletes = Synchronizer.SynchronizeScript(
                should,
                current,
                null,
                (str, c) => table.DeleteSqlSync(c, comment: c.toStr),
                null, Spacing.Double);

            var moves = Synchronizer.SynchronizeScript(
                should,
                current,
                null,
                null,
                (str, s, c) =>
            {
                if (s.id == c.id)
                {
                    return(table.UpdateSqlSync(c, comment: c.toStr));
                }

                var insert = table.InsertSqlSync(s);

                var move = (from t in schema.GetDatabaseTables()
                            from col in t.Columns.Values
                            where col.ReferenceTable == table
                            select new SqlPreCommandSimple("UPDATE {0} SET {1} = {2} WHERE {1} = {3} -- {4} re-indexed"
                                                           .FormatWith(t.Name, col.Name, s.Id, c.Id, c.toStr)))
                           .Combine(Spacing.Simple);

                var delete = table.DeleteSqlSync(c, comment: c.toStr);

                return(SqlPreCommand.Combine(Spacing.Simple, insert, move, delete));
            }, Spacing.Double);

            var creates = Synchronizer.SynchronizeScript(
                should,
                current,
                (str, s) => table.InsertSqlSync(s),
                null,
                null, Spacing.Double);

            return(SqlPreCommand.Combine(Spacing.Double, deletes, moves, creates));
        }
コード例 #19
0
        private static SqlPreCommand AlterTableAddColumnDefault(ITable table, IColumn column, Replacements rep)
        {
            bool temporalDefault = !column.Nullable && !column.Identity && column.Default == null;

            if (!temporalDefault)
            {
                return(SqlBuilder.AlterTableAddColumn(table, column));
            }

            string defaultValue = rep.Interactive ? SafeConsole.AskString("Default value for '{0}.{1}'? (or press enter) ".FormatWith(table.Name.Name, column.Name), stringValidator: str => null) : "";

            if (defaultValue == "null")
            {
                return(SqlBuilder.AlterTableAddColumn(table, column));
            }

            try
            {
                column.Default = defaultValue;

                if (column.Default.HasText() && SqlBuilder.IsString(column.SqlDbType) && !column.Default.Contains("'"))
                {
                    column.Default = "'" + column.Default + "'";
                }

                if (string.IsNullOrEmpty(column.Default))
                {
                    column.Default = SqlBuilder.IsNumber(column.SqlDbType) ? "0" :
                                     SqlBuilder.IsString(column.SqlDbType) ? "''" :
                                     SqlBuilder.IsDate(column.SqlDbType) ? "GetDate()" :
                                     "?";
                }

                return(SqlPreCommand.Combine(Spacing.Simple,
                                             SqlBuilder.AlterTableAddColumn(table, column),
                                             SqlBuilder.DropDefaultConstraint(table.Name, column.Name)));
            }
            finally
            {
                column.Default = null;
            }
        }
コード例 #20
0
        public static SqlPreCommand CreateIndex(Index index, Replacements?checkUnique)
        {
            if (index is PrimaryClusteredIndex)
            {
                var columns = index.Columns.ToString(c => c.Name.SqlEscape(), ", ");

                return(new SqlPreCommandSimple($"ALTER TABLE {index.Table.Name} ADD CONSTRAINT {index.IndexName} PRIMARY KEY CLUSTERED({columns})"));
            }

            if (index is UniqueIndex uIndex)
            {
                if (uIndex.ViewName != null)
                {
                    ObjectName viewName = new ObjectName(uIndex.Table.Name.Schema, uIndex.ViewName);

                    var columns = index.Columns.ToString(c => c.Name.SqlEscape(), ", ");

                    SqlPreCommandSimple viewSql = new SqlPreCommandSimple($"CREATE VIEW {viewName} WITH SCHEMABINDING AS SELECT {columns} FROM {uIndex.Table.Name.ToString()} WHERE {uIndex.Where}")
                    {
                        GoBefore = true, GoAfter = true
                    };

                    SqlPreCommandSimple indexSql = new SqlPreCommandSimple($"CREATE UNIQUE CLUSTERED INDEX {uIndex.IndexName} ON {viewName}({columns})");

                    return(SqlPreCommand.Combine(Spacing.Simple,
                                                 checkUnique != null ? RemoveDuplicatesIfNecessary(uIndex, checkUnique) : null,
                                                 viewSql,
                                                 indexSql) !);
                }
                else
                {
                    return(SqlPreCommand.Combine(Spacing.Double,
                                                 checkUnique != null ? RemoveDuplicatesIfNecessary(uIndex, checkUnique) : null,
                                                 CreateIndexBasic(index, false)) !);
                }
            }
            else
            {
                return(CreateIndexBasic(index, forHistoryTable: false));
            }
        }
コード例 #21
0
ファイル: SqlBuilder.cs プロジェクト: hua7073/framework
        public static SqlPreCommand RenameOrMove(DiffTable oldTable, ITable newTable)
        {
            if (object.Equals(oldTable.Name.Schema, newTable.Name.Schema))
            {
                return(RenameTable(oldTable.Name, newTable.Name.Name));
            }

            if (object.Equals(oldTable.Name.Schema.Database, newTable.Name.Schema.Database))
            {
                var oldNewSchema = oldTable.Name.OnSchema(newTable.Name.Schema);

                return(SqlPreCommand.Combine(Spacing.Simple,
                                             AlterSchema(oldTable.Name, newTable.Name.Schema),
                                             oldNewSchema.Equals(newTable.Name) ? null : RenameTable(oldNewSchema, newTable.Name.Name)));
            }

            return(SqlPreCommand.Combine(Spacing.Simple,
                                         CreateTableSql(newTable),
                                         MoveRows(oldTable.Name, newTable.Name, newTable.Columns.Keys),
                                         DropTable(oldTable.Name)));
        }
コード例 #22
0
        internal static SqlPreCommand CopyData(ITable newTable, DiffTable oldTable, Replacements rep)
        {
            var selectColumns = newTable.Columns
                                .Select(col => oldTable.Columns.TryGetC(col.Key)?.Name ?? GetDefaultValue(newTable, col.Value, rep))
                                .ToString(", ");

            var insertSelect = new SqlPreCommandSimple(
                $@"INSERT INTO {newTable.Name} ({newTable.Columns.Values.ToString(a => a.Name, ", ")})
SELECT {selectColumns}
FROM {oldTable.Name}");

            if (!newTable.PrimaryKey.Identity)
            {
                return(insertSelect);
            }

            return(SqlPreCommand.Combine(Spacing.Simple,
                                         SqlBuilder.SetIdentityInsert(newTable.Name, true),
                                         insertSelect,
                                         SqlBuilder.SetIdentityInsert(newTable.Name, false)
                                         ));
        }
コード例 #23
0
 public static SqlPreCommand Combine(this IEnumerable <SqlPreCommand> preCommands, Spacing spacing)
 {
     return(SqlPreCommand.Combine(spacing, preCommands.ToArray()));
 }
コード例 #24
0
        public static SqlPreCommand SynchronizeTablesScript(Replacements replacements)
        {
            Dictionary <string, ITable> model        = Schema.Current.GetDatabaseTables().ToDictionaryEx(a => a.Name.ToString(), "schema tables");
            HashSet <SchemaName>        modelSchemas = Schema.Current.GetDatabaseTables().Select(a => a.Name.Schema).Where(a => !SqlBuilder.SystemSchemas.Contains(a.Name)).ToHashSet();

            Dictionary <string, DiffTable> database        = DefaultGetDatabaseDescription(Schema.Current.DatabaseNames());
            HashSet <SchemaName>           databaseSchemas = DefaultGetSchemas(Schema.Current.DatabaseNames());

            if (SimplifyDiffTables != null)
            {
                SimplifyDiffTables(database);
            }

            replacements.AskForReplacements(database.Keys.ToHashSet(), model.Keys.ToHashSet(), Replacements.KeyTables);

            database = replacements.ApplyReplacementsToOld(database, Replacements.KeyTables);

            Dictionary <ITable, Dictionary <string, Index> > modelIndices = model.Values
                                                                            .ToDictionary(t => t, t => t.GeneratAllIndexes().ToDictionaryEx(a => a.IndexName, "Indexes for {0}".FormatWith(t.Name)));

            model.JoinDictionaryForeach(database, (tn, tab, diff) =>
            {
                var key = Replacements.KeyColumnsForTable(tn);

                replacements.AskForReplacements(diff.Columns.Keys.ToHashSet(), tab.Columns.Keys.ToHashSet(), key);

                diff.Columns = replacements.ApplyReplacementsToOld(diff.Columns, key);

                diff.Indices = ApplyIndexAutoReplacements(diff, tab, modelIndices[tab]);
            });

            Func <ObjectName, ObjectName> ChangeName = (ObjectName objectName) =>
            {
                string name = replacements.Apply(Replacements.KeyTables, objectName.ToString());

                return(model.TryGetC(name)?.Name ?? objectName);
            };


            Func <ObjectName, SqlPreCommand> DeleteAllForeignKey = tableName =>
            {
                var dropFks = (from t in database.Values
                               from c in t.Columns.Values
                               where c.ForeignKey != null && c.ForeignKey.TargetTable.Equals(tableName)
                               select SqlBuilder.AlterTableDropConstraint(t.Name, c.ForeignKey.Name)).Combine(Spacing.Simple);

                if (dropFks == null)
                {
                    return(null);
                }

                return(SqlPreCommand.Combine(Spacing.Simple, new SqlPreCommandSimple("---In order to remove the PK of " + tableName.Name), dropFks));
            };

            using (replacements.WithReplacedDatabaseName())
            {
                SqlPreCommand createSchemas = Synchronizer.SynchronizeScriptReplacing(replacements, "Schemas",
                                                                                      modelSchemas.ToDictionary(a => a.ToString()),
                                                                                      databaseSchemas.ToDictionary(a => a.ToString()),
                                                                                      (_, newSN) => SqlBuilder.CreateSchema(newSN),
                                                                                      null,
                                                                                      (_, newSN, oldSN) => newSN.Equals(oldSN) ? null : SqlBuilder.CreateSchema(newSN),
                                                                                      Spacing.Double);

                //use database without replacements to just remove indexes
                SqlPreCommand dropStatistics =
                    Synchronizer.SynchronizeScript(model, database,
                                                   null,
                                                   (tn, dif) => SqlBuilder.DropStatistics(tn, dif.Stats),
                                                   (tn, tab, dif) =>
                {
                    var removedColums = dif.Columns.Keys.Except(tab.Columns.Keys).ToHashSet();

                    return(SqlBuilder.DropStatistics(tn, dif.Stats.Where(a => a.Columns.Any(removedColums.Contains)).ToList()));
                },
                                                   Spacing.Double);

                SqlPreCommand dropIndices =
                    Synchronizer.SynchronizeScript(model, database,
                                                   null,
                                                   (tn, dif) => dif.Indices.Values.Where(ix => !ix.IsPrimary).Select(ix => SqlBuilder.DropIndex(dif.Name, ix)).Combine(Spacing.Simple),
                                                   (tn, tab, dif) =>
                {
                    Dictionary <string, Index> modelIxs = modelIndices[tab];

                    var removedColums = dif.Columns.Keys.Except(tab.Columns.Keys).ToHashSet();

                    var changes = Synchronizer.SynchronizeScript(modelIxs, dif.Indices,
                                                                 null,
                                                                 (i, dix) => dix.Columns.Any(removedColums.Contains) || dix.IsControlledIndex ? SqlBuilder.DropIndex(dif.Name, dix) : null,
                                                                 (i, mix, dix) => !dix.IndexEquals(dif, mix) ? SqlPreCommand.Combine(Spacing.Double, dix.IsPrimary ? DeleteAllForeignKey(dif.Name) : null, SqlBuilder.DropIndex(dif.Name, dix)) : null,
                                                                 Spacing.Simple);

                    return(changes);
                },
                                                   Spacing.Double);

                SqlPreCommand dropForeignKeys = Synchronizer.SynchronizeScript(
                    model,
                    database,
                    null,
                    (tn, dif) => dif.Columns.Values.Select(c => c.ForeignKey != null ? SqlBuilder.AlterTableDropConstraint(dif.Name, c.ForeignKey.Name) : null)
                    .Concat(dif.MultiForeignKeys.Select(fk => SqlBuilder.AlterTableDropConstraint(dif.Name, fk.Name))).Combine(Spacing.Simple),
                    (tn, tab, dif) => SqlPreCommand.Combine(Spacing.Simple,
                                                            Synchronizer.SynchronizeScript(
                                                                tab.Columns,
                                                                dif.Columns,
                                                                null,
                                                                (cn, colDb) => colDb.ForeignKey != null ? SqlBuilder.AlterTableDropConstraint(dif.Name, colDb.ForeignKey.Name) : null,
                                                                (cn, colModel, colDb) => colDb.ForeignKey == null ? null :
                                                                colModel.ReferenceTable == null || colModel.AvoidForeignKey || !colModel.ReferenceTable.Name.Equals(ChangeName(colDb.ForeignKey.TargetTable)) ?
                                                                SqlBuilder.AlterTableDropConstraint(dif.Name, colDb.ForeignKey.Name) :
                                                                null, Spacing.Simple),
                                                            dif.MultiForeignKeys.Select(fk => SqlBuilder.AlterTableDropConstraint(dif.Name, fk.Name)).Combine(Spacing.Simple)),
                    Spacing.Double);

                SqlPreCommand tables =
                    Synchronizer.SynchronizeScript(
                        model,
                        database,
                        (tn, tab) => SqlBuilder.CreateTableSql(tab),
                        (tn, dif) => SqlBuilder.DropTable(dif.Name),
                        (tn, tab, dif) =>
                        SqlPreCommand.Combine(Spacing.Simple,
                                              !object.Equals(dif.Name, tab.Name) ? SqlBuilder.RenameOrMove(dif, tab) : null,
                                              Synchronizer.SynchronizeScript(
                                                  tab.Columns,
                                                  dif.Columns,
                                                  (cn, tabCol) => SqlPreCommandSimple.Combine(Spacing.Simple,
                                                                                              tabCol.PrimaryKey && dif.PrimaryKeyName != null ? SqlBuilder.DropPrimaryKeyConstraint(tab.Name) : null,
                                                                                              AlterTableAddColumnDefault(tab, tabCol, replacements)),
                                                  (cn, difCol) => SqlPreCommandSimple.Combine(Spacing.Simple,
                                                                                              difCol.Default != null ? SqlBuilder.DropDefaultConstraint(tab.Name, difCol.Name) : null,
                                                                                              SqlBuilder.AlterTableDropColumn(tab, cn)),
                                                  (cn, tabCol, difCol) => SqlPreCommand.Combine(Spacing.Simple,
                                                                                                difCol.Name == tabCol.Name ? null : SqlBuilder.RenameColumn(tab, difCol.Name, tabCol.Name),
                                                                                                difCol.ColumnEquals(tabCol, ignorePrimaryKey: true) ? null : SqlPreCommand.Combine(Spacing.Simple,
                                                                                                                                                                                   tabCol.PrimaryKey && !difCol.PrimaryKey && dif.PrimaryKeyName != null ? SqlBuilder.DropPrimaryKeyConstraint(tab.Name) : null,
                                                                                                                                                                                   SqlBuilder.AlterTableAlterColumn(tab, tabCol),
                                                                                                                                                                                   tabCol.SqlDbType == SqlDbType.NVarChar && difCol.SqlDbType == SqlDbType.NChar ? SqlBuilder.UpdateTrim(tab, tabCol) : null),
                                                                                                difCol.DefaultEquals(tabCol) ? null : SqlPreCommand.Combine(Spacing.Simple,
                                                                                                                                                            difCol.Default != null ? SqlBuilder.DropDefaultConstraint(tab.Name, tabCol.Name) : null,
                                                                                                                                                            tabCol.Default != null ? SqlBuilder.AddDefaultConstraint(tab.Name, tabCol.Name, tabCol.Default) : null),
                                                                                                UpdateByFkChange(tn, difCol, tabCol, ChangeName)),
                                                  Spacing.Simple)),
                        Spacing.Double);

                if (tables != null)
                {
                    tables.GoAfter = true;
                }

                var tableReplacements = replacements.TryGetC(Replacements.KeyTables);
                if (tableReplacements != null)
                {
                    replacements[Replacements.KeyTablesInverse] = tableReplacements.Inverse();
                }

                SqlPreCommand syncEnums;

                try
                {
                    syncEnums = SynchronizeEnumsScript(replacements);
                }
                catch (Exception e)
                {
                    syncEnums = new SqlPreCommandSimple("-- Exception synchronizing enums: " + e.Message);
                }

                SqlPreCommand addForeingKeys = Synchronizer.SynchronizeScript(
                    model,
                    database,
                    (tn, tab) => SqlBuilder.AlterTableForeignKeys(tab),
                    null,
                    (tn, tab, dif) => Synchronizer.SynchronizeScript(
                        tab.Columns,
                        dif.Columns,
                        (cn, colModel) => colModel.ReferenceTable == null || colModel.AvoidForeignKey ? null :
                        SqlBuilder.AlterTableAddConstraintForeignKey(tab, colModel.Name, colModel.ReferenceTable),
                        null,
                        (cn, colModel, coldb) =>
                {
                    if (colModel.ReferenceTable == null || colModel.AvoidForeignKey)
                    {
                        return(null);
                    }

                    if (coldb.ForeignKey == null || !colModel.ReferenceTable.Name.Equals(ChangeName(coldb.ForeignKey.TargetTable)))
                    {
                        return(SqlBuilder.AlterTableAddConstraintForeignKey(tab, colModel.Name, colModel.ReferenceTable));
                    }

                    var name = SqlBuilder.ForeignKeyName(tab.Name.Name, colModel.Name);
                    return(SqlPreCommand.Combine(Spacing.Simple,
                                                 name != coldb.ForeignKey.Name.Name ? SqlBuilder.RenameForeignKey(coldb.ForeignKey.Name, name) : null,
                                                 (coldb.ForeignKey.IsDisabled || coldb.ForeignKey.IsNotTrusted) && !replacements.SchemaOnly ? SqlBuilder.EnableForeignKey(tab.Name, name) : null));
                },
                        Spacing.Simple),
                    Spacing.Double);

                bool?createMissingFreeIndexes = null;

                SqlPreCommand addIndices =
                    Synchronizer.SynchronizeScript(model, database,
                                                   (tn, tab) => modelIndices[tab].Values.Where(a => !(a is PrimaryClusteredIndex)).Select(SqlBuilder.CreateIndex).Combine(Spacing.Simple),
                                                   null,
                                                   (tn, tab, dif) =>
                {
                    var columnReplacements = replacements.TryGetC(Replacements.KeyColumnsForTable(tn));

                    Func <IColumn, bool> isNew = c => !dif.Columns.ContainsKey(columnReplacements?.TryGetC(c.Name) ?? c.Name);

                    Dictionary <string, Index> modelIxs = modelIndices[tab];

                    var controlledIndexes = Synchronizer.SynchronizeScript(modelIxs, dif.Indices,
                                                                           (i, mix) => mix is UniqueIndex || mix.Columns.Any(isNew) || SafeConsole.Ask(ref createMissingFreeIndexes, "Create missing non-unique index {0} in {1}?".FormatWith(mix.IndexName, tab.Name)) ? SqlBuilder.CreateIndex(mix) : null,
                                                                           null,
                                                                           (i, mix, dix) => !dix.IndexEquals(dif, mix) ? SqlBuilder.CreateIndex(mix) :
                                                                           mix.IndexName != dix.IndexName ? SqlBuilder.RenameIndex(tab, dix.IndexName, mix.IndexName) : null,
                                                                           Spacing.Simple);

                    return(SqlPreCommand.Combine(Spacing.Simple, controlledIndexes));
                }, Spacing.Double);

                SqlPreCommand dropSchemas = Synchronizer.SynchronizeScriptReplacing(replacements, "Schemas",
                                                                                    modelSchemas.ToDictionary(a => a.ToString()),
                                                                                    databaseSchemas.ToDictionary(a => a.ToString()),
                                                                                    null,
                                                                                    (_, oldSN) => DropSchema(oldSN) ? SqlBuilder.DropSchema(oldSN) : null,
                                                                                    (_, newSN, oldSN) => newSN.Equals(oldSN) ? null : SqlBuilder.DropSchema(oldSN),
                                                                                    Spacing.Double);

                return(SqlPreCommand.Combine(Spacing.Triple, createSchemas, dropStatistics, dropIndices, dropForeignKeys, tables, syncEnums, addForeingKeys, addIndices, dropSchemas));
            }
        }
コード例 #25
0
        public static SqlPreCommand SynchronizeTablesScript(Replacements replacements)
        {
            Schema s = Schema.Current;

            Dictionary <string, ITable> model        = s.GetDatabaseTables().Where(t => !s.IsExternalDatabase(t.Name.Schema.Database)).ToDictionaryEx(a => a.Name.ToString(), "schema tables");
            HashSet <SchemaName>        modelSchemas = model.Values.Select(a => a.Name.Schema).Where(a => !SqlBuilder.SystemSchemas.Contains(a.Name)).ToHashSet();

            Dictionary <string, DiffTable> database        = DefaultGetDatabaseDescription(s.DatabaseNames());
            HashSet <SchemaName>           databaseSchemas = DefaultGetSchemas(s.DatabaseNames());

            SimplifyDiffTables?.Invoke(database);

            replacements.AskForReplacements(database.Keys.ToHashSet(), model.Keys.ToHashSet(), Replacements.KeyTables);

            database = replacements.ApplyReplacementsToOld(database, Replacements.KeyTables);

            Dictionary <ITable, Dictionary <string, Index> > modelIndices = model.Values
                                                                            .ToDictionary(t => t, t => t.GeneratAllIndexes().ToDictionaryEx(a => a.IndexName, "Indexes for {0}".FormatWith(t.Name)));

            //To --> From
            Dictionary <ObjectName, ObjectName> copyDataFrom = new Dictionary <ObjectName, ObjectName>();

            //A -> A_temp
            Dictionary <ObjectName, ObjectName> preRenames = new Dictionary <ObjectName, ObjectName>();

            model.JoinDictionaryForeach(database, (tn, tab, diff) =>
            {
                var key = Replacements.KeyColumnsForTable(tn);

                replacements.AskForReplacements(diff.Columns.Keys.ToHashSet(), tab.Columns.Keys.ToHashSet(), key);

                diff.Columns = replacements.ApplyReplacementsToOld(diff.Columns, key);

                diff.Indices = ApplyIndexAutoReplacements(diff, tab, modelIndices[tab]);

                var diffPk = diff.Columns.TryGetC(tab.PrimaryKey.Name);
                if (diffPk != null && tab.PrimaryKey.Identity != diffPk.Identity)
                {
                    if (tab.Name.Equals(diff.Name))
                    {
                        var tempName = new ObjectName(diff.Name.Schema, diff.Name.Name + "_old");
                        preRenames.Add(diff.Name, tempName);
                        copyDataFrom.Add(tab.Name, tempName);

                        if (replacements.Interactive)
                        {
                            SafeConsole.WriteLineColor(ConsoleColor.Yellow, $@"Column {diffPk.Name} in {diff.Name} is now Identity={tab.PrimaryKey.Identity}.");
                            Console.WriteLine($@"Changing a Primary Key is not supported by SQL Server so the script will...:
  1. Rename {diff.Name} table to {tempName}
  2. Create a new table {diff.Name} 
  3. Copy data from {tempName} to {tab.Name}.
  4. Drop {tempName}
");
                        }
                    }
                    else
                    {
                        copyDataFrom.Add(tab.Name, diff.Name);
                        if (replacements.Interactive)
                        {
                            SafeConsole.WriteLineColor(ConsoleColor.Yellow, $@"Column {diffPk.Name} in {diff.Name} is now Identity={tab.PrimaryKey.Identity}.");
                            Console.WriteLine($@"Changing a Primary Key is not supported by SQL Server so the script will...:
  1. Create a new table {tab.Name} 
  2. Copy data from {diff.Name} to {tab.Name}.
  3. Drop {diff.Name}
");
                        }
                    }
                }
            });

            var columnsByFKTarget = database.Values.SelectMany(a => a.Columns.Values).Where(a => a.ForeignKey != null).GroupToDictionary(a => a.ForeignKey.TargetTable);

            foreach (var pr in preRenames)
            {
                var diff = database[pr.Key.ToString()];
                diff.Name = pr.Value;
                foreach (var col in columnsByFKTarget.TryGetC(pr.Key).EmptyIfNull())
                {
                    col.ForeignKey.TargetTable = pr.Value;
                }

                database.Add(pr.Value.ToString(), diff);
                database.Remove(pr.Key.ToString());
            }

            Func <ObjectName, ObjectName> ChangeName = (ObjectName objectName) =>
            {
                string name = replacements.Apply(Replacements.KeyTables, objectName.ToString());

                return(model.TryGetC(name)?.Name ?? objectName);
            };


            Func <ObjectName, SqlPreCommand> DeleteAllForeignKey = tableName =>
            {
                var dropFks = (from t in database.Values
                               from c in t.Columns.Values
                               where c.ForeignKey != null && c.ForeignKey.TargetTable.Equals(tableName)
                               select SqlBuilder.AlterTableDropConstraint(t.Name, c.ForeignKey.Name)).Combine(Spacing.Simple);

                if (dropFks == null)
                {
                    return(null);
                }

                return(SqlPreCommand.Combine(Spacing.Simple, new SqlPreCommandSimple("---In order to remove the PK of " + tableName.Name), dropFks));
            };

            using (replacements.WithReplacedDatabaseName())
            {
                SqlPreCommand preRenameTables = preRenames.Select(a => SqlBuilder.RenameTable(a.Key, a.Value.Name)).Combine(Spacing.Double);

                if (preRenameTables != null)
                {
                    preRenameTables.GoAfter = true;
                }

                SqlPreCommand createSchemas = Synchronizer.SynchronizeScriptReplacing(replacements, "Schemas",
                                                                                      modelSchemas.ToDictionary(a => a.ToString()),
                                                                                      databaseSchemas.ToDictionary(a => a.ToString()),
                                                                                      (_, newSN) => SqlBuilder.CreateSchema(newSN),
                                                                                      null,
                                                                                      (_, newSN, oldSN) => newSN.Equals(oldSN) ? null : SqlBuilder.CreateSchema(newSN),
                                                                                      Spacing.Double);

                //use database without replacements to just remove indexes
                SqlPreCommand dropStatistics =
                    Synchronizer.SynchronizeScript(model, database,
                                                   null,
                                                   (tn, dif) => SqlBuilder.DropStatistics(tn, dif.Stats),
                                                   (tn, tab, dif) =>
                {
                    var removedColums = dif.Columns.Keys.Except(tab.Columns.Keys).ToHashSet();

                    return(SqlBuilder.DropStatistics(tn, dif.Stats.Where(a => a.Columns.Any(removedColums.Contains)).ToList()));
                },
                                                   Spacing.Double);

                SqlPreCommand dropIndices =
                    Synchronizer.SynchronizeScript(model, database,
                                                   null,
                                                   (tn, dif) => dif.Indices.Values.Where(ix => !ix.IsPrimary).Select(ix => SqlBuilder.DropIndex(dif.Name, ix)).Combine(Spacing.Simple),
                                                   (tn, tab, dif) =>
                {
                    Dictionary <string, Index> modelIxs = modelIndices[tab];

                    var removedColums = dif.Columns.Keys.Except(tab.Columns.Keys).ToHashSet();

                    var changes = Synchronizer.SynchronizeScript(modelIxs, dif.Indices,
                                                                 null,
                                                                 (i, dix) => dix.Columns.Any(removedColums.Contains) || dix.IsControlledIndex ? SqlBuilder.DropIndex(dif.Name, dix) : null,
                                                                 (i, mix, dix) => !dix.IndexEquals(dif, mix) ? SqlPreCommand.Combine(Spacing.Double, dix.IsPrimary ? DeleteAllForeignKey(dif.Name) : null, SqlBuilder.DropIndex(dif.Name, dix)) : null,
                                                                 Spacing.Simple);

                    return(changes);
                },
                                                   Spacing.Double);

                SqlPreCommand dropForeignKeys = Synchronizer.SynchronizeScript(
                    model,
                    database,
                    null,
                    (tn, dif) => dif.Columns.Values.Select(c => c.ForeignKey != null ? SqlBuilder.AlterTableDropConstraint(dif.Name, c.ForeignKey.Name) : null)
                    .Concat(dif.MultiForeignKeys.Select(fk => SqlBuilder.AlterTableDropConstraint(dif.Name, fk.Name))).Combine(Spacing.Simple),
                    (tn, tab, dif) => SqlPreCommand.Combine(Spacing.Simple,
                                                            Synchronizer.SynchronizeScript(
                                                                tab.Columns,
                                                                dif.Columns,
                                                                null,
                                                                (cn, colDb) => colDb.ForeignKey != null ? SqlBuilder.AlterTableDropConstraint(dif.Name, colDb.ForeignKey.Name) : null,
                                                                (cn, colModel, colDb) => colDb.ForeignKey == null ? null :
                                                                colModel.ReferenceTable == null || colModel.AvoidForeignKey || !colModel.ReferenceTable.Name.Equals(ChangeName(colDb.ForeignKey.TargetTable)) ?
                                                                SqlBuilder.AlterTableDropConstraint(dif.Name, colDb.ForeignKey.Name) :
                                                                null, Spacing.Simple),
                                                            dif.MultiForeignKeys.Select(fk => SqlBuilder.AlterTableDropConstraint(dif.Name, fk.Name)).Combine(Spacing.Simple)),
                    Spacing.Double);

                SqlPreCommand preRenamePks = preRenames.Select(a => SqlBuilder.DropPrimaryKeyConstraint(a.Value)).Combine(Spacing.Double);

                SqlPreCommand tables =
                    Synchronizer.SynchronizeScript(
                        model,
                        database,
                        (tn, tab) => SqlPreCommand.Combine(Spacing.Double,
                                                           SqlBuilder.CreateTableSql(tab),
                                                           copyDataFrom.ContainsKey(tab.Name) ? CopyData(tab, database.GetOrThrow(copyDataFrom.GetOrThrow(tab.Name).ToString()), replacements).Do(a => a.GoBefore = true) : null
                                                           ),
                        (tn, dif) => SqlBuilder.DropTable(dif.Name),
                        (tn, tab, dif) =>
                        SqlPreCommand.Combine(Spacing.Simple,
                                              !object.Equals(dif.Name, tab.Name) ? SqlBuilder.RenameOrMove(dif, tab) : null,
                                              Synchronizer.SynchronizeScript(
                                                  tab.Columns,
                                                  dif.Columns,
                                                  (cn, tabCol) => SqlPreCommand.Combine(Spacing.Simple,
                                                                                        tabCol.PrimaryKey && dif.PrimaryKeyName != null ? SqlBuilder.DropPrimaryKeyConstraint(tab.Name) : null,
                                                                                        AlterTableAddColumnDefault(tab, tabCol, replacements)),
                                                  (cn, difCol) => SqlPreCommand.Combine(Spacing.Simple,
                                                                                        difCol.Default != null ? SqlBuilder.DropDefaultConstraint(tab.Name, difCol.Name) : null,
                                                                                        SqlBuilder.AlterTableDropColumn(tab, cn)),
                                                  (cn, tabCol, difCol) => SqlPreCommand.Combine(Spacing.Simple,
                                                                                                difCol.Name == tabCol.Name ? null : SqlBuilder.RenameColumn(tab, difCol.Name, tabCol.Name),
                                                                                                difCol.ColumnEquals(tabCol, ignorePrimaryKey: true) ? null : SqlPreCommand.Combine(Spacing.Simple,
                                                                                                                                                                                   tabCol.PrimaryKey && !difCol.PrimaryKey && dif.PrimaryKeyName != null ? SqlBuilder.DropPrimaryKeyConstraint(tab.Name) : null,
                                                                                                                                                                                   SqlBuilder.AlterTableAlterColumn(tab, tabCol),
                                                                                                                                                                                   tabCol.SqlDbType == SqlDbType.NVarChar && difCol.SqlDbType == SqlDbType.NChar ? SqlBuilder.UpdateTrim(tab, tabCol) : null),
                                                                                                difCol.DefaultEquals(tabCol) ? null : SqlPreCommand.Combine(Spacing.Simple,
                                                                                                                                                            difCol.Default != null ? SqlBuilder.DropDefaultConstraint(tab.Name, tabCol.Name) : null,
                                                                                                                                                            tabCol.Default != null ? SqlBuilder.AddDefaultConstraint(tab.Name, tabCol.Name, tabCol.Default, tabCol.SqlDbType) : null),
                                                                                                UpdateByFkChange(tn, difCol, tabCol, ChangeName, copyDataFrom)),
                                                  Spacing.Simple)),
                        Spacing.Double);

                if (tables != null)
                {
                    tables.GoAfter = true;
                }

                var tableReplacements = replacements.TryGetC(Replacements.KeyTables);
                if (tableReplacements != null)
                {
                    replacements[Replacements.KeyTablesInverse] = tableReplacements.Inverse();
                }

                SqlPreCommand syncEnums;

                try
                {
                    syncEnums = SynchronizeEnumsScript(replacements);
                }
                catch (Exception e)
                {
                    syncEnums = new SqlPreCommandSimple("-- Exception synchronizing enums: " + e.Message);
                }

                SqlPreCommand addForeingKeys = Synchronizer.SynchronizeScript(
                    model,
                    database,
                    (tn, tab) => SqlBuilder.AlterTableForeignKeys(tab),
                    null,
                    (tn, tab, dif) => Synchronizer.SynchronizeScript(
                        tab.Columns,
                        dif.Columns,
                        (cn, colModel) => colModel.ReferenceTable == null || colModel.AvoidForeignKey ? null :
                        SqlBuilder.AlterTableAddConstraintForeignKey(tab, colModel.Name, colModel.ReferenceTable),
                        null,
                        (cn, colModel, coldb) =>
                {
                    if (colModel.ReferenceTable == null || colModel.AvoidForeignKey)
                    {
                        return(null);
                    }

                    if (coldb.ForeignKey == null || !colModel.ReferenceTable.Name.Equals(ChangeName(coldb.ForeignKey.TargetTable)))
                    {
                        return(SqlBuilder.AlterTableAddConstraintForeignKey(tab, colModel.Name, colModel.ReferenceTable));
                    }

                    var name = SqlBuilder.ForeignKeyName(tab.Name.Name, colModel.Name);
                    return(SqlPreCommand.Combine(Spacing.Simple,
                                                 name != coldb.ForeignKey.Name.Name ? SqlBuilder.RenameForeignKey(coldb.ForeignKey.Name, name) : null,
                                                 (coldb.ForeignKey.IsDisabled || coldb.ForeignKey.IsNotTrusted) && !replacements.SchemaOnly ? SqlBuilder.EnableForeignKey(tab.Name, name) : null));
                },
                        Spacing.Simple),
                    Spacing.Double);

                bool?createMissingFreeIndexes = null;

                SqlPreCommand addIndices =
                    Synchronizer.SynchronizeScript(model, database,
                                                   (tn, tab) => modelIndices[tab].Values.Where(a => !(a is PrimaryClusteredIndex)).Select(SqlBuilder.CreateIndex).Combine(Spacing.Simple),
                                                   null,
                                                   (tn, tab, dif) =>
                {
                    var columnReplacements = replacements.TryGetC(Replacements.KeyColumnsForTable(tn));

                    Func <IColumn, bool> isNew = c => !dif.Columns.ContainsKey(columnReplacements?.TryGetC(c.Name) ?? c.Name);

                    Dictionary <string, Index> modelIxs = modelIndices[tab];

                    var controlledIndexes = Synchronizer.SynchronizeScript(modelIxs, dif.Indices,
                                                                           (i, mix) => mix is UniqueIndex || mix.Columns.Any(isNew) || SafeConsole.Ask(ref createMissingFreeIndexes, "Create missing non-unique index {0} in {1}?".FormatWith(mix.IndexName, tab.Name)) ? SqlBuilder.CreateIndex(mix) : null,
                                                                           null,
                                                                           (i, mix, dix) => !dix.IndexEquals(dif, mix) ? SqlBuilder.CreateIndex(mix) :
                                                                           mix.IndexName != dix.IndexName ? SqlBuilder.RenameIndex(tab, dix.IndexName, mix.IndexName) : null,
                                                                           Spacing.Simple);

                    return(SqlPreCommand.Combine(Spacing.Simple, controlledIndexes));
                }, Spacing.Double);

                SqlPreCommand dropSchemas = Synchronizer.SynchronizeScriptReplacing(replacements, "Schemas",
                                                                                    modelSchemas.ToDictionary(a => a.ToString()),
                                                                                    databaseSchemas.ToDictionary(a => a.ToString()),
                                                                                    null,
                                                                                    (_, oldSN) => DropSchema(oldSN) ? SqlBuilder.DropSchema(oldSN) : null,
                                                                                    (_, newSN, oldSN) => newSN.Equals(oldSN) ? null : SqlBuilder.DropSchema(oldSN),
                                                                                    Spacing.Double);

                return(SqlPreCommand.Combine(Spacing.Triple, preRenameTables, createSchemas, dropStatistics, dropIndices, dropForeignKeys, preRenamePks, tables, syncEnums, addForeingKeys, addIndices, dropSchemas));
            }
        }
コード例 #26
0
        static SqlPreCommand SynchronizeEnumsScript(Replacements replacements)
        {
            Schema schema = Schema.Current;

            List <SqlPreCommand> commands = new List <SqlPreCommand>();

            foreach (var table in schema.Tables.Values)
            {
                Type enumType = EnumEntity.Extract(table.Type);
                if (enumType != null)
                {
                    IEnumerable <Entity>        should       = EnumEntity.GetEntities(enumType);
                    Dictionary <string, Entity> shouldByName = should.ToDictionary(a => a.ToString());

                    List <Entity> current = Administrator.TryRetrieveAll(table.Type, replacements);
                    Dictionary <string, Entity> currentByName = current.ToDictionaryEx(a => a.toStr, table.Name.Name);

                    string key = Replacements.KeyEnumsForTable(table.Name.Name);

                    replacements.AskForReplacements(currentByName.Keys.ToHashSet(), shouldByName.Keys.ToHashSet(), key);

                    currentByName = replacements.ApplyReplacementsToOld(currentByName, key);

                    var mix = shouldByName.JoinDictionary(currentByName, (n, s, c) => new { s, c }).Where(a => a.Value.s.id != a.Value.c.id).ToDictionary();

                    HashSet <PrimaryKey> usedIds = current.Select(a => a.Id).ToHashSet();

                    Dictionary <string, Entity> middleByName = mix.Where(kvp => usedIds.Contains(kvp.Value.s.Id)).ToDictionary(kvp => kvp.Key, kvp => Clone(kvp.Value.c));

                    if (middleByName.Any())
                    {
                        var moveToAux = SyncEnums(schema, table,
                                                  currentByName.Where(a => middleByName.ContainsKey(a.Key)).ToDictionary(),
                                                  middleByName);
                        if (moveToAux != null)
                        {
                            commands.Add(moveToAux);
                        }
                    }

                    var com = SyncEnums(schema, table,
                                        currentByName.Where(a => !middleByName.ContainsKey(a.Key)).ToDictionary(),
                                        shouldByName.Where(a => !middleByName.ContainsKey(a.Key)).ToDictionary());
                    if (com != null)
                    {
                        commands.Add(com);
                    }

                    if (middleByName.Any())
                    {
                        var backFromAux = SyncEnums(schema, table,
                                                    middleByName,
                                                    shouldByName.Where(a => middleByName.ContainsKey(a.Key)).ToDictionary());
                        if (backFromAux != null)
                        {
                            commands.Add(backFromAux);
                        }
                    }
                }
            }

            return(SqlPreCommand.Combine(Spacing.Double, commands.ToArray()));
        }