There's two things going on here. First, no query is submitted to the database until some operation is done that requires execution of that query. For example, if you were to do something like:
var foos = db.Foos.Where(...);
No query has actually been issued yet. However, if you were to then do something like:
foreach (var foo in foos)
{
...
}
Then, the query is sent to the database. Other things that will cause the query to be executed are things like calling ToList()
, Count()
, etc. Basically, whenever there's a need for the actual data, then, and only then does Entity Framework send the query.
Then, there's the totally separate concept of eager vs lazy loading. This is about related items and is basically about whether Entity Framework should issue one or more joins as part of the query or not. By using Include()
, you're instructing Entity Framework to issue a join for that relationship. Again, no query will be issued until it is evaluated (iteration, enumeration, count, etc.), but when you do evaluated it, the both the set of entities and related entities you included will all be pull at once.
If you choose to not include a relationship, then you fallback to lazy-loading, which means the relationship will not be materialized unless you access it in some way. This is similar in some respects to how the initial query worked. The related items are only fetched at the point where the data is actually needed; otherwise no query is issued. However, this will then be an entirely separate query.
Long and short, you just need to pay attention to what data you need and when. If you're going to utilize related entities, then you should include those before the query is evaluated, but either way, the query will only be sent when the data it represents is necessary.