2017-05-26 25 views
1

現在我們中的一些人已經在生產中運行多年並且積累了大量遷移的Code First項目,是否有人遇到過大量問題?是不是有太多的遷移?反對實體框架中的遷移膨脹代碼第一個應用程序

如果是這樣,那麼補救措施是什麼?一些注意事項: - 顯然我們不能刪除& rescaffold生產分貝。 - 我們無法刪除所有遷移,__MigrationHistory,並創建一個新的初始(在我的情況下),因爲我們的許多遷移有數據種子/更新,甚至調整生成的命令。

有沒有一種方法/工具將遷移合併爲更少的遷移?這甚至會有所作爲嗎?

謝謝!

+0

我有一個prod數據庫和代碼優先的方法,我們已經刪除了所有從項目中遷移文件夾的遷移。運行舊的遷移並有最新的遷移可能你可以試試 – ISHIDA

+0

我應該補充說我們使用NCrunch來運行一些自動化的數據庫測試,所以這些測試需要所有的遷移 –

+0

我會說創建一個空的遷移,其中包含所有的而不是太多的遷移,你將只有一次遷移,這將減少遷移的時間並提高速度。 – ISHIDA

回答

0

從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 ...「)將會解決這個問題。

+0

您獲得了什麼?一個巨大的遷移文件數量較少,有很多潛在的錯誤。如果知道所有已部署的數據庫已應用它們,則始終可以刪除前面的遷移。因此,如果您有100次遷移,但您已知1到50次已部署,則可以刪除這些遷移。如果您擔心舊的數據庫會彈出 - 在刪除之前將其編碼並存儲。 –

+0

是的,如果遷移數量成爲問題,我的遷移數量就會減少。此外,該文章解釋了爲什麼我需要所有原始遷移。 –

相關問題