【问题标题】:Entity Framework TPT - Insert sub-type for existing base-type实体框架 TPT - 为现有基本类型插入子类型
【发布时间】:2018-07-21 08:20:55
【问题描述】:

我遇到了一个问题,我想为一个子类型插入一条记录,并为基类型插入一条现有记录。

基本类型可以是由以下描述的 Person 实体:

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

具有以下描述的子类型:(更新:这里也没有真正的 Id 字段)

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

我的创作可以这样说明:

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

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

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

-----------             -------------
| Persons |             | Employees |
-----------             -------------
| Id      |   1 to 0..1 | Id        |
-----------             -------------

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

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

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

【问题讨论】:

  • EF 无法做到这一点。您正在解释的场景更像是从 Person 到 Employee 的 1 到 0.1,而不是继承。
  • 通过使用TPT,你只是说你想在一个表中插入不同的对象,这些对象有一些共同的字段。实体框架将创建一个表,其中每个字段有一列,最后一列鉴别器告诉您该字段中存储了哪种对象。您不能将一个对象转换为另一个对象。
  • @IvanStoev 是的,您对关系为 1 到 0...1 的解释是正确的。谢谢!我会更新这个问题。你确定这不能用 EF 完成吗?
  • 当被建模为继承时,实体要么是Person要么Employee。 IE。您不能插入代表相同Person 的第二条记录。如果Person 应该变成Employee,则必须删除Person 并插入新的Employee

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


【解决方案1】:

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

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();

【讨论】:

    【解决方案2】:

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

    如果允许在添加新项目时提供 Id,那么您可以创建两个不同的员工,它们都指向同一个人。更改一名员工的生日将导致更改另一名员工的生日。你肯定不想要这个。

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

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

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

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

    【讨论】:

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