entity-framework/ef6/modeling/designer/inheritance/tph.md
This step-by-step walkthrough shows how to implement table-per-hierarchy (TPH) inheritance in your conceptual model with the Entity Framework Designer (EF Designer). TPH inheritance uses one database table to maintain data for all of the entity types in an inheritance hierarchy.
In this walkthrough we will map the Person table to three entity types: Person (the base type), Student (derives from Person), and Instructor (derives from Person). We'll create a conceptual model from the database (Database First) and then alter the model to implement the TPH inheritance using the EF Designer.
It is possible to map to a TPH inheritance using Model First but you would have to write your own database generation workflow which is complex. You would then assign this workflow to the Database Generation Workflow property in the EF Designer. An easier alternative is to use Code First.
Table-per-Type (TPT) is another type of inheritance in which separate tables in the database are mapped to entities that participate in the inheritance. For information about how to map Table-per-Type inheritance with the EF Designer, see EF Designer TPT Inheritance.
Table-per-Concrete Type Inheritance (TPC) and mixed inheritance models are supported by the Entity Framework runtime but are not supported by the EF Designer. If you want to use TPC or mixed inheritance, you have two options: use Code First, or manually edit the EDMX file. If you choose to work with the EDMX file, the Mapping Details Window will be put into “safe mode” and you will not be able to use the designer to change the mappings.
To complete this walkthrough, you will need:
The Entity Designer, which provides a design surface for editing your model, is displayed. All the objects that you selected in the Choose Your Database Objects dialog box are added to the model.
That is how the Person table looks in the database.
The Person table has the Discriminator column, which can have one of two values: “Student” and “Instructor”. Depending on the value the Person table will be mapped to the Student entity or the Instructor entity. The Person table also has two columns, HireDate and EnrollmentDate, which must be nullable because a person cannot be a student and an instructor at the same time (at least not in this walkthrough).
Two new entity types were added to the design surface. An arrow points from the new entity types to the Person entity type; this indicates that Person is the base type for the new entity types.
Right-click the Instructor and select Table Mapping. The Instructor entity is selected in the Mapping Details window.
Click <Add a Table or View> in the Mapping Details window. The <Add a Table or View> field becomes a drop-down list of tables or views to which the selected entity can be mapped.
Select Person from the drop-down list.
The Mapping Details window is updated with default column mappings and an option for adding a condition.
Click on <Add a Condition>. The <Add a Condition> field becomes a drop-down list of columns for which conditions can be set.
Select Discriminator from the drop-down list.
In the Operator column of the Mapping Details window, select = from the drop-down list.
In the Value/Property column, type Instructor. The end result should look like this:
Repeat these steps for the Student entity type, but make the condition equal to Student value.
The reason we wanted to remove the Discriminator property, is because you cannot map a table column more than once. This column will be used for conditional mapping, so it cannot be used for property mapping as well. The only way it can be used for both, if a condition uses an Is Null or Is Not Null comparison.
Table-per-hierarchy inheritance is now implemented.
Open the Program.cs file where the Main method is defined. Paste the following code into the Main function. The code executes three queries. The first query brings back all Person objects. The second query uses the OfType method to return Instructor objects. The third query uses the OfType method to return Student objects.
using (var context = new SchoolEntities())
{
Console.WriteLine("All people:");
foreach (var person in context.People)
{
Console.WriteLine(" {0} {1}", person.FirstName, person.LastName);
}
Console.WriteLine("Instructors only: ");
foreach (var person in context.People.OfType<Instructor>())
{
Console.WriteLine(" {0} {1}", person.FirstName, person.LastName);
}
Console.WriteLine("Students only: ");
foreach (var person in context.People.OfType<Student>())
{
Console.WriteLine(" {0} {1}", person.FirstName, person.LastName);
}
}