public IEnumerable <Action> Compare(IEnumerable <TableInfo> schemaTables, IEnumerable <ColumnInfo> schemaColumns)
        {
            List <Action> results = new List <Action>();

            if (CommandProvider.SupportsSchemas)
            {
                var createSchemas = GetNewSchemas(ModelTables, schemaTables);
                results.AddRange(createSchemas.Select(s => new CreateSchema(s)));
            }

            var createTables = GetNewTables(ModelTables, schemaTables);

            results.AddRange(createTables.Select(tbl => new CreateTable(tbl.ModelType)));

            // when looking for modified columns, don't include tables that were just created
            var existingModelColumns = ModelColumns.Where(col => !createTables.Contains(col.TableInfo));

            var schemaColumnsByTable = schemaColumns.ToLookup(row => row.TableInfo);
            var modelColumnsByTable  = existingModelColumns.ToLookup(row => row.TableInfo);
            var tablesToTypes        = ModelTypes.ToDictionary(t => CommandProvider.GetTableInfo(t));

            foreach (TableInfo tbl in schemaColumnsByTable)
            {
                if (AnyModifiedColumns(schemaColumnsByTable[tbl], modelColumnsByTable[tbl],
                                       out IEnumerable <ColumnInfo> added, out IEnumerable <ColumnInfo> modified, out IEnumerable <ColumnInfo> deleted))
                {
                    if (tbl.RowCount == 0)
                    {
                        // empty tables can be dropped and re-created
                        results.Add(new RebuildTable(tablesToTypes[tbl], added, modified, deleted));
                    }
                    else
                    {
                        // must modify columns directly
                        results.AddRange(added.Select(a => new AddColumn(a)));
                        results.AddRange(deleted.Select(d => new DropColumn(d)));
                        results.AddRange(modified.Select(m => new AlterColumn(m)));
                    }
                }
            }

            //var addColumns = await GetNewColumnsAsync(ModelTypes, createTables.Concat(rebuiltTables), connection);
            //results.AddRange(addColumns.Select(pi => new AddColumn(pi)));

            var dropTables = GetDeletedTables(ModelTables, schemaTables);

            results.AddRange(dropTables.Select(tbl => new DropTable(tbl)));

            var newForeignKeys = ModelColumns.Where(col => createTables.Contains(col.TableInfo) && col.IsForeignKey);

            results.AddRange(newForeignKeys.Select(col => new AddForeignKey(col.ForeignKeyInfo)));

            return(results);
        }
        public ModelMerge(CommandProvider <TKey> commandProvider, IEnumerable <Type> modelTypes)
        {
            CommandProvider = commandProvider;
            ModelTypes      = modelTypes;
            ModelTables     = modelTypes.Select(t => CommandProvider.GetTableInfo(t));

            var mappedColumns = modelTypes.SelectMany(t => commandProvider.GetMappedColumns(t));

            ModelProperties = mappedColumns.ToLookup(pi => pi.DeclaringType);

            ModelColumns = mappedColumns.Select(pi =>
            {
                var col = new ColumnInfo(pi);
                CommandProvider.MapProviderSpecificInfo(pi, col);
                return(col);
            });
        }
        public override IEnumerable <string> SqlCommands <TKey>(CommandProvider <TKey> commandProvider, IDbConnection connection)
        {
            TableInfo tableInfo  = commandProvider.GetTableInfo(ModelType);
            var       rebuildFKs = commandProvider.GetDependentForeignKeys(connection, tableInfo);

            DropTable drop = new DropTable(tableInfo, rebuildFKs);

            foreach (var cmd in drop.SqlCommands(commandProvider, connection))
            {
                yield return(cmd);
            }

            CreateTable create = new CreateTable(ModelType);

            foreach (var cmd in create.SqlCommands(commandProvider, connection))
            {
                yield return(cmd);
            }

            foreach (var fk in rebuildFKs)
            {
                yield return(commandProvider.AddForeignKeyCommand(fk));
            }
        }