Many times the data structure we need in our applications isn’t as simple as the ideal examples found at most manuals. Sometimes we need more advanced mechanics for the persistence of our data entities.

In today’s article, we’re going to create an entity structure containing a collection of polymorphic elements, in other words, a collection that can contain several object types, all of them inheriting from a common ancestor class.

The problem with polymorphic collections is that, even though their components share a common class, they don’t share all the same properties implemented, so they can’t be saved in a single table at the database. They need a different table for every different final entity.

This is a very common problem but it’s a little difficult to explain. For this, I’ve created a little example project in a “real world” context to try to explain it the best I can, using Entity Framework 6.0 Code First with POCO entities and using the TPT (Table Per Type) feature of EF 6.0+ that simplifies a lot the scenario.

This article includes a link to my Git repository, where you can find a full example solution that will allow you to see the result by yourself, and get your hands dirty making new tests.

Download the solution in .ZIP format
Clone the GIT repository

Data model

For this example, in our test scenario we need an application able to keep a list of cars with all their car parts. To keep it simple, in our Car class, we will only have a Model name and a collection with the parts composing it, with three types of parts: Wheel, Door and Seat.


Our start point is a Car that can have n parts, but instead of making a collection for every part type, we will make a single collection from a unique class called CarPart that will contain all the parts even if they’re different. We will accomplish this by making all the parts Door, Wheel and Seat inherit from CarPart, where we will only have a SerialNo that is common to all the part types.

public virtual ICollection<CarPart> Parts { get; set; }

The problem we are facing when we save or read our data from the database, is that Parts elements are not homegeneous, in other words, a Wheel has width, radius, brand and so on, while a door has its position in the car and a seat has material and style, for example. This can’t be saved in the same table (without sparing a lot of data columns that won’t be used). To make it right, we must save each row in it’s own table depending on the part type.

For architectural reasons, it’s better and easier to keep all the parts in a single Parts collection instead of having a collection for every part type. That last scenario would force us to write much more code when, for example, we need a part by its serial number.

Normally, having a single collection would require some complex code at our infrastructure layer, having to check for every object’s type in the collection and calling it’s context to save it. Using Entity Framework‘s TPT makes this process very trivial.

Creating our Domain

We’ll start creating our POCO entities. BaseEntity is our base entity (obvious?) and it only contains a long property Id.

    public class BaseEntity
    {
        public long Id { get; set; }
    }

The central class of our Domain is Car. It contains a model name and the polymorphic collection of parts.

    public class Car : BaseEntity
    {
        public string Model { get; set; }
        public virtual ICollection<CarPart> Parts { get; set; }
    }

The CarPart entity is our union between the parts and the car. It will only contain the CarId of the car it belongs to, and a SerialNo that will be common to all parts, of any type.

    public class CarPart : BaseEntity
    {
        public long CarId { get; set; }
        public virtual Car Car { get; set; }
        public string SerialNo { get; set; }
    }

From here, we will define the classes for every part type, inheriting from CarPart.

    public class Door : CarPart
    {
        public enum DoorPositionEnum
        {
            FrontLeft = 0,
            FrontRight = 1,
            RearLeft = 2,
            RearRight = 3
        }

        public DoorPositionEnum Position { get; set; }
    }
    public class Seat : CarPart
    {
        public enum SeatMaterialEnum
        {
            Fabric = 0,
            Leather = 1
        }

        public enum SeatTypeEnum
        {
            Comfort = 0,
            Sportive = 1
        }

        public string Brand { get; set; }
        public SeatMaterialEnum Material { get; set; }
        public SeatTypeEnum Type { get; set; }
    }
    public class Wheel : CarPart
    {
        public double Radius { get; set; }
        public double Width { get; set; }
        public string Brand { get; set; }
    }

Once we have all our POCO entities, we must prepare our infrastructure project for Entity Framework 6.0, and there, create the mappers for every entity class against the database.

Mapping entities for EF 6.0 Code First

