原文連結:https://www.thereformedprogrammer.net/handling-entity-framework-core-database-migrations-in-production-part-2/
作者:jon p smith
在生產中運用 efcore 的模式實戰
这是使用 EF Core 迁移数据库的系列文章中的第二篇。本文着眼于将迁移应用于数据库,并从第 1 部分开始,该部分介绍了如何创建迁移脚本。如果您还没有阅读第 1 部分,那么本文的某些部分将毫无意义,因此这里是第 1 部分的快速回顾。
- 可以將兩種類型的遷移應用於資料庫:
- 添加新的表,列等,稱為不間斷的更改(簡單)。
- 更改列/表並需要複製數據,這稱為重大更改(困難)。
- 將遷移應用於資料庫的主要方法有兩種
- 使用 ef core 遷移功能
- 使用 ef core 創建遷移,然後手動修改遷移。
- 使用第三方遷移構建器在 c#中編寫遷移。
- 使用 sql 資料庫比較工具比較資料庫並輸出 sql 更改腳本。
- 通過複製 ef core 的 sql 編寫自己的 sql 遷移腳本。
因此,既然您現在知道如何創建遷移腳本,那麼我將研究可以將遷移應用於生產資料庫的不同方式,以及這些方式所具有的利弊。
tl; dr –內容摘要
注意:單擊連結可直接轉到涵蓋該點的部分。
- 您具有影響遷移方法可以使用的應用程式的類型。·您必須考慮可能發生的錯誤並制定計劃。·有四種方法可以將遷移應用於資料庫
- 在啟動時調用 context.database.migrate()very easy,但是存在一些嚴重的問題,限制了它的實用性。
- 通過控制台應用程式調用 context.database.migrate()-easy,並且效果很好,尤其是在部署管道中
- 將 ef core 遷移輸出為 sql 腳本並在目標資料庫上執行該腳本 -hard,但是卻能提供很好的控制。
- 使用資料庫遷移應用程式工具來應用您自己的 sql 腳本 -hard,但是您卻可以很好地控制。
- 應用遷移的三個不同級別。
- 在遷移資料庫時停止應用程式是最安全的選擇,但並非總是可能的。
- 在應用程式運行時,可以將某些(但不是全部)不間斷的更改應用於資料庫。
- 對於連續服務應用程式(7*24 小時運行的服務),要應用重大更改需要五個步驟。
場景分析–您的產品是哪種應用程式?
在第 1 部分中,我們著重於創建“有效”的遷移,以及遷移是不間斷的變更還是重大變更(請參閱本文開頭的快速定義,或第 1 部分中的此連結。
現在,我們正在考慮將遷移應用於資料庫,但是我們擁有的選項取決於正在訪問資料庫的一個或多個應用程式。這是您需要考慮的問題。
是只有一個應用程式訪問該資料庫,還是您的應用程式是橫向擴展的 web 應用程式,即,同時運行多個版本的應用程式。如果您的應用程式是橫向擴展,則將刪除其中一個選項。
您可以在將遷移應用到資料庫時停止應用程式,還是您的應用程式提供 7*24 小時連續服務?在應用重大變更方面,更新連續服務應用程式會帶來一些挑戰。
在遷移生產資料庫時,有點偏執是可以的。
正如我在第 1 部分末尾所說的那樣-當您將遷移應用於生產資料庫時,最恐怖的部分到來了。更改包含關鍵業務數據需求(需求!)的資料庫,請仔細計劃和測試。您需要考慮如果(何時!)遷移因錯誤而失敗時該怎麼辦。
在考慮應用遷移的不同方法時,您應該腦海中浮現“如果有錯誤會發生什麼?”。這可能會促使您採用更複雜的遷移方法,因為它更易於測試或還原。我不能為您提供規則或建議,因為每個系統都不同,但是對故障有點偏執並不是一件壞事。我應該讓您構建一個更健壯的用於遷移應用程式及其資料庫的系統。
第 2 部分:如何將遷移應用於資料庫。
下面的列表提供了將遷移應用於資料庫的不同方法。我列出了 ef core 案例的三個選項:第一個是最簡單的,但是它有其他兩個選項所沒有的限制。sql 遷移沒有實際限制,但確實需要資料庫遷移應用程式工具才能以正確的順序應用 sql 腳本。
這是您可以應用遷移的方法列表。
efcore 遷移
在啟動時調用 context.database.migrate()
通過控制台應用程式或管理命令調用 context.database.migrate()
將遷移輸出作為 sql 腳本輸出,然後在目標資料庫上執行該腳本。
sql 遷移
使用資料庫遷移應用程式工具。
最後,如何應用遷移取決於遷移類型(中斷或不中斷)和要更新的應用程式類型(單個應用程式,並行運行的多個應用程式或必須停止的應用程式)。這是所有這些排列的圖表。

外部的深藍色表示可以在所有情況下都應用 sql 遷移,而內部較淺的方框表示可以在其中添加不同類型的 ef core 遷移。以下是有關該圖的一些澄清說明:
- 該圖顯示了標準 ef 遷移和手工修改的 ef 遷移,但是當我談論應用遷移時,兩者之間沒有區別-我們很簡單地應用 ef core 遷移。·圖中的“五個階段的應用程式更新”紅色框表示您需要對無法停止的應用程式進行重大更改所需要的複雜階段。我將在文章末尾居間。
現在,我將詳細居間應用遷移的每種方式。
1a。在啟動時調用 context.database.migrate()
到目前為止,這是應用遷移的最簡單方法,但是它有一個很大的局限性–您不應同時運行 migrate 方法的多個實例。如果橫向擴展 web 應用程式,則可能會發生這種情況。引用安德魯·洛克(andrew lock)的話:“
我们不能保证这会给您带来麻烦,但是除非您非常谨慎地确保幂等更新和错误处理,否则您很可能会陷入困境
” –请参阅他的帖子的这一部分“ 在 ASP.NET Core 中的应用启动时运行异步任务”。
| 建議 | 詳述 |
|---|---|
| 好處 | ·相對容易實現(請參閱提示) ·確保在應用程式運行之前資料庫是最新的。 |
| 壞處 | ·不得並行運行兩個或多個 migrate 方法。·如果遷移有錯誤,則您的應用程式將不可用。·難以診斷啟動錯誤 |
| 局限性 | 不適用於連續服務系統 |
| 提示 | 我非常喜欢 Andrew Lock 的文章中的在启动时运行迁移的 选项 。我在一些使用内存数据库的演示系统中使用了类似的方法,这些数据库需要初始化(请参见本示例) |
| 我的建議 | 如果您正在運行單個 web 應用程式或類似的 web 應用程式,並且可以在沒有人使用它的情況下更新系統,那麼這可能對您有用。我沒有像我使用的許多系統那樣使用橫向擴展。 |
1b。通過控制台應用程式或管理命令調用 context.database.migrate()
如果您不能並行運行多個 migrate 方法,那麼確保此方法的一種方法是在設計為僅執行 migrate 方法的獨立應用程式內調用 migrate 方法。您可以在主 web 應用程式解決方案中添加一個控制台應用程式項目,該項目可以訪問 dbcontext 並可以調用 migrate。您既可以自己運行它,也可以讓您的部署系統運行它(ef6.x 用戶注意–這等效於運行 migrate.exe,但其中已編譯應用程式 dll)。
| 建議 | 詳述 |
|---|---|
| 好處 | 它適用於所有情況。·與部署系統配合良好。 |
| 壞處 | 還有更多工作。 |
| 局限性 | –無–,但請注意持續進行的五階段應用程式更新 |
| 提示 | 如果您的控制台應用程式使用連接字符串來定義要將遷移應用到哪個資料庫,那麼它將更易於在部署管道中使用。 |
| 我的建議 | 如果您具有部署管道,那麼這是一個不錯的選擇,因為您可以在部署過程中執行控制台應用程式。如果您是手動應用遷移,則有命令 update-database。 |
1c。將 ef core 遷移轉換為腳本並將其應用於資料庫
通過使用腳本遷移命令 ef core 會將特定的遷移或默認情況下的所有遷移轉換為 sql 腳本。然後,您可以使用可以在要更新的特定資料庫上執行 sql 的方法來應用此方法。您可以在 sql server management studio 中手動執行 sql ,但是通常您的發布管道中有一些內容可以在適當的時間執行。
| 建議 | 詳述 |
|---|---|
| 好處 | 它適用於所有情況。·與可以使用 sql 腳本的部署系統一起很好地工作。·您可以在運行 sql 之前先查看它,看看它是否正常。 |
| 壞處 | 比控制台應用程式(1b)更多的工作 ·您需要一些應用程式將腳本應用於正確的資料庫。 |
| 局限性 | –無–,但請注意持續進行的五階段應用程式更新 |
| 提示 | sql 包含用於更新遷移歷史記錄的代碼,但是您必須在 script-migration 命令中包括 idempotent 選項,以獲取阻止兩次應用遷移的檢查。 |
| 我的建議 | 如果您想使用 ef core 的 migrate 方法,那麼我建議您使用控制台應用程式 1b。它與使用腳本一樣安全,並且執行相同的工作。但是,如果您的管道已經可以使用 sql 更改腳本,那麼這非常適合您。 |
2a。使用遷移工具應用 sql 腳本
如果創建了一系列 sql 遷移腳本,則需要以下步驟:a)以正確的順序應用它們,b)僅應用一次。ef core 的遷移包含執行“正確順序”和“僅一次”規則的代碼,但是當我們編寫自己的遷移腳本時,我們需要一個可以提供這些功能的工具。
我和其他許多人使用了一個名為 dbup 的開源庫,該庫提供了這些功能(以及更多功能),還支持多種資料庫類型。我按字母順序排列遷移腳本,例如“ script0001 –初始遷移”,“ script0002 –添加種子數據”以供 dbup 應用。就像 ef core 遷移一樣,dbup 使用一個表來列出哪些遷移已應用到資料庫,並且僅在該表中沒有遷移時才應用。
還可以使用其他遷移工具,例如 octopus deploy 和各種 redgate 工具(但我沒有使用過它們,因此請檢查它們是否具有正確的功能)。
| 建議 | 詳述 |
|---|---|
| 好處 | 它適用於所有情況。與部署系統配合良好。 |
| 壞處 | 您必須管理腳本。 |
| 局限性 | –無–,但請注意持續進行五階段應用程式更新 |
| 提示 *(適用於 dbup) | 我製作了一個控制台應用程式,該應用程式接受連接字符串,然後運行 dbup,因此可以在部署管道中使用它。·為了進行測試,我使運行 dbup 的方法在“僅以調試模式運行”單元測試中可用於我的單元測試程式集,該方法使用我的 compareefsql 工具正確遷移了本地資料庫(請參閱本系列第 1 部分中有關測試遷移的部分。 |
| 我的建議 | 使用 ef core 的項目上使用這種方法。 |
應用程式和應用程式遷移
將遷移應用於資料庫時,可以停止應用程式,或者在某些情況下可以在遷移運行時應用遷移。在本節中,我將居間為您提供的不同選項。
1.在遷移資料庫時停止應用程式
這是最安全的選項,可與重大更改和不中斷更改一起使用,但是您的用戶和您的業務可能並不那麼滿意。我稱其為“維護站點”。在“站點關閉”方法中,您不想在用戶輸入數據或完成訂單時停止應用程式。這就是您或您的公司獲得不良聲譽的方式。
我早在 2015 年就遇到了這個問題,並且我創建了一種方法來警告人們該網站將要關閉,然後停止除管理員以外的所有人員訪問該應用程式。我之所以選擇這種方法,是因為對於正在使用的 web 應用程式,此方法比支持破壞性更改同時保持 web 應用程式運行的開銷要小(我將在稍後居間對連續服務應用程式進行中斷)。通常在周末和晚上,您可能會遇到所使用服務的“此站點已關閉維護”。
注意:我寫了一篇名為“ 如何使 asp.net mvc 網站“為了維護而停機 ””的文章,您可能希望看一下-該代碼是針對 asp.net mvc5 的,因此需要一些工作才能使其正常工作。. net core,但該想法仍然有效。
在應用程式運行時應用不間斷的遷移
從理論上講,通過不間斷的更改,您可以在舊應用程式運行時將其應用於資料庫,但是有些問題可能會讓您失望。例如,如果您添加了一個沒有 sql 默認值且不知道該新列的舊軟體的新的非空列,並嘗試插入新行,則您會收到一條 sql 錯誤,因為舊軟體沒有提供了非空列的值。
但是,如果您知道不間斷的遷移沒有問題,那麼在舊應用程式運行時應用遷移將為您的用戶提供連續的服務。有多種方法可以執行此操作,具體取決於您選擇了哪種遷移應用程式方法,想到的就是 azure 的暫存槽(已經存在了很長時間)和更新的 azure pipelines。
將重大更改應用於連續運行的應用程式:五階段的應用程式更新。
最困難的工作是對不斷運行的應用程式進行重大更改。在顯示不同方法的圖表中,右上方會顯示一個名為“五階段應用程式更新”的紅色框。該名稱來自以下事實:您需要分階段遷移,通常為五個階段,如下圖所示。
注意:安德魯·洛克(andrew lock)稱讚我在上一節中描述的“添加不可為空的列”問題可以分三個階段處理:a)添加新列但可為空,b)部署已知該列的新軟體,以及 c)將列更改為不可為空。
這是我的《efcore》一書的第 11.5.3 節中的圖表,該圖顯示了添加重大更改所需的五個階段,這些更改將現有的 customerandaddress 表分為兩個表,customers 和 addresses。

