首页 > 解决方案 > 首先在实体框架代码中转换为派生类型

问题描述

我在 MVC C# 中使用 EntityFramework 6,代码优先。我有几个看起来像这样的简单实体:

public class Person {
    public int Id { get; set; }
    public string FirstName {get; set;}
    public string LastName {get;set;}
    public string EmailAddress { get; set; }
}

public class Employee : Person {
    public DateTime DateStarted { get; set; }
    public ICollection<Roles> Roles { get; set; }
}

你明白了。我遇到的问题是当数据库中的现有人员成为员工时。所以我已经有一个与他们关联的 Person 记录,但现在他们已经成为员工,所以现在他们需要一个 Employee 记录。我看不到任何方法可以用 EF 做到这一点。我希望能够做的事情如下:

Person person = GetPerson();
Employee employee = (employee)person;
context.Employees.Add(employee);
SaveChanges();

但是 C# 不允许你将基类型转换为子类型,所以我不能这样做,如果我创建一个新的 Employee 记录,那么 Entity 框架也会创建一个新的 Person 记录。有谁知道实现这一目标的简单方法?我认为设计是正确的,因为 Employee是一个Person,所以在这种情况下,对组合的继承肯定是正确的选择。

我可以自己编写一些 SQL 来将我需要的记录插入到 Employee 表中,或者我可以删除旧记录并用新记录替换它(这会带来一大堆外键问题),但如果我这样做我接受 Entity Framework 基本上让我失望了一个非常简单和常见的要求。有没有办法解决这个问题?

提前感谢您的任何答案。

标签: inheritanceormcastingentity-framework-6ef-code-first

解决方案


您的问题的原因是表格及其列对您来说并不是很清楚。

数据库中的每个对象都有一个用于标识对象属性的主键。对象的属性可能会改变,对象所代表的事物将是相同的事物。

一个人可能会改变他的地址,他甚至可能改变他的名字、性别或生日,因为数据库仍然是同一个人。只有你改变他的Id,它才真正成为一个不同的人。

显然你有Persons那还不是一个Employee. 如果Person开始为你工作,这是否意味着他变得与众不同Person?他的身份应该改变吗?

您可以决定,如果PersonID 为 10Employee的对象变为 ,则创建EmployeeID 为 10 的对象,如果这Person也变为对象,则Customer创建CustomerID 为 10 的对象。如果Employee停止为您工作,则删除EmployeeID 为 10 的对象并保留和ID 为 10 PersonCustomer

尽管这可行,但它需要您自己进行 ID 编号。数据库很难检查你是否做了非法的事情,比如杀死一个Person仍然是你的Employees.

与其使用一个 ID 来识别 your Employee、 yourPerson和 your Customer,不如给它们自己的主键。给Employee他们Customer一个外键Person。事实上, Person 更像是PersonData. 员工不是个人,员工有个人数据

class PersonData // your old Person
{
     public int Id {get; set;}
     ...
}
class Employee
{
    public int Id {get; set;}

    // every Employee has PersonData using foreign key
    public int PersonDataId {get; set;}
    public virtual PersonData PersonData {get; set;}
    ...
}
class Customer
{
    public int Id {get; set;}

    // every Customerhas PersonData using foreign key
    public int PersonDataId {get; set;}
    public virtual PersonData PersonData {get; set;}
    ...
}

这不会改变您的三个表:每个表都有一个名为 Id 的主键。员工和客户具有 PersonData 表的外键。不过,如果您已经有一个数据库,您可能需要一些流畅的 API 来匹配列名(不是真正的代码优先吗?)。

回到你的问题

你有一个现有的 Person,由他的 Id 标识,他开始为你工作:你只需添加一个新的 Employee,这个 Person 的外键

var addedEmployee = myDbcontext.Employees.Add(new Employee()
{
     PersonId = PersonId,
     ...
})

如果这个人也有不同的工作,只需添加一个具有相同 PersonId 的新员工。如果他决定退出旧功能:删除旧员工,但保持新员工不变。如果另一个 Person 将执行此 Employee 的功能:只需更改 PersonId。如果员工也成为客户:添加一个 PersonId 等于员工的 PersonId 的新客户。

恕我直言,此解决方案比您尝试保持 Employee / Customer / Person 的主键值相同的解决方案更简单、更自然。如果您仍然想要这个,请阅读Entity Framework Table Per Type (TPT)


推荐阅读