天天看點

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可控一點。

繼續閱讀