英文:
EF Core randomly renames a column, despite no changes to model
问题
在我的ASP.Net Core MVC应用程序中,我有一个简单的Game
类,以及两个用于发出请求或在视图上显示的GameRequest
和GameResponse
类(在下面的片段中)。
在添加新的迁移(与无关的功能相关)时,我注意到EF Core添加了一个.RenameColumn()
操作,具体来说是从Games.NumberCodeDisplay -> Games.NumberCode
,这是毫无意义的。Games
表从一开始就没有NumberCodeDisplay
列,甚至在创建它的上一个迁移中也没有。
奇怪的是,这个错误的列名与GameResponse
的列名相同,尽管它没有出现在应用程序的DbContext
中。
// GameModels.cs
public class Game
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string NameCode { get; set; } = string.Empty;
public decimal NumberCode { get; set; } // <--- this property has *never* changed
public int YearReleased { get; set; }
}
public class GameRequest
{
public string Name { get; set; } = string.Empty;
public string NameCode { get; set; } = string.Empty;
public decimal NumberCode { get; set; }
public int YearReleased { get; set; }
}
public class GameResponse
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string NameCode { get; set; } = string.Empty;
public string NumberCodeDisplay { get; set; } = string.Empty;
public int YearReleased { get; set; }
public static string GetNumberCodeDisplay(decimal numberCode)
{
// ...
}
}
// migration file generated after `add-migration`
public partial class AddField_Game_CoverImageUrl : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "NumberCodeDisplay",
table: "Games",
newName: "NumberCode");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "NumberCode",
table: "Games",
newName: "NumberCodeDisplay");
}
}
// AppDbContext.cs
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
public DbSet<Song> Songs { get; set; } = default!;
public DbSet<Game> Games { get; set; } = default!;
}
英文:
In my ASP.Net Core MVC app, I have a simple Game
class, plus 2 GameRequest
and GameResponse
classes (in snippets below) that are used for making requests, or for displaying on a view.
On adding a new migration (for an unrelated feature), I noticed EF Core adding a .RenameColumn()
operation, specifically from Games.NumberCodeDisplay -> Games.NumberCode
, which makes no sense. The Games
table never had the NumberCodeDisplay
column in the first place, even in the previous migration where it was created.
Curiously, this incorrect column name is the same as that of GameResponse
's despite it not being in the app's DbContext
.
// GameModels.cs
public class Game
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string NameCode { get; set; } = string.Empty;
public decimal NumberCode { get; set; } // <--- this property has *never* changed
public int YearReleased { get; set; }
}
public class GameRequest
{
public string Name { get; set; } = string.Empty;
public string NameCode { get; set; } = string.Empty;
public decimal NumberCode { get; set; }
public int YearReleased { get; set; }
}
public class GameResponse
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string NameCode { get; set; } = string.Empty;
public string NumberCodeDisplay { get; set; } = string.Empty;
public int YearReleased { get; set; }
public static string GetNumberCodeDisplay(decimal numberCode)
{
// ...
}
}
// migration file generated after `add-migration`
public partial class AddField_Game_CoverImageUrl : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "NumberCodeDisplay",
table: "Games",
newName: "NumberCode");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "NumberCode",
table: "Games",
newName: "NumberCodeDisplay");
}
}
// AppDbContext.cs
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}
public DbSet<Song> Songs { get; set; } = default!;
public DbSet<Game> Games { get; set; } = default!;
}
答案1
得分: 0
我找到了问题,尽管我不太清楚最初是什么原因导致的。
我忘记添加之前创建表的迁移文件(我们称之为Migration_1
;帖子中的空迁移将是Migration_2
),以及模型快照文件。但我发现的是:
- C#模型类始终是正确的(
Game
有一个名为NumberCode
的字段,从未是NumberCodeDisplay
) - 我添加了
Migration_1
迁移。生成的迁移文件[timestamp]_Migration_1.cs
是正确的:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Games",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(type: "nvarchar(max)", nullable: false),
NameCode = table.Column<string>(type: "nvarchar(max)", nullable: false),
NumberCode = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
YearReleased = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Games", x => x.Id);
});
}
- 但是,迁移设计器文件(
[timestamp]_Migration_1.Designer.cs
)出现错误,错误地指定应创建一个具有NumberCodeDisplay
列的Games
表(在应用到实际数据库之前):
partial class Add_Game
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.7")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("MyProject.Models.Game", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("NameCode")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<decimal>("NumberCodeDisplay") // <------ 这里
.HasColumnType("decimal(18,2)");
b.Property<int>("YearReleased")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("Games");
});
// ...
}
}
- 但是在数据库本身中,
Games
表确实具有正确的NumberCode
列名称。
这可能是因为在Migration_1
之后我添加/删除了一些迁移,特别是在我决定剪切掉所有模型更改(针对与此无关的功能)并测试一个空迁移(当前的Migration_2
)之前有一些“Migration_2
”。但我不能确定。
目前,我只是手动编辑了Migration_1
的设计器文件和模型快照文件,然后进一步的迁移不会再次重命名。
英文:
I found the problem, though I don't really know what caused it in the first place.
I forgot to add the previous migration files where I created the table (let's call it Migration_1
; the empty migration in the post would be Migration_2
), and the model snapshot file. But what I've found is that:
- The C# model class is always correct (
Game
has a field calledNumberCode
, never has it beenNumberCodeDisplay
) - I added the
Migration_1
migration. The resulting migration file[timestamp]_Migration_1.cs
is correct:
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Games",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(type: "nvarchar(max)", nullable: false),
NameCode = table.Column<string>(type: "nvarchar(max)", nullable: false),
NumberCode = table.Column<decimal>(type: "decimal(18,2)", nullable: false),
YearReleased = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Games", x => x.Id);
});
}
- However, the migration designer file (
[timestamp]_Migration_1.Designer.cs
) for some reason incorrectly specified that aGames
table with theNumberCodeDisplay
column should be created (before being applied to the actual database):
partial class Add_Game
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.7")
.HasAnnotation("Relational:MaxIdentifierLength", 128);
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
modelBuilder.Entity("MyProject.Models.Game", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
b.Property<string>("Name")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<string>("NameCode")
.IsRequired()
.HasColumnType("nvarchar(max)");
b.Property<decimal>("NumberCodeDisplay") // <------ Here
.HasColumnType("decimal(18,2)");
b.Property<int>("YearReleased")
.HasColumnType("int");
b.HasKey("Id");
b.ToTable("Games");
});
// ...
}
}
This is probably due to me adding/removing some migrations after Migration_1
, notably there were a couple "Migration_2
s" before I decided to cut out all the model changes (for an unrelated feature) and test out an empty migration (the current Migration_2
). But I can't be sure.
For now, I've just manually edited Migration_1
's designer file, and the model snapshot file, and then further migrations wouldn't have the rename again.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论