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.
- Create the new tables: Define the specialized tables for your subclasses in your
DbContextusingmodelBuilder.Entity<Subclass>().ToTable("Subclasses"). - 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.Sqlto perform anINSERT INTO ... SELECToperation:migrationBuilder.Sql("INSERT INTO Subclasses (Id, SpecificField) SELECT Id, SpecificField FROM MainTable WHERE Discriminator = 'Subclass'"); - 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.