Syndication

Contribute

Entity Framework and Lazy Loading

Microsoft's Entity Framework is a new, powerful tool bringing data modeling, O/RM (object relational mapping) functionality and more. One expected feature of major ORMs is 'Lazy Loading'. Learn how the Entity Framework provides this functionality in a different way. This article will explain the design reasons behind why EF is different than what you would expect, as well as how to achieve the lazy-load functionality you're looking for.

It is important to realize that that ORMs are not a new concept. There are a lot of excellent ORMs out there for Ruby, Python and even for the .Net framework (NHibernate). As a result, when you "jump in" to EF, you may run into an 'issue' similar to what I did (with lazy loading not working the way I thought it would). Because I was used to LINQ to SQL, I was expecting implicit lazy loading, and therefore I thought that EF was broken. This misconception was wrong, and I'll explain more as we go on.

Before I go into detail about the difference in design between the Entity Framework and LINQ to SQL (or other ORMs like NHibernate), I want to show you the code that threw me for a loop. The scenario is simple, I had a "Customers" table and an "Orders" table in my SQL database. I used the LINQ to SQL designer and then the Entity Framework designer (Entity Data Model designer, or EDM). Both designers easily generated my c# code for me that will interact with my database.

My SQL tables had only a few records in there. The "Customers" table had one record, and the "Orders" table had three records that were linked to the customer. So, here's the code I wrote where I initially misjudged EF:

The above code worked exaclty as I thought it would. The first customer object was recieved from the database, and then when I accessed that customer's orders, LINQ to SQL went back to the database and got the orders. Now, here is what I thought was the same thing using the Entity Framework. Notice how many rows were in my datagrid:

// Using the Entity Framework
EFEntities entityFrameworkContext = new EFEntities();

And that was it. Something so simple as that caused me to spiral into a dark room of confusion. In fact, there are people out there who have 'given up' on EF right there. The problem here is not with the Entity Framework, but with my lack of understanding the underlying design of EF.

Why EF Didn't Lazy Load

As I mentioned before, the Entity Framework supplies ORM functionality, which includes 'lazy loading' of sorts. Actually, EF never claims to follow the Lazy Loading design pattern as is commonly understood. Instead, they provide "deferred" loading capabilities. As a side point, lazy loading, lazy initialization, deferred loading, on-demand loading and just-in-time loading all mean the same thing.

In the above example, LINQ to SQL *automatically* went back to the database and loaded the orders for that first customer. The team behind EF didn't want this *automatic* behavior happening. The reason behind this decision is simple: When architecting a larger project, it is highly important for developers to clearly understand when they are accessing certain resources, such as the database.

As a result, they require an *explicit* call to the ".Load" method of the deferred object. Or, you could "eagerly" load the properties in the initial call using the ".Include" method. Example:

// Explicitly include the orders from the database in one shot.this.MyDataGrid2.DataSource = entityFrameworkContext.Customers
.Include("Orders").First().Orders;

The Need for Automatic Lazy Loading in Entity Framework

While the reasoning above is good, it does not meet all design scenarios. Here is an example where you would want the automatic lazy loading, and then I'll show you how to achieve this functionality right there in EF!

Take this scenario as an example. Let's say we have a team of developers working on a SharePoint 2007 project. The end result will be a configurable web application where the end user will be able to add and remove web parts himself for display reasons. We are going to assume the following:

The lead developer built a static class called "BusinessObjects", and exposed a few properties, one being "CurrentCustomer".

Web part "CustomerBasicInfo" will display the current customer's name.

Web part "CustomerAvailableAddresses" will display a list of all addresses the customer has on record.

Web part "CustomerBillingHistory" will display a grid of any orders the customer has made in the past.

In this scenario, it is vital that the "BusinessObjects.CurrentCustomer" property does not eagerly load the ".Addresses" and ".Orders" of the customer object. Think about it, if the end user doesn't have web parts on his screen that utilizes that data, it would be a huge waste to download that data.

Also, it would be inappropriate for the developers of those web parts to call ".Load" on those objects. What if someone else loaded the objects? The developers of these web parts should simply create a "view" to the business object, not provide their own tracking code.

We have talked about the reasons why EF requires an explicit call to load these deferred objects, but now we see a scenario where we want implicit loading. Which brings us to our next section:

Configuring Lazy Loading in Entity Framework

As I promised, I will now show how you can achieve implicit lazy loading using the Entity Framework. The code I'm about to show you is automatically created by the EDM designer if you were to point to a database and have it generate the EDM from there. Then, I'll add one simple line of code (which I've already shown you) that will make everything work just the way you'd expect it.

This solution is simple. You get all the great power of the Entity Framework, the Entity Data Model designer, Entity SQL (and I could go on) and you can perform Lazy Loading the way you want to. Again, the decision to not automatically load deferred objects was a decided upon, debated and ultimately well made choice. But now you can see how easy it is to enable automatic lazy loading using Microsoft's Entity Framework.

Conclusion

You may not like my solution here, but EF is not being forced on anyone. As I mentioned above, there is LINQ to SQL, NHibernate and many other choices. Now that I understand the design reasons, and because I know the other great features of EF, I'll be yet another adopter of the product.

I realize that this is a semi-controversial topic, so please feel free to comment. But try to be constructive :)

BEAUTIFUL :) - Maybe we could get together and see if the EDM designer team would add a property for implicit lazy loading, and simply auto-generate the code. There are good points for both sides of the coin, and I think it would be in everyone's best interests if EF could support both design decisions out-of-the-box.

Unless I misundertand, it looks like you're asking us to modify the code that was written by the desiginer. It's great that this is possible but it's not a very good solution unless you're working with a model that never changes. Also keep in mind that code may have to be regenerated due to incompatibilities with updates and service packs (Visual Studio, C#, the entity framework itself).

IMO, this needs to optional:

Add calls to partial methods in these classes (e.g. OnAccessOrders) so I can implement the loading without my changes being overwritten.

-- OR

1. A default setting (LoadOnDemand) on the data/object/entity context.

2. A setting at the class/entity level (settable in the designed), initially set to "use entity context default".

3. A setting at the relationship/property level, initially set to "use class default".

----------

IMO: I disagree that the load on demand feature makes something unclear. This is a persistent object framework, the data is loaded when I ask for it. Sometimes you ask via query, sometimes you ask via property access. I'd like the data when I ask for it. I'd rather not make any network access unless I really need that data. Load on demand can be very efficient -- and -- the database could be local.