EF Core 2.2.1迁移更新失败:可空int转非空枚举类型问题
解决EF Core 2.2.1中修改可空int为非空枚举并设置默认值的迁移错误
这个问题的核心原因是:当你把可空列改成非空列时,现有表中已经存在NULL值的行,而EF Core自动生成的迁移脚本通常会先将列设置为NOT NULL,再添加默认值——这就导致了更新失败,因为NULL值无法存入非空列。
正确的解决步骤:
我们需要调整迁移脚本的执行顺序,先把现有NULL值的行填充为默认枚举值,再修改列的属性为非空并设置默认值。
1. 查看并修改自动生成的迁移文件
当你运行dotnet ef migrations add [MigrationName]生成迁移后,打开对应的迁移文件(比如XXXXXX_ChangeCountryCodeToEnum.cs),你会看到类似这样的代码:
protected override void Up(MigrationBuilder migrationBuilder) { migrationBuilder.AlterColumn<CountryCode>( name: "CountryCode", table: "User", nullable: false, defaultValue: CountryCode.Unknown, oldClrType: typeof(int?), oldNullable: true); }
这段代码的问题在于,它直接把列改成非空并设置默认值,但现有NULL行还没处理。我们需要先添加SQL语句更新现有数据,再执行AlterColumn:
修改后的Up方法应该是这样:
protected override void Up(MigrationBuilder migrationBuilder) { // 第一步:先将现有NULL的CountryCode更新为默认枚举值(假设Unknown对应的数值是0) migrationBuilder.Sql(@" UPDATE [dbo].[User] SET [CountryCode] = 0 WHERE [CountryCode] IS NULL "); // 第二步:修改列属性为非空,并设置默认值 migrationBuilder.AlterColumn<CountryCode>( name: "CountryCode", table: "User", nullable: false, defaultValue: CountryCode.Unknown, oldClrType: typeof(int?), oldNullable: true); }
注意:这里的
0要对应你CountryCode枚举中Unknown的实际数值,如果你的枚举是从1开始的,记得改成对应的数字。
2. 执行迁移
修改完成后,再运行dotnet ef database update,这次就能顺利执行了——因为先把所有NULL值填充为默认枚举值,再把列改成非空,同时设置新行的默认值。
额外注意点:
- 确保你的
CountryCode枚举在EF Core中正确映射:EF Core 2.2默认会把枚举映射为对应的int值,如果你有自定义数值,需要在实体配置中明确指定:builder.Property(e => e.CountryCode) .HasDefaultValue(CountryCode.Unknown) .HasConversion<int>(); // 明确指定转换为int类型 - 如果你的表数据量很大,执行
UPDATE语句时要考虑性能,可以分批处理,但一般小型项目直接执行即可。
这样修改后,数据库中的User表CountryCode列会变成非空,并且新插入的行如果没有指定该值,会自动使用Unknown作为默认值,同时现有数据也被正确填充。
内容的提问来源于stack exchange,提问作者refex
相关产品推荐
相关产品推荐

