EF Core 5 .NET 5 中的数据迁移:在独立库和自动部署中






3.50/5 (2投票s)
如何在 .NET 5 中创建 Entity Framework Core 5 数据迁移
我一直在考虑写这个主题一段时间了。我过去曾用 EF 数据迁移做过一个项目,但事情已经发生了变化,它的库依赖关系也发生了变化。现在,我将在 .NET 5 项目和 EF Core 5 (5.0.3) 中进行操作。
1. 引言
这篇博文的主要思想是,您将使用 Entity Framework 编写一个 Web 应用程序,并且不仅如此,您还希望项目附带一个数据迁移计划。当您编写应用程序时,数据库可能会随着时间的推移而演变,并且您希望在活动的生产环境中平滑、逐步地迁移数据库。这就是 EF 数据迁移发挥作用的地方。本文将通过一系列步骤带您完成此操作。为了清晰地阐述核心问题——数据迁移,我们将跳过所有其他编码方面,例如配置、编码标准、验证等,甚至包括实体框架建模。
2. 前提条件
Microsoft 允许使用 Visual Studio IDE 模板或使用 dotnet 命令行 (CLI) 界面创建项目。在本文中,我们将使用 dotnet CLI 创建项目。此外,我们将使用 Visual Studio Code 而不是 Visual Studio IDE,但其使用将仅限于编辑文件和浏览项目文件夹。所有应用程序的构建和运行都将通过 dotnet CLI 命令完成。以下是需要满足的一些前提条件:
- 在此处下载并安装 Visual Studio Code。
- 运行 Visual Studio Code,并安装来自 OmniSharp 的 C# 扩展。要安装扩展,请单击左侧面板中的图标,或单击菜单 视图 --> 扩展。
- 在此处下载并安装 dotnet 5 SDSK,您可以下载任何 SDK 版本 v5.0.0 或更高版本。如果您使用的是 Windows 操作系统,请确保已将安装目录包含在您的计算机系统
PATH
中。 - 确保您有一个已启用 Windows 身份验证的 MS SQL Server 本地实例。
2. 使用 Dotnet CLI 创建解决方案和项目骨架
我们将创建一个包含两个项目的解决方案,主项目将从空 Web 模板生成,另一个项目是库项目,其中包含我们的数据库模型、上下文,以及稍后我们的迁移文件。在这里,我们将通过命令行提示符使用 dotnet CLI 来完成此操作,或者您可以从 Visual Studio Code 中打开终端。
- 创建一个目录用于我们的解决方案 '
EFCoreMigration
',并进入该目录mkdir EFCoreMigration cd EFCoreMigration
- 运行 dotnet 命令创建一个新的解决方案文件
dotnet new sln
这将创建一个以当前目录命名的解决方案文件,或者您可以使用参数
-n
指定解决方案文件的名称。dotnet new sln -n EFCoreMigration
- 创建两个项目,一个用于
WebApp
,类型为web
;另一个用于DataAccess
,类型为classlib
。dotnet new web -o WebApp dotnet new classlib -o DataAccess
要查看所有可用的项目模板,您可以使用以下命令列出它们:
dotnet new -l
- 将这两个项目添加到解决方案中
dotnet sln add WebApp dotnet sln add DataAccess
注意,如果您不指定解决方案名称,它将使用默认名称,即当前目录的名称。完整的命令可以如下所示:
dotnet sln [solution name] add WebApp
或者您也可以指定项目文件的完整路径,例如:
dotnet sln [solution name] add WebApp\WebApp.csproj
- 在
WebApp
项目中添加对DataAccess
项目的引用dotnet add WebApp reference DataAccess
或者您也可以指定项目文件的完整路径:
dotnet add WebApp\WebApp.csproj reference DataAccess\DataAccess.csproj
3. 在 DataAcess 中创建模型和数据上下文
在这里,我们使用 Entity Framework 的代码优先方法。使用了非常基础的模型。
- 在 Visual Studio Code 中,打开 DataAccess 目录,并将 Class1.cs 重命名为 Book.cs,然后键入以下代码:
using System; namespace DataAccess { public class Book { public int Id { get; set; } public string Name { get; set; } public string Description {get;set;} } }
- 在终端中,转到 DataAccess 目录,并添加
Microsoft.EntityFrameworkCore
包(版本 5.0.3)。cd DataAccess dotnet new package Microsoft.EntityFrameworkCore -v 5.0.3
- 在 Visual Studio Code 中,在
DataAccess
项目中创建 DataContext.cs。using System; using Microsoft.EntityFrameworkCore; namespace DataAccess { public class DataContext: DbContext { public DbSet<Book> Books { get; set; } public DataContext(DbContextOptions options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { //Can add constraint, index, check, data type, and even data seed } } }
- 请务必保存所有更改,并在终端中键入以编译
DataAccess
项目,以确保其成功构建。dotnet build
4. 在 WebApp 中初始化数据库
- 在终端中,转到 WebApp 目录,并添加
Microsoft.EntityFrameworkCore.SqlServer
(版本 5.0.3)。此步骤取决于您使用的数据库服务器;如果您使用的不是 MS SQL Server,请查找适合您数据库服务器的提供程序包。dotnet new package Microsoft.EntityFrameworkCore.Sqlserver -v 5.0.3
- 在 Visual Studio Code 中,打开 WebApp 目录,并编辑 Startup.cs。在
ConfigureServices
部分添加 DB 上下文。using Microsoft.EntityFrameworkCore; ....... public void ConfigureServices(IServiceCollection services) { services.AddDbContext<DataAccess.DataContext>(options => options.UseSqlServer( "Server=localhost;Database=EFCoreMigration;Trusted_Connection=True;")); }
UseSqlServer
是Microsoft.EntityFrameworkCore.SqlServer
中的一个扩展方法,要使用它,您需要在顶部添加using Microsoft.EntityFrameworkCore
。该代码将使用登录用户账户连接到 MS SQL Server 的本地实例,并创建一个EFCoreMigration
数据库。 - 此外,在 Startup.cs 的
Configure
方法中添加一个DataContext
,并在执行数据库相关中间件之前确保数据库已创建,方法是在它们前面放置Database.EnsureCreated()
。public void Configure( IApplicationBuilder app, IWebHostEnvironment env, DataAccess.DataContext dataContext) { dataContext.Database.EnsureCreated();
- 请务必保存所有更改。在终端中,转到 WebApp 目录并键入:
dotnet run
- 通过在浏览器中运行服务正在监听的端口(例如,在我的机器上是 https://:5000 和 https://:5001)来检查应用程序是否正在工作。要取消服务,请按 + c。
-
通过检查 MS SQL Server 的本地实例中是否存在
EFCoreMigration
数据库(例如,使用 Microsoft Server Management Studio)来验证数据库是否已实例化。 -
我没有展示如何使用
DataContext
。通常,要使用DataContext
,您只需在控制器构造函数中添加DataContext
并将其分配给控制器中的一个变量。之后,您可以在控制器中的任何位置使用它。由于此项目只是一个基础的 Web 应用程序,并且没有配置 WebAPI、MVC、Razor 或 Blazor 中间件和终结点,因此您可以通过调用中间件中传递的HttpContext
对象来获取在服务中注册的DataContext
。以下是示例,请参阅context.RequestServices.GetService<DataAccess.DataContract>()
。您可以重新运行应用程序,然后在浏览器中检查,现在它将显示书籍的数量。请注意,您不能使用传递给Configure
方法的DataContext
,因为该对象是在中间件构建时传递的,并且早已被释放。public void Configure( IApplicationBuilder app, IWebHostEnvironment env, DataAccess.DataContext dataContext) { dataContext.Database.EnsureCreated(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapGet("/", async context => { using var dataContext = context.RequestServices .GetService<DataAccess.DataContext>(); await context.Response.WriteAsync( $"Book Count : {dataContext.Books.Count()}"); }); }); }
5. 添加数据迁移功能
到目前为止,我们已经在代码中使用了 Entity Framework,但没有使用数据迁移功能。在大多数项目中,数据库可能会随着时间的推移而演变,因此我们可能需要制定一个随时间更改数据库的策略。Entity Framework Core 具有数据迁移功能,以下是其中一种方法。
- 首先,我们需要将 EF 工具链安装到 dotnet 命令中。在终端键入:
dotnet tool install --global dotnet-ef --version 5.0.3
这将允许我们运行
dotnet ef
命令。 - 将
Microsoft.EntityFrameworkCore.Design
添加到DataAccess
项目。在终端中,转到 DataAccess 目录,然后键入:dotnet add Microsoft.EntityFrameworkCore.Design -v 5.0.3
- 在 Visual Studio Code 中,转到 DataAccess 目录,并创建 DataContextFactory.cs。
using System; using Microsoft.EntityFrameworkCore.Design; using Microsoft.EntityFrameworkCore; namespace DataAccess { public class DataContextFactory : IDesignTimeDbContextFactory<DataContext> { public DataContext CreateDbContext(string[] args) { var builder = new DbContextOptionsBuilder<DataContext>(); //this code will be never executed in runtime only in design time builder.UseSqlServer( "Server=localhost;Database=EFCoreMigration;Trusted_Connection=True;"); return new DataContext(builder.Options); } } }
- 在终端中,转到 DataAccess 目录,键入:
dotnet ef migrations add InitialSchema
这将创建一个包含三个文件的 Migrations 目录:
- [yyyyMMddHHmmss]_InitialSchema.cs
- [yyyyMMddHHmmss]_InitialSchema.Design.cs
- DataContextModelSnapshot.cs
InitialSchema
包含两个方法:Up
和Down
。Up
在将迁移应用于数据库时执行,Down
在从数据库中删除迁移时执行。DataContextModelSnapshot
包含在将迁移应用于最新迁移时数据库模型的快照。因此,如果添加或删除了新的迁移,DataContextModelSnapshot.cs 将会被覆盖。 - 迁移功能能够在运行时应用数据库更改,方法是在 Startup.cs 中进行设置。在 Visual Studio Code 中,打开 WebApp 目录,并编辑 Startup.cs。将
dataContext.Database.EnsureCreate()
更改为dataContext.Database.Migrate()
。 -
删除之前创建的
EFCoreMigration
数据库。请务必保存所有更改,然后转到终端并运行 Web 应用程序。dotnet run
- 成功运行应用程序后,请检查
EFCoreMigration
数据库。数据库将拥有一个名为dbo.__EFMigrationsHistory
的表,其中包含列:MigrationId
和ProductVersion
。ProductVersion
列供 Entity Framework 内部使用,并反映EntityFrameworkCore
版本,而MigrationId
的值格式为 [yyyyMMddHHmmss]_[Migration name]。
6. 修改数据库模型
启用数据迁移后,下一个问题是如何处理数据库模型更改。当然,数据库模型更改的范围很广,并非所有更改的复杂程度都相同。但是,对于常见的更改场景,以下过程应该足够了。
- 可以对数据模型进行更改,但请注意不要进行破坏性更改。
- 可以在
DataContext
的OnModelCreating
方法中进行更改。 - 在终端中,转到 DataAccess 目录,键入:
dotnet ef migrations add [Your Own migration name]
- 照常部署,Startup.cs 中的
Migrate
方法将自动将迁移应用于最新更改。 - 如果您想回滚上次迁移,请键入:
dotnet ef migrations remove
之后,照常部署。
历史
- 2021 年 2 月 15 日:初始版本