Explicit Loading with DbContext

Description and code samples
Table of Contents
Description

What it is

Explicit loading is specific lazy loading variant in which related data is loaded separately, after the main data has been loaded. However, a explicit call to a method must be done to load the data.

When/Why to use it

  • Navigation properties does not need to be declared as virtual. In specific scenarios it may not be possible to change the existent POCO entity classes;
  • Only what is required is loaded: lazy loading can potentially generate an unexpected number of queries submitted to the database.

How to do it

Explicit loading is achieved using the DbContext.Entry method.

Together with the internal information that DbContext has about an entity object, the Entry method gives access to loading operators for navigation properties, namelly:

  1. Obtain the target entity, using a LINQ query;
  2. Use the Entry method parameterized with the target entity object instance (returns result of type DbEntityEntry);
  3. Use the DbEntityEntry.Collection or the DbEntityEntry.Reference parameterized with a lambda expression to specify the property to drill into (returns result of type DbCollectionEntry or DbReferenceEntry); and
  4. Use the Load method to submit a LINQ query for the related data and load it into memory OR use the Query method to create a Linq To Entities query for the associated entity. These two methods can also be combined to load partial contents of a collection navigation property
Explicit loading executes separated queries for related data.

 

Operations
Loading collecion navigation property (full contents)
How to do it
using (var context = new BreakAwayContext())
  {
    var query = from d in context.Destinations
                where d.Name == "Grand Canyon"
                select d;

    var canyon = query.Single();

    context.Entry(canyon)
      .Collection(d => d.Lodgings)
      .Load();

    Console.WriteLine("Grand Canyon Lodging:");
    foreach (var lodging in canyon.Lodgings)
    {
      Console.WriteLine(lodging.Name);
    }
  }
Loading reference navigation property
How to do it
using (var context = new BreakAwayContext())
{
  var lodging = context.Lodgings.First();

  context.Entry(lodging)
    .Reference(l => l.PrimaryContact)
    .Load();

    Console.WriteLine(lodging.PrimaryContact.Name);
}
Loading collecion navigation property
How to do it

Load partial contents based in a Linq To Entities query:

using (var context = new BreakAwayContext())
  {
    var canyonQuery = from d in context.Destinations
                      where d.Name == "Grand Canyon"
                      select d;

    var canyon = canyonQuery.Single();

    var lodgingQuery = context.Entry(canyon)
      .Collection(d => d.Lodgings)
      .Query();

    var distanceQuery = from l in lodgingQuery
                  where l.MilesFromNearestAirport <= 10
                  select l;

    foreach (var lodging in distanceQuery)
    {
      Console.WriteLine(lodging.Name);
    }
  }

Load partial contents combining Query and Load methods:

using (var context = new BreakAwayContext())
{
  context.Entry(canyon)
  .Collection(d => d.Lodgings)
  .Query()
  .Where(l => l.Name.Contains("Hotel"))
  .Load();
}
Checking if a navigation property has been loaded
Remarks

The IsLoaded propeprty will be set to true when lazy, eager, or explicit loading is used to load the contents of the navigation property.

How to do it
using (var context = new BreakAwayContext())
  {
    var canyon = (from d in context.Destinations
                  where d.Name == "Grand Canyon"
                  select d).Single();

    var entry = context.Entry(canyon);

    Console.WriteLine(
      "Before Load: {0}",
      entry.Collection(d => d.Lodgings).IsLoaded);

    entry.Collection(d => d.Lodgings).Load();

    Console.WriteLine(
      "After Load: {0}",
      entry.Collection(d => d.Lodgings).IsLoaded);
  }