本文章是由機器翻譯。

資料點

代碼的第一次遷移之謎:解決

Julie Lerman

Julie Lerman一位朋友最近問我一個問題關於Entity Framework(EF) 代碼第一次遷移,把我弄糊塗,差不多一樣困惑著他 — — 但出於不同的原因。

對話是這樣的:

"嗨朱莉,為什麼我的 Azure Web 網站會自動遷移我的資料庫?"

"是你確定你沒有自動遷移設置為 true 嗎?它是假的預設情況。

"絕對不會。我並不改變該設置。

"遷移初始值設定項怎麼樣?那能做它,太好了"。

讓我在這裡打斷的話,請確保你真正瞭解,初始值設定項。如果遷移是顯式的東西你創建和執行在封裝管理員主控台中,為什麼會有一個初始值設定項嗎?

第一個初始值設定項的代碼

第一次帶有三個初始值設定項: 啟動代碼

CreateDatabaseIfNotExists:這將創建一個,如果資料庫找不到它,也結束了它的工作。如果您修改資料庫時,資料庫不會重新創建或遷移。只是,你會建議你使用不同的方法來管理資料庫異常。具體地說,這項建議將使用遷移。

DropCreateDatabaseAlways:這種集成測試的理想選擇。它將刪除現有的資料庫和運行您已經添加在任何種子邏輯的從頭重新創建它。 為集成測試,它是一個偉大的方式,總是有一個一致的資料庫。

DropCreateDatabaseIfModelChanges:有遷移之前,這是十分有用的選項,在發展中,如果你不需要保留的資料或任何其他您可能已更改,如添加索引或觸發器的資料庫中的架構。

為完整起見,我想還指出在 EF6,我們得到了 NullDatabaseInitializer 為那些人發現很難記住 (或發現) 其他語法用於禁用初始化:SetDatabaseInitialier < MyCoNtext > (null)。

然後遷移到達 EF4.3。 遷移並不是活躍在您的資料層,直到您顯式啟用他們從封裝管理員主控台視窗通過鍵入啟用遷移。這確實就是將與配置類的一個新的資料夾添加到您的專案。如果啟用過程發現綁在您的上下文的現有資料庫,它將創建初始遷移類。這是為了確保當您執行遷移,代碼優先不會嘗試創建已存在的資料庫物件。

事實上,你會看到一條說明性消息在主控台中的啟用遷移後如中所示圖 1

T對由初始值設定項創建的現有資料庫的啟用遷移反應
[圖 1]對由初始值設定項創建的現有資料庫的啟用遷移反應

如果你看看在你的資料庫中,在新的 __MigrationHistory 檔中,您將看到反映已經在資料庫上執行初始遷移表中的行。

它是重要的是理解還有沒有別的 — — 沒有添加到您的應用程式佈建或任何其他隱藏的移徙拼圖板件。配置類是至關重要的雖然。

這裡是從在啟用 migra 的時的預設實現­,關於我的資料層,在那裡我有 DbCoNtext 類稱為的 MigratoryBirdsCoNtext:

internal sealed class Configuration : 
  DbMigrationsConfiguration<MigratoryBirdsContext>
  {
    public Configuration()
    {
      AutomaticMigrationsEnabled = false;
      ContextKey = "DataLayer.MigratoryBirdsContext";
    }
    protected override void Seed(MigratoryBirdsContext context)
    {
    }
  }

因為我會顯式使用此類進一步,就會將其簽名改成公。對於那些你只需掃描通過代碼,這裡是進行新的聲明:

public class Configuration : DbMigrationsConfiguration<MigratoryBirdsContext>

遷移可以自動運行意義會發現模型變化和遷移對應變化將創建並在資料庫上執行。所有這一切都發生在運行時期間資料庫初始化。自動遷移是方便簡單的應用程式,但你很少控制他們,我通常不推薦使他們。在代碼第一切換預設值為 false 時,我很高興。

在運行時,代碼第一次看起來綁一個上下文,當這種情況下通過其資料的 DbMigrationsConfiguration 類­初始化過程的基礎。如果找到此類,則任何顯式調用或設置要將資料庫初始化設置為原來的三個初始值設定項的任何 — — 其工作是創建或刪除並創建資料庫 — — 將創建使用遷移的資料庫。這是一個為 EF6.1 的新模式。 在此之前,那些三個初始值設定項將會使用他們自 EF4.3,總是已經使用了推斷模型和設定資料庫架構的初始化邏輯。這種變化對 EF6.1 是方便使用的開發人員,像我一樣,DropCreateDatabase­總是在他們的測試中的初始值設定項。現在,它將刪除資料庫,但使用我的遷移,然後重新創建它。如果我已經自訂遷移課,我會到我的資料庫,以及應用該自訂。

