Данное руководство устарело. Актуальное руководство: Руководство по Entity Framework Core 7
По умолчанию при работе с цепочками наследования классов Entity Framework Core использует подход TPH (Table Per Hierarchy / Таблица на одну иерархию классов). При использовании данного подхода TPH для всех классов из одной иерархии в базе данных создается одна таблица. А чтобы определить, к какому именно классу относится строка в таблице, в этой же таблице создается дополнительный столбец - дискриминатор.
Например, у нас есть следующая иерархия классов:
public class User { public int Id { get; set; } public string Name { get; set; } } public class Employee : User { public int Salary { get; set; } } public class Manager : User { public string Departament { get; set; } }
Есть базовый класс User, который представляет пользователя и от которого наследуются класс Employee - класс работника и Manager - класс управляющего.
Определим контекст данных:
using Microsoft.EntityFrameworkCore; public class ApplicationContext : DbContext { public DbSet<User> Users { get; set; } public DbSet<Employee> Employees { get; set; } public DbSet<Manager> Managers { get; set; } public ApplicationContext() { Database.EnsureDeleted(); Database.EnsureCreated(); } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=inheritedb;Trusted_Connection=True;"); } }
Чтобы включить все классы из иерархии наследования в базу данных, в контексте данных для каждого типа должен быть определен набор DbSet.
Сгенерированная база данных будет содержать для всех типов одну таблицу Users. Кроме всех свойств классов User, Employee и Manager здесь также появляется еще один столбец - Discriminator. Он имеет тип nvarchar (то есть строка), а в качестве значения он принимает название класса, к которому относится строка в таблице. В итоге в бд будет создаваться следующая таблица:
CREATE TABLE [dbo].[Users] ( [Id] INT IDENTITY (1, 1) NOT NULL, [Name] NVARCHAR (MAX) NULL, [Discriminator] NVARCHAR (MAX) NOT NULL, [Salary] INT NULL, [Departament] NVARCHAR (MAX) NULL, CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([Id] ASC) );
Пример использования:
using (ApplicationContext db = new ApplicationContext()) { User user1 = new User { Name = "Tom" }; User user2 = new User { Name = "Bob" }; db.Users.Add(user1); db.Users.Add(user2); Employee employee = new Employee { Name = "Sam", Salary = 500 }; db.Employees.Add(employee); Manager manager = new Manager { Name = "Robert", Departament = "IT" }; db.Managers.Add(manager); db.SaveChanges(); var users = db.Users.ToList(); Console.WriteLine("Все пользователи"); foreach (var user in users) { Console.WriteLine(user.Name); } Console.WriteLine("\n Все работники"); foreach (var emp in db.Employees.ToList()) { Console.WriteLine(emp.Name); } Console.WriteLine("\nВсе менеджеры"); foreach (var man in db.Managers.ToList()) { Console.WriteLine(man.Name); } }
Консольный вывод:
Все пользователи Tom Bob Sam Robert Все работники Sam Все менеджеры Robert
И в итоге данные таблицы Users в бд будут выглядеть следующим образом:
При необходимости мы даже можем добавить в класс User свойство Discriminator:
public class User { public int Id { get; set; } public string Name { get; set; } public string Discriminator { get; set; } }
Однако надо учитывать, что на уровне базы данных соответствующий столбец установлен как readonly, то есть только для чтения. Поэтому мы сможем только получать его значения, но не изменять.