從ISHIDA的建議,我創建了一種結合遷移的方法。這絕不是唯一的/正確的解決方案,也不回答移徙膨脹是否有問題的問題,但這是一個好的開始。
爲了測試這一點,我有2個表,這是一個控制檯應用程序:
public class Account
{
[Required]
[StringLength(100)]
public string Id { get; set; }
[Required]
[StringLength(10)]
public string AccountNumber { get; set; }
public virtual List<Policy> Policies { get; set; }
}
public class Policy
{
[Required]
[StringLength(100)]
public string Id { get; set; }
[Required]
public int PolicyNumber { get; set; }
[Required]
public string AccountId { get; set; }
public virtual Account Account { get; set; }
}
有4遷移這創造這些表中,添加的數據,並從串改變PolicyNumber的數據類型爲int。假裝這個程序是實時的,所有這些程序都在生產環境中運行。
public partial class InitialCreate : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Accounts",
c => new
{
Id = c.String(nullable: false, maxLength: 100),
AccountNumber = c.String(nullable: false, maxLength: 10),
})
.PrimaryKey(t => t.Id);
}
public override void Down()
{
DropTable("dbo.Accounts");
}
}
public partial class SeedAccounts : DbMigration
{
readonly string[] accountIds = new string[] { "IdAcct101", "IdAcct102" };
public override void Up()
{
Sql($"INSERT INTO Accounts (Id, AccountNumber) VALUES ('{accountIds[0]}','101')");
Sql($"INSERT INTO Accounts (Id, AccountNumber) VALUES ('{accountIds[1]}','102')");
}
public override void Down()
{
Sql($"DELETE FROM Accounts WHERE ID = '{accountIds[0]}'");
Sql($"DELETE FROM Accounts WHERE ID = '{accountIds[1]}'");
}
}
}
public partial class AddPolicyTable : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.Policies",
c => new
{
Id = c.String(nullable: false, maxLength: 100),
PolicyNumber = c.String(nullable: false, maxLength: 100),
AccountId = c.String(nullable: false, maxLength: 100),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Accounts", t => t.AccountId, cascadeDelete: true)
.Index(t => t.AccountId);
}
public override void Down()
{
DropForeignKey("dbo.Policies", "AccountId", "dbo.Accounts");
DropIndex("dbo.Policies", new[] { "AccountId" });
DropTable("dbo.Policies");
}
}
public partial class ChangeAndSeedPolicies : DbMigration
{
readonly string[] accountIds = new string[] { "IdAcct101", "IdAcct102" };
readonly string[] policyIds = new string[] { "IdPol101a", "IdPol101b", "IdPol102a" };
public override void Up()
{
AlterColumn("dbo.Policies", "PolicyNumber", c => c.Int(nullable: false));
Sql($"INSERT INTO Policies (Id, AccountId, PolicyNumber) VALUES ('{policyIds[0]}', '{accountIds[0]}', '10101')");
Sql($"INSERT INTO Policies (Id, AccountId, PolicyNumber) VALUES ('{policyIds[1]}', '{accountIds[0]}', '10102')");
Sql($"INSERT INTO Policies (Id, AccountId, PolicyNumber) VALUES ('{policyIds[2]}', '{accountIds[1]}', '10201')");
}
public override void Down()
{
Sql($"DELETE FROM Policies WHERE ID = '{policyIds[0]}'");
Sql($"DELETE FROM Policies WHERE ID = '{policyIds[1]}'");
Sql($"DELETE FROM Policies WHERE ID = '{policyIds[2]}'");
AlterColumn("dbo.Policies", "PolicyNumber", c => c.String(nullable: false, maxLength: 100));
}
}
下面是該項目的主要代碼:
using (var dc = new DataContext())
{
foreach (var account in dc.Accounts.OrderBy(q => q.AccountNumber).ToList())
{
Console.WriteLine("Account " + account.AccountNumber);
foreach (var policy in account.Policies)
Console.WriteLine(" Policy " + policy.PolicyNumber);
}
}
DataContext類:
public class DataContext : DbContext
{
public DataContext() : base("DefaultConnection") { }
public DbSet<Account> Accounts { get; set; }
public DbSet<Policy> Policies { get; set; }
}
輸出是:
Account 101
Policy 10101
Policy 10102
Account 102
Policy 10201
很簡單。現在我想將這些遷移合併爲一個。記住:
- 我們不想放棄& rescaffold因爲產量將有數據 不是什麼移民加
- 其他事先遷移必須能夠爲集成測試&新環境
重新運行
這是我遵循的步驟:
- 備份你將要運行的任何環境。
- 創建一個新的遷移(這應該是空白,如無尚未改變)包控制檯管理(PMC)
- ,運行「更新數據庫」創建__MigrationHistory記錄
- 驗證應用程序正常運行時在這一點
- 副本都最多從舊的遷移方法到新
- 副本從老移民都向下方法到新的以相反的順序
- 驗證應用程序通常在這一點上運行(應該檢測不新的遷移需要)
- 刪除所有舊遷移
- 刪除所有舊__MigrationHistory記錄(只留下新)
- 驗證應用程序正常運行,在這一點上
要驗證新移民確實一切舊的(對於新環境或測試),只需刪除數據庫中的所有表(包括__MigrationHistory),在PMC中運行「update-database」,並查看它是否運行。
這是我的新移民的樣子:
public partial class CombinedMigration : DbMigration
{
readonly string[] accountIds = new string[] { "IdAcct101", "IdAcct102" };
readonly string[] policyIds = new string[] { "IdPol101a", "IdPol101b", "IdPol102a" };
public override void Up()
{
CreateTable(
"dbo.Accounts",
c => new
{
Id = c.String(nullable: false, maxLength: 100),
AccountNumber = c.String(nullable: false, maxLength: 10),
})
.PrimaryKey(t => t.Id);
Sql($"INSERT INTO Accounts (Id, AccountNumber) VALUES ('{accountIds[0]}','101')");
Sql($"INSERT INTO Accounts (Id, AccountNumber) VALUES ('{accountIds[1]}','102')");
CreateTable(
"dbo.Policies",
c => new
{
Id = c.String(nullable: false, maxLength: 100),
PolicyNumber = c.String(nullable: false, maxLength: 100),
AccountId = c.String(nullable: false, maxLength: 100),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Accounts", t => t.AccountId, cascadeDelete: true)
.Index(t => t.AccountId);
AlterColumn("dbo.Policies", "PolicyNumber", c => c.Int(nullable: false));
Sql($"INSERT INTO Policies (Id, AccountId, PolicyNumber) VALUES ('{policyIds[0]}', '{accountIds[0]}', '10101')");
Sql($"INSERT INTO Policies (Id, AccountId, PolicyNumber) VALUES ('{policyIds[1]}', '{accountIds[0]}', '10102')");
Sql($"INSERT INTO Policies (Id, AccountId, PolicyNumber) VALUES ('{policyIds[2]}', '{accountIds[1]}', '10201')");
}
public override void Down()
{
// Each prior "Down" section was added in reverse order.
Sql($"DELETE FROM Policies WHERE ID = '{policyIds[0]}'");
Sql($"DELETE FROM Policies WHERE ID = '{policyIds[1]}'");
Sql($"DELETE FROM Policies WHERE ID = '{policyIds[2]}'");
AlterColumn("dbo.Policies", "PolicyNumber", c => c.String(nullable: false, maxLength: 100));
DropForeignKey("dbo.Policies", "AccountId", "dbo.Accounts");
DropIndex("dbo.Policies", new[] { "AccountId" });
DropTable("dbo.Policies");
Sql($"DELETE FROM Accounts WHERE ID = '{accountIds[0]}'");
Sql($"DELETE FROM Accounts WHERE ID = '{accountIds[1]}'");
DropTable("dbo.Accounts");
}
}
警告:如果您的遷移有創建一個新的DC和做一些數據庫更新.NET代碼,遷移合併時,那些可能無法正常工作。例如,如果遷移1添加帳戶表,並且遷移2使用.NET代碼將記錄插入到帳戶中,則它將在組合遷移中崩潰,因爲帳戶在技術上尚未創建。用Sql替換這樣的語句('INSERT INTO ...「)將會解決這個問題。
我有一個prod數據庫和代碼優先的方法,我們已經刪除了所有從項目中遷移文件夾的遷移。運行舊的遷移並有最新的遷移可能你可以試試 – ISHIDA
我應該補充說我們使用NCrunch來運行一些自動化的數據庫測試,所以這些測試需要所有的遷移 –
我會說創建一個空的遷移,其中包含所有的而不是太多的遷移,你將只有一次遷移,這將減少遷移的時間並提高速度。 – ISHIDA