Question

I have a model where most of the entities inherit the same base functionality. That functionality is encapsulated in an abstract base class. Above that, there are two branches of functionality and thus there are two abstract classes that inherit from the abstract base class. At this point, concrete classes inherit from their respective intermediate abstract classes.

Below is an example of the classes and EF mapping for one branch of this type of model model:

public class TestContext : DbContext
{
    public DbSet<Base> Bases { get; set; }
    public DbSet<Intermediate> Intermediates { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Intermediate>().ToTable("Concretes");
        modelBuilder.Entity<Concrete1>().ToTable("Concretes");
        modelBuilder.Entity<Concrete2>().ToTable("Concretes");
    }
}
public abstract class Base
{
    public int Id { get; set; }
    public string BaseString { get; set; }
    public int BaseInteger { get; set; }
}

public abstract class Intermediate : Base
{
    public string IntermediateString { get; set; }
    public int IntermediateInteger { get; set; }
}

public class Concrete1 : Intermediate
{
    public string Concrete1String { get; set; }
    public int Concrete1Integer { get; set; }
}

public class Concrete2 : Intermediate
{
    public string Concrete2String { get; set; }
    public int Concrete2Integer { get; set; }
}

Where I am running into issues is with the table mapping. While mapping Intermediate, Concrete1, and Concrete2 does generate a database- and even gives me a discriminator column- it does not make the columns nullable as is required for TPH mapping and therefore I end up with the following exception message:

(28,10) : error 3023: Problem in mapping fragments starting at line 28:Column Concretes.Concrete1Integer in table Concretes must be mapped: It has no default value and is not nullable.

I've tried several permutations of this-

  • Only mapping Intermediate to a custom table- works, but the concrete types' fields are mapped to the "Bases" table.
  • Mapping Intermediate to its own table and Concrete1 & Concrete2 to a table named "Concretes"- Exact same issues as the original mapping in the code example above.
  • Mapping every entity to it's own table - This works, but it's purely TPT which isn't what I want.
  • Mapping nothing- this puts everything in the "Bases" table and is purely TPH, which for the real results in an unacceptably wide and sparse table.

Is there not some way to get the mapping I'm looking for in the code example? That is, a "Bases" table and a "Concretes" table that uses a discriminator?

Was it helpful?

Solution

As of version Entity Framework 6.1.0, this is an outstanding bug. It sounds like it will be a bug in 6.1.1 as well, but a fix has been scheduled for 6.1.2.

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