Search code examples
c#entity-frameworkoopdiscriminator

Entity Framework Add Discriminator Column for Only One Child Model


I have one parent model that's abstract so no instances of it can be made, and currently I have one child class that inherits from it. For example, I have something like this:

public abstract class Parent {
     public virtual int Id { get; set; }
}

public class Child1 : Parent {
     public override int Id { get; set; }
     public string SomeAttribute1 { get; set; }
     public string SomeAttribute2 { get; set; }
}

I'm using entity framework to populate my db models, and when I add

public virtual IDbSet<Child1> Child1 { get; set; } to my context, I get the following table with the following columns:

Parent:

  • Id
  • SomeAttribute1
  • SomeAttribute2

Which is what I would expect. However the problem I have is that it is very likely I will be later adding more children models to this parent class, for example another class such as:

public class Child2 : Parent {
     public override int Id { get; set; }
     public string Child2Attribute1 { get; set; }
     public string Child2Attribute2 { get; set; }
}

And when I add this child model to the context, my Parent column then turns into this:

Parent:

  • Id
  • SomeAttribute1
  • SomeAttribute2
  • Child2Attribute1
  • Child2Attribute2
  • Discriminator

I understand the concept of the discriminator, however my problem is that all the Child1 objects that already exist in my db before the Child2 class gets added won't have the discriminator column, and will then have empty values.

I imagine these empty discriminator values would cause problems later trying to access them, so my question is, is there a way to force a discriminator column on a model that only has 1 child entity?

Or else is there a better way of preemptively handling/preparing for more child classes to be added at a later time?

Or is there a good way of having these two child classes be their own tables? I've never done much fancy OOP with Entity Framework, so I'm not sure what they best way to handle this issue would be.

Thanks for any help!

EDIT

I have looked into the 3 different inheritance models: TPH, TPT, and TPC. TPH is not a model that will work for my scenario, however both TPT and TPC can work. As I mentioned in the answers I got TPT working, however TPC is ideal for my use-case as I don't necessarily want/need to store the parent class in the database (but would still like it in my context). I managed to get TPC nearly working making the following changes to my code:

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

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

and changing my parent model to:

public abstract class Parent {
    [DatabaseGenerated(DatabaseGenerationOption.Identity)]
    public virtual int Id { get; set; }
}

However then the problem I'm seeing is that the Ids being populated across children are not unique (i.e. both Child1 and Child2 could have an Id = 1, however that means there are then 2 Parent objects with Id = 1, which violates the unique key constraints.

Is there a way I can force the auto-generated Ids to be unique across children?


Solution

  • I found the solution to my problem thanks to what Bradley Uffner suggested:

    Table-Per-Type did the trick by simply adding just the parent class to the context but then creating separate tables for each child class as they get added like so:

    public virtual IDbSet<Parent> Parents { get; set; }
    
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
         modelBuilder.Entity<Child1>().ToTable("Child1");
         modelBuilder.Entity<Child2>().ToTable("Child2");
    }