Entity Framework

Loading related entities

Remarks#

If models are correctly related you can easily load related data using EntityFramework. You have three options to chose from: lazy loading, eager loading and explicit loading.

Models used in examples:

public class Company
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public string ShortName { get; set; }

    // Navigation properties
    public virtual Person Founder { get; set; }
    public virtual ICollection<Address> Addresses { get; set; }
}

public class Address 
{        
    public int Id { get; set; }
    public int CompanyId { get; set; }
    public int CountryId { get; set; }
    public int CityId { get; set; }
    public string Street { get; set; }

    // Navigation properties
    public virtual Company Company { get; set; }
    public virtual Country Country { get; set; }
    public virtual City City { get; set; }
}

Lazy loading

Lazy loading is enabled by default. Lazy loading is achieved by creating derived proxy classes and overriding virtual navigation proeprties. Lazy loading occurs when property is accessed for the first time.

int companyId = ...;
Company company = context.Companies
    .First(m => m.Id == companyId);
Person founder = company.Founder; // Founder is loaded
foreach (Address address in company.Addresses)
{
    // Address details are loaded one by one.        
}

To turn Lazy loading off for specific navigation properties just remove virtual keyword from property declaration:

public Person Founder { get; set; } // "virtual" keyword has been removed

If you want to completely turn off Lazy loading, then you have to change Configuration, for example, at Context constructor:

public class MyContext : DbContext        
{
    public MyContext(): base("Name=ConnectionString")
    {
        this.Configuration.LazyLoadingEnabled = false;
    }
}

Note: Please remember to turn off Lazy loading if your are using serialization. Because serializers access every property you are going to load all of them from database. Additionally, you can run into loop between navigation properties.

Eager loading

Eager loading lets you load all your needed entities at once. If you prefer to get all your entities to work on in one database call, then Eager loading is the way to go. It also lets you load multiple levels.

You have two options to load related entities, you can choose either strongly typed or string overloads of the Include method.

Strongly typed.

// Load one company with founder and address details
int companyId = ...;
Company company = context.Companies
    .Include(m => m.Founder)
    .Include(m => m.Addresses)
    .SingleOrDefault(m => m.Id == companyId);

// Load 5 companies with address details, also retrieve country and city
// information of addresses
List<Company> companies = context.Companies
    .Include(m => m.Addresses.Select(a => a.Country));
    .Include(m => m.Addresses.Select(a => a.City))
    .Take(5).ToList();

This method is available since Entity Framework 4.1. Make sure you have the reference using System.Data.Entity; set.

String overload.

// Load one company with founder and address details
int companyId = ...;
Company company = context.Companies
    .Include("Founder")
    .Include("Addresses")
    .SingleOrDefault(m => m.Id == companyId);

// Load 5 companies with address details, also retrieve country and city
// information of addresses
List<Company> companies = context.Companies
    .Include("Addresses.Country");
    .Include("Addresses.City"))
    .Take(5).ToList();

Explicit loading

After turning Lazy loading off you can lazily load entities by explicitly calling Load method for entries. Reference is used to load single navigation properties, whereas Collection is used to get collections.

Company company = context.Companies.FirstOrDefault();
// Load founder
context.Entry(company).Reference(m => m.Founder).Load();
// Load addresses
context.Entry(company).Collection(m => m.Addresses).Load();

As it is on Eager loading you can use overloads of above methods to load entiteis by their names:

Company company = context.Companies.FirstOrDefault();
// Load founder
context.Entry(company).Reference("Founder").Load();
// Load addresses
context.Entry(company).Collection("Addresses").Load();

Filter related entities.

Using Query method we can filter loaded related entities:

Company company = context.Companies.FirstOrDefault();
// Load addresses which are in Baku
context.Entry(company)
    .Collection(m => m.Addresses)
    .Query()
    .Where(a => a.City.Name == "Baku")
    .Load();

Projection Queries

If one needs related data in a denormalized type, or e.g. only a subset of columns one can use projection queries. If there is no reason for using an extra type, there is the possibility to join the values into an anonymous type.

var dbContext = new MyDbContext();
var denormalizedType = from company in dbContext.Company
                       where company.Name == "MyFavoriteCompany"
                       join founder in dbContext.Founder
                       on company.FounderId equals founder.Id
                       select new 
                       {
                           CompanyName = company.Name,
                           CompanyId = company.Id,
                           FounderName = founder.Name,
                           FounderId = founder.Id
                       };

Or with query-syntax:

var dbContext = new MyDbContext();
var denormalizedType = dbContext.Company
                       .Join(dbContext.Founder, 
                                    c => c.FounderId,
                                    f => f.Id ,
                                    (c, f) => new 
                                    {
                                        CompanyName = c.Name,
                                        CompanyId = c.Id,
                                        FounderName = f.Name,
                                        FounderId = f.Id
                                    })
                       .Select(cf => cf);

This modified text is an extract of the original Stack Overflow Documentation created by the contributors and released under CC BY-SA 3.0 This website is not affiliated with Stack Overflow