【发布时间】:2014-05-02 17:06:11
【问题描述】:
我有一个模型,其中大多数实体都继承了相同的基本功能。该功能被封装在一个抽象基类中。除此之外,还有两个功能分支,因此有两个抽象类继承自抽象基类。此时,具体类从它们各自的中间抽象类继承。
以下是此类模型模型的一个分支的类和 EF 映射示例:
public class TestContext : DbContext
{
public DbSet<Base> Bases { get; set; }
public DbSet<Intermediate> Intermediates { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Intermediate>().ToTable("Concretes");
modelBuilder.Entity<Concrete1>().ToTable("Concretes");
modelBuilder.Entity<Concrete2>().ToTable("Concretes");
}
}
public abstract class Base
{
public int Id { get; set; }
public string BaseString { get; set; }
public int BaseInteger { get; set; }
}
public abstract class Intermediate : Base
{
public string IntermediateString { get; set; }
public int IntermediateInteger { get; set; }
}
public class Concrete1 : Intermediate
{
public string Concrete1String { get; set; }
public int Concrete1Integer { get; set; }
}
public class Concrete2 : Intermediate
{
public string Concrete2String { get; set; }
public int Concrete2Integer { get; set; }
}
我遇到的问题是表映射。虽然映射 Intermediate、Concrete1 和 Concrete2 确实会生成一个数据库 - 甚至给我一个鉴别器列 - 它不会像 TPH 映射所需的那样使这些列可以为空,因此我最终得到以下异常消息:
(28,10) : 错误 3023:从第 28 行开始映射片段时出现问题:必须映射表 Concretes 中的列 Concretes.Concrete1Integer:它没有默认值且不可为空。
我已经尝试了几种排列方式-
- 仅将
Intermediate映射到自定义表格,但具体类型的字段映射到“Bases”表格。 - 将
Intermediate映射到它自己的表,并将Concrete1和Concrete2映射到一个名为“Concretes”的表- 与上述代码示例中的原始映射完全相同。 - 将每个实体映射到它自己的表 - 这可行,但它纯粹是 TPT,这不是我想要的。
- 不作任何映射 - 这会将所有内容都放在“Bases”表中,并且纯粹是 TPH,这实际上会导致表的宽度和稀疏度令人无法接受。
没有什么方法可以在代码示例中获得我正在寻找的映射吗?即一个“Bases”表和一个“Concretes”表使用了判别器?
【问题讨论】:
-
您是否考虑过仅映射具体类型的选项,即让 EF 忽略基本类型?
-
是的,但它不适用于我们使用的真实模型。即使这样做了,那也是很多冗余字段。通常不鼓励 TPC,除非您正在使用强制您使用它的现有数据库,或者您有一个非常好的/奇怪的理由。
-
很多冗余字段...您仍然可以拥有继承,但只是不要告诉 EF,因此公共字段仍然在基本类型中。这样做,对继承映射类有很大帮助,例如here。也许您可以将
Base类排除在EF 模型之外,仅将Intermediate映射为TPH 或TPT。 -
我开始了一个 Codeplex 问题,似乎我发现了另一个错误。当我确定时我会适当地回答:entityframework.codeplex.com/workitem/2254
标签: c# entity-framework table-per-type table-per-hierarchy entity-framework-6.1