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

EF6 - TPH foreign key mapping in derived classes using base class property(EF6 - 使用基类属性的派生类中的 TPH 外键映射)

本文介绍了EF6 - 使用基类属性的派生类中的 TPH 外键映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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:

  • Id:int,主键
  • TagType:字符串,确定标签的类型,usertag"或movietag"
  • ItemId:int,包含被引用项目的ID(用户ID或电影ID)
  • Id: int, primary key
  • TagType: string, determine the type of tag, either "usertag" or "movietag"
  • ItemId: int, contains the Id of the item to which is referred (either a User Id or a Movie 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; }
}

如您所见,我的派生类具有导航属性,这些属性由基类中的 ItemId 属性的值支持.我的映射如下:

As you can see my derived classes have navigation properties, which are backed by the value of the ItemId property in the base class. 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);
        }
    }
}

抛出的异常是:

未处理的异常:System.InvalidOperationException:外键组件ItemId"不是UserTag"类型的声明属性.验证它没有被明确地从模型中排除,并且它是一个有效的原始属性

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

Yes the ItemId property is not declared on the type UserTag, but it is inherited from the base Tag class. To me it seems that this mapping should be possible. Is this a bug or a restriction in Entity Framework 6?

推荐答案

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

It is a restriction. EF is quite tightly bound to the way how relational database works. What you are trying to do in terms of the database is to put two foreign key constraints on single ItemId column. 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.

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

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. 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.

您需要在它们的特定标签中具有单独的 UserIdMovieId.

You need to have separate UserId and MovieId in their specific tags.

这篇关于EF6 - 使用基类属性的派生类中的 TPH 外键映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:EF6 - 使用基类属性的派生类中的 TPH 外键映射