Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple inheritance with Entity Framework TPC

I tried to map some classes using Entity Framework in TPC style and got the following error:

Error: The type 'A' cannot be mapped as defined because it maps inherited properties from types that use entity splitting or another form of inheritance. Either choose a different inheritance mapping strategy so as to not map inherited properties, or change all types in the hierarchy to map inherited properties and to not use splitting.

This error occurs when I use the following classes:

public abstract class BaseEntityTest
public abstract class BaseEntityTest2 : BaseEntityTest
public abstract class BaseEntityTest3 : BaseEntityTest2
public class A: BaseEntityTest3 // this class is the only one with a table in the db

In the OnModelCreating method I added the following code to get the TPC mapping

modelBuilder.Entity<A>().Map(m =>
{
  m.MapInheritedProperties();
  m.ToTable("A");
});

When I exclude BaseEntityTest2 from the structure (so that A inherits only from BaseEntityTest instead of BaseEntityTest2) the error goes away. Does that mean that it is not possible to create this mapping or do I just miss something?

EDIT:

Properties of classes:

public abstract class BaseEntityTest
{

    [Key]
    public Guid Id { get; set; }

    public String Info { get; set; }

    [Required]
    public DateTime CreationDate { get; set; }

    [Required]
    public String CreationUser { get; set; }

    [Required]
    public DateTime ModificationDate { get; set; }

    [Required]
    public String ModificationUser { get; set; }

    [ConcurrencyCheck]
    [Required]
    public int LockVersion { get; internal set; }
}

public abstract class BaseEntityTest2 : BaseEntityTest
{
    [Required]
    public string Name { get; set; }

    public string Description { get; set; }

}

public abstract class BaseEntityTest3: BaseEntityTest2 
{

    [Required]
    public DateTime FromDate { get; set; }

    public DateTime ThruDate { get; set; }
}

public class A: BaseEntityTest3{
    public String Test { get; set; }
}
like image 953
Eggi Avatar asked Dec 27 '22 14:12

Eggi


2 Answers

The error occurs for EF 4.3.1 and earlier versions, but not for EF 4.4 and EF 5.0. (EF 4.4 is actually EF 5.0, but with .NET 4.0 as target platform.)

BUT: The error occurs only if you are using your abstract classes as entities in your model, that means

  • you either have DbSets for them in your context class, like

    public DbSet<BaseEntityTestX> BaseEntityTestXs { get; set; }
    
  • or you have some Fluent mapping for BaseEntityTestX, some modelBuilder.Entity<BaseEntityTestX>()... stuff

  • or you are using one of the BaseEntityTestX as a navigation property in another (concrete) entity type

Do you need any of this?

Having a DbSet<BaseEntityTestX> in your context would only make sense if you really want to query for one of the abstract entities, like:

List<BaseEntityTest> list = context.BaseEntityTests
    .Where(b => b.Info == "abc").ToList();

The result is of course a list of concrete entities that inherit from BaseEntityTest, but it can be a mix of different types, like some As and some Bs. Do you need such queries? Or do you only want to query for some of the concrete objects:

List<A> list = context.As
    .Where(b => b.Info == "abc").ToList();

In the latter case you don't need a DbSet for the abstract base classes and you don't need any inheritance mapping. You can just remove the DbSet<BaseEntityTestX> from your context class and remove the TPC mapping and your error will go away.

The last point - having a navigation property to one of the abstract entities in another entity - doesn't make sense with TPC mapping. It is just not mappable to a relational database because with TPC mapping there is no table for the abstract entity, hence there is no target the foreign key relationship could refer to from the table of the concrete class that has the navigation property.

The error will also disappear if you extend your TPC mapping to the base classes:

modelBuilder.Entity<BaseEntityTestX>().Map(m =>
{
    m.MapInheritedProperties();
    m.ToTable("BaseEntityTestX");
});

But it will create tables for those abstract entities that don't seem to make sense to me.

like image 163
Slauma Avatar answered Jan 15 '23 01:01

Slauma


in EF6.0 its happed when

EntityTypeConfiguration'<'YourBaseClass'>'

did not detailed ALL your derived class with

        this.Map<DerivedClass1>(m =>
        {
            m.MapInheritedProperties();
            m.ToTable("..");
        });

if just one dervied class in the assembley not configured like so you get this exception

like image 33
ari Avatar answered Jan 15 '23 01:01

ari