导读:本期聚焦于猫儿创作的《C#如何使用EF Core迁移实现Code First生成与更新数据库?【基础】》,敬请观看详情。EF Core迁移机制的核心是一张模型快照表与一组按时间排序的迁移文件。每次执行添加迁移命令时,工具会对比当前DbContext模型与上一次快照,只把差异部分写入新的迁移文件;执行更新数据库命令时则按顺序运行尚未应用的迁移。这种方式让Code First开发不必手动编写建表语句,也能保留数据库结构的版本历史。对于刚开始接触EF Core的开发者,常见困惑在于如何从零生成数据库、修改实体后如何更新表结构,以及迁移文件里Up和Down方法分别承担什么职责。本文从基础流程出发,结合C#控制台项目演示安装工具、创建初始迁移、更新数据库、追加迁移和回滚操作,帮助读者把迁移命令与底层机制对应起来,避免只记命令不理解原理。

在EF Core的Code First开发模式中,实体类和数据库上下文是数据结构的主要来源。要让关系型数据库与这些C#类保持一致,手动编写SQL脚本不仅工作量大,而且当模型频繁调整时很容易遗漏字段或索引。EF Core的迁移功能正是为解决这一问题而设计:它把模型变化转化为一组可重复执行的迁移文件,并能自动判断哪些迁移尚未应用到目标数据库。本文以控制台项目为例,完整演示如何安装迁移工具、生成初始迁移、更新数据库,以及后续修改实体后如何追加迁移和回滚。

C#如何使用EF Core迁移实现Code First生成与更新数据库?【基础】

一、EF Core迁移机制解决了什么问题

EF Core迁移并不是在每次启动时清空数据库再重新建表,而是基于模型快照进行增量对比。项目第一次执行迁移命令时,工具会为整个DbContext生成一个初始快照文件,同时创建第一个迁移类。快照记录的是当前模型完整的结构信息,例如每个实体包含哪些属性、最大长度、是否可空、主外键关系等。后续添加迁移时,EF Core会把当前模型与快照进行差异比较,只把新增、修改或删除的部分写入新的迁移文件,并同步更新快照。

这样做的好处有两个:一是数据库结构变更可以纳入版本控制,多人协作时只要提交迁移文件,其他成员拉取代码后执行更新命令就能得到相同结构;二是迁移文件本身可读可改,遇到特殊需求时可以在自动生成的UpDown方法中手动补充SQL逻辑。相比完全依赖数据库优先或手动维护SQL脚本,Code First迁移更适合以领域模型为中心、需求持续变化的项目。

理解这套机制后再看命令,就不容易混淆。添加迁移只负责生成文件,不会连接数据库执行任何变更;更新数据库才真正读取迁移记录并应用尚未执行的迁移。因此日常开发通常是先改实体,再添加迁移,最后更新本地开发库。

二、创建初始迁移并生成数据库

第一步是准备一个包含EF Core的C#项目。可以在空控制台项目中加入Microsoft.EntityFrameworkCore.SqlServerMicrosoft.EntityFrameworkCore.Tools两个包,前者提供SQL Server数据库提供程序,后者提供迁移命令。以.NET 8控制台项目为例,项目文件中的包引用如下。

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0" />
  </ItemGroup>
</Project>

接下来定义实体和数据库上下文。这里创建一个简单的Blog实体,包含主键、标题、正文和创建时间,并让AppDbContext继承DbContext,在OnConfiguring方法中配置SQL Server连接字符串。为了演示简洁,连接字符串直接写在代码中;实际项目建议读取配置文件。

using Microsoft.EntityFrameworkCore;

public class Blog
{
    public int Id { get; set; }
    public string Title { get; set; } = string.Empty;
    public string Content { get; set; } = string.Empty;
    public DateTime CreatedAt { get; set; }
}

public class AppDbContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; } = null!;

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=DemoDb;Trusted_Connection=True;");
    }
}

完成模型定义后,在项目根目录打开终端,先执行添加初始迁移命令。命令执行成功后,项目中会出现Migrations文件夹,里面包含一个以时间戳加InitialCreate命名的迁移类、一个设计时工厂类和一个模型快照文件。随后执行更新数据库命令,EF Core会连接数据库,创建Blogs表和__EFMigrationsHistory记录表。

