コード例 #1
0
ファイル: Synchronizer.cs プロジェクト: goldenauge/framework
    public static SqlPreCommand?SynchronizeScriptReplacing <N, O>(
        Replacements replacements,
        string replacementsKey,
        Spacing spacing,
        Dictionary <string, N> newDictionary,
        Dictionary <string, O> oldDictionary,
        Func <string, N, SqlPreCommand?>?createNew,
        Func <string, O, SqlPreCommand?>?removeOld,
        Func <string, N, O, SqlPreCommand?>?mergeBoth)
        where O : class
        where N : class
    {
        replacements.AskForReplacements(
            oldDictionary.Keys.ToHashSet(),
            newDictionary.Keys.ToHashSet(), replacementsKey);

        var repOldDictionary = replacements.ApplyReplacementsToOld(oldDictionary, replacementsKey);

        return(SynchronizeScript(spacing, newDictionary, repOldDictionary, createNew, removeOld, mergeBoth));
    }
コード例 #2
0
        public static void SynchronizeReplacing <O, N>(
            Replacements replacements, string replacementsKey,
            Dictionary <string, O> oldDictionary,
            Dictionary <string, N> newDictionary,
            Action <string, O> removeOld,
            Action <string, N> createNew,
            Action <string, O, N> merge)
            where O : class
            where N : class
        {
            replacements.AskForReplacements(
                oldDictionary.Keys.ToHashSet(),
                newDictionary.Keys.ToHashSet(), replacementsKey);

            var repOldDictionary = replacements.ApplyReplacementsToOld(oldDictionary, replacementsKey);

            HashSet <string> set = new HashSet <string>();

            set.UnionWith(repOldDictionary.Keys);
            set.UnionWith(newDictionary.Keys);

            foreach (var key in set)
            {
                var oldVal = repOldDictionary.TryGetC(key);
                var newVal = newDictionary.TryGetC(key);

                if (oldVal == null)
                {
                    createNew(key, newVal !);
                }
                else if (newVal == null)
                {
                    removeOld(key, oldVal);
                }
                else
                {
                    merge(key, oldVal, newVal);
                }
            }
        }
