【问题标题】:Mapping inheritance in EntityFramework CoreEntityFramework Core 中的映射继承
【发布时间】:2016-10-20 12:26:31
【问题描述】:

我正在使用 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,如何对多种类型使用discriminator field?

    b.如果是 TPT,在 EF Core 1.0 中如何使用这个策略?

  2. 它是业务模型的最佳架构吗?

感谢您的关注和合作

【问题讨论】:

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


    【解决方案1】:

    我在玩 EF 核心时简要研究了这一点,已经习惯了 EF6,并且广泛使用了 table-per-type。

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

    【讨论】:

    • 感谢您的回答 Alex,但我的意图是将子类视为一个独特的人,以便在一个独特的点更改诸如“联系人信息”之类的值。
    猜你喜欢
    • 2013-03-04
    • 2014-09-24
    • 2015-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-07
    • 2011-11-22
    • 2010-11-25
    相关资源
    最近更新 更多