天天看点

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

作者:DotNET技术圈

前言

今天遇到了一个很奇怪的问题,这个项目原来的版本是.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>(able: false)
 .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
 Name = table.Column<string>(able: true),
 Type = table.Column<int>(able: 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",
 able: true,
 oldClrType: typeof(int),
 oldType: "integer");
 }

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

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

ALTER TABLE "UserInfos" ALTER COLUMN "Type" TYPE text;
ALTER TABLE "UserInfos" ALTER COLUMN "Type" DROP NOT ;
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 ;

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

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

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

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

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

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

最后

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

继续阅读