How to Work With Inheritance in Entity Framework Core

April 5th, 2022

Entity Framework Core from Microsoft is a cross-platform, lightweight, and flexible version of its predecessor, Entity Framework. EF Core is an object-relational mapper (ORM) tool that offers a standardized way of storing and retrieving data to and from diverse data sources.

By programming against a conceptual rather than a relational model. As a result, there is no impedance mismatch between how data is represented in the application and how it is stored in the database.

Inheritance is a feature of Object-Oriented Programming that enables you to create subclasses from a base class thereby extending the features of the base class. Entity Framework Core provides excellent support for inheritance. This article talks about how we can implement inheritance in Entity Framework Core. We’ll take advantage of Entity Developer to talk to the database.

Pre-requisites

To be able to work with the code examples demonstrated in this article, you should have the following installed in your system:

  • Visual Studio 2019 Community Edition (download)
  • dotConnect for PostgreSQL (download)
  • Entity Developer

You can download a copy of Entity Developer (trial version) from here: https://www.devart.com/entitydeveloper/download.html.

Create a Database

Now that the ASP.NET Core Web API project has been created in Visual Studio 2019; the next step is to create the database. Note that for the sake of simplicity we’ll use a database with a few two tables with simple designs in this example. Create a database called Demo and create three tables (Person, User, and Manager) in it. The fields in these tables should map with the properties of the model classes shown later in this article.

Create a new ASP.NET Core Web API Project

Assuming that the necessary software has been installed on your computer to be able to work with the Entity Developer, follow the steps outlined below to create a new ASP.NET Core Web API project.

1. First off, open the Visual Studio 2019 IDE.
2. Next, click Create a new project once the IDE has loaded.
3. Click Create a new project.
4. Next, select ASP.NET Core Web Application.
5. Click Next.
6. Specify the project name and location – where it should be stored in your system.
7. Optionally, click the Place solution and project in the same directory checkbox.
8. Next, click Create.
9. In the Create a new ASP.NET Core Web Application dialog window that is shown next, select API as the project template.
10. Select ASP.NET Core 3.1 or later as the version.
11. You should disable the Configure for HTTPS and Enable Docker Support options by disabling the respective checkboxes.
12. Since we’ll not be using authentication in this example, specify authentication as No Authentication.
13. Finally, click on the Create button to finish the process.

Create an Entity Data Model

The next thing you should do is create an entity data model. When you create a model in Entity Developer, there are two options to choose from: Database First (this is selected by default) and Model First. In this example, we’ll take advantage of the Database First approach. Remember to select the Generate from Database option to generate your model from the database and select the database objects you would want to be a part of your entity data model.

Follow these steps outlined below to create an entity data model in Entity Developer using the database-first approach.

1. Select your project in the Solution Explorer Window.
2. Right-click and select Add >New Item.
3. Select Devart EF Core Model as the template as shown below.

4. Specify a name for your entity data model and click Add.
5. Specify the connection properties and test the connection.
6. Click Next to continue.
7. By default, the option “Generate from Database” will be selected. Since we want the model to be created from the database, click Next to continue.
8. Deselect all options and then specify only the database objects you would like to be a part of the model. Here’s where you should select the Products and Categories tables.
9. In the Setup naming rules screen, you can optionally specify naming rules for your entities.
10. In the next screen you can optionally specify the model properties.
11. In the next screen you can optionally choose the model diagram content.
12. In the next screen you can optionally specify code generation templates.
13. Specify the code generation template of your choice.
14. Lastly, click Finish to complete the process.

Your ADO.NET Entity Data Model using Entity Developer will be created along with the data context and model classes.

Inheritance in Entity Framework Core

Entity Framework Core (EF Core) allows you to map a .NET class hierarchy to a database. Hence, you can create your .NET entities represented as the base and derived types, and EF Core can generate the database schema for you. However, since EF Core does not automatically look for base or derived classes, you must explicitly declare a CLR type on your model if you want it to be mapped. It should be noted that specifying only the base type will not suffice, i.e., it will not automatically force EF Core to include all sub-types.

The following code listing illustrates how you can create a custom data context for a class as well as its subclass.

public class DemoDbContext : DbContext {
    public DbSet<Person> Person { get; set; }
    public DbSet<Author> Authors { get; set; }
}

public class Person {
    public int PersonId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class Author : Person {
    public string SubjectArea { get; set; }
}

Table Per Hierarchy (TPH)

In the Table Per Hierarchy (TPH) type of inheritance (this is the default inheritance type in EF Core), you would have just one table for the whole hierarchy to represent all the classes. To differentiate between different types, a “discriminator” column is used. By default, the table is named after the base class or a DbSet field linked with it. The table’s name would be the name of the base class or its corresponding DbSet attribute by default.

The following code snippet illustrates how Table Per Hierarchy can be represented:

public abstract class Person {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public class User : Person {
        public string UserName { get; set; }
        public string Password { get; set; }
    }

    public class Manager : Person {
        public string Department { get; set; }
    }

Table Per Type (TPT)

Table Per Type (TPT) approach inheritance relationships are depicted as foreign keys. In this approach, a separate table represents each type (including abstract types) of the inheritance chain. The foreign keys are used to link tables that represent derived type types with their base type. In this strategy, EF Core creates a base table in the database and multiple tables specific to each derived type.

The following code listing shows how the Table Per Type (TPT) approach can be implemented:

public abstract class Person {
    public int Id { get; set; }
    public string FullName { get; set; }
}

[Table("Users")]
public class User : Person {
     public string UserName { get; set; }
     public string Password { get; set; }
}

[Table("Managers")]
public class Manager : Person {
     public string Department { get; set; }
}

Table Per Concrete Type (TPC)

In the Table Per Concrete Type (TPC) approach, each concrete type in the inheritance chain is represented by a distinct table in the database but not the abstract class. Properties of any abstract base type are created as fields in the table of each concrete type.

The class design will be the same as TPH. Here’s how you can specify a table for each of the subclasses:

public class MyDbContext : DbContext {
    public DbSet<Person> Person { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder) {
        modelBuilder.Entity<User>().Map(m => {
            m.MapInheritedProperties();
            m.ToTable("Users");
        });

        modelBuilder.Entity<Author>().Map(m => {
            m.MapInheritedProperties();
            m.ToTable("Managers");
        });
    }
}

Summary

Entity Framework Core can be executed on any platform that supports .NET Standard 2.1. This includes .NET Core 3.1 as well as.NET 5. However, it will not execute on .NET Standard 2.0, which implies that beginning with EF Core 5.0, you will be unable to leverage EF Core with .NET Framework. Happy reading!

Comments are closed.