Производные типы, генерирующие собственное поле ForeignKey в коде, сначала с использованием TPH

Я использую EF Core и реализую наследование в подходе таблицы на иерархию (TPH). Я обнаружил, что после добавления объектов иерархии в мою модель данных миграция добавляет внешний ключ для базовой таблицы и что-то похожее на дубликат, который используют классы-потомки.

Отношения от Transaction (родитель) в TransactionItem (Ребенок).

Иерархия объектов:

  • TransactionItem (Базовый класс)
    • прикрепление
    • Проверьте
    • Конверт
    • огрызок

Использование Fluent API для определения отношений между Transaction а также TransactionItem с использованием TransactionItem.TransactionId поле в качестве внешнего ключа:

modelBuilder.Entity<TransactionItem>(t =>
{
    t.ToTable("TransactionItem");
    t.HasKey(a => a.Id);
    t.Property(a => a.ConcurrencyStamp)
        .IsRequired()
        .IsConcurrencyToken();
    t.Property(a => a.Created)
        .IsRequired();
    t.HasOne(a => a.Transaction)
        .WithMany(a => a.TransactionItems)
        .HasForeignKey(a => a.TransactionId)
        .OnDelete(DeleteBehavior.Restrict);
    t.HasDiscriminator<string>("ItemType")
        .HasValue<Check>("Check")
        .HasValue<Stub>("Stub")
        .HasValue<Envelope>("Envelope")
        .HasValue<Attachment>("Attachment");
});

Метод миграции Up создает таблицу базовых классов (TPH) с TransactionId а также TransactionId2 столбцы, каждый из которых относится к одной родительской таблице:

migrationBuilder.CreateTable(
name: "TransactionItem",
columns: table => new
{
    Id = table.Column<int>(nullable: false)
        .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
    ConcurrencyStamp = table.Column<string>(nullable: false),
    Created = table.Column<DateTimeOffset>(nullable: false),
    ItemType = table.Column<string>(nullable: false),
    PageName = table.Column<string>(nullable: true),
    Sequence = table.Column<int>(nullable: false),
    TransactionId = table.Column<int>(nullable: false),
    TransactionId2 = table.Column<int>(nullable: true),
    CheckType = table.Column<string>(nullable: true),
    Micr = table.Column<string>(nullable: true),
    MicrValid = table.Column<bool>(nullable: true),
    OcrId = table.Column<string>(nullable: true)
},
constraints: table =>
{
    table.PrimaryKey("PK_TransactionItem", x => x.Id);
    table.ForeignKey(
        name: "FK_TransactionItem_Transaction_TransactionId",
        column: x => x.TransactionId,
        principalTable: "Transaction",
        principalColumn: "Id",
        onDelete: ReferentialAction.Restrict);
    table.ForeignKey(
        name: "FK_TransactionItem_Transaction_TransactionId2",
        column: x => x.TransactionId2,
        principalTable: "Transaction",
        principalColumn: "Id",
        onDelete: ReferentialAction.Restrict);
});

Когда я смотрю на код ModelSnapshot.cs, я вижу следующие отношения, специфичные для объектов в модели наследования, устанавливающих внешний ключ для объектов производного класса, используя TransactionId2 колонка.

modelBuilder.Entity("SampleProject.Data.DataModels.TransactionItem", b =>
    {
        b.HasOne("SampleProject.Data.DataModels.Transaction", "Transaction")
            .WithMany("TransactionItems")
            .HasForeignKey("TransactionId");
    });

modelBuilder.Entity("SampleProject.Data.DataModels.Attachment", b =>
    {
        b.HasOne("SampleProject.Data.DataModels.Transaction")
            .WithMany("Attachments")
            .HasForeignKey("TransactionId2");
    });

modelBuilder.Entity("SampleProject.Data.DataModels.Check", b =>
    {
        b.HasOne("SampleProject.Data.DataModels.Transaction")
            .WithMany("Checks")
            .HasForeignKey("TransactionId2");
    });

modelBuilder.Entity("SampleProject.Data.DataModels.Envelope", b =>
    {
        b.HasOne("SampleProject.Data.DataModels.Transaction")
            .WithMany("Envelopes")
            .HasForeignKey("TransactionId2");
    });

modelBuilder.Entity("SampleProject.Data.DataModels.Stub", b =>
    {
        b.HasOne("SampleProject.Data.DataModels.Transaction")
            .WithMany("Stubs")
            .HasForeignKey("TransactionId2");
    });

Я явно что-то упускаю, но не могу понять, что это такое. Я хочу иметь возможность использовать иерархию наследования с подходом TPH и одно поле внешнего ключа из таблицы базового класса (TransactionItem) к родителю (Transaction). Я ценю любую помощь, которую вы можете оказать.

Спасибо!

1 ответ

Решение

Как указал Иван Стоев, я создал эту проблему, имея родительский объект (Transaction в этом случае) реализовать удобные свойства только для чтения для списков моих производных типов классов.

Так как Transaction объявленные свойства, как показано ниже, efigration создала для них новые отношения / внешние ключи.

public List<Check> Checks
{
    get
    {
        return this.TransactionItems?.OfType<Check>().ToList();
    }
}

С тех пор я реализовал их как методы, чтобы не противоречить соглашениям ef.

Большое спасибо Ивану Стоеву за подсказку этого открытия!

Другие вопросы по тегам