2

An exception is thrown while running add-migration (EF core 3.1.1):

CLR property 'DiscriminatorLevel2Id' cannot be added to entity type 'CustomerBase' because it is declared on the CLR type 'InternalCustomer'

The following Image shows the needed hierarchy (briefly):

Class Diagram

Mapping looks like:

// Discriminator (Level 1)
modelBuilder.Entity<CustomerBase>()              
            .HasDiscriminator(b => b.CustomerTypeId)
            .HasValue<InternalCustomer>((int)CustomerType.Internal)
            .HasValue<ExternalCustomer>((int)CustomerType.External);

// Discriminator (Level 2)
modelBuilder.Entity<InternalCustomer>()
         .HasDiscriminator(b => b.DiscriminatorLevel2Id)
         .HasValue<VIPCustomer>((int)DiscriminatorLevel2.VIP)
         .HasValue<RegularCustomer>((int)DiscriminatorLevel2.Regular);

Is "Multilevel Inheritance TPH" supported on Entity Framework Core 3.1.1?

2
  • Multilevel discriminator - no. Multilevel inheritance with common discriminator - yes. Commented Feb 3, 2020 at 17:47
  • Thanks Ivan Stove, How is "Multilevel inheritance with common discriminator" implemented, what are changes that need to be done in the above example? Commented Feb 4, 2020 at 7:12

1 Answer 1

5

It's possible, but with single shared discriminator at the root abstract level containing values for all possible creatable (non abstract) direct or indirect derived entities.

Applying to your sample requires removing the DiscriminatorLevel2 property (column), removing Internal from CustomerType enum (assuming InternalCustomer is abstract) and merging Regular and VIP into it, e.g. something like this:

Model:

public abstract class CustomerBase
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int CustomerTypeId { get; set; }
}

public abstract class InternalCustomer : CustomerBase
{
    public decimal Points { get; set; }
}

public class RegularCustomer : InternalCustomer
{
    public int PartnerId { get; set; }
}

public class VIPCustomer : InternalCustomer
{
    public string CardNo { get; set; }
}

public class ExternalCustomer : CustomerBase
{
}

public enum CustomerType { External, Regular, VIP }

Configuration:

modelBuilder.Entity<CustomerBase>()
    .HasDiscriminator(b => b.CustomerTypeId)
    .HasValue<ExternalCustomer>((int)CustomerType.External)
    .HasValue<VIPCustomer>((int)CustomerType.VIP)
    .HasValue<RegularCustomer>((int)CustomerType.Regular);

modelBuilder.Entity<InternalCustomer>();

When you want to query InternalCustomer derived entities, you could use db.Set<InternalCustomer>() or db.Set<CustomerBase>().OfType<InternalCustomer>() and EF Core will apply filter similar to t.CustomerTypeId IN (1,2), i.e. the IN clause will contain list of discriminator values for all final entities derived from InternalCustomer.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.