实体框架TPT - 为现有基础类型插入子类型

时间:2018-02-10 19:45:12

标签: c# sql-server entity-framework-6 ef-code-first poco

我遇到了一个问题,我想插入一个子类型的记录,其中包含基类型的现有记录。

base-type可以是由以下内容描述的Person实体:

std::make_index_sequence

用下面描述的子类型:(更新:在这里也确实有Id字段)

public class Person {
    [Key, Column("Id"), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public DateTime? BirthDate { get; set; }
}

我的创作可以通过以下方式说明:

public class Employee : Person {
    public DateTime HireDate { get; set; }
}

SQL Server数据库有两个表,Persons和Employees,它们在Id字段和Person.Id之间有一个外键是自动生成的。

var employee = new Employee
    {
       Id = 1,
       HireDate = DateTime.Now
    });

context.Employees.Add(employee);
context.SaveChanges();

虽然这就像EF-Code First,但是我通过编写POCO手动实现它,然后手动在SSMS中创建表。

现在,有一个Id = 1的人事记录。当我尝试创建一个新的Employee,并将Id分配为1时,Entity Framework忽略我的Id分配并使用生成的Id插入一个全新的Person记录从那里分配员工表的Id。

如何使用/关联现有人员记录创建员工记录?我真的想探索这个想法。但是,如果它不可能:有什么替代方案呢?

2 个答案:

答案 0 :(得分:0)

忘掉这里的继承,并将其建模为一对一的关系。

public class Person
{
    public int Id { get; set; }
    public DateTime? BirthDate { get; set; }
}

public class Employee
{
    public int Id { get; set; }
    public DateTime HireDate { get; set; }
    public Person Person { get; set; }
}


var person = new Person { BirthDate = DateTime.Now };

var employee = new Employee
{
    Person = person,
    HireDate = DateTime.Now
};

context.Employees.Add(employee);
context.SaveChanges();

答案 1 :(得分:0)

因为您使用函数Add,所以您通知您的DbContext新的员工正在插入数据库,而您的DbContext应该为主键生成新值您的新员工。

如果在添加新项目时允许提供ID,则可以创建两个不同的Employees,两者都引用同一个Person。更改一个员工的生日将导致更改另一个员工的生日。当然你不会想要这个。

因此:当向DbSet添加项目时,DbContext会将其转换为SQL Insert语句,忽略您提供的Id。

  

如何使用现有人员记录创建员工记录?

您指定员工“是”一个人,而不是“拥有”一个人。如果创建新的Employee对象,则还会创建新的Person-data。这是面向对象的设计。它与数据库无关。如果您想要一个具有相同Person属性值的新Employee对象,则必须复制Person属性。

如果您希望概念拥有一个没有新Person的新Employee,那么您不应该派生,而是聚合。对于Employee-Person来说,这是一个相当奇怪的概念,但对于Employee-Address来说,这是很正常的:一个员工住在一个地址上。新员工可能住在同一个地址上。您可以创建一个新的员工,并为其提供原始员工的相同地址(不是副本!)。结果是你将拥有两个员工,两个员工都有相同的地址。您甚至可以向其中一个员工提供不同的地址,这不会影响其他员工的地址。