EF LINQ include multiple and nested entities

.Netasp.net Mvc-3LinqEntity FrameworkEntity Framework-5

.Net Problem Overview


Ok, I have tri-leveled entities with the following hierarchy: Course -> Module -> Chapter

Here was the original EF LINQ statement:

Course course = db.Courses
                .Include(i => i.Modules.Select(s => s.Chapters))
                .Single(x => x.Id == id); 

Now, I want to include another entity called Lab which is associated with a course.

How do I include the Lab entity?

I tried the following but it didn't work:

Course course = db.Courses
                .Include(i => i.Modules.Select(s => s.Chapters) && i.Lab)
                .Single(x => x.Id == id); 

Any ideas on including the 2nd Entity?

Any piece of advise or information would be highly appreciated. Thanks!

.Net Solutions


Solution 1 - .Net

Have you tried just adding another Include:

Course course = db.Courses
                .Include(i => i.Modules.Select(s => s.Chapters))
                .Include(i => i.Lab)
                .Single(x => x.Id == id);

Your solution fails because Include doesn't take a boolean operator

Include(i => i.Modules.Select(s => s.Chapters) &&          i.Lab)
                           ^^^                  ^             ^ 
                          list           bool operator    other list

Update To learn more, download LinqPad and look through the samples. I think it is the quickest way to get familiar with Linq and Lambda.

As a start - the difference between Select and Include is that that with a Select you decide what you want to return (aka projection). The Include is a Eager Loading function, that tells Entity Framework that you want it to include data from other tables.

The Include syntax can also be in string. Like this:

           db.Courses
            .Include("Module.Chapter")
            .Include("Lab")
            .Single(x => x.Id == id);

But the samples in LinqPad explains this better.

Solution 2 - .Net

In Entity Framework Core (EF.core) you can use .ThenInclude for including next levels.

var blogs = context.Blogs
    .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
    .ToList();

More information: https://docs.microsoft.com/en-us/ef/core/querying/related-data

Note: Say you need multiple ThenInclude() on blog.Posts, just repeat the Include(blog => blog.Posts) and do another ThenInclude(post => post.Other).

var blogs = context.Blogs
    .Include(blog => blog.Posts)
        .ThenInclude(post => post.Author)
    .Include(blog => blog.Posts)
        .ThenInclude(post => post.Other)
 .ToList();

Solution 3 - .Net

Include is a part of fluent interface, so you can write multiple Include statements each following other

 db.Courses.Include(i => i.Modules.Select(s => s.Chapters))
           .Include(i => i.Lab)
           .Single(x => x.Id == id); 

Solution 4 - .Net

You can also try

db.Courses.Include("Modules.Chapters").Single(c => c.Id == id);

Solution 5 - .Net

One may write an extension method like this:

    /// <summary>
    /// Includes an array of navigation properties for the specified query 
    /// </summary>
    /// <typeparam name="T">The type of the entity</typeparam>
    /// <param name="query">The query to include navigation properties for that</param>
    /// <param name="navProperties">The array of navigation properties to include</param>
    /// <returns></returns>
    public static IQueryable<T> Include<T>(this IQueryable<T> query, params string[] navProperties)
        where T : class
    {
        foreach (var navProperty in navProperties)
            query = query.Include(navProperty);

        return query;
    }

And use it like this even in a generic implementation:

string[] includedNavigationProperties = new string[] { "NavProp1.SubNavProp", "NavProp2" };

var query = context.Set<T>()
.Include(includedNavigationProperties);

Solution 6 - .Net

this is from my project

 var saleHeadBranch = await _context.SaleHeadBranch
 .Include(d => d.SaleDetailBranch)
 .ThenInclude(d => d.Item)
 .Where(d => d.BranchId == loginTkn.branchId)
 .FirstOrDefaultAsync(d => d.Id == id);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAnimaSolaView Question on Stackoverflow
Solution 1 - .NetJens KlosterView Answer on Stackoverflow
Solution 2 - .NetNick N.View Answer on Stackoverflow
Solution 3 - .NetIlya IvanovView Answer on Stackoverflow
Solution 4 - .NetMartin LarssonView Answer on Stackoverflow
Solution 5 - .NetMohsen AfshinView Answer on Stackoverflow
Solution 6 - .NetRameesh PuthukkudyView Answer on Stackoverflow