Ef Core花里胡哨系列(8) 如何可控管理Ef Core的迁移?

Ef Core花里胡哨系列(8) 如何可控管理Ef Core的迁移?

通常使用Ef Core迁移时,可能就是简单的使用命令dotnet-ef migrations add或者dotnet ef database update等等,基本都需要靠命令维护,非常的繁琐。特别是现在很多项目都是迭代型项目,很容易造成开发人员和运维人员的负担,所以,我们是否可以将其自动化?

自动迁移

自动迁移顾名思义,就是可以让程序启动的时候自己执行迁移,不需要运维人员参与,开发人员只需要保证迁移顺序的正确性即可。

自动建库

如果想使用首次自动建库,那我们就需要生成首次迁移时,直接删除首次迁移的文件,留下[Sample]DbContextModelSnapshot快照文件即可,当然,这些不是主要内容,只是用来引出下面的可控迁移

var app = builder.Build();


await using var scoped = app.Services.CreateAsyncScope();
using var db = scoped.ServiceProvider.GetRequiredService<SampleDbContext>();
try
{
   
   
    // db.Database.Migrate(); // 需要保留首次迁移文件,并且后续启动可以自动迁移
    db.Database.EnsureCreated(); // 不需要保留首次迁移文件
}
catch
{
   
   
    Console.WriteLine("init database error.");
}

可控迁移

可控迁移即我们可以通过封装Ef Core内置的各种Service来帮助我们实现控制迁移的效果。

EfMigrationHistory

我们要可控迁移,那么我们就需要想办法操控__EFMigrationsHistory这张表,它是Ef Core内置的表,用来记录迁移的记录,这张表是一张无状态的表,他只负责存储成功的迁移名称和迁移时Ef Core的版本,其它没有关联,我们如何管理它呢?我们只需在DbContext中创建一个同名的表即可,并且可以预先设计好其它审计用字段,后续不可更改。

例如我们重新设计这张表,除了迁移IdMigrationIdEf Core的版本ProductVersion外,我们添加迁移应用时间,和迁移应用类型字段。

[Table("__EFMigrationsHistory")]
public class EFMigrationsHistory
{
   
   
    [Key]
    [MaxLength(150)]
    public required string MigrationId {
   
    get; set; }

    [MaxLength(32)]
    public string ProductVersion {
   
    get; set; } = null!;

    [NotMapped]
    public string Sort => MigrationId.Split("_")[0];

    [Comment("迁移时间")]
    public DateTime? MigrationTime {
   
    get; set; } = DateTime.Now;

    [Column(TypeName = "varchar(20)")]
    public MigrationType MigrationType {
   
    get; set; } = MigrationType.Success;
}

添加迁移类型的目的是为了增加迁移执行顺序的丰富性,下面提供了成功Success、尝试但失败TryFail、尝试但成功TrySuccess以及跳过Skip等多种方式。其中HistoryInstall为记录型,主要是为了标记历史记录和安装时间。

public enum MigrationType
{
   
   
    Success,
    TryFail,
    TrySuccess,
    Skip,
    History,
    Install
}

随后我们将其添加到DbContext上下文中即可,我们的新结构会替代原来的结构实行职能。

public interface IMigrationDbContext
{
   
   
    DbSet<EFMigrationsHistory> EFMigrationsHistory {
   
    get; set; }
}

public class SampleDbContext : IMigrationDbContext
{
   
   
    public SampleDbContext(DbContextOptions<SampleDbContext> options) : base(options) 
    {
   
    

    }

    public DbSet<EFMigrationsHistory> EFMigrationsHistory {
   
    get; set; }
}

迁移控制

我们已经将__EFMigrationsHistory注册到了DbContext的上下文中,成为了我们可用的表,我们接下来就是了解Ef Core是如何迁移的,我们如何加入自己的逻辑。

我们之前有提到__EFMigrationsHistory只记录了成功的迁移,如果迁移没有成功,则会立即中断,那么他是怎么实现的?其实就是读取本地的文件列表,然后按照迁移名称进行排序并和表中的对比,然后开始逐一执行。

如此我们就可以模仿他的操作,来实现我们自己的逻辑。

迁移管理

我喜欢将迁移输出到类库,这个方便读取和管理,需要调用的地方只需引用该类库即可。

services.AddDbContext<SampleDbContext>(opts =>
{
   
   
    optionsBuilder.UseMySql(connStr, new MySqlServerVersion(new Version(8, 0)), opts => opts.MigrationsAssembly("Sample.Migrations"));
});

每个迁移文件都分为两部分,xxxx.csxxxx.Designer.cs,其中xxxx.Designer.cs中以下部分是我们需要的部分。

  • [DbContext(typeof(SampleDbContext))]这个特性向我们指明了迁移对应的DbContext是哪个,也就是说,我们可以自定义多个DbContext从其判断执行不同的迁移。
  • [Migration("20231108075812_XXXXX")]这个特性向我们指明了迁移名称,当然,也代表了迁移的顺序。
[DbContext(typeof(SampleDbContext))]
[Migration("20231108075812_XXXXX")]
partial class 20231108075812_XXXXX
{
   
   

}

而且,我们可以根据需要扩充这些特性,来满足我们不同的顺序需求:

/// <summary>
/// 标记的迁移失败会自动跳过
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖纸不争

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值