I have a few Entity Framework 7 (Core) entities:
public class Person {
public virtual Address Address { get; set; }
public virtual ICollection<Hobby> Hobbies { get; set; }
}
public class Address {
public String Street { get; set; }
public virtual Country Country { get; set; }
}
And I have a string array as follows:
String[] entities = new String[] { "Hobbies", "Address.Country" }
Given this string array I got:
context.Persons
.Include(x => x.Hobbies)
.Include(x => x.Address).ThenInclude(x => x.Country);
In EF6 I could do something like:
context.Persons.Include(entities[0]).Include(entities[1]);
But in EF7 Include does not allow strings. I created the dictionary:
private readonly Dictionary<String, LambdaExpression> _properties = new Dictionary<String, LambdaExpression>();
Which would have something like:
x => x.Hobbies is for "Hobbies"
x => x.Address.Country is for "Address.Country"
And I have the extension:
public static IQueryable<T> Include<T>(this IQueryable<T> source, Dictionary<String, LambdaExpression> properties) {
}
Where I need to given the Dictionary apply the following:
For "x => x.Hobbies" just do:
source.Include(x => x.Hobbies);
If the expression is something like "x => x.Address.Country" add:
source.Include(x => x.Address).ThenInclude(x => x.Country);
Can this be done?
Not sure about ThenInclude()
and EF 7, but you can do something like this in your repositories (tested with EF 6):
public MyEntity GetMyEntity_EagerlyLoad(DbContext context, int id, params Expression<Func<MyEntity, object>>[] propertiesToLoad)
{
var q = context.MyEntities.Where(m => m.ID == id);
foreach (var prop in propertiesToLoad)
q = q.Include(prop);
return q.SingleOrDefault();
}
You can then call it like this:
repo.GetMyEntity_EagerlyLoad(context, id, m => m.Property1, m => m.Property2, m => m.Property1.NestedProperty)
EDIT: There is also the alternative way to do eager loading with EF using projection. You could do a generic repository method like this:
public MyEntity GetMyEntity_EagerlyLoad<T>(DbContext context, int id, Expression<Func<MyEntity, T>> loadingProjection, Func<T, MyEntity> resultProjection)
{
var q = context.MyEntities.Where(m => m.ID == id);
return q.Select(loadingProjection).AsEnumerable().Select(resultProjection).SingleOrDefault();
}
And then call it with the properties you want loaded and the entity you want the method to return:
repo.GetMyEntity_EagerlyLoad(context, id, m => new { myEntity = m, m.Property1, m.Property2, m.Property1.NestedProperty }, m => m.myEntity)