/// <summary>
        /// Generates schema migrations from the datasource as C# source code
        /// </summary>
        /// <param name="context">Define data required to generate the C# migrations</param>
        public void Generate(SchemaMigrationContext context)
        {
            Announcer.AnnounceTime = context.AnnounceTime;
             Announcer.Say(string.Format("Generating schema {0} migrations from {1}", context.Type, context.FromConnectionString));
             using (var connection = GetConnection(context))
             {

            var processor = GetProcessor(connection);
            var schemaDumper = GetSchemaDumper(processor);

            if (context.MigrationRequired(MigrationType.Tables) || context.MigrationRequired(MigrationType.Indexes) || context.MigrationRequired(MigrationType.Data) || context.MigrationRequired(MigrationType.ForeignKeys))
            {
               var tables = new CSharpTableMigrationsWriter(Announcer);
               tables.GenerateMigrations(context, schemaDumper);
            }

            if (context.MigrationRequired(MigrationType.Procedures))
            {
               var procedures = new CSharpProcedureMigrationsWriter(Announcer);
               procedures.GenerateMigrations(context, schemaDumper);
            }

            if (context.MigrationRequired(MigrationType.Functions))
            {
               var functions = new CSharpFunctionMigrationsWriter(Announcer);
               functions.GenerateMigrations(context, schemaDumper);
            }

            // Migrate the views last as procedures or functions may be included in them
            if (context.MigrationRequired(MigrationType.Views))
            {
               var views = new CSharpViewMigrationsWriter(Announcer);
               views.GenerateMigrations(context, schemaDumper);
            }
             }
        }
        /// <summary>
        /// Creates a table and optionally inserts data into the table if <see cref="SchemaMigrationContext.MigrateData"/> is <c>True</c>
        /// </summary>
        /// <param name="context">The context that controls how the column should be generated</param>
        /// <param name="table">the table to generate the migration for</param>
        /// <param name="output">The output stream to append the C# code to</param>
        private void WriteTable(SchemaMigrationContext context, TableDefinition table, StreamWriter output)
        {
            if ( context.MigrationRequired(MigrationType.Tables) )
              {
              output.WriteLine("\t\t\tif (Schema.Table(\"{0}\").Exists()) return;", table.Name);
              output.WriteLine("");

              output.WriteLine("\t\t\tCreate.Table(\"" + table.Name + "\")");
              foreach (var column in table.Columns)
              {
                  WriteColumn(context, column, output, column == table.Columns.Last());
              }
              if (context.MigrationRequired(MigrationType.Data))
              {
                  WriteInsertData(output, table, context);
              }
              }

              if ( context.MigrationRequired(MigrationType.Indexes) && table.Indexes.Count > 0 )
             {
             var primaryKey = table.Columns.Where(c => c.IsPrimaryKey);
             var primaryKeyName = string.Empty;
             if ( primaryKey.Count() > 0 )
             {
                 primaryKeyName = primaryKey.First().PrimaryKeyName;
             }

            foreach (var index in table.Indexes.Where(i => i.Name != primaryKeyName))
               WriteIndex(output, index, context);

             }
        }
        /// <summary>
        /// Generates C# Migrations that Create tables Migrations
        /// </summary>
        /// <param name="context">The context that define how parts of the C# will be formatted</param>
        /// <param name="schemaDumper">The schema dump to use as the source of the schema migration</param>
        public void GenerateMigrations(SchemaMigrationContext context, ISchemaDumper schemaDumper)
        {
            _announcer.Say("Reading database schema");
             var defs = schemaDumper.ReadDbSchema();

             if (context.PreMigrationTableUpdate != null)
            context.PreMigrationTableUpdate(defs);

             SetupMigrationsDirectory(context);

             var migrations = 0;

             var foreignkeyTables = new List<TableDefinition>();

             foreach (var table in defs)
             {
            // Check if we want to exclude this table
            if ( context.ExcludeTables.Contains(table.Name))
            {
               _announcer.Say("Exluding table " + table.Name);
               continue;
            }

            if (context.MigrationRequired(MigrationType.Tables) || (context.MigrationRequired(MigrationType.Indexes) && table.Indexes.Count > 0))
            {
               migrations++;

               var migrationsFolder = Path.Combine(context.WorkingDirectory, context.MigrationsDirectory);
               var csFilename = Path.Combine(migrationsFolder, context.MigrationClassNamer(context.MigrationIndex + migrations, table) + ".cs");
               _announcer.Say("Creating migration " + Path.GetFileName(csFilename));
               using (var writer = new StreamWriter(csFilename))
               {
                  WriteToStream(context, table, context.MigrationIndex + migrations, writer);
               }
            }

            if (context.MigrationRequired(MigrationType.Data))
            {
               var data = schemaDumper.ReadTableData(table.SchemaName, table.Name);

               if (data != null && data.Tables.Count > 0 && data.Tables[0].Rows.Count > 0)
               {
                  var dataDirectory = Path.Combine(context.WorkingDirectory, context.DataDirectory);
                  if (!Directory.Exists(dataDirectory))
                     Directory.CreateDirectory(dataDirectory);
                  data.Tables[0].WriteXmlSchema(Path.Combine(dataDirectory, table.Name + ".xsd"));

                  using (var writer = new XmlTextWriter(Path.Combine(dataDirectory, table.Name + ".xml"), context.MigrationEncoding))
                  {
                     data.Tables[0].WriteXml(writer);
                  }

               }
            }

            if (context.MigrationRequired(MigrationType.ForeignKeys) && table.ForeignKeys.Count > 0)
            {
               // Add to list of tables to apply foreign key
               // ... done as two part process as may me interdepdancies between tables
               foreignkeyTables.Add(table);
            }

             }

             context.MigrationIndex += migrations;

             if (context.MigrationRequired(MigrationType.ForeignKeys))
            GenerateForeignKeyMigrations(context, foreignkeyTables);
        }
        private void GenerateForeignKeyMigrations(SchemaMigrationContext context, List<TableDefinition> tables)
        {
            if (!context.MigrationRequired(MigrationType.ForeignKeys) || tables.Count <= 0)
             {
            return;
             }

             _announcer.Say(string.Format("Found {0} tables with foreign keys", tables.Count));

             var migrations = 0;

             foreach (var foreignkeyTable in tables)
             {
            var migrationsFolder = Path.Combine(context.WorkingDirectory, context.MigrationsDirectory);

            migrations++;

            var migrationIndex = context.MigrationIndex+ migrations;
            var table = foreignkeyTable;

            var csFilename = Path.Combine(migrationsFolder,
                                          context.MigrationClassNamer(migrationIndex, table) + "ForeignKey.cs");
            _announcer.Say("Creating migration " + Path.GetFileName(csFilename));
            using (var writer = new StreamWriter(csFilename))
            {
               WriteMigration(writer, context, migrationIndex
                              , () => context.MigrationClassNamer(migrationIndex, table) + "ForeignKey"
                              , () => WriteForeignKey(table, writer)
                              , () => WriteDeleteForeignKey(table, writer));
            }
             }

             context.MigrationIndex +=  migrations;
        }
        private static void WriteDeleteTable(SchemaMigrationContext context, TableDefinition table, StreamWriter output)
        {
            if (context.MigrationRequired(MigrationType.Indexes) && table.Indexes.Count > 0)
              {
              var primaryKey = table.Columns.Where(c => c.IsPrimaryKey);
              var primaryKeyName = string.Empty;
              if (primaryKey.Count() > 0)
              {
                  primaryKeyName = primaryKey.First().PrimaryKeyName;
              }

              foreach (var index in table.Indexes.Where(i => i.Name != primaryKeyName))
                  WriteDeleteIndex(output, index);
              }

              if (context.MigrationRequired(MigrationType.Tables))
              {
              output.WriteLine("\t\t\tDelete.Table(\"" + table.Name + "\");");
              }
        }