コード例 #3
0
ファイル: AuthLogic.cs プロジェクト: mapacheL/extensions
        public static void SynchronizeRoles(XDocument doc)
        {
            Table table = Schema.Current.Table(typeof(RoleEntity));
            TableMList relationalTable = table.TablesMList().Single();

            Dictionary<string, XElement> rolesXml = doc.Root.Element("Roles").Elements("Role").ToDictionary(x => x.Attribute("Name").Value);

            {
                Dictionary<string, RoleEntity> rolesDic = Database.Query<RoleEntity>().ToDictionary(a => a.ToString());
                Replacements replacements = new Replacements();
                replacements.AskForReplacements(rolesDic.Keys.ToHashSet(), rolesXml.Keys.ToHashSet(), "Roles");
                rolesDic = replacements.ApplyReplacementsToOld(rolesDic, "Roles");

                Console.WriteLine("Part 1: Syncronize roles without relationships");

                var roleInsertsDeletes = Synchronizer.SynchronizeScript(rolesXml, rolesDic,
                    (name, xelement) => table.InsertSqlSync(new RoleEntity { Name = name }, includeCollections: false),
                    (name, role) => SqlPreCommand.Combine(Spacing.Simple,
                            new SqlPreCommandSimple("DELETE {0} WHERE {1} = {2} --{3}"
                                .FormatWith(relationalTable.Name, ((IColumn)relationalTable.Field).Name.SqlEscape(), role.Id, role.Name)),
                            table.DeleteSqlSync(role)),
                    (name, xElement, role) =>
                    {
                        var oldName = role.Name;
                        role.Name = name;
                        role.MergeStrategy = xElement.Attribute("MergeStrategy")?.Let(t => t.Value.ToEnum<MergeStrategy>()) ?? MergeStrategy.Union;
                        return table.UpdateSqlSync(role, includeCollections: false, comment: oldName);
                    }, Spacing.Double);

                if (roleInsertsDeletes != null)
                {
                    SqlPreCommand.Combine(Spacing.Triple,
                       new SqlPreCommandSimple("-- BEGIN ROLE SYNC SCRIPT"),
                       new SqlPreCommandSimple("use {0}".FormatWith(Connector.Current.DatabaseName())),
                       roleInsertsDeletes,
                       new SqlPreCommandSimple("-- END ROLE  SYNC SCRIPT")).OpenSqlFileRetry();

                    Console.WriteLine("Press [Enter] when executed...");
                    Console.ReadLine();
                }
                else
                {
                    SafeConsole.WriteLineColor(ConsoleColor.Green, "Already syncronized");
                }
            }

            {
                Console.WriteLine("Part 2: Syncronize roles relationships");
                Dictionary<string, RoleEntity> rolesDic = Database.Query<RoleEntity>().ToDictionary(a => a.ToString());

                var roleRelationships = Synchronizer.SynchronizeScript(rolesXml, rolesDic,
                 (name, xelement) => { throw new InvalidOperationException("No new roles should be at this stage. Did you execute the script?"); },
                 (name, role) => { throw new InvalidOperationException("No old roles should be at this stage. Did you execute the script?"); },
                 (name, xElement, role) =>
                 {
                     var should = xElement.Attribute("Contains").Value.Split(new []{','},  StringSplitOptions.RemoveEmptyEntries);
                     var current = role.Roles.Select(a=>a.ToString());

                     if(should.OrderBy().SequenceEqual(current.OrderBy()))
                         return null;

                     role.Roles = should.Select(rs => rolesDic.GetOrThrow(rs).ToLite()).ToMList();

                     return table.UpdateSqlSync(role);
                 }, Spacing.Double);

                if (roleRelationships != null)
                {
                    SqlPreCommand.Combine(Spacing.Triple,
                       new SqlPreCommandSimple("-- BEGIN ROLE SYNC SCRIPT"),
                       new SqlPreCommandSimple("use {0}".FormatWith(Connector.Current.DatabaseName())),
                       roleRelationships,
                       new SqlPreCommandSimple("-- END ROLE  SYNC SCRIPT")).OpenSqlFileRetry();

                    Console.WriteLine("Press [Enter] when executed...");
                    Console.ReadLine();
                }
                else
                {
                    SafeConsole.WriteLineColor(ConsoleColor.Green, "Already syncronized");
                }
            }
        }
コード例 #4
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());
        }
コード例 #5
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());

            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);
            }
        }
