I'm trying to write a repository method for Entity Framework Core 2.0 that can handle returning child collections of properties using .ThenInclude, but I'm having trouble with the second expression. Here is a working method for .Include, which will return child properties (you supply a list of lambdas) of your entity.
public T GetSingle(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties)
{
IQueryable<T> query = _context.Set<T>();
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty);
}
return query.Where(predicate).FirstOrDefault();
}
Now here is my attempt at writing a method that will take a Tuple of two Expressions and feed those into a .Include(a => a.someChild).ThenInclude(b => b.aChildOfSomeChild) chain. This isn't a perfect solution because it only handles one child of a child, but it's a start.
public T GetSingle(Expression<Func<T, bool>> predicate, params Tuple<Expression<Func<T, object>>, Expression<Func<T, object>>>[] includeProperties)
{
IQueryable<T> query = _context.Set<T>();
foreach (var includeProperty in includeProperties)
{
query = query.Include(includeProperty.Item1).ThenInclude(includeProperty.Item2);
}
return query.Where(predicate).FirstOrDefault();
}
Intellisense returns an error saying "The type cannot be inferred from the usage, try specifying the type explicitly". I have a feeling it's because the expression in Item2 needs to be classified as somehow related to Item1, because it needs to know about the child relationship it has.
Any ideas or better techniques for writing a method like this?
Back in EF6 we could write something like this:
And it was perfect and simple. We could expose it in an repository without dragging references from the EF assembly to other projects.
This was removed from EF Core, but since EF6 is open-source, the method that transforms the lambda expressions in paths can easily be extracted to use in EF Core so you can get the exact same behavior.
Here's the complete extension method.
Then you can use it like this (put it in an
QueryableExtensions
class or something like that):And then in your repository you call it normally like you would do in EF6:
References:
How to pass lambda 'include' with multiple levels in Entity Framework Core?
https://github.com/aspnet/EntityFramework6
I found this repository method online and it does exactly what I wanted. Yared's answer was good, but not all the way there.
Usage:
I had the same issue since EF Core doesn't support lazy loading but i tried to get workaround in the following way:
First create an attribute class to mark our desired navigation properties from other properties of a given class.
Extension methods to filter out navigation properties and apply Include/ThenInclude using string based Eager loading.
Sample POCO classes implementing
NavigationPropertyAttribute
Usage in Repository
Json result for sample class C would be: