202

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!

3
  • 1
    Adding another .Include should work unless you mean that the additional include is a grandchild of Course. See this or a better option is this Commented Apr 2, 2013 at 12:55
  • Related / possible duplicate of stackoverflow.com/q/3356541 Commented Aug 6, 2018 at 10:35
  • .Include(t => t.Prop).ThenInclude(p => p.NestedProp) Commented Jul 25, 2024 at 22:02

7 Answers 7

276

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.

Sign up to request clarification or add additional context in comments.

5 Comments

Appreciate it! Where can I learn more of this? I'm especially interested in the difference between Include and Select
Only this one worked for me: .Include("Module.Chapter"). Any idea why would that be?
@JoSmo you need to import the namespace System.Data.Enity to access the extensionmethod. more info here
You might need to disable lazy loading to avoid infinite loop errors: dbContext.Configuration.LazyLoadingEnabled = false;
upvoted for mentioning the brilliant linqpad, and tip to use System.Data.Entity, thx Jens
120

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://learn.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(); 

5 Comments

In EF.core I seem to not be able to do .Include(i => i.Modules.Select(s => s.Chapters)), specifically the .Select inside .Include. Can anyone confirm or speak to?
@ttugates What do you intent to do with this select? I think what you want to do is exactly what you do with ThenInclude in EF core. Perhaps make a question with a good example, so that we can answer it.
@Nick N - Entity Framework Linq Query: How to Where on Multiple Nav Properties and Select from 3rd Nav Property. Because what I Select is not what I am matching on, the Includes are not necessary so the question is tangential. My question may be too "narrow" but appreciate any help.
Ah. Actually, .ThenInclude() does work. Just takes forever for the intellisense to display the related tables.
The best answer
25

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); 

2 Comments

appreciate it! could you point me to where I can learn more of this? Thanks!
Do you know what the syntax is if Modules has multiple tables you want to join? Say it links to Chapters and something else?
25

You can also try

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

3 Comments

Thanks - the dot notation in the string very useful
This can be useful, but, one reason not to use this is ease of refactoring later: if you rename the "Chapters" entity at some point, the other example will automatically be renamed. Another is that errors will be found sooner: at compile time, not run time.
@MGOwen I agree with your comment. However, could use: db.Courses.Include($"{nameof(Modules)}.{nameof(Chapters)}").Single(c => c.Id == id); as well.
6

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); 

2 Comments

I was trying your answer, but it's throwing stackoverflowexceptions due to an infinite loop with itself.
@VictoriaS., you can rename the extension method so that it doesn't interfere with the real Include
4

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); 

1 Comment

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

Here is my working example. AccountInfoes is parent for User, User is parent for Currency and for Country.

var accountinfo = _context.AccountInfoes.Include(a => a.User) .Include(a=>a.User.Currency) .Include(a => a.User.Country) .FirstOrDefaultAsync(ai => ai.UserId == userId); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.