Lazy Loading
Lazy loading is not a new concept and I must confess I didn’t know what it is. Thanks to Entity Framework (EF) for having it because It led me to understand lazy loading concept before I know how it can be used in the EF. 🙂
Alright, let us take the following example:-
1: // member variable
2: private List<Customer> customers= null;
3:
4: // property
5: public List<Customer> Customers
6: {
7: get
8: {
9: if (customers== null)
10: customers= GetCustomers();
11:
12: return customers;
13: }
14: }
Now, anywhere in your program when you use CustomerDataSet, It sees If the customers are already loaded, If not load it (e.g from a data store).
But this is not a new concept, right? Absolutely! However, the point is this concept is very important when you try to load related objects. Suppose Customers have Orders. You when you get all the customers, do you want to get all the orders placed by them? Probably not. You probably want to get the orders for customers when you need it (you are lazy here) and don’t want to get all the orders for all the customers when you just wanted customers.
Coming back to EF, lazy loading is enabled by default and it is controlled by the following property:-
1: contextObject.ContextOption.EnableLazyLoading
where contextObject is an instance of the type of ObjectContext. By default the lazy loading is enabled in EF.
So, how does it work in EF?. I generated the following model from an existing database.
So, as per the above model, a contact can have many addresses. Now, lets try to retrieve contacts having more than one address:-
Before I ran the above example, I opened the Sql Server profile and started a new trace and then ran the above. Following is the output:-
Following is what’s going on in the profiler:-
Disregard the “Trace Start” in the above and you should notice there are 12 rows. The very first query executed is the following which gets all the contacts in the system and DOES NOT get the addresses associated with all the contacts:-
The next 11 queries are the for getting the addresses for each of the 11 contacts the very first time we access the Addresses properties for each contact. In this case the query to get all the addresses will be fired when the item.Addresses.Count is called.
Following is the Sql query which gets fired to get addresses for each contact. There would be 11 trips to the database with the following query.
Eager loading:-
What If we want to load all the addresses as well for all the contacts when we get the contacts. Surely It can be done. However, for this, we need to turn off the lazyLoading behavior in EF. As I said before, It is on by default.
1: context.ContextOptions.LazyLoadingEnabled = false;
You just need to use “Include” method on the list, in this case the contact’s list and pass the path to other collection for each contact. In this case, each contact has “Addresses” collection, so we pass “Addresses”.
The query results which show multiple entries for same contact id, because It is listing all the addresses for all the contacts:-
Explicit (lazy) Loading:-
You check for the IsLoaded property of the collection (e.g. Addresses) and if It was not loaded for a given contact, you call the Load() method to load the Addresses for a given contact.
You should see the same number of same queries (same number of database trips) as you saw in case of lazy loading.
So the explicit loading is nothing but the lazy loading, however, in explicit loading we explicitly load the child collections (relations) and in lazy loading, we dont have to “load” them, they get loaded when they are accessed.