【问题标题】:EF 6 Code First Create new Subtype from SupetypeEF 6 Code First 从 Supetype 创建新的子类型
【发布时间】:2018-02-21 12:40:09
【问题描述】:

我有以下数据结构:

class Person
{
     public int PersonId {get; set}
     public string Name {get; set;}
     public string FieldWithUniqueConstraint {get; set}
}

class Student : Person
{
     public string StudentNumber {get; set;}
}

class Teacher : Person
{
     public string EmployeeNumber {get; set;}
}

我在 EF6 中使用 TPT Hierarchy,因此上述实体在 SQL Server 中以 3 个表的形式存在。

创建新学生和教师工作正常,但现在教师也需要是学生。

如果我使用现有的 PersonId 在数据库中为学生子类型手动创建新记录,则 SQL Server 不会抱怨。我尽可能使用db.Students/Teachers.SingleOrDefault(e => e.PersonId == personId);从数据库中获取学生/教师

但是我到底如何使用现有的老师来创建新的学生?由于主键违规,简单地做db.Students.Add() 不起作用,我明白为什么。

如果我确实创建了一个,你会如何只删除一种类型?

诀窍在于属性FieldWithUniqueContraint 必须存在于结构中,否则解决方案很简单,只需创建另一个记录,但两个子类型必须共享 Person 记录。

任何对此问题的见解将不胜感激。

【问题讨论】:

  • 这不仅仅是一个 EF 问题。这是您的类层次结构中的问题。在您的班级层次结构中,一个人不能既是老师又是学生。
  • 这需要完全不同的类设计。继承表示一个是一种关系(并且一个对象只能be一种类型)。你需要的是一个有一个关系,例如一个Person 有一个学生角色和一个老师角色。
  • @GertArnold,是的,a have a relationship 会在这里工作得更好,这是我看的第一件事,但由于这已经在生产中,有 1000 条记录,现在改变结构不是一个选项
  • @HansKilian 请您详细说明一下,我认为我没有正确理解您。手动更新记录后,可以使用'await db.Student/Teacher.SingleOrDefaultAsync(l => l.PersonId == id)'获得学生和老师我绝对不能说Person p = db.Students...等
  • 现在改变结构不是一种选择然后你必须解决现在发生的数据重复(2 Persons事实上是同一个人)这是更以后更难修复。我会说,现在咬紧牙关修复它。

标签: c# entity-framework


【解决方案1】:

我解决此问题的“正确”方法是将我的结构简化为一个表(类似于 TPH,但没有鉴别器)并按照@GertArnold 在问题的 cmets 中建议的那样为 Person 分配角色(请参阅下面):

class Person
{
     public int PersonId {get; set}
     public string Name {get; set;}
     public string StudentNumber {get; set;}
     public string FieldWithUniqueConstraint {get; set}
     public string EmployeeNumber {get; set;}
     public virtual ICollection<PersonRole> PersonRoles {get; set}  
}

class PersonRole
{
     public in PersonRoleId {get; set;}
     public ICollection<Person> People {get; set;}
     public string RoleName {get; set;}
}

但由于时间限制和需要将多个表中的实时数据合并为一个,我不得不接受一个快速而肮脏的解决方案。在我们的场景中,学生/教师也需要成为教师/学生的情况很少见(万分之一),因此我们最终“手动”创建了所需子类型的记录:

db.Database.ExecuteSqlCommand("INSERT INTO Learner (PersonId, StudentNumber) VALUES (@PersonId, @StudentNumber)",
                    new SqlParameter("@PersonId", id),
                    new SqlParameter("@StudentNumber", "The Student's Number"));

对我来说,这有点像“黑客”,但就目前而言,这就足够了。欢迎评论。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多