我创建了这些类,以便通过 EntityFramework 6 代码优先方法生成数据库模型:
public class Vehicle
{
public long Id { get; set; }
public long ResponsiblePersonId { get; set; }
}
public class Car: Vehicle {
public int HorsePower { get; set; }
}
public class Bike: Vehicle {
public int FrameSize { get; set; }
}
public class Organisation
{
public Organisation()
{
Cars = new List<Car>();
Bikes = new List<Bikes>();
}
public long Id { get; set; }
public List<Car> Cars { get; set; }
public List<Bike> Bikes { get; set; }
}
到目前为止,这似乎适合我。
但不幸的是,结果表如下所示:
Id | ResponsiblePersonId | HorsePower | FrameSize | Discriminator | Organisation_Id | Organisation_Id1
为什么组织外键生成两次?我预计该表只有一个 Organization_Id 列。
Thanks
EF 有多种方法来实现继承层次结构的物理表。默认的(您正在使用的)称为“每层次结构表”(TPH)。它仅使用一张表来存储所有派生实体,其中一个Discriminator
列来指定记录中包含的实体的类型。 EF 还在表中为任何派生实体中包含的每个属性添加一列。
因此,派生实体和Organisation
是在子级别定义的(列表Car
and Bike
属性在Organisation
实体)EF 决定为每个子实体类型创建一个单独的列Organisation_Id
,而你不希望这样。
如何改变这个?有以下几种方法:
-
不要使用 TPH。请改用 TPC(每个具体类的表)。也就是说,EF 为每个子实体创建一个单独的表。如何做到这一点:删除DbSet<Vehicle>
来自你的财产DbContext
。如果这不起作用,请为派生自的每个实体的物理表名称设置显式配置Vehicle
像这样:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
...
modelBuilder.Entity<Car>().ToTable("Cars");
modelBuilder.Entity<Bike>().ToTable("Bikes");
}
-
如果您需要继续使用 TPH,我不知道有什么方法可以实现仅生成一个OrganisationId
数据库中的列和之间只有一个外键Vehicle
and Organisation
。常识会说你可以定义Organisation
外键位于Vehicle
基础实体级别。但是在生成迁移时会出现错误:
组织:FromRole:NavigationProperty“组织”不是
有效的。在 FromRole 'Organization_Cars_Target' 中输入 'Car'
AssociationType“Organization_Cars”必须与类型完全匹配
声明此 NavigationProperty 的“车辆”。
似乎当关系在基础级别定义时,EF 期望列表在Organisation
被定义为类型Vehicle
并不是Car
or Bike
。这不适合你的模型。
如果你尝试定义OrganisationId
or Organisation
派生类中的属性,然后在生成迁移时会出现不同的错误,因为不允许对不同子实体中的属性使用相同的名称。您可以使用不同的名称,但随后您会再次获得两列。也没有办法以这种方式获得一列。
因此,如果您坚持使用 TPH,据我所知,您必须忍受为您的内容设置两列。OrganisationId
。至少你可以通过一些流畅的配置以更详细的方式命名它们:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
...
modelBuilder.Entity<Organisation>()
.HasMany(o => o.Bikes)
.WithRequired()
.Map(x => x.MapKey("OrganisationIdBike"));
modelBuilder.Entity<Organisation>()
.HasMany(o => o.Cars)
.WithRequired()
.Map(x => x.MapKey("OrganisationIdCar"));
}
我建议您更改为 TPC,因为您的模型的流畅映射编写起来稍微简单一些。
为了更好地理解 TPH、TPC 和 TPT(每个类型的表,继承层次结构的另一种实现),请阅读这个帖子 https://blogs.msdn.microsoft.com/alexj/2009/04/14/tip-12-how-to-choose-an-inheritance-strategy/.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)