Migrating from LINQ to SQL to Entity Framework: Eager Loading

Published 07 October 08 09:58 PM | dpblogs 

Since the release of the Entity Framework, we have received a number of requests for details and best practices from customers who are looking at migrating their LINQ to SQL based applications to the Entity Framework.  In order to address this topic, we are beginning a new series of blogs posts that will look at various aspects of migration.

This first post in the series covers Eager Loading in LINQ to SQL, and the steps for migrating to equivalent constructs in the Entity Framework in .NET 3.5 SP1. Subsequent posts will cover Deferred Loading, LINQ specifics, concurrency, mapping, stored procedure support, and other topics. As we continue to approach the next release of the Entity Framework we will revisit how some of the new features aid in migration.

What is Eager Loading?

Eager, or immediate, loading occurs when you query for an object and all of the related objects are also returned. One of the major differences in how LINQ to SQL and the Entity Framework implement eager loading is that LINQ to SQL allows eager loading behavior to be specified at the context level, and the Entity Framework supports it at the query level.

Eager Loading an entity’s related data with LINQ to SQL

LINQ to SQL allows you to define the eager loading behavior at the Context level. The DataLoadOptions class allows you to define the load behavior and attach it to a context. This defines the eager loading behavior for all entities that are fetched for that particular DataContext instance. For more information, see Deferred versus Immediate Loading (LINQ to SQL).

DataLoadOptions dataLoadOptions = new DataLoadOptions();
dataLoadOptions.LoadWith<Customer>(c => c.Order);
db.LoadOptions = dataLoadOptions;

List<Customer> customers = db.Customer.ToList();

Eager Loading an entity’s related data with Entity Framework

The Entity Framework allows you to define eager loading at the query level by using the Include method. For more information, see Shaping Query Results.

List<Customer> customers = db.Customer.Include("Order").ToList();

The scope of eager loading differs between LINQ to SQL and the Entity Framework. LINQ to SQL supports per-context eager loading options and the Entity Framework supports per-query eager loading options.

Using LINQ to SQL for cascading eager loading spanning multiple entity types

In LINQ to SQL, you can define eager loading for any type of entity that is passed with the LoadWith method. For example, you can specify EntitySets that are directly available on an entity as an argument. For each EntitySet that is to be eager loaded, declare a new LoadWith clause and include it as a part of DataLoadOptions.

If this is done for a chain of hierarchy as shown in the below example, Customer ->Loadwith ->Orders->Loadwith ->OrderDetails, we can eagerly load multiple levels in the object graph.

DataLoadOptions dataLoadOptions = new DataLoadOptions();
dataLoadOptions.LoadWith<Customer>(c => c.Order);
dataLoadOptions.LoadWith<Order>(c => c.OrderDetail);
db.LoadOptions = dataLoadOptions;

List<Customer> customers = db.Customer.ToList();

Cascading Eager Loading in Entity Framework

The Include method allows multiple hierarchies of the EntityCollection to be denoted with dot (.) notation.

 

List<Customer> customers = 
db.Customer.Include("Order.OrderDetail").ToList();

In the Entity Framework, a single call of the Include method can eagerly load the multilevel hierarchy in an EntityCollection, per query.

Eager Loading of multiple relationships in LINQ to SQL

In LINQ to SQL, multiple EntitySets can be eagerly loaded with an entity by adding each one of them using the LoadWith method of the DataLoadOptions class and attaching the DataLoadOptions object to the DataContext.

DataLoadOptions dataLoadOptions = new DataLoadOptions();
dataLoadOptions.LoadWith<Product>(c => c.OrderDetail);
dataLoadOptions.LoadWith<Product>(c => c.Supplier);
db.LoadOptions = dataLoadOptions;

Product firstProduct = db.Product.First();

Eager Loading of multiple relationships in Entity Framework

In the Entity Framework, you can use the Include method multiple times in a query to eager load multiple EntityCollections.

Product firstProduct = 
db.Product.Include("OrderDetail").Include("Supplier").First();

LINQ to SQL keeps multiple LoadWith clauses in an array within DataLoadOptions. The Entity Framework allows you to add multiple Include methods on an entity for a particular query.

In our next post, will look at Deferred/Lazy Loading. 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

