Отображение наследования в ядре EntityFramework

#entity-framework #design-patterns #orm #entity-framework-core #ef-fluent-api

#entity-framework #шаблоны проектирования #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 # 2266

    a. Если TPH, как использовать поле дискриминатора для многих типов?

    б. Если TPT, как использовать эту стратегию в EF Core 1.0?

  2. Является ли это лучшей архитектурой для бизнес-модели?

благодарим вас за внимание и сотрудничество

Ответ №1:

Я кратко рассмотрел это, когда играл с EF core, поскольку привык к EF6 и широко использовал таблицу для каждого типа.

1a) Мой опыт показывает, что сопоставления по умолчанию работают довольно хорошо, если вы просто добавляете каждый тип объекта в качестве набора баз данных в свой контекст. При необходимости вы можете настроить это в переопределении OnModelBuilding в вашем DbContext:

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

1b) В настоящее время вы не можете использовать TPT с ядром EF. Это запланировано для будущих выпусков и в настоящее время указано в качестве высокоприоритетного в дорожной карте EF core

2) Если мы используем строгие принципы DDD, то бизнес-уровень должен моделировать / отражать реальный домен как можно точнее и не зависеть от уровня данных приложения. Лично я думаю, что наследование, изложенное вами выше, является хорошим отражением реальной ситуации. Однако команда EF core, похоже, придерживается позиции «предпочтение композиции перед наследованием», что может привести к созданию таких моделей предметной области, как:

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

Комментарии:

1. Спасибо за ваш ответ, Алекс, но я намерен рассматривать подклассы как уникального пользователя, чтобы при изменении значений, таких как «контактная информация», в одной уникальной точке.