它也是重要的是要時刻牢記,預設初始值設定項 — — CreateDatabaseIfNotExists — — 還將使用遷移創建一個資料庫,如果遷移存在,但資料庫不會。

所以,現在可以看看第四個初始值設定項,MigrateDatabaseToLatestVersion,這是的一個當他正要拿到的神秘遷移源在他的 Azure 網站上關於問我的朋友。由於遷移在 EF4.3 中引入此初始值設定項已經存在。

名稱,MigrateDatabaseToLatestVersion,似乎表明它將工作就像自動遷移,但只有單一的、 重大的差別。而由現有遷移類觸發此初始值設定項任務由改變在模型中,觸發自動遷移。

要看到這是如何工作的讓我們開始與預設狀態後您已經啟用遷移。在劇中還有沒有 MigrateDatabaseToLatestVersion 初始值設定項和 AutomaticMigrations 設置為 false。

這裡有個基本集成測試在 MigratoryBirdsCoNtext 上執行一個簡單的查詢:

[TestMethod]
public void CanInitializeDatabase() {
  using (var context = new MigratoryBirdsContext())
  {
    context.MigratoryBirds.ToList();
  }
  Assert.Inconclusive("If we're here, it did not crash");
}

如果要更改類在我的模型之一,並在運行此測試會引發一個異常,告訴我,"自資料庫創建以來,支援 MigratoryBirdsCoNtext 上下文模型已經改變了。考慮使用代碼第一次遷移來更新資料庫"。

即使已啟用遷移和我手邊的 MigrationsConfiguration 類,那所有的 EF 知道是當前模型不匹配 MigrationHistory 表中存儲的最新版本。在這一點上,我可以使用添加遷移和更新資料庫來解決該問題,但我想告訴你,初始值設定項是如何工作的會讓一個不同的路徑:我將修改測試以便在初始值設定項。如果你不熟悉它的建構函式語法,你必須指向設定檔的目標 DbCoNtext,像這樣:

[TestMethod]
public void CanInitializeDatabase()
{
  Database.SetInitializer(
    new MigrateDatabaseToLatestVersion<MigratoryBirdsContext, 
    DataLayer.Migrations.Configuration>());
  using (var context = new MigratoryBirdsContext())
  {
    context.MigratoryBirds.ToList();
  }
  Assert.Inconclusive("If we're here, it did not crash");
}

再次運行測試引發另一個異常,和其消息突出顯示此初始值設定項和自動遷移之間的區別:"無法更新資料庫,以匹配當前的模型,因為有暫止的變更並自動遷移已停用。寫入掛起模式更改基於代碼的遷移或啟用自動遷移。"

AutomaticMigrations 會注意的區別,創建遷移和更新資料庫 — — 所有飛和安靜。然而,AutomaticMigrations 並不存在任何遷移,它將創建為您的專案中的類。雖然此初始值設定項注意到變化,它不會自動創建為您遷移。它可以只使用現有的遷移。

如果你沒有手動之前進行遷移,它是一個兩步過程:

首先,用添加遷移命令創建遷移。這將會讀取您的模型和查詢的資料庫中遷移歷史記錄表,最新的條目,然後比較這兩個。如果您的模型已更改,因為它最後存儲,它將創建一個新的遷移類遷移的資料庫的當前架構的指示,以配合您的模型中的更改。接下來,你在資料庫上執行,移徙 (或遷移命令語法的基礎的某種組合)。鍵入封裝管理員主控台的基本命令是更新資料庫。

不是很多開發人員意識到可以執行更新資料庫,以程式設計方式,以及。我知道它是可能的但沒這麼做很久了,我不得不去看看我在 Pluralsight 上的代碼第一次遷移過程中的詳細資訊。遷移 API 有一個 DbMigrator 類使您可以使用相同的選項,您可以從更新資料庫命令存取控制台中更新資料庫。

關鍵步驟是要具現化您的遷移設定檔 ; 具現化 API DbMigrator 類,通過實例遷移配置類 ; 然後調用更新:

