tl;dr: я пытаюсь сопоставить модель code-first с существующей базой данных, в которой определенная иерархия объектов имеет смешанную схему наследования. Некоторые конкретные классы используют 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));
Но это не сработало, потому что:
- Он хочет создать дескриминатор
FooTpt.FooType
в таблицеFooTpts
- #P6# <блочная цитата> #P7# блочная цитата>
Вернуться к доске для рисования. В этом ответе предлагается создать промежуточный абстрактный объект, сопоставленный с родительской (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
абстрактный тип?)
Итак, что мне не хватает? Как я могу выполнить то, что я пытаюсь сделать?