4

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.

Richiban
  • 5,569
  • 3
  • 30
  • 42

1 Answers1

5

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.

Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
  • How did you model the relationships w.r.t. which table has the foreign key? I was unable to get your example working when the child references its parent. – Richiban Aug 17 '15 at 12:24
  • @Richiban: Child and parent? It sounds like you are doing references between inheriting classes, do you? In my example there are no parent-child foreign keys and you don't mention foreign keys in your post. – Wiktor Zychla Aug 17 '15 at 13:27
  • Well, I'm not sure how or why but I essentially destroyed the data layer and started again... and it worked! Thanks to your answer I had confidence that what I wanted to do was actually supported and I could stick to my guns. Eventually got there. – Richiban Aug 19 '15 at 12:45
  • @Richiban: if you even find out what was wrong in the first place, drop a short note under this answer or under your question so that someone could benefit from learning it. Regards. – Wiktor Zychla Aug 19 '15 at 13:48
  • How you can use TPHChild4 in linq query directly? i.e. `var q= from ch4 in tphchild4 where age>10 select ch4 ` – Hamid Mar 18 '16 at 21:05