dotnet ef migrations add InitialCreate
dotnet ef database update

此时可以打开数据库查看,Blogs表的字段与Blog实体一一对应,__EFMigrationsHistory表中则记录了InitialCreate这条迁移的Id和生成时间。如果数据库不存在,EF Core会先创建数据库再执行迁移;如果数据库已经存在但没有迁移记录表,首次更新时会自动创建该表并执行所有迁移。

三、修改模型后的增量迁移与回滚

初始数据库生成后,需求发生变化,例如Blog需要增加一个Author字段。正确流程是先在Blog类中添加属性,然后再次执行添加迁移命令,并给这次迁移起一个能描述变更的名称。

public class Blog
{
    public int Id { get; set; }
    public string Title { get; set; } = string.Empty;
    public string Content { get; set; } = string.Empty;
    public string Author { get; set; } = string.Empty;
    public DateTime CreatedAt { get; set; }
}

然后执行命令:dotnet ef migrations add AddBlogAuthor。EF Core会对比当前模型与快照,识别出Blogs表多了一个Author列,并生成新的迁移文件。打开该迁移类可以看到自动生成的UpDown方法,分别对应升级和降级操作。

public partial class AddBlogAuthor : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.AddColumn<string>(
            name: "Author",
            table: "Blogs",
            type: "nvarchar(max)",
            nullable: true);
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropColumn(
            name: "Author",
            table: "Blogs");
    }
}

执行更新数据库命令后,数据库中的Blogs表会新增Author列,__EFMigrationsHistory表也会追加AddBlogAuthor记录。如果发现这次变更有问题,可以回滚到上一个迁移版本。例如执行dotnet ef database update InitialCreate,EF Core会运行AddBlogAuthor迁移类的Down方法,删除Author列,并把迁移记录从历史表中移除。回滚操作依赖Down方法,因此自动生成的迁移都提供默认降级逻辑,但如果手动修改了Up方法,也要同步修改Down方法,保证来回切换不会产生不一致。

在开发阶段如果只生成了迁移文件但尚未应用到数据库,可以使用dotnet ef migrations remove删除最后一个迁移。这个命令要求该迁移尚未被数据库执行,否则会报错。频繁调整模型时,先用remove撤销未应用的迁移,再修改实体后重新添加,可以保持迁移历史简洁。

四、迁移文件的内部结构与注意事项

每个迁移通常对应三个文件。以AddBlogAuthor为例,AddBlogAuthor.cs是迁移主文件,包含UpDown方法;AddBlogAuthor.Designer.cs用于设计时元数据,帮助工具在后续变更中准确对比;AppDbContextModelSnapshot.cs是模型快照,每次添加迁移后都会更新为当前完整模型。迁移主文件中的migrationBuilder参数提供了大量API,例如AddColumnDropColumnCreateIndexAlterColumn,这些API最终由数据库提供程序翻译成具体的DDL语句。

数据库中的__EFMigrationsHistory表是迁移执行状态的关键。它只有两列:MigrationIdProductVersion。更新数据库时,EF Core先读取该表已应用的迁移Id,再按依赖顺序执行尚未应用的迁移;如果某个迁移已经执行过,就会被跳过。因此不要手动删除该表中的记录,否则EF Core可能认为某些变更尚未应用,导致重复建表或列名冲突。

实际使用中还有几个容易忽略的点。第一,修改实体属性类型或长度时,如果数据库列不允许隐式转换,自动生成的AlterColumn语句可能失败,此时需要在Up方法中手动先执行SQL转换数据,再修改列定义。第二,迁移文件一旦提交到版本库并被其他环境应用,就不要私自改动历史迁移类的代码,应该新增一个迁移来修正。第三,生产环境部署时如果没有安装dotnet-ef工具,可以在应用启动时调用context.Database.Migrate(),让程序自动执行待处理的迁移。

using (var context = new AppDbContext())
{
    context.Database.Migrate();
}

掌握这些基础操作后,可以进一步学习种子数据迁移、复杂索引、表拆分等高级主题。EF Core迁移的价值在于把数据库结构纳入C#代码的版本管理流程中,让团队协作和部署更加可靠。

EF Core迁移Code First数据库更新修改时间:2026-08-28 22:40:02

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。