Данное руководство устарело. Актуальное руководство: Руководство по Entity Framework Core 7
Начиная с версии 5.0 в EntityFramework Core стал доступен подход TPT или Table Per Type. Он позволяет выделить для каждого класса из одной иерархии классов в базе данных отдельную таблицу. Для его реализации мы можем использовать два способа: через атрибуты или через Fluent API.
С помощью атрибута [Table] мы можем указать для каждого класса свою таблицу:
using System.ComponentModel.DataAnnotations.Schema; using Microsoft.EntityFrameworkCore; namespace HelloApp { public class User { public int Id { get; set; } public string Name { get; set; } } [Table("Employees")] public class Employee : User { public int Salary { get; set; } } [Table("Managers")] public class Manager : User { public string Departament { get; set; } } 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;"); } } }
В этом случае в бд будут создаваться следующие три таблицы:
CREATE TABLE [dbo].[Users] ( [Id] INT IDENTITY (1, 1) NOT NULL, [Name] NVARCHAR (MAX) NULL, CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED ([Id] ASC) ); CREATE TABLE [dbo].[Employees] ( [Id] INT NOT NULL, [Salary] INT NOT NULL, CONSTRAINT [PK_Employees] PRIMARY KEY CLUSTERED ([Id] ASC), CONSTRAINT [FK_Employees_Users_Id] FOREIGN KEY ([Id]) REFERENCES [dbo].[Users] ([Id]) ); CREATE TABLE [dbo].[Managers] ( [Id] INT NOT NULL, [Departament] NVARCHAR (MAX) NULL, CONSTRAINT [PK_Managers] PRIMARY KEY CLUSTERED ([Id] ASC), CONSTRAINT [FK_Managers_Users_Id] FOREIGN KEY ([Id]) REFERENCES [dbo].[Users] ([Id]) );
Здесь мы видим, что все свойства базового класса User будут храниться в одной таблице, а те данные, которые относятся только к производным классам, хранятся в отдельных таблицах.
Пример использования:
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
Также мы можем настроить TPT с помощью метода ToTable() во Fluent API:
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; } } 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;"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Employee>().ToTable("Employees"); modelBuilder.Entity<Manager>().ToTable("Managers"); } }
В остальном применение классов будет аналогично примеру с атрибутом [Table]
.