How can I mix TPH and TPT in Entity Framework 6?

initial situation

I have an application that uses an existing database currently using NHibernate as an O / R-Mapper.
Now I need to upgrade to Entity Framework 6.1.1 using Code First and the Fluent API configuration .

But now I have a problem with part of the data model, because it uses different types of inheritance strategies (TPT and TPH)

Structure

Note. Carrying out a complete data model here seemed to me too huge, so I reproduced the problem that I encounter in a small POC program.

CLASS                  | TABLE              | TYPE
-----------------------+--------------------+------
BaseEntity (abstract)  | BaseTable          |
Inherited_TPH          | BaseTable          |  1
Inherited_TPT          | Inherited_TPT      |  2

The column used as the discriminator in the table is called Type

, Intermediate_TPH :

Diagram of classes and mapping

: ID=3 Inherited_TPT

Data

:

class MyContext : DbContext
{
    public MyContext ( string connectionString )
        : base ( connectionString )
    {
    }

    public DbSet<Inherited_TPH> TPH_Set { get; set; }
    public DbSet<Inherited_TPT> TPT_Set { get; set; }
    public DbSet<SomethingElse> Another_Set { get; set; }

    protected override void OnModelCreating ( DbModelBuilder modelBuilder )
    {
        modelBuilder
        .Entity<BaseEntity> ()
        .ToTable ( "BaseTable" );

        modelBuilder
        .Entity<Inherited_TPH> ()
        .Map ( t => t.Requires ( "Type" ).HasValue ( 1 ) );

        modelBuilder
        .Entity<Intermediate_TPT> ()
        .Map ( t => t.Requires ( "Type" ).HasValue ( 2 ) );

        modelBuilder
        .Entity<Intermediate_TPT> ()
        .Map<Inherited_TPT> ( t => t.ToTable ( "Inherited_TPT" ) ); 

        modelBuilder
        .Entity<SomethingElse> ()
        .ToTable ( "SomethingElse" )
        .HasKey ( t => t.Id );
    }
}

public abstract class BaseEntity
{
    public virtual int Id { get; set; }
    public virtual string Title { get; set; }
}
public class Inherited_TPH : BaseEntity
{
}
public abstract class Intermediate_TPT : BaseEntity
{
}
public class Inherited_TPT : Intermediate_TPT
{
    public virtual string Comment { get; set; }
}
public class SomethingElse
{
    public virtual string Description { get; set; }
    public virtual int Id { get; set; }
}

.

    static void Main ( string[] args )
    {
        Database.SetInitializer<MyContext> ( null );
        var ctx = new MyContext ( @"Data Source=(local);Initial Catalog=nh_ef;Integrated Security=true" );
        try
        {
            // Accessing Inherited_TPH works just fine
            foreach ( var item in ctx.TPH_Set ) Console.WriteLine ( "{0}: {1}", item.Id, item.Title );
            // Accessing Inherited_TPT works just fine
            foreach ( var item in ctx.TPT_Set ) Console.WriteLine ( "{0}: {1} ({2})", item.Id, item.Title, item.Comment );
            // The rror occurs when accessing ANOTHER entity:
            foreach ( var item in ctx.Another_Set ) Console.WriteLine ( "{0}: {1}", item.Id, item.Description );
        }
        catch ( Exception ex )
        {
            Console.WriteLine ( ex.Message );
            if( ex.InnerException != null ) { Console.WriteLine ( ex.InnerException.Message ); }
        }
    }

:

1:
2:
3: ( SMITH)
4: ( MILLER)
. . .

(26,10): 3032: , 14, 26: EntityTypes PoC.Inherited_TPH, PoC.Inherited_TPT BaseEntity. , .

, , Inherited_TPT Inherited_TPH. .

, ?

+4
1

- . , - ...

  • TPH

, , , :

protected override void OnModelCreating ( DbModelBuilder modelBuilder )
{
    // Not changed
    modelBuilder
        .Entity<BaseEntity> ()
        .ToTable ( "BaseTable" );


    // --- CHANGED ---
    modelBuilder.Entity<BaseEntity> ()
        // TPH => Discriminator
        .Map<Inherited_TPH> ( m => m.Requires ( "Type" ).HasValue ( 1 ).IsOptional () ) 
        // TPT => Mapping to table
        .Map<Inherited_TPT> ( m => m.ToTable ( "Inherited_TPT" ) ); 

    // Not changed
    modelBuilder
        .Entity<SomethingElse> ()
        .ToTable ( "SomethingElse" )
        .HasKey ( t => t.Id );
}
+3

All Articles