随着模型的变化,迁移会在正常开发过程中被添加和删除,迁移文件会被签入项目的版本控制中。 若要管理迁移,必须先安装 EF Core 命令行工具。
小提示
如果 DbContext
与启动项目位于不同的程序集中,则可以在 包管理器控制台工具 或 .NET Core CLI 工具中显式指定目标和启动项目。
添加迁移
当您的模型已发生更改后,您可以为该更改添加迁移步骤:
dotnet ef migrations add AddBlogCreatedTimestamp
迁移名称可以像版本控制系统中的提交消息一样使用。 例如,如果更改是指 Blog
实体上的新 CreatedTimestamp
属性,你可以选择诸如 AddBlogCreatedTimestamp 之类的名称。
在 迁移 目录下,三个文件已添加到您的项目中。
- XXXXXXXXXXXXXX_AddBlogCreatedTimestamp.cs--主迁移文件。 包含应用迁移所需的操作(在
Up
中)和还原迁移所需的操作(在Down
中)。 - XXXXXXXXXXXXXX_AddBlogCreatedTimestamp.Designer.cs--迁移元数据文件。 包含 EF 所用的信息。
- MyContextModelSnapshot.cs--当前模型的快照。 用于确定添加下一迁移时的更改内容。
文件名中的时间戳有助于按时间顺序排列它们,以便查看变化的过程。
命名空间
你可以自由移动迁移文件并手动更改其命名空间。 新建的迁移和上个迁移同级。 或者,可以在生成时指定目录,如下所示:
dotnet ef migrations add InitialCreate --output-dir Your/Directory
注释
还可以使用 --namespace
独立于目录更改命名空间。
自定义迁移代码
虽然 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");
小提示
迁移基架过程会在作业可能导致数据丢失(如删除列)时发出警告。 如果看到该警告,请务必检查迁移代码的准确性。
添加原始 SQL
虽然可以通过内置 API 重命名列,但在许多情况下是不可能实现的。 例如,我们可能需要将现有 FirstName
和 LastName
属性替换为单个新的 FullName
属性。 EF Core 生成的迁移如下:
migrationBuilder.DropColumn(
name: "FirstName",
table: "Customer");
migrationBuilder.DropColumn(
name: "LastName",
table: "Customer");
migrationBuilder.AddColumn<string>(
name: "FullName",
table: "Customer",
nullable: true);
与以前一样,这会导致不需要的数据丢失。 若要从旧列传输数据,我们将重新排列这些迁移并引入原始 SQL 操作,如下所示:
migrationBuilder.AddColumn<string>(
name: "FullName",
table: "Customer",
nullable: true);
migrationBuilder.Sql(
@"
UPDATE Customer
SET FullName = FirstName + ' ' + LastName;
");
migrationBuilder.DropColumn(
name: "FirstName",
table: "Customer");
migrationBuilder.DropColumn(
name: "LastName",
table: "Customer");
通过原始 SQL 进行任意更改
原始 SQL 还可用于管理 EF Core 不知道的数据库对象。 为此,请在不进行任何模型更改的情况下添加迁移;将生成一个空迁移,然后您可以用原始 SQL 操作来填充它。
例如,以下迁移创建 SQL Server 存储过程:
migrationBuilder.Sql(
@"
EXEC ('CREATE PROCEDURE getFullName
@LastName nvarchar(50),
@FirstName nvarchar(50)
AS
RETURN @LastName + @FirstName;')");
小提示
当语句必须是 SQL 批处理中的第一个语句或只有一个语句时,将使用 EXEC
。 它还可以用来解决幂等迁移脚本中的分析程序错误,当表中当前不存在引用的列时,可能会发生此类错误。
这可用于管理数据库的任何方面,包括:
- 存储过程
- 全文搜索
- 功能
- 触发器
- 浏览量
在大多数情况下,EF Core 会在应用迁移时自动将每个迁移包装在其各自的事务中。 遗憾的是,某些迁移操作不能在某些数据库中的事务中执行。对于这些情况,可以通过将 suppressTransaction: true
传递给 migrationBuilder.Sql
来选择不使用事务。
删除迁移
有时,您在添加迁移后会意识到,在应用之前需要对 EF Core 模型进行额外更改。 若要删除上次迁移,请使用此命令。
dotnet ef migrations remove
删除迁移后,可以进行其他模型更改,然后再次添加它。
警告
避免删除已应用于生产数据库的任何迁移。 这样做意味着无法将这些迁移从数据库中恢复,并可能会破坏后续迁移所基于的假设。
列出迁移
可以按如下所示列出所有现有迁移:
dotnet ef migrations list
检查挂起的模型更改
注释
EF Core 8.0 中添加了此功能。
有时,你可能想要检查自上次迁移以来是否进行了任何模型更改。 这可以帮助你了解你或团队成员是否忘记添加迁移。 执行此作的一种方法是使用此命令。
dotnet ef migrations has-pending-model-changes
还可以使用 context.Database.HasPendingModelChanges()
以编程方式执行此检查。 这可用于编写会在忘记添加迁移时失败的单元测试。
重置所有迁移
在某些极端情况下,可能需要删除所有迁移并重新开始。 可以通过删除 迁移 文件夹和删除数据库来轻松完成此作;此时,可以创建新的初始迁移,其中包含整个当前架构。
还可以重置所有迁移并合并为一个迁移,而不会丢失数据。 这有时称为“壁球”,涉及一些手动工作:
- 备份数据库,以防出现问题。
- 在数据库中,从迁移历史记录表中删除所有行(例如 SQL Server 上的
DELETE FROM [__EFMigrationsHistory]
)。 - 删除 Migrations 文件夹。
- 创建新的迁移并为其生成 SQL 脚本(
dotnet ef migrations script
)。 - 在迁移历史记录中插入一行,以记录第一个迁移已经应用,因为表已经存在。 插入 SQL 是上面生成的 SQL 脚本中的最后一项作,如下所示(不要忘记更新值):
INSERT INTO [__EFMigrationsHistory] ([MIGRATIONID], [PRODUCTVERSION])
VALUES (N'<full_migration_timestamp_and_name>', N'<EF_version>');
警告
删除 迁移 文件夹时,任何 自定义迁移代码 都将丢失。 必须手动将任何自定义项应用到新的初次迁移中,才能被保留。
其他资源
- Entity Framework Core 工具参考 - .NET Core CLI:包括用于更新、丢弃、添加、移除等的命令。
- Entity Framework Core 工具参考 - Visual Studio 中的 Package Manager Console:包括更新、删除、添加、移除等命令。