# Migrating from LINQ to SQL to Entity Framework: Eager Loading : EasyCoded said on October 8, 2008 1:07 AM:

PingBack from http://www.easycoded.com/migrating-from-linq-to-sql-to-entity-framework-eager-loading/

# Jay said on October 8, 2008 5:23 AM:

When is the next release of Entity Framework scheduled?

# Ido Flatow said on October 8, 2008 6:22 AM:

Unfortunately, .Include supports loading only one related end, thus making us load each and every related end by code. I'd think that there should be something like .Include("*") to load all referenced entities, and event .Include("*/*") for getting all cascaded entities. If i'm writing a service that returns an entity with all related data, I won't want to start writing numerous lines of code, just to mention that "oh, yes, of course I want to return ALL the data of the entity".

# Paul Blamire said on October 8, 2008 6:37 AM:

Nice work. Looking forward to the rest of this series

# Joseph F said on October 8, 2008 12:04 PM:

Fantastic! I've always hated the way LINQ2SQL handled eager fetching. But, where is the strong typing. A string just doesn't seem like the ideal way of specifying this.

# divega said on October 8, 2008 12:22 PM:

Hello Ido,

Something like Include("*") is intentionally not supported. While the Include API makes it easy to modify a query for it to load related information, each related end that you add comes at a cost.

Loading multiple paths and/or multiple levels, very quickly results in extremely complex queries.

My recommendation is to eager load only what is needed, always adding related ends and levels one at a time. As soon as you see any performance degradation, go one step back and try using other techniques. Sometimes it may help to do explicit load (as an example, it is not necessary to expand all orders, only the one you are displaying details for).

Other times you may want to take advantage of the relationship fix-up that we do for tracked queries. As an example, you can load Orders and the corresponding OrderLines in two separate AppendOnly queries. Once you have loaded the results of both queries, the stack will have fixed-up all relationships, so you will find each order’s OrderLines collection is loaded.

Diego

# Craig Stuntz said on October 8, 2008 12:46 PM:

How do you eager load properties of a subtype? For example, let's say I have a type Department which has a navigation property (0..1) Chairman of type Employee.  Some of the employees are Managers.  Managers has a Supervises property which returns a list of Employees.  When I eager load the department Chairman, I would also like to eager load all Employees supervised if the Chairman is a Manager.

