隨著模型的變更,遷移會在正常開發過程中被新增或移除,並且遷移檔案會簽入您專案的版本控制系統。 若要管理移轉,您必須先安裝 EF Core 命令列工具。
Tip
DbContext如果 位於與啟動專案不同的元件中,您可以在套件管理員控制台工具或 .NET CLI 工具中明確指定目標和啟動專案。
新增移轉
在修改模型後,您可以為該變更新增一個遷移:
dotnet ef migrations add AddBlogCreatedTimestamp
移轉名稱可以像版本控制系統中的認可訊息一樣使用。 例如,如果您針對 實體新增一個新 CreatedTimestamp 屬性,您可能會選擇一個名稱如 Blog。
移轉 目錄下,會將三個檔案新增至您的專案:
-
XXXXXXXXXXXXXX_AddBlogCreatedTimestamp.cs--主要移轉檔案。 包含套用遷移所需的操作(在
Up中),以及還原該遷移(在Down中)。 - XXXXXXXXXXXXXX_AddBlogCreatedTimestamp.Designer.cs--遷移的元數據檔案。 包含EF所使用的資訊。
- MyContextModelSnapshot.cs--您目前模型的快照集。 用來判斷新增下一次遷移時有哪些變更。
檔名中的時間戳有助於讓它們依時間順序排序,讓您可以看到變更的進展。
Namespaces
您可以自由移動移轉檔案,並手動變更其命名空間。 新的遷移會被建立成為上次遷移的同級。 或者,您可以在產生時間指定目錄,如下所示:
dotnet ef migrations add InitialCreate --output-dir Your/Directory
Note
您也可以使用 --namespace,獨立變更目錄的命名空間。
一步建立並套用遷移
Note
此功能於 EF Core 11 中加入。
此 dotnet ef database update 指令支援透過選項 --add 在單一步驟內建立並套用遷移。 此系統使用 Roslyn 在執行時編譯遷移,實現像 .NET Aspire 及容器化應用程式等無法停止與重建的場景:
dotnet ef database update InitialCreate --add
與 dotnet ef migrations add 項目可用的選項相同:
dotnet ef database update AddProducts --add --output-dir Migrations/Products --namespace MyApp.Migrations
此指令架構以指定名稱進行新的遷移,使用 Roslyn 編譯後立即套用到資料庫。 遷移檔案仍會儲存在磁碟中,以便進行原始碼控制及未來重新編譯。
若未偵測到待處理的模型變更,該指令會套用任何現有待處理的遷移,而不建立新的。
自定義移轉程序代碼
雖然 EF Core 通常會建立精確的移轉,但您應該一律檢閱程式碼,並確定它對應至所需的變更;在某些情況下,甚至有必要這樣做。
欄重新命名
需要自定義移轉的一個值得注意的範例是重新命名屬性。 例如,如果您將屬性從 Name 重新命名為 FullName,EF Core 將會產生下列移轉:
migrationBuilder.DropColumn(
name: "Name",
table: "Customers");
migrationBuilder.AddColumn<string>(
name: "FullName",
table: "Customers",
nullable: true);
EF Core 通常無法知道何時打算卸除數據行並建立新的數據行(兩個不同的變更),以及何時應該重新命名數據行。 如果套用上述移轉 as-is,則所有客戶名稱都會遺失。 若要重新命名數據行,請使用下列內容取代上述產生的移轉:
migrationBuilder.RenameColumn(
name: "Name",
table: "Customers",
newName: "FullName");
Tip
遷移鷹架程序在某個操作可能導致資料遺失時會發出警告(例如刪除欄位)。 如果您看到該警告,請務必檢查移轉程式碼以確保正確性。
資料作業
遷移不僅能移動資料,也能改變結構。 根據遷移寫入時值是否已知來選擇操作:
- 使用
InsertData、UpdateData和DeleteData來表示固定值及以明確鍵標示的列。 EF Core 將這些操作轉換成提供者專屬的 SQL,因此在產生腳本和套件時也能運作。 - 當必須從現有資料庫資料計算新值時,請使用
Sql。 SQL 語法可能因提供者而異;必要時再多做MigrationBuilder.ActiveProvider。 - 當可重用操作需要提供者專屬的 SQL 產生時,定義 自訂遷移操作 。
遷移時不要使用目前 DbContext 或實體的 CLR 類型來移動資料。 歷史遷移在這些類型被更改或移除後,必須繼續編譯並保持相同行為。
轉換現有資料
替換欄位時,請保留來源資料,直到目的地資料被填入:
- 將目的欄位設為可空。
- 從現有的柱子中填充。
- 如果需要,請填寫目的地欄位。
- 刪除來源欄位。
以下遷移實作了 SQL Server 與 SQLite 的該序列:
migrationBuilder.AddColumn<string>(
name: "FullName",
table: "Customers",
nullable: true);
if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.SqlServer")
{
migrationBuilder.Sql(
"""
UPDATE [Customers]
SET [FullName] = [FirstName] + N' ' + [LastName];
""");
}
else if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.Sqlite")
{
migrationBuilder.Sql(
"""
UPDATE "Customers"
SET "FullName" = "FirstName" || ' ' || "LastName";
""");
}
else
{
throw new NotSupportedException(
$"Data migration is not implemented for provider {migrationBuilder.ActiveProvider}.");
}
migrationBuilder.AlterColumn<string>(
name: "FullName",
table: "Customers",
nullable: false,
oldClrType: typeof(string),
oldNullable: true);
migrationBuilder.DropColumn(
name: "FirstName",
table: "Customers");
migrationBuilder.DropColumn(
name: "LastName",
table: "Customers");
為應用程式支援的每個提供者新增一個分支。 丟給未知供應商比悄悄套用不完整的遷移更安全。 不要用不受信任的值來建立 SQL;遷移 SQL 以變更結構的權限執行。
有些轉換無法逆轉而不損失資訊。 只有在原始數值能安全重建時才實施 Down 。 否則,則會明確失敗,並需要在回滾過程中從備份還原資料。
插入固定資料
當遷移時鍵與值已知時,請使用 InsertData :
migrationBuilder.InsertData(
table: "Countries",
columns: new[] { "CountryId", "Name" },
values: new object[,]
{
{ 1, "United States" },
{ 2, "Canada" }
});
對應 Down 的方法應該會用 DeleteData 相同的金鑰呼叫。
更新固定資料
UpdateData 透過鍵來識別一列,並將一個或多個欄位設定為固定值:
migrationBuilder.UpdateData(
table: "Countries",
keyColumn: "CountryId",
keyValue: 1,
column: "Name",
value: "United States of America");
該 Down 方法應該會恢復先前的值。
刪除固定資料
DeleteData 也以鍵標示列:
migrationBuilder.DeleteData(
table: "Countries",
keyColumn: "CountryId",
keyValue: 2);
如果刪除必須是可 Down 逆的,該方法應該用 InsertData 來還原所有刪除的值。 這些操作不會查詢目前的資料庫狀態;當行為依賴於現有資料時,使用 Sql 初始化時間做種。
透過原始 SQL 進行任意變更
原始 SQL 也可以用來管理 EF Core 不知道的資料庫物件。 若要這樣做,請新增一個遷移而不進行任何模型變更;系統會產生一個空的遷移,然後您就可以填入原始 SQL 操作。
例如,下列移轉會建立 SQL Server 預存程式:
migrationBuilder.Sql(
@"
EXEC ('CREATE PROCEDURE getFullName
@LastName nvarchar(50),
@FirstName nvarchar(50)
AS
SELECT @LastName + @FirstName;')");
Tip
當語句必須是 SQL 批次中的第一個或只有一個時,就會使用 EXEC。 它也可以用來解決數據表上目前不存在參考數據行時可能發生的等冪移轉腳本中的剖析器錯誤。
這可用來管理資料庫的任何層面,包括:
- 預存程序
- 全文檢索
- Functions
- Triggers
- Views
在大部分情況下,EF Core 會在套用移轉時,自動將每個移轉包裝在自己的交易中。 不幸的是,某些資料庫中交易中無法執行某些遷移操作;在這種情況下,你可以選擇退出交易,方法是傳遞 suppressTransaction: true 給 migrationBuilder.Sql。
Note
在 EF Core 9 中,EF Core 預設以單一交易跨越所有待處理遷移(EF Core 10 則回復此規定)。 詳情請參閱 突發變更說明 。
移除遷移
有時候,您會新增移轉,並意識到在套用之前必須先對 EF Core 模型進行其他變更。 若要移除最後一個移轉,請使用此命令。
dotnet ef migrations remove
拿掉移轉之後,您可以進行其他模型變更,然後再次新增。
Warning
避免移除已套用至生產資料庫的任何移轉。 這樣做表示您將無法從資料庫中回覆這些移轉,並可能會破壞後續移轉所依據的假設。
如果遷移是在當地實施的
對於一次性開發資料庫,先將資料庫更新到先前的遷移,然後從專案中移除遷移。 移除第一次遷移時,將目標用作 0 目標。
dotnet ef database update PreviousMigration
dotnet ef migrations remove
或者, --force 執行以下兩個步驟:
dotnet ef migrations remove --force
如果遷移是應用到共享資料庫
不要刪除已套用到共享、測試或生產資料庫的遷移。 通常,將遷移保留在專案中,並新增一個修正遷移。 若需要計畫回滾,請在原始遷移程式碼尚未取得時執行回滾,並協調應用程式與資料庫部署。
移除較舊的未套用遷移
這些工具只會移除最新的遷移。 不要刪除序列中間的遷移,然後手動編輯模型快照。 如果遷移及其後的遷移都未公開且未套用,則以相反順序移除後續遷移,移除不想要的遷移,然後再用支架形式改變保留模型。
如果遷移是在不同分支建立的,則改用 分開遷移樹 的工作流程。
列表遷移
您可以列出所有現有的移轉,如下所示:
dotnet ef migrations list
你也可以以程式化方式檢查移民州:
var allMigrations = context.Database.GetMigrations();
var appliedMigrations = await context.Database.GetAppliedMigrationsAsync();
var pendingMigrations = await context.Database.GetPendingMigrationsAsync();
GetPendingMigrationsAsync 比較配置中的遷移組件與目標資料庫中記錄的遷移。 它不會偵測遷移過程中未被捕捉到的模型變更;請使用下方的待定模型變更檢查。
檢查待處理的模型變更
Note
此功能是在 EF Core 8.0 加入。
有時候,您可能想要檢查上次移轉之後是否有任何模型變更。 這能協助您知道自己或隊友何時忘記新增移轉。 其中一種方法是使用此命令。
dotnet ef migrations has-pending-model-changes
您也可以使用 context.Database.HasPendingModelChanges()以程式設計方式執行這項檢查。 這可以用來撰寫單元測試,如果忘記新增遷移,測試將會失敗。
Note
從 EF Core 9 開始,若在有擱置中的模型變更時呼叫 Migrate 或 MigrateAsync,就會擲回例外狀況(事件 ID PendingModelChangesWarning)。 更多資訊請參閱 應用程式遷移文件 及 突發變更說明 。
重設所有遷移
在某些極端情況下,可能需要移除所有移轉並重新開始。 刪除 移轉 資料夾並卸除資料庫,即可輕鬆完成此作業;此時,您可以建立新的初始移轉,其中包含整個目前的架構。
您也可以重設所有移轉,並建立單一移轉,而不會遺失您的數據。 這稱為 壓迫遷移,涉及一些人工作業。 EF Core 目前沒有自動壓縮指令;請參見 dotnet/efcore#2174。
- 備份資料庫,萬一發生問題。
- 在您的資料庫中,從移轉歷程記錄數據表中刪除所有數據列(例如 SQL Server 上的
DELETE FROM [__EFMigrationsHistory])。 - 刪除你的 遷移 資料夾。
- 建立新的移轉,併為其產生 SQL 腳本(
dotnet ef migrations script)。 - 在遷移紀錄中插入一個單一數據列,以記錄首次遷移已經執行,因為您的數據表已經存在。 插入 SQL 是上述產生的 SQL 腳本中的最後一個作業,如下所示(別忘了更新值):
INSERT INTO [__EFMigrationsHistory] ([MIGRATIONID], [PRODUCTVERSION])
VALUES (N'<full_migration_timestamp_and_name>', N'<EF_version>');
Warning
刪除 移轉 資料夾時,任何 自定義移轉程式代碼 都會遺失。 任何自定義項目都必須手動套用至新的初始移轉,才能保留。
壓縮前,請確認每個已部署的資料庫都處於已知遷移階段並備份。 新資料庫必須從新的初始遷移中建立,而現有資料庫則必須記錄替代遷移,且不執行已套用的結構操作。 部署前先測試兩條路徑。
其他資源
- Entity Framework Core 工具參考 - .NET CLI :包含更新、卸除、新增、移除等等的命令。
- Entity Framework Core 工具參考 - Visual Studio 中的套件管理員控制台:包含更新、卸除、新增、移除等命令。