We will create a BaseEntityConfiguration class inheriting EF’s EntityTypeConfiguration to map the Id in all our entities.

    public class BaseEntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
        where TEntity : BaseEntity
    {
        public BaseEntityConfiguration()
        {
            this.HasKey(t => t.Id);
            this.Property(t => t.Id)
                .HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations
                                             .Schema.DatabaseGeneratedOption.Identity);
        }
    }

As you can see in the example, we are telling EF that the key of our table will be always Id with .HasKey and then we add a Identity constraint to the database’s column.

Let’s go on with the remaining mapping entities:

    public class CarMap : BaseEntityConfiguration<Car>
    {
        public CarMap() : base()
        {
            this.ToTable("Cars");
            this.Property(t => t.Model)
                .IsRequired();
        }
    }

… indicating for each one what table will receive their data with .ToTable and flagging required properties with .IsRequired

    public class DoorMap : BaseEntityConfiguration<Door>
    {
        public DoorMap()
        {
            this.ToTable("Doors");

            this.Property(t => t.Position).IsRequired();
        }
    }
    public class SeatMap : BaseEntityConfiguration<Seat>
    {
        public SeatMap()
        {
            this.ToTable("Seats");

            this.Property(t => t.Brand).IsRequired();
            this.Property(t => t.Material).IsRequired();
            this.Property(t => t.Type).IsRequired();
        }
    }
    public class WheelMap : BaseEntityConfiguration<Wheel>
    {
        public WheelMap()
        {
            this.ToTable("Wheels");

            this.Property(t => t.Brand).IsRequired();
            this.Property(t => t.Radius).IsRequired();
            this.Property(t => t.Width).IsRequired();
        }
    }

The real EF 6.0 “magic” comes when we define the CarPart class mapping. As we saw before, our car will have a collection of car parts called Parts that will contain elements from any class inheriting Carpart class. What we have to tell to Entity Framework is where it should save each different final entity based on its type, like this:

    public class CarPartMap : BaseEntityConfiguration<CarPart>
    {
        public CarPartMap() : base()
        {
            this.ToTable("Parts");

            this.Property(t => t.SerialNo)
                .IsRequired();

            this.Map<Wheel>(t => t.ToTable("Wheels"))
                .Map<Door>(t => t.ToTable("Doors"))
                .Map<Seat>(t => t.ToTable("Seats"));

            this.HasRequired(t => t.Car)
                .WithMany(car => car.Parts)
                .HasForeignKey(t => t.CarId);

        }
    }

Let’s split this. First we are indicating the we are going to use a Parts table. This table will be an intermediate table between the car and its parts.

Following on, we set what table should receive each entity type using Map<T>, and finally we create the one to many relation between the car and its parts.

With this information, Entity Framework will know what it has to do with each entity in our domain. Now we’re gonna tell it how to stick it all together in a database.

Creating the context

Once the entity mapping is finished, we are going to create a database context to be able to access the data:

    public class CarBoundContext : DbContext
    {

        public CarBoundContext(): base("CarsDB")
        {
            Database.SetInitializer(new CreateDatabaseIfNotExists<CarBoundContext>());
        }

        public DbSet<Car> Cars { get; set; }
        public DbSet<Door> Doors { get; set; }
        public DbSet<Wheel> Wheels { get; set; }
        public DbSet<Seat> Seats { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Configurations.Add(new CarMap());
            modelBuilder.Configurations.Add(new DoorMap());
            modelBuilder.Configurations.Add(new WheelMap());
            modelBuilder.Configurations.Add(new SeatMap());

            base.OnModelCreating(modelBuilder);
        }
    }

Our class CarBoundContext inherits from Entity Framework’s context DbContext, overriding its method OnModelCreating so it gets our database definition mapping classes with modelBuilder.Configurations.Add for each of our mappers.

We also publish DbSet for every table we are going to use. Notice we did’nt publish a DbSet for CarPart since it’s a intermediate table and we won’t be using it normally, since it’s used internally by EF to get the different part types. We could add it if we should need it, anyway.

