Используем Дискриминатор в Entity Framework
Допустим вы создаёте систему управления школой, в которой есть разные типы сотрудников Учитель и Администратор. Они имеют как общие свойства (Id, Имя, Дата найма), так и уникальные (например, Предмет у учителя и Отдел у администратора).
public class StaffЕсли вы хотите получить всех сотрудников, вам нужно сделать отдельные свойства контекста и запросы для учителей и администраторов:
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime HireDate { get; set; }
}
public class Teacher : Staff
{
public string Subject { get; set; }
}
public class Administrator : Staff
{
public string Department { get; set; }
}
var teachers = context.Teachers.ToList();Это требует не только больше кода, но и ручного управления этими отношениями. Для общих операций придётся дважды написать один и тот же код для учителей и администраторов. Также может быть сложнее поддерживать согласованность данных, особенно если в будущем появится больше типов сотрудников.
var admins = context.Administrators.ToList();
Столбец-дискриминатор в используется в сценариях наследования Table-per-Hierarchy, для представления отношений наследования в реляционной БД. Он предполагает использование одной таблицы для представления всех различных типов в иерархии со специальным столбцом (дискриминатор) для различения типов.
public class SchoolContext : DbContextВ методе OnModelCreating мы вызываем HasDiscriminator для настройки столбца-дискриминатора, задавая ему имя (StaffType) и тип. Метод HasValue позволяет указать, какие значения следует использовать для представления каждого типа в иерархии.
{
public DbSet<Staff> StaffMembers { get; set; }
protected override void OnModelCreating(ModelBuilder mb)
{
mb.Entity<Staff>()
.HasDiscriminator<string>("StaffType")
.HasValue<Teacher>("Teacher")
.HasValue<Administrator>("Administrator");
}
}
Теперь в запросах StaffMembers EF Core будет использовать столбец-дискриминатор для правильного создания экземпляров Teacher или Administrator в зависимости от ситуации.
var staff = context.StaffMembers.ToList();Также можно добавлять экземпляры этих классов, и EF Core автоматически задаст нужное значение дискриминатора при вставке строки в БД.
foreach (var s in staff)
{
switch (s)
{
case Teacher t:
…
case Administrator a:
…
}
}
Преимущества
1. Простота. Одна таблица для всей иерархии может упростить понимание и поддержку схемы БД.
2. Повторное использование кода. Общие операции для всех типов используют один и тот же код.
3. Производительность. Часто можно получить данные с меньшим числом обращений к БД.
Недостатки
1. Неиспользуемое пространство. В одной таблице должны быть столбцы для всех свойств всех типов в иерархии, даже если некоторые типы не используют определенные свойства.
2. Ограниченная гибкость. Подход может стать сложным, если у вас сложная иерархия наследования или если нужно смоделировать отношения «многие-ко-многим» между различными типами.
3. Целостность данных. С одной таблицей сложнее обеспечить целостность данных на уровне БД. Например, вы не можете запретить строке, которая должна представлять учителя, иметь значение в столбце «Отдел» (который должен быть специфичным для администраторов).
Источник: https://stefandjokic.tech/blog/