seebiscuit seebiscuit - 2 months ago 12
C# Question

Does the eager Include function call data in-memory?

I was reading this answer and I realized that I'm not clear on how eager loading works in the in-memory lifecycle of an

IQueryable
.

Say you have
db.Customers.Include("Orders")
, which generates an object graph like this:

Customer
Order
Order
Order


If you don't enumerate the return from an
Include
does it load the data in-memory?

That is, does

IQueryable<Customer> customersWithOrders = db.Customers.Include("Orders");


imply that the
Customer
collection (and his
Orders
) has been brought in-memory by the eagerly included
Orders
? Or, does "eagerness" mean that if/when the
Customer
collection is enumerated, the orders will be brought in-memory as well?

Answer

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.