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

Eri*_*oom 4 c# entity-framework single-table-inheritance table-per-hierarchy entity-framework-6

我正在将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; }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,我的派生类具有导航属性,这些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);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,当我尝试使用以下代码使用此映射时,出现异常:

using System.Data.Entity;

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

引发的异常是:

Unhandled Exception: System.InvalidOperationException: The foreign key component 'ItemId' is not a declared property on type 'UserTag'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property

是的,该ItemId属性未在type上声明UserTag,但它是从基Tag类继承的。在我看来,这种映射应该是可能的。这是Entity Framework 6中的错误还是限制?

Lad*_*nka 5

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

以不同的方式考虑它。如果它以您尝试定义它的方式工作,则没有理由在子实体中拥有UserMovie导航属性-在父实体中具有单个导航属性就足够了。您必须在子实体中定义它们的事实是因为每个子实体都不同,这也意味着您需要具有两个不同的外键。

你需要有独立的UserIdMovieId在其特定的标签。