#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; }
}
Бизнес-логический
В этом случае пользователи, сотрудники и заказчики являются людьми, однако сотрудники и заказчики также являются пользователями, а также сотрудник может стать клиентом. И каждый тип используется в разных контекстах приложения.
Я реализовал этот способ, чтобы без необходимости не использовать значения из других контекстов приложения.
Вопросы:
-
Каковы наилучшие методы отображения модели базы данных? Иерархия типов для каждого типа или таблица для каждого типа? Учитывая, что для многих TPT обычно является антишаблоном и впоследствии приводит к значительным проблемам с производительностью. согласно проблемам EF # 2266
a. Если TPH, как использовать поле дискриминатора для многих типов?
б. Если TPT, как использовать эту стратегию в EF Core 1.0?
- Является ли это лучшей архитектурой для бизнес-модели?
благодарим вас за внимание и сотрудничество
Ответ №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. Спасибо за ваш ответ, Алекс, но я намерен рассматривать подклассы как уникального пользователя, чтобы при изменении значений, таких как «контактная информация», в одной уникальной точке.