简体   繁体   English

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

[英]EF6 - TPH foreign key mapping in derived classes using base class property

I am using Entity Framework 6.0.2 with an existing database in which tags are stored in a single table that looks like this: 我正在将Entity Framework 6.0.2与现有数据库一起使用,其中标记存储在单个表中,如下所示:

  • Id : int, primary key Id :int,主键
  • TagType : string, determine the type of tag, either "usertag" or "movietag" TagType :string,确定标签的类型,“usertag”或“movietag”
  • ItemId : int, contains the Id of the item to which is referred (either a User Id or a Movie Id) ItemId :int,包含要引用的项的Id(用户ID或电影ID)

The following classes describe this situation: 以下类描述了这种情况:

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; }
}

As you can see my derived classes have navigation properties, which are backed by the value of the ItemId property in the base class. 如您所见,我的派生类具有导航属性,这些属性由基类中ItemId属性的值支持。 My mapping is as follows: 我的映射如下:

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);
    }
}

Now when I try to use this mapping using the following code, I get an exception: 现在当我尝试使用以下代码使用此映射时,我得到一个异常:

using System.Data.Entity;

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

The exception that is thrown is: 引发的异常是:

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

Yes the ItemId property is not declared on the type UserTag , but it is inherited from the base Tag class. 是的, ItemId属性未在UserTag类型上UserTag ,但它继承自基类Tag类。 To me it seems that this mapping should be possible. 对我而言,似乎这种映射应该是可能的。 Is this a bug or a restriction in Entity Framework 6? 这是实体框架6中的错误还是限制?

It is a restriction. 这是一个限制。 EF is quite tightly bound to the way how relational database works. EF与关系数据库的工作方式紧密相关。 What you are trying to do in terms of the database is to put two foreign key constraints on single ItemId column. 您在数据库方面要做的是在单个ItemId列上放置两个外键约束。 The foreign constraint in database is not conditional so the record will always use both constraints no matter of the tag type. 数据库中的外部约束不是有条件的,因此无论标记类型如何,记录都将始终使用这两个约束。 That is not what you want because such definition will always require both user and movie with specific Id to exist for every single tag. 这不是你想要的,因为这样的定义总是要求每个标签都存在具有特定Id的用户和电影。

Think about it in different way. 以不同的方式思考它。 If it works the way how you are trying to define it there would be no reason why to have User and Movie navigation properties in child entities - it would be enough to have single navigation property in parent. 如果它的工作方式与您尝试定义它的方式不同,则没有理由在子实体中具有UserMovie导航属性 - 在父级中具有单个导航属性就足够了。 The fact that you have to define them in child entities because they are different for each of them also means you need to have two different foreign keys. 您必须在子实体中定义它们,因为它们对于每个实体都是不同的,这也意味着您需要有两个不同的外键。

You need to have separate UserId and MovieId in their specific tags. 您需要在其特定标记中包含单独的UserIdMovieId

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM