EF Core migration分析
NETCore的資料庫遷移主要分二個步驟
- 生成遷移檔案
- 資料庫遷移
具體命令我們不討論,我們只討論最基本的2個命令後面做了什麼,以及我們可能碰到的問題。
0. 前言
整個遷移過程涉及到三個基本概念,我們先明確一下:
* 資料庫:比如mysql下某個具體的資料庫例項 * 原始碼:專案的原始碼,包括一個或多個DBContext * 遷移檔案:預設在專案原始碼根目錄下的migrations目錄下,包含遷移增量檔案和映象檔案
其中第一個步驟需要用到原始碼生成遷移檔案,第二個步驟根據遷移檔案更新資料庫
1. 生成遷移檔案
dotnet ef migrations add mirgation1 -v
加上-v引數可以看到執行的詳細過程,這個過程涉及到上面提到的三個基本概念,同時整個過程也包含了三部分:
1.1 執行dotnet build 編譯整個原始碼,原始碼必須保證編譯沒有錯誤才能遷移(廢話)。
1.2 執行編譯後的dll,並不是dotnet run,而是dotnet exec。所以原始碼必須執行沒有問題,這個不是廢話,因為我們有的時候執行專案是帶引數的,帶引數能執行,並不能表示不帶引數執行不出錯。
另外這個步驟同時會去查詢所有繼承了DbContext的類,如果有多個類,會提示執行失敗需要加上-context引數。
注意,mirgations add是不需要用到資料庫的,但是執行dll可能會需要連線上資料庫,但是這個資料庫可以不是最終真正的資料庫,一個臨時測試的資料庫也可以。
dotnet exec --depsfile C:\Work\Github\jianshu_sample\MigrationsSample\MigrationsSample\bin\Debug\netcoreapp2.0\MigrationsSample.deps.json --additionalprobingpath C:\Users\liuyi\.nuget\packages --additionalprobingpath "C:\Program Files\dotnet\sdk\NuGetFallbackFolder" --runtimeconfig C:\Work\Github\jianshu_sample\MigrationsSample\MigrationsSample\bin\Debug\netcoreapp2.0\MigrationsSample.runtimeconfig.json "C:\Program Files\dotnet\sdk\2.1.400\DotnetTools\dotnet-ef\2.1.1\tools\netcoreapp2.1\any\tools\netcoreapp2.0\any\ef.dll" migrations add mirgation1 --assembly C:\Work\Github\jianshu_sample\MigrationsSample\MigrationsSample\bin\Debug\netcoreapp2.0\MigrationsSample.dll --startup-assembly C:\Work\Github\jianshu_sample\MigrationsSample\MigrationsSample\bin\Debug\netcoreapp2.0\MigrationsSample.dll --project-dir C:\Work\Github\jianshu_sample\MigrationsSample\MigrationsSample\ --language C# --working-dir C:\Work\Github\jianshu_sample\MigrationsSample\MigrationsSample --verbose --root-namespace MigrationsSample
1.3 結束上個步驟的執行,生成或修改映象檔案和增量檔案。
這裡經常碰到一個問題,執行上面的步驟1.2的時候沒法結束,導致整個遷移卡死,原因是執行1.2的時候有可能會啟動一個死迴圈的前臺執行緒,導致程序沒法正常結束。

image.png
這個過程搜尋DBContext類下所有的DBSet以及對應的所有欄位,然後和映象檔案比較,如果映象檔案不存在,則生成一個並把所有的表和欄位都新增上,如果存在,則比較現有原始碼裡的表結構和映象檔案的表結構的差異,把差異轉換成增量檔案,並更新映象檔案。
所以執行migrations add的時候,實際上是,所以映象檔案就可以理解是資料庫完整表結構的c#實現(如上圖DataContextModelSnapshot.cs)。
而增量檔案就是一堆AddColum,DropColumn,CreateTable,RemoveTable等函式,表示這次變化是添加了新欄位,刪除新欄位等等增量操作。
2. 資料庫更新
dotnet ef database update -v
根據上面步驟1生成的增量檔案更新資料庫。也分三個步驟:
2.1 編譯專案,和1.1一樣
2.2 執行專案,和1.2一樣
2.3 在資料庫裡查詢_efmigrationshistory表裡的記錄

image.png
根據裡面的MigrationId到當前的所有遷移增量檔案裡找,如果有對應的增量檔案,則忽略,把沒有在這個表裡的所有增量檔案執行一遍,通過AddColum,DropColumn,CreateTable,RemoveTable等函式來更新資料庫。
所以這個步驟實際上是