I have a class
public class Level1
{
public int Id {get; set;}
public virtual List<Level2> Level2List {get; set;}
}
public class Level2
{
public int Id {get; set;}
public int Level3Id {get; set;}
public virtual Level3 Level3 {get; set;}
}
public class Level3
{
public int Id {get; set;}
public string Name {get; set;}
}
Using navigation properties i could load List<Level2>
like this
var myList = _myLevel1Repository.GetSingle(x=>x.Id == Level1Id, x=>x.Level2List);
but how do I load Level3 and its properties that is linked with Level2?
PS: Lazy loading is not possible.
This is the Getsingle
function
public T GetSingle(Func<T, bool> where, params Expression<Func<T, object>>[] navProps)
{
T item = null;
using (var context = new MyDbContext())
item = GetFilteredSet(context, navProps).AsNoTracking().FirstOrDefault(where);
return item;
}
Your GetSingle
method should be this way:
public T GetSingle(Func<T, bool> where, params Expression<Func<T, object>>[] navProps)
{
T item = null;
using (var context = new MyDbContext())
{
IQueryable<T> query = context.Set<T>();
//Include the navigations properties as part of the query
if (navProps!= null)
{
query = navProps.Aggregate(query, (current, include) => current.Include(include));
}
item = query.Where(where).FirstOrDefault();
}
return item;
}
I don't know what are you doing in the GetFilteredSet
method, but I guess you can reorganize the code I show above at your convenience. The key to include more than one level of nav. properties in EF is use the Include
method. When you use this method you are going to load the nav. properties as part of your query (check eager loading section in this link). Now, there are two Include methods :
Whit this method you need to pass the path of the nav. properties you want to load as an string, for example, in your case, it would be:
context.Set<Level1>.Include("Level2List.Level3");
DbExtensions.Include extension method
This is the method that I use in my above code where you can specify the related objects to include using a lambda expression. IMHO this is the best variant because is strongly typed, and if you change some of the nav. properties name in your entities, you are also going to receive a compilation error(s). In the link I share above, you can see all the patterns you can use to include different levels of nav. properties.
context.Set<Level1>.Include(l1=>l1.Level2List.Select(l2=>l2.Level3));
Returning to the initial problem, now you can use your GetSingle
method to include more than one level this way:
var entity= _myLevel1Repository.GetSingle(x=>x.Id == Level1Id, x=>x.Level2List.Select(l2=>l2.Level3));