Entity Framework Code First Inheritance

Introduction

Another post for self reference, this time, how to map inheritance strategies with Entity Framework Code First.

Single Table Inheritance / Table Per Class Hierarchy

First, the default strategy: one table for all classes in the hierarchy. Will store all columns on the same table, so all properties on derived classes must be nullable, and there will be lots of nulls. An additional column will be created, which will contain a discriminator value for deciding which type corresponds to each row.

   1: [Table("Base")]
   2: public abstract class Base
   3: {
   4:     public Int32 BaseId { get; set; }
   5:  
   6:     public String InheritedColumn { get; set; }
   7: }

 

   1: public class DerivedA : Base
   2: {
   3:     public String A { get; set; }
   4: }

 

   1: public class DerivedB : Base
   2: {
   3:     public String B { get; set; }
   4: }

 

image

 

Class Table Inheritance / Table Per Type

This will map all properties of the base class into a table of its own and each derived class in its own table, connected to the base table by a foreign key. No duplication will occur and properties on derived classes can be mapped as not nullable.

   1: [Table("Base")]
   2: public abstract class Base
   3: {
   4:     public Int32 BaseId { get; set; }
   5:  
   6:     public String InheritedColumn { get; set; }
   7: }

 

   1: [Table("DerivedA")]
   2: public class DerivedA : Base
   3: {
   4:     public String ColumnA { get; set; }
   5: }

 

   1: [Table("DerivedB")]
   2: public class DerivedB : Base
   3: {
   4:     public String ColumnB { get; set; }
   5: }

 

image

 

Concrete Table Inheritance / Table Per Concrete Type

No table for the base class, each concrete class will have its own table, which will contain columns for all of the class’ properties, including inherited ones. One record will only exist in one of the tables, so usage of IDENTITY columns as primary keys is not possible, because there will be records with the same ID on all of the tables, unless different seeds and/or increments are used.

   1: public abstract class Base
   2: {
   3:     public Int32 BaseId { get; set; }
   4:  
   5:     public String InheritedColumn { get; set; }
   6: }

 

   1: [Table("DerivedA")]
   2: public class DerivedA : Base
   3: {
   4:     public String ColumnA { get; set; }
   5: }

 

   1: [Table("DerivedB")]
   2: public class DerivedB : Base
   3: {
   4:     public String ColumnB { get; set; }
   5: }

This will require additional configuration at the context level, this strategy is not possible just with attributes:

   1: public class Context : DbContext
   2: {
   3:     protected override void OnModelCreating(DbModelBuilder modelBuilder)
   4:     {
   5:         modelBuilder.Entity<DerivedA>().Map(m =>
   6:         {
   7:             m.MapInheritedProperties();
   8:         });
   9:         modelBuilder.Entity<DerivedB>().Map(m =>
  10:         {
  11:             m.MapInheritedProperties();
  12:         });
  13:     }
  14:  
  15:     public DbSet<Base> Bases { get; set; }
  16: }

 

image

                             

No Comments

Add a Comment

As it will appear on the website

Not displayed

Your website