Implementing Table-per-Hierarchy Inheritance
In the previous tutorial you worked with related data by adding and deleting relationships and by adding a new entity that had a relationship to an existing entity. This tutorial will show you how to implement inheritance in the data model.
In object-oriented programming, you can use inheritance to make it easier to work with related classes. For example, you could create
Student classes that derive from a
Person base class. You can create the same kinds of inheritance structures among entities in the Entity Framework.
In this part of the tutorial, you won’t create any new web pages. Instead, you’ll add derived entities to the data model and modify existing pages to use the new entities.
Table-per-Hierarchy versus Table-per-Type Inheritance
A database can store information about related objects in one table or in multiple tables. For example, in the
School database, the
Person table includes information about both students and instructors in a single table. Some of the columns apply only to instructors (
HireDate), some only to students (
EnrollmentDate), and some to both (
You can configure the Entity Framework to create
Student entities that inherit from the
Person entity. This pattern of generating an entity inheritance structure from a single database table is called table-per-hierarchy (TPH) inheritance.
For courses, the
School database uses a different pattern. Online courses and onsite courses are stored in separate tables, each of which has a foreign key that points to the
Course table. Information common to both course types is stored only in the
You can configure the Entity Framework data model so that
OnsiteCourse entities inherit from the
Course entity. This pattern of generating an entity inheritance structure from separate tables for each type, with each separate table referring back to a table that stores data common to all types, is called table per type (TPT) inheritance.
TPH inheritance patterns generally deliver better performance in the Entity Framework than TPT inheritance patterns, because TPT patterns can result in complex join queries. This walkthrough demonstrates how to implement TPH inheritance. You’ll do that by performing the following steps:
Studententity types that derive from
- Move properties that pertain to the derived entities from the
Personentity to the derived entities.
- Set constraints on properties in the derived types.
- Make the
Personentity an abstract entity.
- Map each derived entity to the
Persontable with a condition that specifies how to determine whether a
Personrow represents that derived type.
Adding Instructor and Student Entities
Open the SchoolModel.edmx file, right-click an unoccupied area in the designer, select Add, then select Entity.
In the Add Entity dialog box, name the entity
Instructor and set its Base type option to
Click OK. The designer creates an
Instructor entity that derives from the
Person entity. The new entity does not yet have any properties.
Repeat the procedure to create a
Student entity that also derives from
Only instructors have hire dates, so you need to move that property from the
Person entity to the
Instructor entity. In the
Person entity, right-click the
HireDate property and click Cut. Then right-click Properties in the
Instructor entity and click Paste.
The hire date of an
Instructor entity cannot be null. Right-click the
HireDate property, click Properties, and then in the Properties window change
Repeat the procedure to move the
EnrollmentDate property from the
Person entity to the
Student entity. Make sure that you also set
False for the
Now that a
Person entity has only the properties that are common to
Student entities (aside from navigation properties, which you’re not moving), the entity can only be used as a base entity in the inheritance structure. Therefore, you need to ensure that it’s never treated as an independent entity. Right-click the
Person entity, select Properties, and then in the Properties window change the value of the Abstract property to True.
Mapping Instructor and Student Entities to the Person Table
Now you need to tell the Entity Framework how to differentiate between
Student entities in the database.
Instructor entity and select Table Mapping. In the Mapping Details window, click Add a Table or View and select Person.
Click Add a Condition, and then select HireDate.
Change Operator to Is and Value / Property to Not Null.
Repeat the procedure for the
Students entity, specifying that this entity maps to the
Person table when the
EnrollmentDate column is not null. Then save and close the data model.
Build the project in order to create the new entities as classes and make them available in the designer.
Using the Instructor and Student Entities
When you created the web pages that work with student and instructor data, you databound them to the
Person entity set, and you filtered on the
EnrollmentDate property to restrict the returned data to students or instructors. However, now when you bind each data source control to the
Person entity set, you can specify that only
Instructor entity types should be selected. Because the Entity Framework knows how to differentiate students and instructors in the
Person entity set, you can remove the
Where property settings you entered manually to do that.
In the Visual Studio Designer, you can specify the entity type that an
EntityDataSource control should select in the EntityTypeFilter drop-down box of the
Configure Data Source wizard, as shown in the following example.
And in the Properties window you can remove
Where clause values that are no longer needed, as shown in the following example.
However, because you’ve changed the markup for
EntityDataSource controls to use the
ContextTypeName attribute, you cannot run the Configure Data Source wizard on
EntityDataSource controls that you’ve already created. Therefore, you’ll make the required changes by changing markup instead.
Open the Students.aspx page. In the
StudentsEntityDataSource control, remove the
Where attribute and add an
EntityTypeFilter="Student" attribute. The markup will now resemble the following example:
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" EntitySetName="People" EntityTypeFilter="Student" Include="StudentGrades" EnableDelete="True" EnableUpdate="True" OrderBy="it.LastName" > </asp:EntityDataSource>
EntityTypeFilter attribute ensures that the
EntityDataSource control will select only the specified entity type. If you wanted to retrieve both
Instructor entity types, you would not set this attribute. (You have the option of retrieving multiple entity types with one
EntityDataSource control only if you’re using the control for read-only data access. If you’re using an
EntityDataSource control to insert, update, or delete entities, and if the entity set it’s bound to can contain multiple types, you can only work with one entity type, and you have to set this attribute.)
Repeat the procedure for the
SearchEntityDataSource control, except remove only the part of the
Where attribute that selects
Student entities instead of removing the property altogether. The opening tag of the control will now resemble the following example:
<asp:EntityDataSource ID="SearchEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" EntitySetName="People" EntityTypeFilter="Student" Where="it.FirstMidName Like '%' + @StudentName + '%' or it.LastName Like '%' + @StudentName + '%'" >
Run the page to verify that it still works as it did before.
Update the following pages that you created in earlier tutorials so that they use the new
Instructor entities instead of
Person entities, then run them to verify that they work as they did before:
- In StudentsAdd.aspx, add
StudentsEntityDataSourcecontrol. The markup will now resemble the following example:
<asp:EntityDataSource ID="StudentsEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" EntitySetName="People" EntityTypeFilter="Student" EnableInsert="True" </asp:EntityDataSource>
- In About.aspx, add
StudentStatisticsEntityDataSourcecontrol and remove
Where="it.EnrollmentDate is not null". The markup will now resemble the following example:
<asp:EntityDataSource ID="StudentStatisticsEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" EntitySetName="People" EntityTypeFilter="Student" Select="it.EnrollmentDate, Count(it.EnrollmentDate) AS NumberOfStudents" OrderBy="it.EnrollmentDate" GroupBy="it.EnrollmentDate" > </asp:EntityDataSource>
- In Instructors.aspx and InstructorsCourses.aspx, add
InstructorsEntityDataSourcecontrol and remove
Where="it.HireDate is not null". The markup in Instructors.aspxnow resembles the following example:
<asp:EntityDataSource ID="InstructorsEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="false" EntitySetName="People" EntityTypeFilter="Instructor" Include="OfficeAssignment" EnableUpdate="True"> </asp:EntityDataSource>
The markup in InstructorsCourses.aspx will now resemble the following example:
<asp:EntityDataSource ID="InstructorsEntityDataSource" runat="server" ContextTypeName="ContosoUniversity.DAL.SchoolEntities" EnableFlattening="False" EntitySetName="People" EntityTypeFilter="Instructor" Select="it.LastName + ',' + it.FirstMidName AS Name, it.PersonID"> </asp:EntityDataSource>
As a result of these changes, you’ve improved the Contoso University application’s maintainability in several ways. You’ve moved selection and validation logic out of the UI layer (.aspx markup) and made it an integral part of the data access layer. This helps to isolate your application code from changes that you might make in the future to the database schema or the data model. For example, you could decide that students might be hired as teachers’ aids and therefore would get a hire date. You could then add a new property to differentiate students from instructors and update the data model. No code in the web application would need to change except where you wanted to show a hire date for students. Another benefit of adding
Student entities is that your code is more readily understandable than when it referred to
Person objects that were actually students or instructors.
You’ve now seen one way to implement an inheritance pattern in the Entity Framework. In the following tutorial, you’ll learn how to use stored procedures in order to have more control over how the Entity Framework accesses the database.