In other words, something like this (I'm making up the syntax):

.Include("Chairman").Include("(Chairman as Manager).Employees").

?

# Mark Smeltzer said on October 8, 2008 5:33 PM:

Regarding the use of strings... here is a comment I posted on the EF design blog a few days ago:

Hey Guys,

It would be really helpful if the code generators could generate a layer of abstractions that contained all of the string constants that are used in the attributes. Currently, it is a real pain that we often need to use string constants when doing things like eSQL or Include()'s.

I wrote my own little utility to parse through the XML bits, and generate classes to do the job for me, but it would be great if this were available for everyone as part of the toolset.

The classes I generate a just a series of nested static classes that allow me to write things like "MyDbContextMetadata.Entities.Customer .Properties.PhoneNumber.PropertyName" or "MyDbContextMetadata.Entities.Customer .Relationships.Supplier.Properties.Id.PropertyName".

That stuff is certainly a bit verbose, but the key benefit is that when model changes so will the metadata structures. Thus, any invalid metadata references will generate compilation errors rather than runtime errors.

# Travis Plummer said on October 9, 2008 10:47 AM:

I second the request by Craig Stuntz. Self joins with subtyped nodes are common and we don't want to recursively load these relationships. When I give the children\nav property name with include, why can't it resolve n levels deep for me?

Thanks,

 Travis

# Steve Strong's Blog said on October 10, 2008 5:51 AM:

Weekly digest of interesting stuff

# Swiss MSDN Team Blog said on October 13, 2008 8:48 AM:

Since the release of the Entity Framework, Microsoft got a number of requests for details and best practices

# ADO.NET team blog said on October 16, 2008 1:52 PM:

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

# Guy Hurst said on October 17, 2008 2:27 PM:

Eager loading in EF apparently has limitations on SQL2000 - we weren't able to Include() nested levels, and had to use separate Load() calls after completing the initial query.

In other words, we had to use multiple sequential queries.

However, when we used SQL2005 as the underlying DB, with MARS enabled, the nested Include()'s worked fine. Does this mean EF requires MARS (Multiple Active Result Sets) to do nested Include()'s ? And by extension, does it therefore need MARS to fully support eager loading?

# Guy Hurst said on October 17, 2008 2:45 PM:

Let me modify my previous comment by specifying that the nested Include()'s that failed were not just nested, but were to the same underlying table. Several Navigation Properties of the entity being queried were actually associating to the same underlying table, and this seems to have been the source of the conflict.

# shawn said on November 2, 2008 8:47 PM:

I'm in agreement with Joseph and Mark's comments, if we can get an option for strongly-typed Include statements to use as an option instead of strings that would be great.  After using LINQ to get away from strings of SQL it is unfortunate to have to embed strings back in as part of Includes.  It just seems a little brittle.

# Daniel said on February 16, 2009 10:00 PM:

A few things I have noticed in the Comments, some said they didn't like the use of a string in the "include" (no strong typing), and I also saw someone say it does not support multuple levels of associated entities.

As far as strong typing the query as opposed to writing the table name in it, I haven't seen a clever way around that, the closest I can get is:

Instead of this:

Product firstProduct =        db.Product.Include("OrderDetail").Include("Supplier").First();

Write this:

Product firstProduct =        db.Product.Include(db.OrderDetail.CommandText).Include(db.Supplier.CommentText).First();

And as far as supporting multiple levels, you can write something like this:

Product firstProduct =        db.Product.Include(db.OrderDetail.CommandText + "." + db.OrderDetailLevel2.CommandText).Include(db.Supplier.CommentText + "." + db.SupplierLevel2.CommandText).First();

You see, the "Include" accepts a "dot-delimited" list of an existing path of associated entities

Hope this helps somebody!

# stuartle said on February 22, 2009 6:03 AM:

I wrote a blog post last year about a possible way to use Include with expressions rather than strings in Entity Framework:

http://blogs.msdn.com/stuartleeks/archive/2008/08/27/improving-objectquery-t-include.aspx

# Jim Wooley said on April 13, 2009 3:55 PM:

Daniel,

Instead of using the CommandText to supply a string representation of the object to be "Included", why not support an expression predicate as LINQ to SQL does in the LoadWith option. That provides a richer option as you can not only strongly type the child relationship, but can also add filtering as well. Thus you could have:

Product firstProduct = db.Product.Include(p => p.OrderDetail);

Or

Product firstProduct = db.Product.Include(p => p.OrderDetail.OfType<ActiveOrders>());

Of course this would entail parsing more expression trees as part of the query evaluation, but could provide a much richer implementation.

# Non-Migrator said on May 15, 2009 6:13 PM:

Since Entity Framework doesn't even support enumerations, why would people want to migrate away?  I guess there are some advanced scenarios where a person would need to, but IMO, Entity Framework just isn't developed enough yet.  Agree?  Disagree?

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

I also saw someone say it does not support multuple levels of associated entities.

As far as strong typing the query as opposed to writing the table name in it, I haven't seen a clever way around that, the closest I can get is:

Instead of this:

Product firstProduct =        db.Product.Include("OrderDetail").Include("Supplier").First();

Write this:

Product firstProduct =        db.Product.Include(db.OrderDetail.CommandText).Include(db.Supplier.CommentText).First();

And as far as supporting multiple levels, you can write something like this:

Product firstProduct =        db.Product.Include(db.OrderDetail.CommandText + "." + db.OrderDetailLevel2.CommandText).Include(db.Supplier.CommentText + "." + db.SupplierLevel2.CommandText).First();

You see, the "Include" accepts a "dot-delimited" list of an existing path of associated entities

Hope this helps somebody!

# hikaye said on July 4, 2009 3:28 PM:

This is fantastic. I am going to add it to my sites. Thanks!

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

Fantastic! I've always hated the way LINQ2SQL handled eager fetching. But, where is the strong typing. A string just doesn't seem like the ideal way of specifying this.

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

This is fantastic. I am going to add it to my sites. Thanks!

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required

Search

This Blog

Syndication

Page view tracker