I am trying to eager load properties from elements of a collection which itself is a property of another class. The elements of the collection are polymorphic, not sharing the properties I am trying to include, and tracked in the DB via TPH (Table-per-Hierachry). When I try to eager load them an exception is thrown stating that the base class does not contain the requested property.
I have an abstract base class Base
and two derived classes DerivedA
and DerivedB
. Base
has been configured for TPH like this
internal static void Configure(ModelBuilder builder)
{
// Get the EntityTypeBuilder from the given ModelBuilder
EntityTypeBuilder<Base> entityBuilder = builder.Entity<Base>();
// Configure TPH
entityBuilder.ToTable("Bases").HasDiscriminator<int>("DerivedType")
.HasValue<DerivedA>(0)
.HasValue<DerivedB>(1);
}
Furthermore I have a class ToBeLoaded
with a property public ICollection<Base> Bases {get; set; }
which does contain both DerivedA
and DerivedB
. I am expecting EF Core to be able to handle this. Am I wrong with that?
The EF Core Docs say I can use as
or a direct cast within ThenInclude()
like I do in my extension method.
public static IQueryable<ToBeLoaded> LoadRelated(this DbSet<ToBeLoaded> toBeLoadedSet)
{
return toBeLoadedSet.Include(tbl => tbl.Bases)
.ThenInclude(b => (b as DerivedA).PropA)
.Include(tbl => tbl.Bases)
.ThenInclude(b => (b as DerviedB).PropB);
}
When then calling context.ToBeLoadedSet.LoadRelated.ToList();
the following exception is thrown
System.InvalidOperationException: 'The property 'PropA' is not a navigation property of entity type 'Base'. The 'Include(string)' method can only be used with a '.' separated list of navigation property names.'
I already tried to use the other ways to achieve this suggested in the docs, namely direct cast and the Include(string)
method.
I am aware that this is somewhat different from the example in the docs, but that is the closest thing to my situation I could find.
Is this even theoretically possible using the Include interface or should I just try to use RawSQL?
So after writing the whole question up I tried one more thing. Just including Bases
like toBeLoadedSet.Include(tbl => tbl.Bases)
. For some reason I thought I tried this before and then PropA
and ProbB
where null
, but just wanted to be sure.
Since it's there now anyways and it might prevent someone else from wasting their time, I will just post it. Thanks for being my rubber duck.
To be clear, the LoadRelated
method looks like this now
public static IQueryable<ToBeLoaded> LoadRelated(this DbSet<ToBeLoaded> toBeLoadedSet)
{
return toBeLoadedSet.Include(tbl => tbl.Bases);
}