Question

I my domain model I have a Company base class which is abstract and three different Company types represented by subclasses of Company:

public abstract class Company
{
    public int Id { get; set; }
    ...
}

public class Supplier : Company
{
    ...
}

public class Dealer : Company
{
    public DealerFundsAccount FundsAccount { get; set; }
    ...
}

public class Retailer : Company
{
    public RetailerFundsAccount FundsAccount { get; set; }
    ...
}

In the same way, I have another base class that defines a Funds Account and two subtypes that implement specific properties:

public abstract class FundsAccount
{
    public int Id { get; set; }
    ...
}

public class DealerFundsAccount : FundsAccount
{
    public Dealer Dealer { get; set; }
    ...
}

public class RetailerFundsAccount : FundsAccount
{
    public Retailer Retailer { get; set; }
    ...
}

My mapping strategy for these types is table-per-hierarchy, so in my DbContext class I only define DbSets for the base classes, which makes me able to perform both polymorphic and non-polymorphic queries:

public DbSet<Company> Companies { get; set; }
public DbSet<FundsAccount> FundsAccounts { get; set; }

Now comes the tricky part, my requirements state that:

  • Supplier must not have a funds account
  • Dealer must have a DealerFundsAccount
  • Retailer must have a RetailerFundsAccount

It should be this simple:

modelBuilder.Entity<Retailer>()
    .HasRequired(r => r.FundsAccount)
    .WithRequiredDependent(rfa => rfa.Retailer);

modelBuilder.Entity<Dealer>()
    .HasRequired(d => d.FundsAccount)
    .WithRequiredDependent(dfa => dfa.Retailer);

But EF Migrations fails miserably trying to update the database schema. Due to TPH, Dealers and Retailers are mapped to the same Company database table while RetailerFundsAccounts and DealerFundsAccounts are mapped to a FundsAccount db table, all of which is desired, but since I defined two one-to-one relationships between subtypes, EF tries to define the Foreign Key to the FundsAccount Id field twice.

I know I can hack a solution by defining a one-to-many relationship for each of the Company tables that has a funds account an prevent one-to-many behaviour using unique constraints in it's FK, but I wanted to check with you if there's a better solution.

Was it helpful?

Solution

Turns out that EF migrations was to blame. If I try to create the database schema from scratch, everything is fine, but if you create a migration to add these entities, EF fails by trying to create the index and foreign key twice, like this:

        CreateTable(
            "dbo.FundsAccount",
            c => new
                {
                    Id = c.Int(nullable: false),
                    Discriminator = c.String(nullable: false, maxLength: 128),
                })
            .PrimaryKey(t => t.Id)
            .ForeignKey("dbo.Company", t => t.Id)
            .ForeignKey("dbo.Company", t => t.Id) // duplicate
            .Index(t => t.Id)
            .Index(t => t.Id); // duplicate

The solution is to edit the migration, removing the duplicated FK and index entries.

I'll also update the question's title to better describe the problem.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top