Смешивание таблиц на иерархии и таблиц на основе типов в коде Entity Framework с существующей базой данных

tl; dr: я пытаюсь отобразить модель кода в существующую базу данных, в которой определенная иерархия объектов имеет смешанную схему наследования. Некоторые конкретные классы используют TPH, а некоторые используют TPT. Кажется, я не могу правильно составить карту.


У меня есть иерархия объектов, которые я пытаюсь сопоставить с существующей базой данных. Некоторые из конкретных классов содержат дополнительные свойства, поэтому у них есть собственная таблица; некоторые из конкретных классов этого не делают, поэтому они живут в базовой таблице и полагаются на столбец дискриминатора. Чтобы упростить вещи, я создал POC. Структура базы данных выглядит следующим образом:

CREATE TABLE Foos (
    Id INT IDENTITY NOT NULL PRIMARY KEY,
    FooType TINYINT NOT NULL
)

CREATE TABLE FooTpts (
    Id INT NOT NULL PRIMARY KEY 
        FOREIGN KEY REFERENCES Foos(Id),
    Value INT NOT NULL
)

И эквивалентные POCO будут:

public abstract class Foo
{
    public int Id { get; set; }
}

public class FooTph : Foo {}

public class FooTpt : Foo
{
    public int Value { get; set; }
}

Кажется достаточно простым. Поэтому моей первой попыткой было следующее сопоставление (свободно или с атрибутами, результат тот же):

modelBuilder.Entity<Foo>()
    .ToTable("Foos")
    .Map<FooTph>(m => m.ToTable("Foos").Requires("FooType").HasValue(1))
    .Map<FooTpt>(m => m.ToTable("FooTpts").Requires("FooType").HasValue(2));

Но это не сработало, потому что:

  1. Хочет создать FooTpt.FooType описатель в FooTpts Таблица
  2. Попытка выполнить команду дает мне следующую ошибку (предположительно из-за пункта 1 выше):

    (6,10): ошибка 3032: проблема в отображении фрагментов, начинающихся со строк 6, 11:EntityTypes ConsoleApplication1.FooTph, ConsoleApplication1.FooTpt отображаются в те же строки в таблице Foo. Условия сопоставления могут использоваться для различения строк, в которые сопоставляются эти типы.


Вернуться к доске для рисования. В этом ответе предлагается создать промежуточную абстрактную сущность, сопоставленную с родительской таблицей (TPH). Все всегда можно решить с помощью другого уровня абстракции, верно? Поэтому я делаю несколько изменений:

+ public abstract class FooTptBase : Foo {}

- public class FooTpt : Foo
+ public class FooTpt : FooTptBase

И измените отображение:

modelBuilder.Entity<Foo>()
    .ToTable("Foos")
    .Map<FooTph>(m => m.ToTable("Foos").Requires("FooType").HasValue(1))
    .Map<FooTptBase>(m => m.ToTable("Foos").Requires("FooType").HasValue(2));

modelBuilder.Entity<FooTpt>().ToTable("FooTpts");

База данных теперь выглядит хорошо, и у нас есть один дискриминатор в родительской таблице. Но чего-то не хватает, и мы получаем ту же ошибку:

(6,10): ошибка 3032: проблема в отображении фрагментов, начинающихся со строк 6, 11:EntityTypes ConsoleApplication1.FooTph, ConsoleApplication1.FooTpt отображаются в те же строки в таблице Foo. Условия сопоставления могут использоваться для различения строк, в которые сопоставляются эти типы.

Это не имеет смысла, потому что все FooTptдолжно быть FooTptBase по определению, которое должно требовать FooType == 2, (Это почти как если бы модельер игнорировал мой промежуточный FooTptBase абстрактный тип?)

Итак, что мне не хватает? Как я могу выполнить то, что я пытаюсь сделать?

0 ответов

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