I´m using EF6 and trying to eager fetch the whole structure of an object. The problem is that i´m using inheritance.
Let´s say that i have this classes.
DbContext
DbSet<A> A { get; set; }
Example classes
public class A
{
public string Id { get; set; }
public IList<Base> Bases { get; set; }
}
public abstract class Base
{
public int Id { get; set; }
public string Name { get; set; }
}
public abstract class Base1 : Base
{
public SomeClass SomeClass { get; set; }
}
public class Base2 : Base1
{
}
public class Base3 : Base1
{
public SomeOtherClass SomeOtherClass { get; set; }
}
The error i get is:
The Include path expression must refer to a navigation property defined on the type.
Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
Why doesn´t it work with the following ?
public IEnumerable<A> GetAll(string id)
{
return _ctx.A
.Include(x => x.Bases.OfType<Base1>().Select(y=>y.SomeClass))
.Where(x => x.Id.Equals(id)).ToList();
}
New example
public IEnumerable<A> GetAll(string id)
{
var lists = _dbContext.A.Where(x => x.Id == id);
lists.SelectMany(a => a.Bases).OfType<Base1>().Include(e=>e.SomeClass).Load();
lists.SelectMany(b => b.Bases).OfType<Base3>().Include(e => e.SomeOtherClass).Load();
return lists;
}
EDIT: Added a new example that seems to work.
Eager loading is the process whereby a query for one type of entity also loads related entities as part of the query. Eager loading is achieved by use of the Include method. For example, the queries below will load blogs and all the posts related to each blog. Include is an extension method in the System.
Eager loading means that the related data is loaded from the database as part of the initial query. Explicit loading means that the related data is explicitly loaded from the database at a later time.
We can disable lazy loading for a particular entity or a context. To turn off lazy loading for a particular property, do not make it virtual. To turn off lazy loading for all entities in the context, set its configuration property to false.
Lazy loading with proxiesAddDbContext<BloggingContext>( b => b. UseLazyLoadingProxies() . UseSqlServer(myConnectionString)); EF Core will then enable lazy loading for any navigation property that can be overridden--that is, it must be virtual and on a class that can be inherited from.
Shortly, it's not possible out of the box.
The only workaround I can suggest is to materialize the master query result, then execute several OfType
queries with the necessary Includes
using the same filter as the master query, and rely on EF navigation property fixup.
It requires an inverse navigation property in the Base
class:
public abstract class Base
{
// ...
public A A { get; set; }
}
Then you can use something like this:
public IEnumerable<A> GetAll(string id)
{
var a = _ctx.A.Where(x => x.Id == id).ToList();
_ctx.Base.OfType<Base1>().Include(e => e.SomeClass).Where(e => e.A.Id == id).Load();
_ctx.Base.OfType<Base3>().Include(e => e.SomeOtherClass).Where(e => e.A.Id == id).Load();
return a;
}
The same idea can be used w/o inverse navigation property but with using the returned base Ids as filter:
public IEnumerable<A> GetAll(string id)
{
var a = _ctx.A.Include(e => e.Bases)
.Where(x => x.Id == id).ToList();
var baseIds = a.SelectMany(e => e.Bases.OfType<ModelA.Base1>().Select(b => b.Id));
db.Base.OfType<Base1>().Include(e => e.SomeClass)
.Where(e => baseIds.Contains(e.Id)).Load();
baseIds = a.SelectMany(e => e.Bases.OfType<Base3>().Select(b => b.Id));
db.Base.OfType<Base3>().Include(e => e.SomeOtherClass)
.Where(e => baseIds.Contains(e.Id)).Load();
return a;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With