如您所見,這樣的更新創建起來很複雜,應用起來也很複雜,但這就是運行連續系統的成本。這五個階段沒有任何真正的替代方案,除了您永遠不要對連續運行的系統應用重大更改(我聽說有人說這是他們的方法)。
注意:我在我的书“ Entity Framework Core in Action ”的 11.5.3 节中介绍了持续的,五个阶段的应用程序更新,您还可以在 Neil Ford 的“ Building Evolutionary Architectures ” 一书的第 5 章中找到有关此内容的内容。等。
結論
如果資料庫中的數據和服務的可用性對組織很重要,那麼您必須認真對待資料庫遷移。在第 1 部分中,我居間了創建遷移腳本的不同方法,並且本文居間了如何將這些遷移應用於生產資料庫。本系列文章的目的是為您提供各種選擇,以及它們的優缺點,以便您可以就如何處理遷移做出明智的決定。
就像我在第一篇文章中所说的那样,我与 EF 迁移的第一个磨合是使用 EF6。我非常了解 EF6,并且写过《 Entity Framework Core in Action》一书我对 EF Core 的了解甚至更好。围绕迁移从 EF6 到 EF Core 的变化代表了 EF Core 中整个方法的变化。
ef6 進行了很多“魔法”操作,使其更易於使用- 啟動時自動遷移就是其中之一。問題是,當 ef6 的“魔法”效果不佳時,很難對其進行梳理。ef core 的遷移方法是由您決定如何在何處以及如何使用它-沒有自動的“魔法”。ef core 遷移的許多其他小變化來自於聆聽 ef4 到 6 的用戶。
因此,在生產資料庫上的遷移令人恐懼。我已經為您提供了一些有關選項的見解,但這僅是更改生產資料庫的最低要求。需要根據需要添加備份,策略,產品前測試和部署管道,以構建可靠的系統。
祝你能享受編碼的快樂!