【问题标题】:Table-per-type inheritance with EF 4.1 Fluent Code First使用 EF 4.1 Fluent Code First 的按类型继承表
【发布时间】:2018-01-03 07:56:08
【问题描述】:

我有一组非常简单的数据库表,例如:

Vehicle
 Id
 RegNo

Car
 Id (FK of Vehicle.Id)
 OtherStuff

Bike
 Id (FK of Vehicle.Id)
 MoreStuff

我的类模型如你所料:Vehicle 是一个抽象类,然后 Car 和 Bike 是它的子类。

我的 EF4.1 Code First 配置如下:

class VehicleConfiguration : EntityTypeConfiguration<Vehicle> {
    public VehicleConfiguration() {
        ToTable("Vehicles");
        Property(x => x.Id);
        Property(x => x.RegNo);
        HasKey(x => x.Id);
    }
}

class CarConfiguration : EntityTypeConfiguration<Car> {
    public CarConfiguration() {
        ToTable("Cars");
        Property(x => x.OtherStuff);
    }
}

class BikeConfiguration : EntityTypeConfiguration<Bike> {
    public BikeConfiguration() {
        ToTable("Bikes");
        Property(x => x.MoreStuff);
    }
}

但是,当 EF 尝试构建其模型配置时,我遇到了许多奇怪的异常。

目前它正在抛出这个:

System.Data.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Invalid column name 'Discriminator'.

从哪里获得该列名?它不在我的任何代码或数据库本身中。一定是某种惯例接管了控制权。如何指示 EF 使用 table-per-type?

如果我从 Vehicle 类中删除“abstract”关键字(我在某处进行了健全性测试),那么我会得到一个不同的异常,如下所示:

(35,10) : error 3032: Problem in mapping fragments starting at lines 30, 35:EntityTypes AcmeCorp.Car, AcmeCorp.Bike are being mapped to the same rows in table Vehicles. Mapping conditions can be used to distinguish the rows that these types are mapped to.

我显然做错了什么,但是什么?我已经关注了 MSDN 文档以及我能找到的所有其他 TPT + EF4.1 文章!

【问题讨论】:

  • 您是否真的在派生的DbContextOnModelCreating 中添加了这些配置? modelBuilder.Configurations.Add(new VehicleConfiguration()); 之类的东西应该在那里。不知何故,EF 似乎会使用默认继承映射,即 TPH 而不是 TPT。如果你这样做,你能显示类定义吗?
  • @Slauma,是的,EntityTypeConfiguration 都已正确添加到 DbContext。别担心。类定义简单得离谱,无非就是:public abstract class Vehicle { public Guid Id { get; set; } public String RegNo { get; set; } } public class Car : Vehicle { public String OtherStuff { get; set;} } public class Bike : Vehicle { public String MoreStuff { get; set; } }
  • 您能否在代码中的 3 ToTable 行设置断点,以检查您是否真的到达了它们。基本上ToTable 说:“TPT”。没有 ToTable EF 将使用 TPH。 EF 以某种方式查询“鉴别器”列这一事实意味着它假定 TPH 继承。您能否显示完整的DbContext 定义以及发生异常的确切代码。您现在显示的代码是正确的imo,我相信问题出在其他地方。您是在创建新数据库还是使用现有数据库?你有任何Database.SetInitializer 电话吗?
  • 我想我已经弄清楚是什么原因造成的。我设置了一个完全独立的测试项目,并做了最少的代码,它按预期工作。但是,一旦我在模型中添加了一个新的 Vehicle 子类,但它既没有作为数据库中的表出现,也没有在 EF 映射中配置。 EF 开始抛出“映射片段中的问题......”异常。我的子类被标记为internal,而其他的是public,所以我真的不明白为什么EF 甚至知道它存在!有什么方法可以让 EF 完全忽略这个对我的模型来说是“特例”的子类?
  • 如果您想从 EF 模型中排除类 Foo,您可以将 [NotMapped] 属性放在类上或在 Fluent API 中使用 modelBuilder.Ignore&lt;Foo&gt;();

标签: entity-framework entity-framework-4 entity-framework-4.1 entity-framework-6 table-per-type


【解决方案1】:

你读过下面的文章吗?

这是一篇包含以下方法的 3 部分文章

  1. Table per Hierarchy (TPH): 通过对 SQL 模式,并利用保存类型的类型鉴别器列 信息。

  2. Table per Type (TPT): 表示“是一个”(继承) 关系为“具有”(外键)关系。

  3. Table per Concrete class (TPC): 丢弃多态性并 完全来自 SQL 模式的继承关系。

【讨论】:

  • 我认为这不能解决问题。根据您链接到的相应文章,问题中的代码看起来已经正确。
  • 原发帖人说他们已经阅读了他们能找到的所有文章,那篇 3 部分的文章在 2 年前我与 EF 合作时帮助了我很多,因此我将它们(2 年前)添加到原始海报是否阅读过它们的问题。你是对的,它没有解决确切的问题,但它确实提供了一篇很棒的文章,可以更好地理解 EF 中的继承
【解决方案2】:

当我遇到这个问题时,我发现我有一个未映射的子类。在这个例子中,一些可能的原因是:

  1. 存在一个额外的子类,例如Bus。这未映射。
  2. 其中一个子类(例如 Car)未映射。

在这种情况下,确保每个子类都被映射:

  1. 确保存在子类的映射,包括ToTable 方法调用。
  2. 确保在OnModelCreating 期间实际应用了映射。
  3. 如果您无法跟踪此问题,请尝试使用调试器并在所有映射代码中设置断点。

或者,如果不应该首先映射子类,请确保使用 Ignore 方法调用之一将其忽略。

【讨论】:

  • 这正是我的问题,而且很难找到,因为新的继承类型被添加到代码库中(存根但当前未使用)。经过一整天的尝试搜索“为什么 EF 认为我正在实施 TPH”,我在一个 6 岁的问题中找到了答案:(
  • @CarrieKendall 看起来你没有搜索到正确的地方。文档的Entity Framework Code First Conventions - Type Discovery 部分包含以下内容:“如果您的类型参与继承层次结构,则为基类定义DbSet 属性就足够了,并且派生类型将自动包含在内, 如果它们与基类在同一个程序集中"
猜你喜欢
  • 2014-12-18
  • 1970-01-01
  • 1970-01-01
  • 2011-11-03
  • 2012-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多