var migrator = new DbMigrator(new DbMigrationsConfiguration());
migrator.Update();

而這是在 MigrateDatabaseToLatestVersion 初始值設定項以您的名義做什麼。遷移需要已經存在於您的專案 (或您已編譯的程式集) 和初始值設定項將它們在資料庫上為您在運行時執行。

我已經對我的域類的改變,我現在會往前走並添加遷移命令中添加-遷移捷流。'這裡是我獲取生成的類:

public partial class JetStream : DbMigration
{
  public override void Up()
  {
    AddColumn("dbo.MigratoryBirds", "DependentOnJetStream", c =>
      c.Boolean(nullable: false));
  }
  public override void Down()
  {
    DropColumn("dbo.MigratoryBirds", "DependentOnJetStream");
  }
}

現在這個班是專案的我的一部分。當我再次運行測試時,在那裡我已經建立了遷移-­資料庫初始值設定項,測試不會引發異常。我探測器顯示我之前選擇被執行,資料庫表模式進行更改以在新的 DependentOnJetStream 屬性中添加。

我沒有得到我喜歡的 DropCreateDatabaseAlways 初始值設定項的這種模式是新版本的資料庫的集成測試。要做到這一點,我不得不前播種的資料庫設定檔的種子方法中執行一些原始的 SQL 命令。或者,對於集成測試,我只是可以完全禁用初始化並顯式控制資料庫創建。Eric何傑寫了一個偉大的博客帖子,關於這一點,"使用 SQL 緊湊的集成測試與Entity Framework"(bit.ly/1qgh9Ps)。

MigrateDatabaseToLatestVersion 照耀的地方

如果你編譯該專案並把它給沒有遷移她自己開發資料庫的另一個開發人員,初始值設定項將觸發應用程式來尋找一個遷移。遷移會被發現,因為它是在專案中。初始值設定項將檢查資料庫的遷移歷史記錄表和更新資料庫架構,如有必要。

考慮過這個問題在生產、 不發展、 遷移類將編譯成程式集和部署應用程式的一部分。當應用程式運行時,它將回應 (在適當的位置在您的應用程式) 的 MigrateDatabaseToLatestVersion 設置,並相應地更新資料庫架構。

那麼蔚藍的 Web 網站中發生了什麼?

現在,你已經很好地理解如何 MigrateDatabase­ToLatestVersion 的作品,讓我們回到我的朋友交談。我們在離開:"遷移初始值設定項怎麼樣?這將做它,太好了。"

他回答說他沒有在代碼中設置的遷移初始值設定項在任何地方。所以,現在它是一個巨大的謎。行為完全符合的 MigrateDatabaseToLatestVersion。他到 Azure 部署自己的應用程式。當他跑了它時,應用程式注意到他已經在重新部署之前在模型中所做的更改,並且它更新資料庫架構。

所有的這些問題問和回答,讓我有點困惑,我牽手去我最喜愛的搜尋引擎,提供一些有用的資訊,併發現了一個。

當您將一個 Web 應用程式發佈到 Azure 時,設置頁上有一個核取方塊,預設情況下未選中。但這個核取方塊表示"執行代碼第一次遷移 (運行應用程式啟動)。"檢查這將 MigrateDatabaseToLatestVersion 設置聲明方式添加設定檔中。

我的朋友通過電子郵件發送給他看一張帶有該設置的頁面的截圖和問,"看起來熟悉嗎?"謎團解開了。他曾創建遷移和更新他的開發資料庫。所以遷移被編制成他的議會中,是當他部署它。他記得選中這個核取方塊。

所以當他第一次跑了他的網站上,初始值設定項將調用 DbMigrator.Update,其中比較遷移到 MigrationsHistory 表中的清單元件中的清單和跑任何不是表中存在。

現在他認識到作為一項功能,不是一個謎。


Julie Lerman 是 Microsoft MVP,.NET 的導師和顧問,住在佛蒙特州的山。你可以找到她提出關於資料訪問和其他.NET 主題使用者組和世界各地的會議。她的博客 thedatafarm.com/blog ,是作者的"程式設計Entity Framework"(2010 年),以及代碼第一版 (2011 年) 和 DbCoNtext 版 (2012 年),所有從 O'Reilly 媒體。跟著她在 Twitter 上 twitter.com/julielerman ,看看她的 Pluralsight 課程 juliel.me PS 的-視頻

感謝以下的微軟技術專家對本文的審閱:羅文Miller