At the constructor, we are telling EF that the database should be created if it doesn’t exist with a call to SetInitializer.

Now our context is done

The test

Once our domain and context have been created, it’s time to test. We create a console application that will make a new Car object with some parts on it and save it, then read it again on a new variable.

    class Program
    {

        private static Random _seed = new Random();

        static string NewSerialNumber()
        {
            return string.Format("{0:00000000}", _seed.NextDouble() * (double)100000000);
        }

        static Car NewCar()
        {
            return new Car
            {
                Model = "Chevrolet Cruze LTZ",
                Parts = new List<CarPart>
                {
                    new Wheel(NewSerialNumber(), "Bridgestone",17.0,225.0),
                    new Wheel(NewSerialNumber(), "Bridgestone",17.0,225.0),
                    new Wheel(NewSerialNumber(), "Bridgestone",17.0,225.0),
                    new Wheel(NewSerialNumber(), "Bridgestone",17.0,225.0),
                    new Door(NewSerialNumber(), Door.DoorPositionEnum.FrontLeft),
                    new Door(NewSerialNumber(), Door.DoorPositionEnum.FrontRight),
                    new Seat(NewSerialNumber(),"Sparco",Seat.SeatMaterialEnum.Leather,Seat.SeatTypeEnum.Sportive),
                    new Seat(NewSerialNumber(), "Sparco",Seat.SeatMaterialEnum.Fabric,Seat.SeatTypeEnum.Comfort)
                }
            };
        }

        static void PrintParts(string partName, IEnumerable<CarPart> parts)
        {
            Console.WriteLine("*** {0} ({1}):", partName, parts.Count());
            parts.ToList().ForEach(Console.WriteLine);
        }

        static void Main(string[] args)
        {
            // The database will be created at bin/Debug/ by default
            AppDomain.CurrentDomain.SetData("DataDirectory", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ""));
            // Get a new context for de DB (always "using" to dispose the connection)
            using (var context = new CarBoundContext())
            {
                // If no records, let's create one...
                if (!context.Cars.Any())
                {
                    context.Cars.Add(NewCar());
                    context.SaveChanges();
                }
                // Fetch the record and display its parts!
                var car = context.Cars.First();
                Console.WriteLine("Model: {0}", car.Model);
                Console.WriteLine("Total parts: {0}", car.Parts.Count);

                PrintParts("Doors", car.Parts.Where(part => part is Door));
                PrintParts("Seats", car.Parts.Where(part => part is Seat));
                PrintParts("Wheels", car.Parts.Where(part => part is Wheel));

                Console.ReadLine();
            }
        }
    }

As you can see, by only making .Add(NewCar()) all the rest happens “automagically”, the sub-entities (parts) are chain-saved under the hood. One row is generated at Cars for the car, 8 rows at CarParts for all the parts, and then as much rows as parts of that type in each specific parts table.

When we read again the Car entity, again, TPT magic looks in every needed table to gather the parts of our car, and all of them are added to our Parts collection, where we can use Linq to retrieve and filter them with a simple .Where(part => part is XXXXXX) to get a given type only, or for example .Where(part => part.SerialNo == "XXXXXX") to retrieve a part using its serial number whatever type it is.

Running the solution we should get this result:

4AA2255A-41E4-58E3-8C2C-98ADAF2BB45E.jpg

And what about the DB structure?

With EF 6.0, it’s easy to forget what’s happening underground, so it’s good to give a look to the DB that has just been created:

61183D31-AA10-44E1-0017-6301D33D779C.jpg

Conclusions and References

This is just a small tip on what Entity Framework 6.0 Code First can do for you. If you want more information on the subject, check the Microsoft Entity Framework documentation.
For more information about TPT (Table Per Type), check this link.
If you wanna see more example projects, don’t forget to visit my Git repository

Follow me

Joan Vilariño

Senior .NET Developer at Ohpen
Developer for more than 25 years and IT, gadget, mobile and electronics enthusiast working and publishing from Barcelona.
Follow me