/// <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 + "\");"); } }