Using DbContext in EF 4.1 Part 6: Loading Related Entities

 


The information in this post is out of date.

Visit msdn.com/data/ef for the latest information on current and past releases of EF.

For Loading Related Entities see https://msdn.com/data/jj574232


 

Introduction

Version 4.1 of the Entity Framework contains both the Code First approach and the new DbContext API. This API provides a more productive surface for working with the Entity Framework and can be used with the Code First, Database First, and Model First approaches. This is the sixth post of a twelve part series containing collections of patterns and code fragments showing how features of the new API can be used.

The posts in this series do not contain complete walkthroughs. If you haven’t used EF 4.1 before then you should read Part 1 of this series and also Code First Walkthrough or Model and Database First with DbContext before tackling this post.

Eagerly loading related entities

Eager loading is the process whereby a query for one type of entity also loads related entities as part of the query. Eager loading is achieved by use of the Include method. For example, the queries below will load princesses and all the unicorns related to each princess.

 using (var context = new UnicornsContext())
{
    // Load all princesses and related unicorns
    var princesses1 = context.Princesses
                          .Include(p => p.Unicorns)
                          .ToList();

    // Load one princess and her related unicorns
    var princess1 = context.Princesses
                        .Where(p => p.Name == "Cinderella")
                        .Include(p => p.Unicorns)
                        .FirstOrDefault();

    // Load all princesses and related unicorns using a string
    // to specify the relationship
    var princesses2 = context.Princesses
                          .Include("Unicorns")
                          .ToList();

    // Load one princess and her related unicorns using a string
    // to specify the relationship
    var princess2 = context.Princesses
                        .Where(p => p.Name == "Cinderella")
                        .Include("Unicorns")
                        .FirstOrDefault();
}

Note that Include is an extension method in the System.Data.Entity namespace so make sure you are using that namespace.

Eagerly loading multiple levels of related entities

It is also possible to eagerly load multiple levels of related entities. The queries below show examples of how to do this for both collection and reference navigation properties.

 using (var context = new UnicornsContext())
{
    // Load all castles, all related ladies-in-waiting, and all related
    // princesses
    var castles1 = context.Castles
                       .Include(c => c.LadiesInWaiting.Select(b => b.Princess))
                       .ToList();

    // Load all unicorns, all related princesses, and all related ladies
    var unicorns1 = context.Unicorns
                        .Include(u => u.Princess.LadiesInWaiting)
                        .ToList();

    // Load all castles, all related ladies, and all related princesses
    // using a string to specify the relationships
    var castles2 = context.Castles
                       .Include("LadiesInWaiting.Princess")
                       .ToList();

    // Load all unicorns, all related princesses, and all related ladies
    // using a string to specify the relationships
    var unicorns2 = context.Unicorns
                        .Include("Princess.LadiesInWaiting")
                        .ToList();
}

Note that it is not currently possible to filter which related entities are loaded. Include will always being in all related entities.

Turning off lazy loading for specific navigation properties

Lazy loading is the process whereby an entity or collection of entities is automatically loaded from the database the first time that a property referring to the entity/entities is accessed. When using POCO entity types, lazy loading is achieved by creating instances of derived proxy types and then overriding virtual properties to add the loading hook. (See Part 8 for more information on working with proxies.) For example, when using the Princess entity class defined below, the related unicorns will be loaded the first time the Unicorns navigation property is accessed:

 public class Princess 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<Unicorn> Unicorns { get; set; } 
}

Lazy loading of the Unicorns collection can be turned off by making the Unicorns property non-virtual:

 public class Princess 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public ICollection<Unicorn> Unicorns { get; set; } 
}

Loading of the Unicorns collection can still be achieved using eager loading (see Eagerly loading related entities above) or the Load method (see Explicitly loading related entities below).

Turn off lazy loading for all entities

Lazy loading can be turned off for all entities in the context by setting a flag on the Configuration property. For example:

 public class UnicornsContext : DbContext
{
    public UnicornsContext()
    {
        this.Configuration.LazyLoadingEnabled = false;
    }
}

Loading of related entities can still be achieved using eager loading (see Eagerly loading related entities above) or the Load method (see Explicitly loading related entities below).

Explicitly loading related entities

Even with lazy loading disabled it is still possible to lazily load related entities, but it must be done with an explicit call. To do so you use the Load method on the related entity’s entry. For example:

 using (var context = new UnicornsContext())
{
    var unicorn = context.Unicorns.Find(1);
    var princess = context.Princesses.Find(2);

    // Load the princess related to a given unicorn 
    context.Entry(unicorn).Reference(u => u.Princess).Load();

    // Load the princess related to a given unicorn using a string 
    context.Entry(unicorn).Reference("Princess").Load();

    // Load the unicorns related to a given princess 
    context.Entry(princess).Collection(p => p.Unicorns).Load();

    // Load the unicorns related to a given princess using a string to 
    // specify the relationship 
    context.Entry(princess).Collection("Unicorns").Load();
}

Note that the Reference method should be used when an entity has a navigation property to another single entity. On the other hand, the Collection method should be used when an entity has a navigation property to a collection of other entities.

Applying filters when explicitly loading related entities

The Query method provides access to the underlying query that the Entity Framework will use when loading related entities. You can then use LINQ to apply filters to the query before executing it with a call to a LINQ extension method such as ToList, Load, etc. The Query method can be used with both reference and collection navigation properties but is most useful for collections where it can be used to load only part of the collection. For example:

 using (var context = new UnicornsContext())
{
    var princess = context.Princesses.Find(1);

    // Load the unicorns starting with B related to a given princess 
    context.Entry(princess)
        .Collection(p => p.Unicorns)
        .Query()
        .Where(u => u.Name.StartsWith("B"))
        .Load();

    // Load the unicorns starting with B related to a given princess 
    // using a string to specify the relationship 
    context.Entry(princess)
        .Collection("Unicorns")
        .Query().Cast<Unicorn>()
        .Where(u => u.Name.StartsWith("B"))
        .Load();
}

When using the Query method it is usually best to turn off lazy loading for the navigation property. This is because otherwise the entire collection may get loaded automatically by the lazy loading mechanism either before or after the filtered query has been executed.

Note that while the relationship can be specified as a string instead of a lambda expression, the returned IQueryable is not generic when a string is used and so the Cast method is usually needed before anything useful can be done with it.

Using Query to count related entities without loading them

Sometimes it is useful to know how many entities are related to another entity in the database without actually incurring the cost of loading all those entities. The Query method with the LINQ Count method can be used to do this. For example:

 using (var context = new UnicornsContext())
{
    var princess = context.Princesses.Find(1);

    // Count how many unicorns the princess owns 
    var unicornHaul = context.Entry(princess)
                          .Collection(p => p.Unicorns)
                          .Query()
                          .Count();
}

Summary

In this part of the series we looked at how to load entities eagerly as part of a query, and lazily either automatically or with an explicit call to the Load method. We also looked at how to use the Query method to make adjustments to the loading query.

As always we would love to hear any feedback you have by commenting on this blog post.

For support please use the Entity Framework Forum.

Arthur Vickers

Developer

ADO.NET Entity Framework