C# EF6-使用基类属性的派生类中的TPH外键映射

C# EF6-使用基类属性的派生类中的TPH外键映射,c#,entity-framework,entity-framework-6,single-table-inheritance,table-per-hierarchy,C#,Entity Framework,Entity Framework 6,Single Table Inheritance,Table Per Hierarchy,我将Entity Framework 6.0.2与现有数据库一起使用,其中标记存储在一个表中,如下所示: Id:int,主键 TagType:字符串,确定标记的类型,“usertag”或“movietag” ItemId:int,包含所引用项目的Id(用户Id或电影Id) 以下类别描述了这种情况: public class User { public int Id { get; set; } } public class Movie { public int Id { ge

我将Entity Framework 6.0.2与现有数据库一起使用,其中标记存储在一个表中,如下所示:

  • Id
    :int,主键
  • TagType
    :字符串,确定标记的类型,“usertag”或“movietag”
  • ItemId
    :int,包含所引用项目的Id(用户Id或电影Id)
以下类别描述了这种情况:

public class User
{
    public int Id { get; set; }
}

public class Movie
{
    public int Id { get; set; }
}

public abstract class Tag
{
    public int Id { get; set; }
    public int ItemId { get; set; }
}

public class UserTag : Tag
{
    public virtual User User { get; set; }
}

public class MovieTag : Tag
{
    public virtual Movie Movie { get; set; }
}
正如您所看到的,我的派生类具有导航属性,这些属性由基类中
ItemId
属性的值支持。我的映射如下:

public class Context : DbContext
{
    public DbSet<Tag> Tags { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Tag>()
            .Map<UserTag>(m => m.Requires("TagType").HasValue("usertag"))
            .Map<MovieTag>(m => m.Requires("TagType").HasValue("movietag"));

        modelBuilder.Entity<UserTag>()
            .HasRequired(m => m.User).WithMany().HasForeignKey(m => m.ItemId);

        modelBuilder.Entity<MovieTag>()
            .HasRequired(m => m.Movie).WithMany().HasForeignKey(m => m.ItemId);
    }
}
引发的异常是:

未处理的异常:System.InvalidOperationException:外键组件“ItemId”不是类型“UserTag”上声明的属性。验证是否未从模型中明确排除该属性,以及该属性是否为有效的基本属性


是的,
ItemId
属性未在类型
UserTag
上声明,但它是从基
标记
类继承的。在我看来,这种映射应该是可能的。这是实体框架6中的错误还是限制?

这是限制。EF与关系数据库的工作方式紧密相关。在数据库方面,您试图做的是在单个
ItemId
列上放置两个外键约束。数据库中的外部约束不是有条件的,因此无论标记类型如何,记录都将始终使用这两个约束。这不是您想要的,因为这样的定义将始终要求每个标记都存在具有特定Id的用户和电影

用不同的方式思考。如果它按照您试图定义它的方式工作,那么就没有理由在子实体中有
User
Movie
导航属性-在父实体中有单个导航属性就足够了。您必须在子实体中定义它们,因为它们每个都不同,这一事实也意味着您需要有两个不同的外键


您需要在它们的特定标签中有单独的
UserId
MovieId

我明白了。为了尝试您的解决方案,在中,我们在特定的标记类中添加了UserId和MovieId属性。但是,现在出现以下错误:
ItemId::在角色“Tag”引用的类型中没有定义名为“ItemId”的属性。
。有关我尝试的要点,请参见:
using System.Data.Entity;

class Program
{
    static void Main()
    {
        using (var db = new Context())
        {
            db.Database.Delete();
            db.Database.Initialize(false);
        }
    }
}