Multiple levels of inheritance with Entity Framework using TPH

2.5k Views Asked by At

I am using Entity Framework to create a Table Per Heirachy data model in a new project over an existing legacy database. This means that we don't own the database and therefore I need a solution that doesn't involve adding columns to the OrderDiscount table.

I have the following structure in my data models:

       ┌────── (abstract) OrderDiscountBase ──────┐
       │                                          │
       │                                          │
SaleOrderDiscount          ┌─── (abstract) SellerOrderDiscountBase ───┐
                           │                                          │
                           │                                          │
                FreeShippingOrderDiscount                 PercentageValueOrderDiscount

There is a pre-existing discriminator column to distinguish between the concrete types. It's called DiscountType and can hold the values PercentageOffPromoDiscount, FreeShippingPromoDiscount or SaleDiscount.

I have the following mapping in my project, which is--unfortunately--not working.

private void ConfigureOrderDiscountEntity(EntityTypeConfiguration<OrderDiscountBase> entity)
{
    entity
        .HasKey(orderDiscount => orderDiscount.Id)
        .Map<SaleOrderDiscount>(
            configuration => configuration.Requires("DiscountType").HasValue(OrderDiscountTypes.Sale))
        .Map<PercentageValueOrderDiscount>(
            configuration => configuration.Requires("DiscountType").HasValue(OrderDiscountTypes.PercentageOff))
        .Map<FreeShippingOrderDiscount>(
            configuration => configuration.Requires("DiscountType").HasValue(OrderDiscountTypes.FreeShipping))
        .ToTable(tableName: "OrderDiscount", schemaName: "Orders")
        ;
}

The exception I see is:

EntityTypes SellerOrderDiscountBase, SaleOrderDiscount, FreeShippingOrderDiscount, PercentageValueOrderDiscount are being mapped to the same rows in table OrderDiscountBase. Mapping conditions can be used to distinguish the rows that these types are mapped to.

I've seen people solve this problem in older versions of Entity Framework by adding a second discriminator column but, as I said, I can't make changes to the database.

What I'm asking EF to do doesn't sound difficult, so I assume I have just configured my entities incorrectly.

1

There are 1 best solutions below

5
On BEST ANSWER

Definitely works for me in EF 6.x:

public abstract class TPHBase
{
    public int ID { get; set; }

    public string CommonProperty { get; set; }
}

public class TPHChild1 : TPHBase
{
    public string Child1Property { get; set; }
}

public abstract class TPHChild2 : TPHBase
{
    public int? Child2Property { get; set; }
}

public class TPHChild3 : TPHChild2
{
    public int? Child3Property { get; set; }
}

public class TPHChild4 : TPHChild2
{
    public int? Child4Property { get; set; }
}

protected override void OnModelCreating( DbModelBuilder modelBuilder )
{
    modelBuilder.Entity<TPHBase>()
            .ToTable( "TPHBase" )
            .Map<TPHChild1>( m => m.Requires( "Dyskryminator" ).HasValue( "c1" ) )
            .Map<TPHChild3>( m => m.Requires( "Dyskryminator" ).HasValue( "c3" ) )
            .Map<TPHChild4>( m => m.Requires( "Dyskryminator" ).HasValue( "c4" ) );

    ...

Entities are sucesfully persisted and then retrieved from the database.

I suspect there is something more than you have posted.