EF Core Fluent API HasData 在后续迁移中添加删除数据

问题描述

我正在使用 HasData 来播种数据,它正在正确创建插入数据迁移脚本,但在随后的迁移中,它添加删除迁移,无需任何进一步更改。

实体

国家

public class Country : BaseEntity
 {
     public string CountryName { get; set; }
 }

public class County : BaseEntity
{
    public string CountyName { get;set; }

    public int CountryId { get;set; }

    public Country Country { get; set; }
}

BaseEntity

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

    public Guid ApplicationUserId { get; set; }
}

配置

public class CountyConfiguration : BaseEntityConfiguration<County>
{
    private const string TABLE_NAME = "Counties";

    public CountyConfiguration() : base(TABLE_NAME)
    {

    }

    public override void Configure(EntityTypeBuilder<County> entity)
    {
        base.Configure(entity);

        entity.Property(c => c.CountyName).Isrequired().HasMaxLength(100);
        entity.HasIndex(c => c.CountryId).IsUnique(false);
        entity.HasIndex(c => new {c.CountyName,c.CountryId }).IsUnique();
        entity.HasOne(c => c.Country).WithOne().OnDelete(DeleteBehavior.Cascade);

        entity.Ignore(c => c.ApplicationUserId);
        
        entity.HasData( 
            new County { Id = 1,CountryId = 1,CountyName = "Antrim"},new County { Id = 2,CountyName = "Carlow"},new County { Id = 3,CountyName = "Cavan"},new County { Id = 4,CountyName = "Clare"},new County { Id = 5,CountyName = "Cork"},new County { Id = 6,CountyName = "Derry (Londonderry)"},new County { Id = 7,CountyName = "Donegal"},new County { Id = 8,CountyName = "dublin"},new County { Id = 9,CountyName = "galway"},new County { Id = 10,CountyName = "Kerry"},new County { Id = 11,CountyName = "Kildare"},new County { Id = 12,CountyName = "Kilkenny"},new County { Id = 13,CountyName = "Laois (Queens)"},new County { Id = 14,CountyName = "Leitrim"},new County { Id = 15,CountyName = "Limerick"},new County { Id = 16,CountyName = "Longford"},new County { Id = 17,CountyName = "Louth"},new County { Id = 18,CountyName = "Mayo"},new County { Id = 19,CountyName = "Meath"},new County { Id = 20,CountyName = "Monaghan"},new County { Id = 21,CountyName = "Offaly (Kings)"},new County { Id = 22,CountyName = "Roscommon"},new County { Id = 23,CountyName = "Sligo"},new County { Id = 24,CountyName = "Tipperary"},new County { Id = 25,CountyName = "Waterford"},new County { Id = 26,CountyName = "Westmeath"},new County { Id = 27,CountyName = "Wexford"},new County { Id = 28,CountyName = "Wicklow"}
        );
    } 
}

生成的迁移 1:

public partial class County : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "Counties",columns: table => new
            {
                Id = table.Column<int>(type: "int",nullable: false)
                    .Annotation("sqlServer:Identity","1,1"),CountyName = table.Column<string>(type: "nvarchar(100)",maxLength: 100,nullable: false),CountryId = table.Column<int>(type: "int",nullable: false)
            },constraints: table =>
            {
                table.PrimaryKey("Pk_Counties_Id",x => x.Id);
                table.ForeignKey(
                    name: "FK_Counties_Countries_CountryId",column: x => x.CountryId,principalTable: "Countries",principalColumn: "Id",onDelete: referentialAction.Cascade);
            });

        migrationBuilder.InsertData(
            table: "Counties",columns: new[] { "Id","CountryId","CountyName" },values: new object[,]
            {
                { 3,1,"Cavan" },{ 26,"Westmeath" },{ 25,"Waterford" },{ 24,"Tipperary" },{ 23,"Sligo" },{ 22,"Roscommon" },{ 21,"Offaly (Kings)" },{ 20,"Monaghan" },{ 19,"Meath" },{ 18,"Mayo" },{ 17,"Louth" },{ 16,"Longford" },{ 27,"Wexford" },{ 15,"Limerick" },{ 13,"Laois (Queens)" },{ 12,"Kilkenny" },{ 11,"Kildare" },{ 10,"Kerry" },{ 9,"galway" },{ 8,"dublin" },{ 7,"Donegal" },{ 6,"Derry (Londonderry)" },{ 5,"Cork" },{ 4,"Clare" },{ 2,"Carlow" },{ 14,"Leitrim" },{ 28,"Wicklow" }
            });

        migrationBuilder.CreateIndex(
            name: "IX_Counties_CountryId",table: "Counties",column: "CountryId");

        migrationBuilder.CreateIndex(
            name: "IX_Counties_CountyName_CountryId",columns: new[] { "CountyName","CountryId" },unique: true);
    }

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

下一次迁移 2:(没有任何变化)

public partial class Empty : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DeleteData(
            table: "Counties",keyColumn: "Id",keyvalue: 1);
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DeleteData(
            table: "Counties",keyvalue: 1);

        migrationBuilder.InsertData(
            table: "Counties",values: new object[] { 1,"Antrim" });
    }
}

不确定,为什么要添加 migrationBuilder.DeleteData 删除脚本?

解决方法

这里

entity.HasOne(c => c.Country).WithOne().OnDelete(DeleteBehavior.Cascade);

使用 WithOne(),您基本上是在告诉 EF County.CountryId 必须是唯一的(因为关系数据库中一对一和一对多之间的唯一区别是唯一约束(索引) 用于 FK 列)。

但是,在此之前,您告诉 EF 正好相反

entity.HasIndex(c => c.CountryId).IsUnique(false);

这一系列冲突的配置不知何故混淆了 EF,它开始做奇怪的事情。

虽然这可以被视为他们的错误,但最终问题出在您的代码中,因为显然您不想要一对一的关系。因此,通过将 HasOne 替换为 HasMany

来纠正这一点
entity.HasOne(c => c.Country).WithMany().OnDelete(DeleteBehavior.Cascade);

或完全删除它,因为它所做的一切都与默认的 EF Core 约定相同。

执行此操作后,您还可以删除 HasIndex 配置,因为它也是 EF Core FK 索引约定的默认设置。