【问题标题】:Add PK on a subclass (inheritance) different from parent class ID在与父类 ID 不同的子类(继承)上添加 PK
【发布时间】:2017-08-18 11:55:06
【问题描述】:

这些天我一直在使用实体框架 6(MVC,VisualStudio 2015,代码优先)进行继承。尝试不同的方面,我发现需要生成一个标识子类的 PrimaryKey,与从父类继承的 primaryKey/ForeignKey 分开。 我想发展的想法是这样的:

public class Person
{

    [Key]
    public int PersonId { get; set; }

}

public class Student : Person
{

    [Key]
    public int StudentId { get; set; }

}

我一直在寻找其他尝试过这个的人,但我没有找到任何东西。我不确定是否可以这样做,所以如果有人可以帮助我,我将不胜感激

谢谢。

【问题讨论】:

  • 不确定您是否可以仅使用数据注释,但是....您为什么还要这样做?为您的 PK 使用一致的名称非常有用。

标签: c# visual-studio entity-framework inheritance ef-code-first


【解决方案1】:

如果你要描述一个Student,并且你必须描述Student.StudentIdStudent.PersonId的含义,你能给出一个恰当的描述吗?

在我看来,你想给学生一个新的主键属性的唯一原因是因为这个属性的标识符,而不是因为真正的正确含义。

在实体框架中建模继承时应使用的方法取决于您最常使用的查询类型。

假设您有三种类型的人:学生、教师和家长。考虑一下您最常做的查询类型:

  1. 您最常询问有...的学生,还是...的家长?
  2. 或者,您是否会经常针对...的人,很少针对...的学生或...的老师

(1) 主要要求学生...:使用 TPC

如果您将继承策略建模为Table per Concrete Class (TPC),那么学生、教师和家长将各自拥有自己的表。没有共同的父母表。学生拥有的所有父属性都在学生表中,类似地,所有这些父属性也在教师表中。

如果您主要要求学生...而很少要求...询问...的人总是需要对...的学生和...的老师以及...的父母的查询结果串联

我发现这是我最常用的继承策略。

(2) 主要要求...的人:使用 TPT

如果这些是最常用的查询,最好将所有人员数据建模在一个单独的表中,让学生、教师和家长都可以参考他们的人员数据:Table-Per-Type (TPT)

如何实现 TPC

如果按照TPC来实现继承,那么就不会有单独的Person表了。无需给 Persons 一个 ID。

class Person
{
    public string FirstName {get; set;}
    ...
}

class Student : Person
{
    public int Id {get; set;}
    ...
}

class Teacher : Person
{
    public int Id{get; set;
    ...
}

如果你打算从不实例化一个人,只有学生、老师和家长,才能声明人的类抽象

顺便说一句,如果你给主键属性默认名称Id,实体框架会知道这应该是你的主键。不需要属性,也不需要流畅的 API。

在您的 DbContext 中:

class MyDbContext : DbContext
{
    public DbSet<Student> Students {get; set;}
    public DbSet<Teacher> Teachers {get; set;}
    public DbSet<Parent> Parents {get; set;}

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Student>().Map(student =>
        {
            student.MapInheritedProperties();
            student.ToTable(nameof(MyDbContext.Students));
        });

        modelBuilder.Entity<Teacher>().Map(teacher =>
        {
            teacher.MapInheritedProperties();
            teacher.ToTable(nameof(MyDbContext.Teachers));
        });
        // etc. for Parent
    }
}

如何实施 TPT

会有一个 Persons 表,Student 和 Teachers 将引用 Persons 表。

class Person
{
    public int Id {get;set;}
    ...
}
class Student
 {
    public int Id {get;set;}
    // A student has Person data via foreign key:
    public int PersonId {get; set;}
    public Person Person {get; set;}
    ...        
 }
 class Teacher
 {
    public int Id {get;set;}
    // A Teacher has Person data via foreign key:
    public int PersonId {get; set;}
    public Person Person {get; set;}
    ...        
 }

【讨论】:

  • 感谢您的帮助!!终于实现了(2),我发现如果你不在基类上声明一个PK,那么你可以在子类中定义你自己的PK。但是你不能用 TPT 做到这一点,你应该实现 TPH
猜你喜欢
  • 1970-01-01
  • 2015-03-14
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 2012-04-11
  • 1970-01-01
相关资源
最近更新 更多