Почему EF Core создает новый теневой внешний ключ вместо использования существующего свойства?C#

Место общения программистов C#
Ответить
Anonymous
 Почему EF Core создает новый теневой внешний ключ вместо использования существующего свойства?

Сообщение Anonymous »

У меня есть два класса модели: Entity и EntityVersion (имя Entity здесь не связано с EF, это просто совпадение, учитывая домен моей компании). Их (упрощенные) модели имеют несколько отношений:
  • Одна сущность имеет множество версий EntityVersion – EntityVersion.EntityId
  • Одна сущность имеет одну (необязательно) версию EntityVersion – Entity.LatestEntityVersionId
  • Один набор изменений содержит много EntityVersion — EntityVersion.ChangesetId (модель набора изменений опущена для краткости — я включил эту деталь только из-за составного индекса в построителе моделей)

Код: Выделить всё

public class Entity
{
public Guid Id { get; set; }

public Guid? LatestEntityVersionId { get; set; }

public string? InternalName { get; set; }

public string? MigrationSource { get; set; }
}

public class EntityVersion
{
public Guid Id { get; set; }

public Guid EntityId { get; set; }
public Guid ChangesetId { get; set; }

// More unrelated properties
}
Построитель моделей для этих классов выглядит следующим образом:

Код: Выделить всё

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity(b =>
{
b.HasOne()
.WithMany()
.HasForeignKey(x => x.LatestEntityVersionId);

b.Property(x => x.InternalName).HasColumnName("InternalName");
b.Property(x => x.MigrationSource).HasColumnName("MigrationSource");

b.ToTable("Entities");
});

modelBuilder.Entity(b =>
{
b.HasOne(x => x.Entity)
.WithMany()
.HasForeignKey("EntityId")
.OnDelete(DeleteBehavior.Restrict);

b.HasOne()
.WithMany()
.HasForeignKey(x => x.ChangeSetId);

b.HasIndex(x => x.ChangeSetId);
b.HasIndex(x => x.EntityId);
b.HasIndex(x => new { x.ChangeSetId, x.EntityId })
.IsUnique();

b.ToTable("EntityVersions");
b.ToTable(tb =>
{
// We have to tell it that it has a trigger else update doesn't work. The string argument for HasTrigger() is not important
// See https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-7.0/breaking-changes?tabs=v7
tb.HasTrigger("EntityVersions");
});
});
}
Однако, когда я опубликовал PR, создатель истории попросил меня удалить свойство EntityVersion.EntityId в пользу теневого свойства, основанного на соглашении. Нет проблем, подумал я, просто удалите это свойство и укажите все ссылки наentityVersion.Entity.Id. Например:

Код: Выделить всё

// Old reference
var entityId = entityVersion.EntityId;
// New reference
entityId = entityVersion.Entity.Id;
Однако на самом деле произошла миграция, которая удалила существующие внешние ключи и индексы EntityId (но оставила сам столбец) и добавила новый столбец с именем EntityVersion_EntityId и добавила внешний ключ и индексы обратно для этого нового столбца.
Вот созданная миграция:

Код: Выделить всё

public partial class EntityRelationshipsFixed : Migration
{
/// 
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_EntityVersions_Entities_EntityId",
table: "EntityVersions");

migrationBuilder.DropIndex(
name: "IX_EntityVersions_ChangeSetId_EntityId",
table: "EntityVersions");

migrationBuilder.DropIndex(
name: "IX_EntityVersions_EntityId",
table: "EntityVersions");

migrationBuilder.AddColumn(
name: "EntityVersion_EntityId",
table: "EntityVersions",
type: "uniqueidentifier",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));

migrationBuilder.CreateIndex(
name: "IX_EntityVersions_ChangeSetId_EntityVersion_EntityId",
table: "EntityVersions",
columns: new[] { "ChangeSetId", "EntityVersion_EntityId" },
unique: true);

migrationBuilder.CreateIndex(
name: "IX_EntityVersions_EntityVersion_EntityId",
table: "EntityVersions",
column: "EntityVersion_EntityId");

migrationBuilder.AddForeignKey(
name: "FK_EntityVersions_Entities_EntityVersion_EntityId",
table: "EntityVersions",
column: "EntityVersion_EntityId",
principalTable: "Entities",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}

/// 
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_EntityVersions_Entities_EntityVersion_EntityId",
table: "EntityVersions");

migrationBuilder.DropIndex(
name: "IX_EntityVersions_ChangeSetId_EntityVersion_EntityId",
table: "EntityVersions");

migrationBuilder.DropIndex(
name: "IX_EntityVersions_EntityVersion_EntityId",
table: "EntityVersions");

migrationBuilder.DropColumn(
name: "EntityVersion_EntityId",
table: "EntityVersions");

migrationBuilder.CreateIndex(
name: "IX_EntityVersions_ChangeSetId_EntityId",
table: "EntityVersions",
columns: new[] { "ChangeSetId", "EntityId" });

migrationBuilder.CreateIndex(
name: "IX_EntityVersions_EntityId",
table: "EntityVersions",
column: "EntityId");

migrationBuilder.AddForeignKey(
name: "FK_EntityVersions_Entities_EntityId",
table: "EntityVersions",
column: "EntityId",
principalTable: "Entities",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
Это стало очевидным при запуске модульных тестов, и я продолжал получать ошибки, сообщающие, что я не могу вставить значения NULL в столбец EntityId, который не может иметь значение NULL. Это связано с тем, что EF Core пытается вставить Entity.Id в новое свойство EntityVersion_EntityId.
Почему EF Core создает это новое свойство (

Код: Выделить всё

EntityVersions_EntityId
) вместо существующего EntityId?
Примечание. Мы используем EF Core версии 9.0.4

Подробнее здесь: https://stackoverflow.com/questions/798 ... xisting-pr
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»