コード例 #6
0
ファイル: AuthLogic.cs プロジェクト: crazyants/extensions
        public static void SynchronizeRoles(XDocument doc)
        {
            Table      table           = Schema.Current.Table(typeof(RoleEntity));
            TableMList relationalTable = table.TablesMList().Single();

            Dictionary <string, XElement> rolesXml = doc.Root.Element("Roles").Elements("Role").ToDictionary(x => x.Attribute("Name").Value);

            {
                Dictionary <string, RoleEntity> rolesDic = Database.Query <RoleEntity>().ToDictionary(a => a.ToString());
                Replacements replacements = new Replacements();
                replacements.AskForReplacements(rolesDic.Keys.ToHashSet(), rolesXml.Keys.ToHashSet(), "Roles");
                rolesDic = replacements.ApplyReplacementsToOld(rolesDic, "Roles");

                Console.WriteLine("Part 1: Syncronize roles without relationships");

                var roleInsertsDeletes = Synchronizer.SynchronizeScript(Spacing.Double, rolesXml, rolesDic,
                                                                        createNew: (name, xelement) => table.InsertSqlSync(new RoleEntity {
                    Name = name
                }, includeCollections: false),
                                                                        removeOld: (name, role) => SqlPreCommand.Combine(Spacing.Simple,
                                                                                                                         new SqlPreCommandSimple("DELETE {0} WHERE {1} = {2} --{3}"
                                                                                                                                                 .FormatWith(relationalTable.Name, ((IColumn)relationalTable.Field).Name.SqlEscape(), role.Id, role.Name)),
                                                                                                                         table.DeleteSqlSync(role)),
                                                                        mergeBoth: (name, xElement, role) =>
                {
                    var oldName        = role.Name;
                    role.Name          = name;
                    role.MergeStrategy = xElement.Attribute("MergeStrategy")?.Let(t => t.Value.ToEnum <MergeStrategy>()) ?? MergeStrategy.Union;
                    return(table.UpdateSqlSync(role, includeCollections: false, comment: oldName));
                });

                if (roleInsertsDeletes != null)
                {
                    SqlPreCommand.Combine(Spacing.Triple,
                                          new SqlPreCommandSimple("-- BEGIN ROLE SYNC SCRIPT"),
                                          new SqlPreCommandSimple("use {0}".FormatWith(Connector.Current.DatabaseName())),
                                          roleInsertsDeletes,
                                          new SqlPreCommandSimple("-- END ROLE  SYNC SCRIPT")).OpenSqlFileRetry();

                    Console.WriteLine("Press [Enter] when executed...");
                    Console.ReadLine();
                }
                else
                {
                    SafeConsole.WriteLineColor(ConsoleColor.Green, "Already syncronized");
                }
            }

            {
                Console.WriteLine("Part 2: Syncronize roles relationships");
                Dictionary <string, RoleEntity> rolesDic = Database.Query <RoleEntity>().ToDictionary(a => a.ToString());

                var roleRelationships = Synchronizer.SynchronizeScript(Spacing.Double, rolesXml, rolesDic,
                                                                       createNew: (name, xelement) => { throw new InvalidOperationException("No new roles should be at this stage. Did you execute the script?"); },
                                                                       removeOld: (name, role) => { throw new InvalidOperationException("No old roles should be at this stage. Did you execute the script?"); },
                                                                       mergeBoth: (name, xElement, role) =>
                {
                    var should  = xElement.Attribute("Contains").Value.Split(new [] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    var current = role.Roles.Select(a => a.ToString());

                    if (should.OrderBy().SequenceEqual(current.OrderBy()))
                    {
                        return(null);
                    }

                    role.Roles = should.Select(rs => rolesDic.GetOrThrow(rs).ToLite()).ToMList();

                    return(table.UpdateSqlSync(role));
                });

                if (roleRelationships != null)
                {
                    SqlPreCommand.Combine(Spacing.Triple,
                                          new SqlPreCommandSimple("-- BEGIN ROLE SYNC SCRIPT"),
                                          new SqlPreCommandSimple("use {0}".FormatWith(Connector.Current.DatabaseName())),
                                          roleRelationships,
                                          new SqlPreCommandSimple("-- END ROLE  SYNC SCRIPT")).OpenSqlFileRetry();

                    Console.WriteLine("Press [Enter] when executed...");
                    Console.ReadLine();
                }
                else
                {
                    SafeConsole.WriteLineColor(ConsoleColor.Green, "Already syncronized");
                }
            }
        }
コード例 #7
0
        public static SqlPreCommand SynchronizeTablesScript(Replacements replacements)
        {
            //Temproal HACK
            if (Database.View<SysIndexes>().Any(a => a.name.StartsWith("FIX")) && SafeConsole.Ask("Old index naming convention...rename first?"))
            {
                return Schema.Current.DatabaseNames().Select(db =>
                {
                    using (Administrator.OverrideDatabaseInViews(db))
                    {
                        var indexes =
                            (from s in Database.View<SysSchemas>()
                             from t in s.Tables()
                             from ix in t.Indices()
                             where !ix.is_primary_key
                             select new { schemaName = s.name, tableName = t.name, ix.is_unique, indexName = ix.name }).ToList();

                        return (from ix in indexes
                                let newName = ix.is_unique ? Regex.Replace(ix.indexName, @"^IX_\w+?_", "UIX_") : Regex.Replace(ix.indexName, @"^F?IX_\w+?_", "IX_")
                                where ix.indexName != newName
                                select new SqlPreCommandSimple("EXEC SP_RENAME '{0}.{1}' , '{2}', 'INDEX' ".Formato(
                                    new ObjectName(new SchemaName(db, ix.schemaName), ix.tableName), ix.indexName, newName))).Combine(Spacing.Simple);
                    }
                }).Combine(Spacing.Double);
            }

            Dictionary<string, ITable> model = Schema.Current.GetDatabaseTables().ToDictionary(a => a.Name.ToString(), "schema tables");

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

            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().ToDictionary(a => a.IndexName, "Indexes for {0}".Formato(t.Name)));

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

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

                diff.Colums = replacements.ApplyReplacementsToOld(diff.Colums,  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).Try(a => a.Name) ?? objectName;
            };

            Func<DiffTable, DiffIndex, Index, bool> columnsChanged = (dif, dix, mix) =>
            {
                if (dix.Columns.Count != mix.Columns.Length)
                    return true;

                var dixColumns = dif.Colums.Where(kvp => dix.Columns.Contains(kvp.Value.Name));

                return !dixColumns.All(kvp => dif.Colums.GetOrThrow(kvp.Key).ColumnEquals(mix.Columns.SingleEx(c => c.Name == kvp.Key)));
            };

            //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.Colums.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.Select(ix => SqlBuilder.DropIndex(dif.Name, ix)).Combine(Spacing.Simple),
                (tn, tab, dif) =>
                {
                    Dictionary<string, Index> modelIxs = modelIndices[tab];

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

                    var changes = Synchronizer.SynchronizeScript(modelIxs, dif.Indices,
                        null,
                        (i, dix) => dix.IsControlledIndex || dix.Columns.Any(removedColums.Contains)  ? SqlBuilder.DropIndex(dif.Name, dix) : null,
                        (i, mix, dix) => (mix as UniqueIndex).Try(u => u.ViewName) != dix.ViewName || columnsChanged(dif, dix, mix) ? SqlBuilder.DropIndex(dif.Name, dix) : null,
                        Spacing.Simple);

                    return changes;
                },
                 Spacing.Double);

            SqlPreCommand dropForeignKeys = Synchronizer.SynchronizeScript(
                 model,
                 database,
                 null,
                 (tn, dif) => dif.Colums.Values.Select(c => c.ForeingKey != null ? SqlBuilder.AlterTableDropConstraint(dif.Name, c.ForeingKey.Name) : null).Combine(Spacing.Simple),
                 (tn, tab, dif) => Synchronizer.SynchronizeScript(
                     tab.Columns,
                     dif.Colums,
                     null,
                     (cn, colDb) => colDb.ForeingKey != null ? SqlBuilder.AlterTableDropConstraint(dif.Name, colDb.ForeingKey.Name) : null,
                     (cn, colModel, colDb) => colDb.ForeingKey == null ? null :
                         colModel.ReferenceTable == null || !colModel.ReferenceTable.Name.Equals(ChangeName(colDb.ForeingKey.TargetTable)) ? 
                         SqlBuilder.AlterTableDropConstraint(dif.Name, colDb.ForeingKey.Name) :
                         null, 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.Colums,
                        (cn, tabCol) => SqlBuilder.AlterTableAddColumn(tab, tabCol),
                        (cn, difCol) => SqlPreCommand.Combine(Spacing.Simple,
                                    difCol.DefaultConstraintName.HasText() ? SqlBuilder.AlterTableDropConstraint(tab.Name, difCol.DefaultConstraintName) : 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) ? null : SqlBuilder.AlterTableAlterColumn(tab, tabCol),
                            UpdateByFkChange(tn, difCol, tabCol, ChangeName)),
                        Spacing.Simple)),
                 Spacing.Double);

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

            SqlPreCommand syncEnums = SynchronizeEnumsScript(replacements);

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

                         if(coldb.ForeingKey == null || !colModel.ReferenceTable.Name.Equals(ChangeName(coldb.ForeingKey.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.ForeingKey.Name? SqlBuilder.RenameForeignKey(tab.Name.Schema, coldb.ForeingKey.Name, name) : null, 
                            (coldb.ForeingKey.IsDisabled || coldb.ForeingKey.IsNotTrusted) && !ExecutionMode.IsSynchronizeSchemaOnly ? SqlBuilder.EnableForeignKey(tab.Name,  name) : null);
                     },
                     Spacing.Simple),
                 Spacing.Double);

            bool? createMissingFreeIndexes = null;

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

                    Func<IColumn, bool> isNew = c => !dif.Colums.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 too?") ? SqlBuilder.CreateIndex(mix) : null,
                        null,
                        (i, mix, dix) => (mix as UniqueIndex).Try(u => u.ViewName) != dix.ViewName || columnsChanged(dif, dix, 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);

            return SqlPreCommand.Combine(Spacing.Triple, dropStatistics, dropIndices, dropForeignKeys, tables, syncEnums, addForeingKeys, addIndices);
        }