Course contentsShow
← C#
Lesson 1135 of 1,90810. Entity Framework Core ModelingFree lesson

Entity Inheritance Refactoring

Migrate existing schemas between TPH and TPT inheritance strategies safely.

In this lesson, you will learn how to safely transition your Entity Framework Core inheritance strategy between Table-Per-Hierarchy (TPH) and Table-Per-Type (TPT) without losing data integrity.

The Challenge of Strategy Switching

When you initially model a class hierarchy, you might choose TPH, where all entities in the hierarchy are stored in a single table distinguished by a discriminator column. As your system grows, you might find that TPH results in too many null columns for specialized subclasses, prompting a shift to TPT, where each class gets its own table. Migrating between these strategies requires careful orchestration to ensure your database schema evolves without orphaning records.

Moving from TPH to TPT

If you are moving from TPH to TPT, you are effectively "decomposing" a single wide table into a normalized set of linked tables. EF Core does not perform this migration automatically; you must bridge the gap manually through your migration files.

  1. Create the new tables: Define the specialized tables for your subclasses in your DbContext using modelBuilder.Entity<Subclass>().ToTable("Subclasses").
  2. Data Migration: Before dropping the old columns, create a migration that copies the data from the single TPH table into the new TPT structure. Use migrationBuilder.Sql to perform an INSERT INTO ... SELECT operation:
    migrationBuilder.Sql("INSERT INTO Subclasses (Id, SpecificField) SELECT Id, SpecificField FROM MainTable WHERE Discriminator = 'Subclass'");
    
  3. Cleanup: Once the data is verified in the new tables, generate a subsequent migration to remove the redundant columns from the original table.

Moving from TPT to TPH

Reversing this requires the opposite: merging the specialized tables back into a single table. You must add the discriminator column to your base table, perform a JOIN to pull the specialized data back into the base table, and then drop the now-empty subclass tables.

Always test these transitions against a snapshot of your production data. Because Database Migration Snapshots track the result of your model, ensure your snapshots remain synchronized by running dotnet ef migrations add immediately after altering your DbContext mappings.

Key Takeaway: Migrating between TPH and TPT requires manual SQL data migration steps within your EF Core migrations to ensure data is moved to the new structure before the old schema is destroyed.