Migrating from LINQ to SQL to Entity Framework: Deferred Loading

Published 16 October 08 10:52 AM | dpblogs 

Last week, we covered Eager Loading and how to migrate LINQ to SQL based code that took advantage of Eager Loading. This week, we discuss Deferred Loading.

Generally speaking, queries only retrieve the objects you request, and not their related objects. Deferred Loading (or Lazy Loading) allows you to automatically load objects on demand if and when you attempt to access the object that is not yet loaded (you might do this by trying to access a property that allows you to get to the object you are interested in, for instance).

Automatic Deferred Loading has its advantages and disadvantages – automatic deferred loading that is on by default means more productivity and less code to write. However, it also means less control over when and how you hit the database. In LINQ to SQL, Automatic Deferred Loading is enabled by default, but it can be disabled by using the following code fragment. For more information, see Deferred versus Immediate Loading (LINQ to SQL).

db.DeferredLoadingEnabled = false;

In the example below, you are really only querying for  objects from the Products table – however, because Deferred Loading is enabled, you can access prod.SalesOrderDetail (which automatically fetches the associated SalesOrderDetail values from the database, and surfaces the results as SalesOrderDetail objects for the particular product)

var products = from prod in db.Products
               where prod.Color == "Blue"
               select prod;

foreach (Product prod in products)
{
    foreach (SalesOrderDetail detail in prod.SalesOrderDetail)
    {
        // do something with detail
    }
}

The Entity Framework does not provide an automatic mechanism for deferred loading.  However, a simple addition to the code above achieves the same result.

var products = from prod in db.Product
               where prod.Color == "Blue"
               select prod;

foreach (Product prod in products)
{
    // avoids unnecessary queries
    if (!prod.SalesOrderDetail.IsLoaded)
    {
        prod.SalesOrderDetail.Load();
    }

    foreach (SalesOrderDetail detail in prod.SalesOrderDetail)
    {
        // do something with detail
    }
}

For more information, see Navigation Properties. Also see Jaroslaw Kowalski’s blog series Transparent Lazy Loading for Entity Framework which discusses the EFLazyClassGen samples available on CodeGallery.  EFLazyClassGen could also be extended to support a Link<T> style deferred loading of individual properties.

In our next post, we will look at Stored Procedures. Stay tuned and let us know what you think!

- The ADO.NET Team

 

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# Stephen redd said on October 16, 2008 6:41 PM:

The lack of automatic deferred loading is a deal-breaker.

I respect the "reasons" for not having it enabled by default, and I understand why many might choose not to use it.

The lack of automatic lazy loading means that EF produces entities that you just CANNOT trust. I don't know about anyone else, but when I get a reference to an object, I EXPECT that when I call one of its properties that the property will not blow up in my face! I EXPECT the property to contain data, and that the data will be valid and accurate.

In EF though, when I call the SalesOrderDetail property I have no way to "know" what I'm going to get back. I might get back nothing... but am I getting nothing because it isn't loaded or because there just wasn't any data in the data store? I might get back an error, but it depends on the kind of property... not that getting an error makes me happy either.

Sure, I can explicitly check to see if data is loaded or not, but the mechanism to perform this check requires that I know a lot about the internals of the entity and the relationships between them. For example, I have to know if the property is a navigation property or not in order to know if I should check loaded.  Also, the mechanism to do the IsLoaded check is awkward.

Also, if  you pass the entity to another class as a return value... now you might not have the ability to explicitly load the related data at all (no context)... but the entity will still contain the booby-trapped properties.

Then there is the sheer noise of all those checks for loaded data and loads. Even in rather trivial applications I end up with more code just to do checks and loads than I have code to actually use the data.

The weight of all this is massive.

Look guys, the whole point of using something like EF and LINQ to Entities is to make data access simpler and better...

I shouldn't have to be suspicious and paranoid of each and every call to an entity. I shouldn't have to baby-sit the API constantly asking "are you sure" before I call a property. And I shouldn't have to know THAT much about the inner workings and relationships inside my logical model just to be able to use the entity without having my code blowing up in my face.

The whole point of EF was to gain abstraction... not force me to know the logical model inside-and-out.

Sure... I might WANT explicit deferred loading, but I shouldn't be FORCED to it ALL of the time.

# Gregory Kornblum said on October 19, 2008 11:27 PM:

Very good argument Stephen. You should write an article about this instead of a comment to someone else's.

# Stephen Redd said on October 21, 2008 7:20 PM:

Thanks Gregory,

I did write an article about it on my personal site back when I was still angry over the whole thing, but I was a little harsher in that article (strong language warning):

