2

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 中的相同行。映射条件可用于区分这些类型映射到的行。

这实际上没有意义,因为所有FooTpts 都必须是 aFooTptBase根据定义,这应该需要FooType == 2. (就好像模型构建器忽略了我的中间FooTptBase抽象类型?)

那么,我错过了什么?我怎样才能完成我想做的事情?

4

0 回答 0