如何将EFCore迁移分离到单独类库项目?
上篇文章: EFCore生产环境数据库升级方案 中我们聊了如何将EFCore迁移(实体模型变更)应用到生产环境的方案,在上次的演示中,我们是将所有迁移存放到了定义DbContext的类库项目中去,在这边文章中我来介绍下如何将迁移单独存放到一个类库项目中去,以便管理EF生成的迁移文件。
这篇文章中,我们继续使用 EFCore生产环境数据库升级方案 中的例子项目进行改造,来实现将所有EF迁移文件单独提取到类库项目中去,本文和 EFCore生产环境数据库升级方案 是同一个系列的文章,如果你还没有阅读前一篇文章,强烈建议先阅读前文。
一、新建类库项目,将EF迁移文件及迁移快照文件移动到新的类库项目中
新建名称为 EFMigrations.DataMigrations 的类库项目
这里需要注意的是:如果还没有生成任何迁移文件,则请先至少生成一个,再将新生成的迁移文件复制到新建的类库项目EFMigrations.DataMigrations 中去。
二、类库项目添加对包含DbContext上下文类的引用。
添加EFMigrations.Models类库项目的引用到EFMigrations.DataMigrations,如下:
三、将默认的迁移程序集指定为新建的类库项目。
将EFMigrations.Models 中的所有的EF迁移文件及迁移生成的SQL脚本文件移动到EFMigrations.DataMigrations项目中去。
移动完毕后,EFMigrations.Models中仅包含EF DbContext 上下文类,以及实体模型,如下图所示:
四、告诉启动项目迁移程序集是哪个
启动项目指的是告诉 EF命令行迁移工具从哪个项目开始启动,然后执行迁移文件的生成,这里我们的启动项目是EFMigrations.Web 项目,修改Startup.cs文件中的ConfigureService方法如下:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDbContext>(builder=> {
builder.UseSqlServer(Configuration["ConnectionStrings:ConnectionStr"],optionsBuilder=> {
//这里告诉EFcore 命令行迁移工具,等下生成的迁移文件放到EFMigrations.DataMigrations 项目中去。
optionsBuilder.MigrationsAssembly("EFMigrations.DataMigrations");
});
});
services.AddControllersWithViews();
}
添加EFMigrations.DataMigrations的引用到EFMigrations.Web,然后重新生成下EFMigrations.Web项目,否则等下生成迁移会失败,因为不添加引用等下EFMigrations.Web项目启动后开始生成迁移的时候会找不到EFMigrations.DataMigrations.dll
五、测试新添加的迁移是否正常生成到了新建的类库项目中去。
我们新建一个实体模型OrderInfo,并将其添加到DbContext 上下文中去。
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;
namespace EFMigrations.Models
{
public class OrderInfo
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int OrderId { get; set; }
public int ProductId { get; set; }
public double Price { get; set; }
public int BuyCount { get; set; }
public int UserId { get; set; }
}
}
修改DbContext上下文类,增加OrderInfo实体映射。
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
namespace EFMigrations.Models
{
public class MyDbContext : DbContext
{
/// <summary>
/// 这里一定要声明一个接收DbContextOptions参数的构造函数,否则无法正常添加迁移。
/// </summary>
/// <param name="options"></param>
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
{
}
public DbSet<UserInfo> UserInfos { get; set; }
public DbSet<OrderInfo> OrderInfos { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
}
}
}
打开程序包管理控制台,输入以下命令:
cd ./EFMigrations.DataMigrations 将当前目录定位到迁移程序所在项目的根目录下,免得下面这个步骤生成迁移文件的时候还要额外用-p 参数指定迁移程序集的项目路径。
dotnet ef migrations add OrderInfo_CreateTable -s ../EFMigrations.Web
迁移生成成功后如下:
将新生成的迁移转换成SQL,在程序包管理控制台中输入以下命令:
dotnet ef migrations script 20210830142733_UserInfo_AddColumns 20210902141104_OrderInfo_CreateTable -s ../EFMigrations.Web -o ./SqlScripts/OrderInfo_CreateTable.sql
以上命令的意思是将 20210830142733_UserInfo_AddColumns迁移(不包含)的下一个迁移开始,截止到 20210902141104_OrderInfo_CreateTable(包含) 之间的所有迁移转换成SQL脚本进行生成,生成成功后,SQL脚本如下:
六、将SQL脚本升级到数据库
- 首先需要将生成的SQL脚本设置成在生成项目的时候嵌入到程序集:鼠标右击 OrderInfo_CreateTable.sql ,选择属性->生成操作->嵌入的资源
- 然后将EFMigrations.Models 类中的 ApplicationBuilderExtensions 类移动到EFMigrations.DataMigrations项目中去,之所以这么做是方便dbup-sql 类库找.sql脚本时直接从当前程序集中查找
- 重启网站,看下是否新SQL脚本是否成功被升级到了数据库
这里需要注意的是,由于在上一篇文章中我已经将前面两个SQL 脚本升级到了数据库中,并且很有意思的事情是dbup-sqlserver记录已升级脚本的名称时带上了程序集明明空间,因此这里直接运行会升级失败,我们必须手动先将数据库中的已升级脚本记录的前缀名称更新为EFMigartions.DataMigrations开头方能再次升级成功。
我们将EFMigrations.Models替换成EFMigrations.DataMigrations后再重新升级,如下图显示,表示升级成功了