EF Core迁移脚本:生成和应用数据库变更的完整流程
引言
在软件开发过程中,数据库架构的变更是不可避免的。EF Core(Entity Framework Core)作为.NET平台上的主流ORM(对象关系映射)框架,提供了强大的迁移(Migration)功能来管理数据库架构的变更。迁移脚本不仅能够自动生成数据库变更的SQL语句,还能确保开发、测试和生产环境之间的数据库架构一致性。
本文将深入探讨EF Core迁移脚本的完整生命周期,从生成到应用的每一个环节,帮助你掌握这一关键技能。
迁移的核心概念
什么是迁移?
迁移是EF Core用于管理数据库架构变更的机制。每个迁移代表对数据库模型的一次变更,包括:
- 创建/删除表
- 添加/修改/删除列
- 创建/删除索引
- 外键约束管理
- 数据种子操作
迁移文件结构
每个迁移通常包含三个文件:
// 迁移示例文件结构
20240101000000_InitialCreate.cs // 迁移主文件
20240101000000_InitialCreate.Designer.cs // 迁移元数据
20240101000000_InitialCreate.sql // 生成的SQL脚本(可选)
迁移工作流程
完整流程图
生成迁移脚本
1. 安装必要的工具
首先确保安装了EF Core工具:
dotnet tool install --global dotnet-ef
2. 创建初始迁移
对于新项目,创建初始迁移:
dotnet ef migrations add InitialCreate
3. 添加后续迁移
当数据模型发生变化时:
dotnet ef migrations AddProductTable
dotnet ef migrations AddUserRelationships
4. 迁移命令参数详解
| 参数 | 说明 | 示例 |
|---|---|---|
--output-dir | 指定输出目录 | --output-dir Data/Migrations |
--context | 指定DbContext | --context AppDbContext |
--verbose | 显示详细输出 | --verbose |
--no-build | 跳过项目构建 | --no-build |
迁移文件解析
迁移主文件结构
public partial class AddProductTable : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
// 应用迁移时的操作
migrationBuilder.CreateTable(
name: "Products",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
Price = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
CreatedDate = table.Column<DateTime>(type: "datetime2", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Products", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
// 回滚迁移时的操作
migrationBuilder.DropTable(name: "Products");
}
}
迁移操作类型
EF Core支持丰富的迁移操作:
| 操作类型 | 方法 | 说明 |
|---|---|---|
| 表操作 | CreateTable(), DropTable() | 创建/删除表 |
| 列操作 | AddColumn(), DropColumn() | 添加/删除列 |
| 索引操作 | CreateIndex(), DropIndex() | 创建/删除索引 |
| 外键操作 | AddForeignKey(), DropForeignKey() | 外键管理 |
| 数据操作 | InsertData(), DeleteData() | 数据种子 |
应用迁移到数据库
1. 直接应用迁移
最简单的方式是使用Update-Database命令:
dotnet ef database update
2. 应用到特定迁移版本
# 应用到特定迁移
dotnet ef database update AddProductTable
# 回滚到初始状态
dotnet ef database update 0
# 回滚一个迁移
dotnet ef database update PreviousMigrationName
3. 在生产环境中的应用策略
对于生产环境,建议先生成SQL脚本进行审核:
dotnet ef migrations script --output migration.sql
生成SQL脚本
基本脚本生成
# 生成所有迁移的完整脚本
dotnet ef migrations script
# 生成从特定迁移开始的脚本
dotnet ef migrations script --from InitialCreate --to AddProductTable
# 输出到文件
dotnet ef migrations script --output ./Scripts/migration.sql
脚本生成选项
| 选项 | 说明 | 示例 |
|---|---|---|
--from | 起始迁移 | --from InitialCreate |
--to | 目标迁移 | --to AddProductTable |
--idempotent | 生成幂等脚本 | --idempotent |
--no-transactions | 不包含事务 | --no-transactions |
生成的SQL脚本示例
IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL
BEGIN
CREATE TABLE [__EFMigrationsHistory] (
[MigrationId] nvarchar(150) NOT NULL,
[ProductVersion] nvarchar(32) NOT NULL,
CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId])
);
END;
GO
BEGIN TRANSACTION;
GO
CREATE TABLE [Products] (
[Id] int NOT NULL IDENTITY,
[Name] nvarchar(100) NOT NULL,
[Price] decimal(18,2) NOT NULL,
[CreatedDate] datetime2 NOT NULL,
CONSTRAINT [PK_Products] PRIMARY KEY ([Id])
);
GO
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20240101000000_AddProductTable', N'7.0.0');
GO
COMMIT;
GO
迁移的最佳实践
1. 命名规范
# 好的命名
dotnet ef migrations AddUserEmailVerification
dotnet ef migrations CreateOrderTables
# 不好的命名
dotnet ef migrations Migration1
dotnet ef migrations Update1
2. 迁移大小控制
- 小型迁移:每个迁移只做一件事
- 适时合并:相关的小变更可以合并
- 避免巨型迁移:单个迁移不要包含过多变更
3. 数据迁移策略
protected override void Up(MigrationBuilder migrationBuilder)
{
// 架构变更
migrationBuilder.AddColumn<string>(
name: "Status",
table: "Orders",
type: "nvarchar(20)",
nullable: false,
defaultValue: "Pending");
// 数据迁移
migrationBuilder.Sql(@"
UPDATE Orders
SET Status = 'Completed'
WHERE IsCompleted = 1");
}
4. 回滚策略
确保每个迁移都有完整的Down方法:
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(name: "Status", table: "Orders");
}
常见问题与解决方案
1. 迁移冲突解决
当多个开发者同时创建迁移时:
# 检查迁移状态
dotnet ef migrations list
# 解决冲突后重新创建迁移
dotnet ef migrations remove
dotnet ef migrations add FixedMigrationName
2. 自定义迁移SQL
对于复杂操作,可以使用原始SQL:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(@"
CREATE PROCEDURE dbo.CleanupOldData
AS
BEGIN
DELETE FROM Logs WHERE CreatedDate < DATEADD(month, -6, GETDATE())
END");
}
3. 环境特定的迁移
protected override void Up(MigrationBuilder migrationBuilder)
{
if (migrationBuilder.ActiveProvider == "Microsoft.EntityFrameworkCore.SqlServer")
{
// SQL Server特定的操作
migrationBuilder.AddColumn<string>("TSQL_Column", table: "Table");
}
else if (migrationBuilder.ActiveProvider == "Npgsql.EntityFrameworkCore.PostgreSQL")
{
// PostgreSQL特定的操作
migrationBuilder.AddColumn<string>("PSQL_Column", table: "Table");
}
}
高级迁移技巧
1. 使用迁移Bundle
EF Core 7.0+引入了迁移Bundle功能:
# 创建可执行迁移Bundle
dotnet ef migrations bundle --self-contained
# 生成跨平台Bundle
dotnet ef migrations bundle --runtime linux-x64
2. 自定义迁移生成器
创建自定义迁移操作:
public static class MigrationBuilderExtensions
{
public static OperationBuilder<AddColumnOperation> AddAuditColumns(
this MigrationBuilder migrationBuilder,
string tableName)
{
return migrationBuilder.AddColumn<DateTime>(
name: "CreatedAt",
table: tableName,
defaultValueSql: "GETUTCDATE()");
}
}
3. 迁移验证脚本
生成验证脚本确保迁移正确应用:
dotnet ef migrations script --idempotent --output verify.sql
迁移的版本控制
1. 迁移历史表
EF Core使用__EFMigrationsHistory表跟踪应用的迁移:
SELECT * FROM __EFMigrationsHistory ORDER BY MigrationId;
2. 迁移状态检查
# 检查已应用的迁移
dotnet ef migrations list
# 检查待应用的迁移
dotnet ef migrations script --idempotent
性能优化建议
1. 批量操作优化
protected override void Up(MigrationBuilder migrationBuilder)
{
// 使用批量操作而不是逐条插入
migrationBuilder.InsertData(
table: "Settings",
columns: new[] { "Key", "Value" },
values: new object[,]
{
{ "Theme", "Dark" },
{ "Language", "zh-CN" },
{ "Timezone", "UTC+8" }
});
}
2. 索引优化
在迁移中创建合适的索引:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateIndex(
name: "IX_Users_Email",
table: "Users",
column: "Email",
unique: true);
}
结语
EF Core迁移脚本是管理数据库架构变更的强大工具。通过掌握迁移的生成、应用和维护技巧,你可以确保数据库变更的可控性和可追溯性。记住以下关键点:
- 保持迁移小型且专注:每个迁移应该只完成一个明确的变更
- 始终提供回滚方案:确保每个迁移都有完整的Down方法
- 在生产环境使用脚本:先生成SQL脚本进行审核再执行
- 定期清理旧迁移:合并相关的迁移以保持项目整洁
通过遵循这些最佳实践,你将能够高效、安全地管理数据库架构的演进过程。
下一步学习
- 深入学习EF Core数据种子(Data Seeding)
- 了解EF Core的并发控制机制
- 探索EF Core的性能调优技巧
- 研究EF Core的查询优化策略
掌握EF Core迁移脚本将大大提升你的数据库管理能力,为构建健壮的应用程序奠定坚实基础。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



