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));
但这不起作用,因为:
- 它想在表中创建
FooTpt.FooType
鉴别器FooTpts
尝试执行命令会给我以下错误(可能是因为上面的第 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
s 都必须是 aFooTptBase
根据定义,这应该需要FooType == 2
. (就好像模型构建器忽略了我的中间FooTptBase
抽象类型?)
那么,我错过了什么?我怎样才能完成我想做的事情?