在EntityFramework Core中映射继承

时间:2016-10-20 12:26:31

标签: entity-framework design-patterns orm entity-framework-core ef-fluent-api

我正在使用EntityFramework Core,Code First和Fluent Api来定义模型数据库,并且我遵循了地图继承策略的情况:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class User : Person
{
    public string UserName { get; set; }
    public string Password { get; set; }
}

public class Employee : Person
{
    public decimal Salary { get; set; }
}

public class Customer:Person
{
    public long DiscountPoints { get; set; }
}

商业逻辑

在这种情况下,用户,员工和客户都是人,但员工和客户也是用户,员工也可以成为客户。每种类型都用于不同的应用环境。

我以这种方式实现了不必要地使用来自其他应用程序上下文的值。

问题:

  1. 映射数据库模型的最佳做法是什么?每个层次的类型或每个类型的表?考虑到对于许多人而言, TPT通常是一种反模式,并在以后导致严重的性能问题。根据EF issues #2266

    一个。如果是TPH,如何对多种类型使用鉴别器字段?

    湾如果是TPT,如何在EF Core 1.0中使用这种策略?

  2. 这是商业模式的最佳架构吗?
  3. 感谢您的关注与合作

1 个答案:

答案 0 :(得分:1)

我在使用EF核心时已经习惯了这一点,已经习惯了EF6,并且广泛使用了每种类型的表格。

1a)我的经验是,如果你只是将每个实体类型作为DbSet添加到上下文中,默认映射就会很好。如有必要,您可以在DbContext中的OnModelBuilding覆盖中配置它:

protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>()
            .HasDiscriminator<string>("person_type")
            .HasValue<Employee>("employee")
            .HasValue<Customer>("customer");
    }

1b)目前您不能将TPT与EF核心一起使用。它计划在将来的版本中使用,目前在EF core roadmap

列为高优先级

2)如果我们采用严格的DDD原则,那么业务层应尽可能地模拟/镜像现实域,而不受应用程序数据层的影响。就个人而言,我认为上面提到的继承是对现实生活情况的良好反映。然而,EF核心团队似乎处于“赞成组合而不是继承”阵营,这可能导致域名模型如:

public class Person
{
  public int Id { get; set; }
  public string Name { get; set; }
}

public class User
{
  public int Id {get;set;}
  public Person Person {get; set;}
  public int PersonId {get;set;}
  public string UserName { get; set; }
  public string Password { get; set; }
}

public class Employee
{
  public int Id {get; set;}
  public User User {get; set;}
  public int UserId {get;set;}
  public decimal Salary { get; set; }
}

public class Customer
{
  public int Id {get;set;}
  public User User {get; set;}
  public int UserId {get;set;}
  public long DiscountPoints { get; set; }
}

然后,这些权利将存储在单独的表中,并在它们之间具有外键关系。将员工转变为客户也需要创建一个与员工具有相同用户财产的新客户,例如

public void CreateCustomerFromEmployee(int employeeId) {
  var employee = context.Employees.Where(e => e.Id == employeeId).SingleOrDefault();

  context.Customers.Add(new Customer() 
    {
        UserId = employee.UserId,
        DiscountPoints = 0
    });

  context.SaveChanges();
}