#entity-framework-core #ef-fluent-api #ef-core-3.1
Вопрос:
Я использую 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; }
}
Базовая сущность
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, CountryId = 1, CountyName = "Carlow"},
new County { Id = 3, CountryId = 1, CountyName = "Cavan"},
new County { Id = 4, CountryId = 1, CountyName = "Clare"},
new County { Id = 5, CountryId = 1, CountyName = "Cork"},
new County { Id = 6, CountryId = 1, CountyName = "Derry (Londonderry)"},
new County { Id = 7, CountryId = 1, CountyName = "Donegal"},
new County { Id = 8, CountryId = 1, CountyName = "Dublin"},
new County { Id = 9, CountryId = 1, CountyName = "Galway"},
new County { Id = 10, CountryId = 1, CountyName = "Kerry"},
new County { Id = 11, CountryId = 1, CountyName = "Kildare"},
new County { Id = 12, CountryId = 1, CountyName = "Kilkenny"},
new County { Id = 13, CountryId = 1, CountyName = "Laois (Queens)"},
new County { Id = 14, CountryId = 1, CountyName = "Leitrim"},
new County { Id = 15, CountryId = 1, CountyName = "Limerick"},
new County { Id = 16, CountryId = 1, CountyName = "Longford"},
new County { Id = 17, CountryId = 1, CountyName = "Louth"},
new County { Id = 18, CountryId = 1, CountyName = "Mayo"},
new County { Id = 19, CountryId = 1, CountyName = "Meath"},
new County { Id = 20, CountryId = 1, CountyName = "Monaghan"},
new County { Id = 21, CountryId = 1, CountyName = "Offaly (Kings)"},
new County { Id = 22, CountryId = 1, CountyName = "Roscommon"},
new County { Id = 23, CountryId = 1, CountyName = "Sligo"},
new County { Id = 24, CountryId = 1, CountyName = "Tipperary"},
new County { Id = 25, CountryId = 1, CountyName = "Waterford"},
new County { Id = 26, CountryId = 1, CountyName = "Westmeath"},
new County { Id = 27, CountryId = 1, CountyName = "Wexford"},
new County { Id = 28, CountryId = 1, CountyName = "Wicklow"}
);
}
}
Generated Migration1:
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, 1, "Westmeath" },
{ 25, 1, "Waterford" },
{ 24, 1, "Tipperary" },
{ 23, 1, "Sligo" },
{ 22, 1, "Roscommon" },
{ 21, 1, "Offaly (Kings)" },
{ 20, 1, "Monaghan" },
{ 19, 1, "Meath" },
{ 18, 1, "Mayo" },
{ 17, 1, "Louth" },
{ 16, 1, "Longford" },
{ 27, 1, "Wexford" },
{ 15, 1, "Limerick" },
{ 13, 1, "Laois (Queens)" },
{ 12, 1, "Kilkenny" },
{ 11, 1, "Kildare" },
{ 10, 1, "Kerry" },
{ 9, 1, "Galway" },
{ 8, 1, "Dublin" },
{ 7, 1, "Donegal" },
{ 6, 1, "Derry (Londonderry)" },
{ 5, 1, "Cork" },
{ 4, 1, "Clare" },
{ 2, 1, "Carlow" },
{ 14, 1, "Leitrim" },
{ 28, 1, "Wicklow" }
});
migrationBuilder.CreateIndex(
name: "IX_Counties_CountryId",
table: "Counties",
column: "CountryId");
migrationBuilder.CreateIndex(
name: "IX_Counties_CountyName_CountryId",
table: "Counties",
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",
keyColumn: "Id",
keyValue: 1);
migrationBuilder.InsertData(
table: "Counties",
columns: new[] { "Id", "CountryId", "CountyName" },
values: new object[] { 1, 1, "Antrim" });
}
}
Не уверен, почему он добавляет migrationBuilder.DeleteData
скрипт удаления?
Ответ №1:
Здесь
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 по умолчанию.
Как только вы это сделаете, вы также можете удалить HasIndex
конфигурацию, поскольку она также используется по умолчанию в соответствии с соглашением об индексе EF Core FK.