EFCore之项目升级遇到迁移小问题

前言

今天遇到了一个很奇怪的问题,这个项目原来的版本是.NetCore3.1版本,然后我就趁着这次的需求的开发就想给升级到.Net6版本,我也是第一次接触这个项目。

其实.Net6也不算新了,组内很多项目都已经升级了

遇到问题

开始测试后,测试同学反馈在新库测试的时候就发现程序起不来,有错误信息,并且错误信息看得我一脸懵逼。

首先这个项目启动后会使用EFCore进行数据库迁移,并且初始化后会插入一些基础数据,然后在插入数据的时候,这个表的某个列应该是text类型的,可是迁移后数据库中该列是int类型。这个时候我肯定要先甩锅了,虽然我在这期使用命令行添加过字段生成过迁移文件,但是我这期需求都没涉及这个表以及我才接触这个项目,肯定不是我的原因,嘿嘿

当然问题还是要排查的,排查发现

1、这个表的这个列是在之前又一次迁移的时候列从int改为了text

2、最新版本的迁移文件快照中,这个列是字符串类型,是没问题的

3、找到上个版本的代码,然后去生成数据库也是没问题的(看到这里我就知道亏了,这个锅还是在我头上了)

4、检查我当前需求的的迁移文件(当时开发时候也检查过的),虽然我只是加了几个字段,但是这次迁移文件有1000多行,主要是自动生成的对表的一些注释等操作代码(升级后的迁移文件内容更规范了),没有涉及到那个列的操作

5、我将本期需求生成的迁移文件给删除掉,然后从上个版本中拷贝迁移快照,生成数据库,发现列还是int

6、懵逼。。。

7、那么我就看看迁移的生成的SQL吧,然后就发现了原来如此

情景重现

我创建一个.NetCore3.1版本的Api项目,安装3.x版本的nuget包

<ItemGroup>
  <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.32">
    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
  </PackageReference>
  <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.18" />
</ItemGroup>

创建实体类

public class UserInfo
{
    public int Id { get; set; }

    public string Name { get; set; }

    public int Type { get; set; }
}

以及上下文

public class OpenDbContext : DbContext
{
    public OpenDbContext(DbContextOptions options) : base(options)
    {
    }

    public DbSet<UserInfo> UserInfos { get; set; }
}

注入配置

services.AddDbContext<OpenDbContext>(options =>
{
    options.UseNpgsql(connection);
});

然后我使用EFCore CLI在项目目录下去生成迁移文件(不了解的话可以看这里:https://learn.microsoft.com/zh-cn/ef/core/cli/dotnet)

dotnet ef migrations add Init

然后项目生成了迁移文件如下

public partial class Init : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "UserInfos",
            columns: table => new
            {
                Id = table.Column<int>(nullable: false)
                    .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
                Name = table.Column<string>(nullable: true),
                Type = table.Column<int>(nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_UserInfos", x => x.Id);
            });
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(
            name: "UserInfos");
    }
}

然后我修改UserInfo表Type列的类型为字符串类型,再次执行命令

dotnet ef migrations add update_userinfo_type

生成迁移文件如下

public partial class update_userinfo_type : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.AlterColumn<string>(
            name: "Type",
            table: "UserInfos",
            nullable: true,
            oldClrType: typeof(int),
            oldType: "integer");
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.AlterColumn<int>(
            name: "Type",
            table: "UserInfos",
            type: "integer",
            nullable: false,
            oldClrType: typeof(string),
            oldNullable: true);
    }
}

这时候我使用命令(dotnet ef migrations script)去生成最后一次的迁移SQL

ALTER TABLE "UserInfos" ALTER COLUMN "Type" TYPE text;
ALTER TABLE "UserInfos" ALTER COLUMN "Type" DROP NOT NULL;
ALTER TABLE "UserInfos" ALTER COLUMN "Type" DROP DEFAULT;

INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20230228131804_update_userinfo_type', '3.1.32');

下面我就开始升级该项目到.Net6版本,并且升级Nuget包到新版本

<ItemGroup>
  <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.1">
    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
  </PackageReference>
  <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="7.0.1" />
</ItemGroup>

这个时候我们再使用cli去查看一下最后一次迁移生成的SQL语句

ALTER TABLE "UserInfos" ALTER COLUMN "Type" TYPE text;
ALTER TABLE "UserInfos" ALTER COLUMN "Type" DROP NOT NULL;

INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('20230228131804_update_userinfo_type', '7.0.1');

???我文章都写到这里,问题重现不了了?我切换了版本尝试也不行,那算了,我就截图说明一下吧,在我升级之后更新列类型的那一次迁移没有生成SQL

3987fbb460fb813664d78e3ee77bd563.png

还好我保存了图,早上我可是对比了一下3.x版本生成的更新列类型的迁移文件和7.x版本生成的迁移文件,并且手动修改了迁移文件的内容增加了7.x版本的属性,比如有下面区别

cd9e2b0a3099a16b4d0b116ff8c27f40.png

我按照7.x的方式修改这个迁移文件就可以生成更新列的SQL了,然后重新启动项目看到那个表的列已经被修改过来了。

最后

虽然最后没有重现白天的问题,不过以后像升级项目框架的情况中还是要多多测试,多方面考虑,项目中的表结构等修改还是生成SQL脚本去更新数据库靠谱一点,这样子对生成的SQL可控一点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值