Caution when Eager Loading in the Entity Framework


Silverlight Logo

UPDATE: Roger Jennings correctly stated, I meant to say that Include is *not* a guarantee.

When I am using the Entity Framework for a project, I have gotten into the habit of using eager loading via the Include syntax. In case you're not familiar it, the Entity Framework has a different philosophy than other data layers (e.g. NHibernate). In the Entity Framework, relationships have to be manually loaded when they are lazy loaded (so developers never have network round-trips without explicitly knowing about it). Whether you agree or not with this philosophy, understanding how it works is helpful when you're working with the Entity Framework.

The Entity Framework supports eager loading of the data as well using the Include syntax.  For example:

var qry = from w in ctx.Workshops.Include("Topic")
          orderby w.Name
          select w;

By amending the source of the query with the Include method, you can eager load relationships.  The problem is that these are really hints to the Entity Framework to load the relationships, but not a guarantee.  Depending on the query, these Includes may be dropped. The two scenarios I see this most often are the grouping and subselects:

// Drops the Include
var qry = from e in ctx.Events
          where e.EventDate >= DateTime.Today
          group e by e.EventLocation.Region into r
          select r;

I ran into a good post on the forums on the subject:

In that post, Diego Vega says that Include only makes sense in the following scenarios:

  • Include only applies to items in the query results: objects that are projected at the outermost operation in the query, for instance, the last Select() operation (in your query, you tried to apply Include to a subquery)
  • The type of the results has to be an entity type (not the case in your query)
  • The query cannot contain operations that change the type of the result between Include and the outermost operation (i.e. a GroupBy() or a Select() operation that changes the result type)
  • The parameter taken by Include is a dot-delimited path of navigation properties that have to be navigable from an instance of the type returned at the outermost operation

To alleviate the problem in some scenarios, you can use the EFExtensions Include Extension method to add includes on the complete query like so:

using Microsoft.Data.Extensions;
// ...
var qry = from e in ctx.Events
          where e.EventDate >= DateTime.Today
          select e;

List results = qry.Include("Workshop").ToList();

You can find the EFExtensions at the MSDN Code site here:

Has this bitten you before?

Application Name WilderBlog Environment Name Production
Application Ver Runtime Framework .NETCoreApp,Version=v1.1
App Path D:\home\site\wwwroot Runtime Version .NET Core 4.6.24628.01
Operating System Microsoft Windows 6.2.9200 Runtime Arch X86