Supponiamo ad esempio d'avere il seguente schema di partenza :
E di voler passare al seguente schema di destinazione :
Durante il passaggio dal primo schema al secondo schema, si vuole preservare i dati e quindi eseguire un update durante la migration.
Genererà un codice simile a questo :
public partial class SistemazioneVolo : DbMigration { public override void Up() { DropForeignKey("dbo.Voli", "IdConnessione", "dbo.Connessiones"); DropIndex("dbo.Voli", new[] { "IdConnessione" }); AddColumn("dbo.Voli", "IdCittaFrom", c => c.Int()); AddColumn("dbo.Voli", "IdCittaTo", c => c.Int()); CreateIndex("dbo.Voli", "IdCittaPartenza"); CreateIndex("dbo.Voli", "IdCittaDestinazione"); AddForeignKey("dbo.Voli", "IdCittaFrom", "dbo.Citta", "ID"); AddForeignKey("dbo.Voli", "IdCittaTo", "dbo.Citta", "ID"); DropColumn("dbo.Voli", "IdConnessione"); } public override void Down() { AddColumn("dbo.Voli", "IdConnessione", c => c.Int()); CreateIndex("dbo.Voli", "IdConnessione"); AddForeignKey("dbo.Voli", "IdConnessione", "dbo.Connessiones", "Id"); DropForeignKey("dbo.Voli", "IdCittaFrom", "dbo.Citta"); DropForeignKey("dbo.Voli", "IdCittaTo", "dbo.Citta"); DropIndex("dbo.Voli", new[] { "IdCittaFrom" }); DropIndex("dbo.Voli", new[] { "IdCittaTo" }); DropColumn("dbo.Voli", "IdCittaDestinazione"); DropColumn("dbo.Voli", "IdCittaPartenza"); } }Dovremmo quindi nel metodo Up agguingere lo script di migrazione SQL :
update Voli set [IdCittaFrom] = c.IdCittaFrom, [IdCittaTo] =c.IdCittaTo from Voli v inner join Connessiones c on v.IdConnessione = c.Id
Il metodo Up diventerà quindi :
public override void Up() { DropForeignKey("dbo.Voli", "IdConnessione", "dbo.Connessiones"); DropIndex("dbo.Voli", new[] { "IdConnessione" }); AddColumn("dbo.Voli", "IdCittaFrom", c => c.Int()); AddColumn("dbo.Voli", "IdCittaTo", c => c.Int()); CreateIndex("dbo.Voli", "IdCittaPartenza"); CreateIndex("dbo.Voli", "IdCittaDestinazione"); AddForeignKey("dbo.Voli", "IdCittaFrom", "dbo.Citta", "ID"); AddForeignKey("dbo.Voli", "IdCittaTo", "dbo.Citta", "ID"); Sql("update Voli set [IdCittaFrom] = c.IdCittaFrom, [IdCittaTo] =c.IdCittaTo from Voli v inner join Connessiones c on v.IdConnessione = c.Id"); DropColumn("dbo.Voli", "IdConnessione"); }Se vogliamo dare la compatibilità anche nel "tornare indietro" alla migrazione precedente dovremo provedere alla creazione dello script sql nel metodo Down.
Oltre a degli update possiamo fare degli insert, ad esempio nel caso di creazione di dizionari che contengano dei valori predefiniti.
Se si hanno però molte insert da fare, forse è il caso di spostare questi ultimi in uno script sql da eseguire durante la migrazione.
Ad esempio :
public partial class AggiuntoCapAiComuni : ExpandedDbMigration { public override void Up() { ... SqlFile(@"Bin\Migrations\Sql\InserimentoComuni.sql"); } public override void Down() { ... } }Come potrete notare, in questo caso abbiamo cambiato la classe base, non più DbMigration bensì ExpandedDbMigration. Questo il codice :
public abstract class ExpandedDbMigration : System.Data.Entity.Migrations.DbMigration { ////// Drops an index of the name specified, on the table specified. /// /// The built-in DropIndex command in Migrations interprets your command in a variety of ways that can translate into /// multiple SQL statements, or dropping an index with an expanded name based on Conventions. This command cuts past those /// interpretations and drops exactly what you requested. /// /// Useful on existing databases where indices pre-existed, or where indices have been created by an outside tool like /// Sql Server Missing Indexes. /// public void DropIndexExact(string table, string indexName) { Sql("drop index [" + indexName + "] on [" + table + "]"); } public void DropConstraint(string table, string constraintName) { Sql("alter table [" + table + "] drop constraint [" + constraintName + "]"); } ////// Drop a Primary Key by name. See DropIndexExact for an explanation of how Exact calls differ from EF Migrations built-ins. /// public void DropPrimaryKeyExact(string table, string pkName) { DropConstraint(table, pkName); } ////// Drop a Foreign Key by name. See DropIndexExact for an explanation of how Exact calls differ from EF Migrations built-ins. /// public void DropForeignKeyExact(string table, string fkName) { DropConstraint(table, fkName); } ////// Reads in a .sql file filled with SQL statements and emits them as part of a Migration's data changes ("data motion"). /// /// Usage: SqlFile(@"Migrations\Sql\2013-08-15 FillTable.sql"); /// /// Note: All statements will presumably operate on specific table names, which will need to exist in this database /// already to work properly. /// /// Note: Any error will cause the entire Migration to fail, as EF Migrations always do. /// /// Note: Many statements common in SQL scripts are illegal in Migrations commands, especially "GO". /// To compensate for this, this call tries to filter out common problem statements - but it might be wise to clean out /// your sql script beforehand. Or, just run it and see what happens - the migration always runs in a Transaction so if it /// fails no harm done. /// /// The path to the .sql script relative to the Project that contains this Migration. public void SqlFile(string path) { var cleanAppDir = new Regex(@"\\bin.+"); var dir = AppDomain.CurrentDomain.BaseDirectory; dir = cleanAppDir.Replace(dir, "") + @"\"; var sql = File.ReadAllLines(dir + path); string[] ignore = new string[] { "GO", // Migrations doesn't support GO "/*", // Migrations might not support comments "print" // Migrations might not support print }; foreach (var line in sql) { if (ignore.Any(ig => line.StartsWith(ig))) continue; if (!string.IsNullOrEmpty(line.Trim())) { Sql(line); } } } }