Code through the pain Ladislav Mrnka's professional blog about software development

16Apr/127

Eager loading is one of core features in Entity Framework. It allows us loading related entities with main entities in a single round trip to the database. This feature should be extended in the future because the current implementation has several limitations:

We can't specify conditions for eager loading

A lot has been written about this limitation including existing highly voted UserVoice suggestion. The current implementation always loads all related records so if we have a main entity which has thousand related entities and we want to get only 10 most recent through eager loading we don't have a direct way to achieve that. We can use a projection to a custom type or an anonymous type to overcome this limitation but that is just a workaround for the missing feature. Eager loading should offer possibility to limit eager loaded data through conditions and to limit number of returned entities - generally strongly typed Include method should support extension methods like Where, OrderBy and Take.

We can't declare eager loading globally

The current implementation demands eager loading to be specified in every query through Include extension method. In most cases the eager loading definition can be wrapped to a separate extension method and reused so the global eager loading would be just a nice to have feature but there are situation where current Include method doesn't work - for example eager loading on inheritance hierarchies is problematic. Entity framework should offer additional ways to define eager loading. I can imagine two such new ways:

  • Global eager loading defined directly in mapping as proposed in already existing UserVoice suggestion
  • Context scope eager loading defined per context instance - similar mechanism was available in LINQ-to-SQL and its DataLoadOptions

Both these implementations would force the query engine to automatically use eager loading of related entities every time the main entity is queried. They should work on inheritance strategies but also for example when the main entity is queried through lazy loading (you will lazy load entity with all relations configured for global eager loading).

We can't specify how should eager loading be executed

At the moment all eagerly loaded data are joined to one result set. This can be absolutely fine in some cases (eager loading of reference property or small collection for few entities) but it can have a significant impact on larger queries with a lot of eagerly loaded data - I described this problem in the answer for the question asked by puretechy on Stack Overflow. We should be able to specify if eager loading should use a join or a separate query to load related data. All details to build the separate query automatically are already present in the main query where we are using eager loading. As a workaround we can specify and execute those separate queries manually but the disadvantage is that Entity Framework doesn't offer any way to batch multiple queries to single round trip to the database. I posted the related suggestion to UserVoice yesterday.

All these features would greatly improve our development experience when using Entity Framework and eager loading. They will also fit to the most required feature on UserVoice: Improve SQL Generation because possibility to control how eager loading is executed and how many data are really loaded is nothing more than improved control over generated SQL.

Posted on April 16, 2012 by Ladislav Mrnka
Filed under: Entity framework
Leave a comment
Comments (7) Trackbacks (0)
  1. Do you think that these new features will be present in EF5 or next?

    • Unfortunately neither of these features will be present in EF5 and it will probably take a lot of time before at least some of them appear in EF. All these features most probably require changes in EF core libraries. Even if ADO.NET team decides to implement any of them (they haven’t yet – only the first feature is marked as under review at the moment), the implementation will be dependent either on extracting EF core libraries from .NET framework (another highly voted feature) or next version of .NET framework (or service pack) – I mean version after .NET 4.5.

  2. first request requires them to change the way include method is used. in order to be able to filter and/or order included entities, they should provide generic version of include an overload with 2 extra paramters, one for filtering and one for ordering. they should add an extra generic type paramter which is the type of entity returned from include expression. unfortunetly compiler doesnt infer this extra parameter which leads to ugly code. with string version i think they get rid of this problem with e-sql style strings. i cant anticipate the problems they will encounter with this because i havent ever used e-sql.

    but i think real problem starts when you use more then one level includes. but i think this is still possible to provide a mechanism. at least they can accept a Dictionary paramter, which key is entity type name, value is filter expression.

    • ESQL will not help. ESQL lost its battle against Linq-to-entities and people almost don’t use it. DbContext API even doesn’t expose methods to use it. Moreover ESQL doesn’t contain anything related to eager loading. That feature is outside of ESQL facility.

  3. third request seems easy to implement with 1 level. but becomes more compicated with more levels. after 2. level they have to start to use WHERE FK IN (SELECT PK FROM [FirstQuery]) style nested queries which will cause different performance issues. i think entity framework team is going very slow and they are not working willingly

    • Even with multiple levels you can still build queries with SQL joins.

      Entity Framework team has made a decision to release Code First, DbContext API, Code First Migrations, EF Power Tools + they made improvements to .NET 4.5. It may look that they are slow but they still released a lot of demanding features. As in any other team their resources are limited and allocated to most needed features. By voting on UserVoice we can show that some feature is really needed and hopefully push it to one of next releases.

  4. Hi,

    I read a lot of your answers in Stack Overflow and they are very helpful. Thanks!

    I was able to use this code to do conditional eager loading. I watched it through the SQL profiler and confirmed there is indeed just one DB call. Does this make sense to you?

    =====
    IQueryable query = _context.Set.Where(p => p.PersonId == id)
    .Include(p => p.Person.Salutation);

    if( loadingOptions.HasFlag( ProfileLoadingOptions.SecurityQuestion))
    query = query.Include( p=>p.Person.SecurityQuestion);

    if (loadingOptions.HasFlag(ProfileLoadingOptions.ContactInfo))
    query = query.Include(p => p.Phones).Include(p => p.PersonalUrls);

    // …

    return query.ToList().FirstOrDefault();


Leave a comment

(required)

No trackbacks yet.