外键未从继承中正确映射

时间:2013-05-06 14:46:44

标签: entity-framework

如果我有以下代码生成我的数据库,它会将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");
        });
}

1 个答案:

答案 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。 (此处不能是这种情况,因为Assetabstract但是假设它abstract。)如果Asset有其他派生的类型EF也会加入他们的表,并根据连接行的存在再次决定具体的实体类型。

因此,对于TPT,类型不是由特殊列检测,而是由(左外部)表连接的结果检测。

上面的这句话似乎在某种程度上混淆了EF。但它确实不属于TPT映射,我会使用Fluent API删除整个映射。

我已经测试了删除映射时结果是否正确 - 即将在TankComponentTank表(不是Asset表)之间创建FK关系。