如果我有以下代码生成我的数据库,它会将TankComponent表中的外键分配给Asset表而不是Tank表。有人可以解释原因吗?我是否需要关闭特定约定或更改Fluent API?它真的只是查看列名吗?
[Table("Asset")]
public abstract class Asset
{
[Key]
public int AssetId { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
[Table("Tank")]
public class Tank : Asset
{
public Tank()
{
this.TankCompnents = new Collection<TankComponent>();
}
public int TankField1 { get; set; }
public ICollection<TankComponent> TankCompnents { get; set; }
[NotMapped]
public IEnumerable<Floor> Floors { get { return this.TankCompnents.OfType<Floor>(); } }
}
[Table("TankComponent")]
public abstract class TankComponent
{
[Key]
public int TankComponentId { get; set; }
[ForeignKey("Tank")]
public int AssetId { get; set; }
public Tank Tank { get; set; }
public string Name { get; set; }
}
//forgot this in initial post
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Tank>()
.Map(m =>
{
m.Properties(a => new { a.AssetId, a.Name, a.Description });
m.Requires("AssetType").HasValue(1);
m.ToTable("Asset");
})
.Map(m =>
{
m.Properties(t => new { t.AssetId, t.TankField1 });
m.ToTable("Tank");
});
}
答案 0 :(得分:0)
此映射线......
m.Requires("AssetType").HasValue(1);
...你的评论似乎表明你可能误解了Table-Per-Type(TPT)继承的工作原理。
EF不需要基类Asset
表中的特定列来检测具有给定主键值的实体的实际类型是什么 - 除非您使用Table-Per-Hierarchy(TPH) )继承映射(即在您的实体上没有[Table]
属性的映射)。对于TPH,特定列 - 鉴别器 - 确实需要区分类型,因为继承树中所有实体的所有属性都将存储在单个表中。如果您没有明确指定鉴别器 - 例如AssetType
- EF默认会创建一个名为Discriminator
的列。
现在,TPT是另一回事。如果查询具有其他派生实体的实体 - 例如......
var asset = context.Assets.First();
... EF不仅会在基表上创建一个像SELECT TOP(1) * FROM ASSETS
这样的SQL查询,而是一个 - 可能非常复杂 - 查询到许多LEFT OUTER JOIN
到许多其他属于所有表的表可能的衍生实体。此查询将在Tank
表中找到一行。如果确实发现一个EF将实现Tank
对象。如果不是,它将实现Asset
。 (此处不能是这种情况,因为Asset
是abstract
但是假设它不是abstract
。)如果Asset
有其他派生的类型EF也会加入他们的表,并根据连接行的存在再次决定具体的实体类型。
因此,对于TPT,类型不是由特殊列检测,而是由(左外部)表连接的结果检测。
上面的这句话似乎在某种程度上混淆了EF。但它确实不属于TPT映射,我会使用Fluent API删除整个映射。
我已经测试了删除映射时结果是否正确 - 即将在TankComponent
和Tank
表(不是Asset
表)之间创建FK关系。