http://reddnet.net/code/ado-net-entity-framework-impressive-powerful-useless/

I do make a point to express the same concerns whenever I see the topic come up and it seems like it might be relevant to the discussion.

I might complain loudly, but I am confident that the data team at Microsoft is hearing this same message, and I am confident that they will fix this issue up in the next major release.

But just in case, I keep complaining :P

# Eric and the .NET Framework said on November 3, 2008 11:55 AM:

In 2001 we first demonstrated Object Relational Mapping (ORM) technology for .NET – ObjectSpaces . However

# Allen said on January 5, 2009 5:35 PM:

There is no way we'll use this if we have to check everything to see if a property is loaded or not.  The team better make some changes to that or this thing is DOA.  I can't believe they would make such a huge mistake.

# Simon Segal said on January 9, 2009 10:20 PM:

I believe eager and lazy loading should and need to be possible by developers expressing their intent prior to accessing attributes of objects. I want and need to have Fetching Strategies as per the NHibernate implementation. Using fetching strategies I have the option of injecting them and easily distributing and re-distributing them. I demonstrated this with LINQ to SQL here : http://www.simonsegal.net/blog/2008/09/16/linq-to-sql-going-poco-and-more/ and you could do the same by wrapping the .Includes extension method however it doesn't correlate well with lazy loading which causes a friction in developing a satisfying outcome. I would prefer my code not to be tightly coupled to my fetching requirements over time immemorial as they are by sprinking them explicitly throughout using .Includes() and .IsLoaded().

# TT said on January 15, 2009 3:50 PM:

The main reason for disabling lazy loading is the risk of loosing control over when and how you hit the database.

Inexperienced developers are protected against making database call in an unwanted manner. So why is it that more Linq2Sql developers don't have more problems with lazy loading even though they statistically would be more inexperienced users?

I think it is because if you if you do the error of calling Linq to .... code unaware of what physical storage that lies behind you would get into performance problems very soon and people learn quickly how to avoid this. You cannot be ignorant of what is being called behind the scenes when doing linq queries. That is one of the many reasons I like Linq2Sql over Entity Framework and even NHibernate since it clearly displays the database scheme you are querying. The database is usually the biggest performance factor in a normal web app so every developer should know the database they are querying.

# Ken Smith said on March 4, 2009 11:51 PM:

An even bigger problem with not having Lazy Loading implemented is that there are times you can call the ".Include()" method in your LINQ, and then by the time LINQ gets around to generating your result, it forgets that you've asked it to include the related objects.  For instance, if you use the new {} syntax at the end of your query, none of the navigations that you've asked in the middle of your query are remembered.  

See here for instance:

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=347543

///<Not working!>

var q2 = from p in ent.Products.Include("Categories")

                   where p.ProductID == 1

                   select new

                   {

                       Product = p,

                       SupplierCity = p.Suppliers.City

                   };

var prod2 = q2.First();

//comment: no eager loading -> prod2.Product.CategoriesReferense.IsLoaded == false

///</Not working!>

Whatever else this does, it certainly violates the principle of least astonishment.  It also creates headaches in a number of places, for instance, if you're trying to bind to the results of a query in WPF, and don't have the luxury of checking .IsLoaded() before accessing an object's navigation properties.  This definitely needs to get fixed.

# Medyum said on May 22, 2009 7:01 AM:

There is no way we'll use this if we have to check everything to see if a property is loaded or not.  The team better make some changes to that or this thing is DOA.  I can't believe they would make such a huge mistake.

# hikaye said on July 7, 2009 10:41 AM:

There is no way we'll use this if we have to check everything to see if a property is loaded or not.  The team better make some changes to that or this thing is DOA.  I can't believe they would make such a huge mistake.

# ssk sorgulama said on July 23, 2009 10:42 AM:

   The main reason for disabling lazy loading is the risk of loosing control over when and how you hit the database.

   Inexperienced developers are protected against making database call in an unwanted manner. So why is it that more Linq2Sql developers don't have more problems with lazy loading even though they statistically would be more inexperienced users?

   I think it is because if you if you do the error of calling Linq to .... code unaware of what physical storage that lies behind you would get into performance problems very soon and people learn quickly how to avoid this. You cannot be ignorant of what is being called behind the scenes when doing linq queries. That is one of the many reasons I like Linq2Sql over Entity Framework and even NHibernate since it clearly displays the database scheme you are querying. The database is usually the biggest performance factor in a normal web app so every developer should know the database they are querying.

# zerrin egeliler said on July 23, 2009 12:55 PM:

a very good article da a very useful information ..thank you has to share this information.

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

Search

This Blog

Syndication

Page view tracker