Instructor-led online courses in ASP.NET Core, ASP.NET MVC, and ASP.NET Design Patterns. Read more...
Live instructor-led online courses in ASP.NET Core and Design Patterns. Registration is open for December 2018 batch. More details are available here.

Use Eager, Explicit, and Lazy Loading in Entity Framework Core

You might be aware that Entity Framework Core 2.1 has added support for lazy loading of navigation properties. This means now we have three ways to load data in the navigation properties - eager loading, explicit loading, and lazy loading. This article summarizes all the three options with an example.

To illustrate how these three options can be used we will develop the following ASP.NET Core MVC application :

The page shown above has a search textbox at the top. You can enter a CustomerID from Northwind database and click on Show Details button. The page then displays the customer details along with orders of that customer.

As you might have guessed, a Customer can have one or more Orders. The Orders are filled in Orders navigation property of the Customer. The following code shows how the Customer and Order entity classes look like :

[Table("Customers")]
public partial class Customer
{
    [Key]
    public string CustomerID { get; set; }
    public string CompanyName { get; set; }
    public string ContactName { get; set; }
    public string Country { get; set; }

    [ForeignKey("CustomerID")]
    public List<Order> Orders { get; set; }
}
[Table("Orders")]
public class Order
{
    public int OrderID { get; set; }
    public string CustomerID { get; set; }
    public DateTime OrderDate { get; set; }
}

As you can see, the Customer class has Orders navigation property that is intended to hold all the orders for a customer. Customer and Order entities are related through the CustomerID property.

The NorthwindDbContext class represents the DbContext and is shown below :

public class NorthwindDbContext:DbContext
{

    public NorthwindDbContext
(DbContextOptions<NorthwindDbContext> options) 
: base(options)
    {

    }

    public DbSet<Customer> Customers { get; set; }
    public DbSet<Order> Orders { get; set; }
}

Once the NorthwindDbContext is ready register it with the DI container. This is done in the ConfigureServices() method of the Startup class.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddEntityFrameworkSqlServer();

    services.AddDbContext<NorthwindDbContext>(
options => options.UseSqlServer
("data source=.;initial catalog=Northwind;integrated 
security=true;MultipleActiveResultSets=true"));
}

The Index view that displays the customer details including orders is shown below :

@model EFCoreNavPropDemo.Models.Customer


<form asp-controller="Home" asp-action="Index" 
method="post">
    <input type="text" name="customerID" />
    <button type="submit">Show Details</button>
</form>

@if (Model != null)
{
    <h1>Details For CustomerID @Model.CustomerID</h1>

    <h2>Company Name : @Model.CompanyName</h2>

    <h2>Contact Name : @Model.ContactName</h2>

    <h2>Country : @Model.Country</h2>


    @if (Model.Orders != null && Model.Orders.Count > 0)
    {
        <table border="1" cellpadding="10">
            @foreach (var item in Model.Orders)
            {
                <tr>
                    <td>@item.OrderID</td>
                    <td>@item.OrderDate</td>
                </tr>
            }
        </table>
    }
}

The Index view receives a Customer object as its model and displays customer details such as CustomerID, CompanyName, ContactName, and Country. If a Customer has one or more Orders, they are displayed in a table. Every order has OrderID and OrderDate.

Now that we have models and view ready, it's time to see various navigation property loading options.

Eager Loading

In eager loading all the orders of a customer are fetched from the database along with the initial query. This means when you fetch  the customer details from the Customers table, at the same time you will also fetch order details for that customer. Thus order details are loaded in "eager" way.

[HttpPost]
public IActionResult Index(string customerID)
{
    var query = from c in db.Customers.Include
                (cust => cust.Orders)
                where c.CustomerID == customerID
                select c;

    return View(query.SingleOrDefault());
}

Have a look at the LINQ to Entities query used by the Index() action. It uses Include() clause to specify the path of the navigation property to fill in eager fashion (Orders in this case). The Customer along with its Orders is then realized using the SingleOrDefault() method and is passed to the Index view.

If you run this application and enter ALFKI as the CustomerID, you should see customer details and order details as shown in the earlier figure. 

Explicit Loading

Now let's use explicit loading instead of eager loading. In explicit loading the Orders navigation property won't be filled during the initial query. That means even if you fetch customer details for a customer from the Customers table, the Orders navigation property will be empty. If you need to access order details, you will need to explicitly load the Orders navigation property as shown below :

[HttpPost]
public IActionResult Index(string customerID)
{
    var customer = db.Customers.Find(customerID);

    db.Entry(customer).Collection(cust => cust.Orders).Load();

    return View(customer);
}

The above code fetches a Customer entity using the Find() method. It then loads Orders for that Customer using Collection().Load() method. The Collection() method takes the path of the navigation property to load. The Customer is then passed to the Index view. 

Note : If you have 1:1 relation then instead of Collection(...).Load() you will use Reference(...) .Load()

Lazy Loading

Finally, let's examine lazy loading. In lazy loading Orders navigation property won't be populated with the initial query. However, when you try to access Orders of a Customer for the first time, all the Orders for that Customer are fetched from the database. Obviously, there are going to be more number of database hits when you use lazy loading. So, you should be using it with caution. Luckily, lazy loading is not automatically enabled. You need to enable it either in the Startup class or in the DbContext class. Also, if you wish to use lazy loading the Orders navigation property must be marked as a virtual property as shown below :

[Table("Customers")]
public partial class Customer
{
    [Key]
    public string CustomerID { get; set; }
    public string CompanyName { get; set; }
    public string ContactName { get; set; }
    public string Country { get; set; }

    [ForeignKey("CustomerID")]
    public virtual List<Order> Orders { get; set; }
}

You also need to add Microsoft.EntityFrameworkCore.Proxies NuGet package to your project.

In our example we will enable lazy loading in the Startup class. Here is how that can be done:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    services.AddEntityFrameworkSqlServer();

    services.AddDbContext<NorthwindDbContext>(options => options
.UseSqlServer
("data source=.;initial catalog=Northwind;integrated 
security=true;MultipleActiveResultSets=true")
.UseLazyLoadingProxies());
}

As you can see, we have called UseLazyLoadingProxies() method while adding the NorthwindDbContext. Your Index() action will now look like this :

[HttpPost]
public IActionResult Index(string customerID)
{
    var customer = db.Customers.Find(customerID);
    return View(customer);
}

As you can see, we haven't done anything special to the Customer entity under consideration. When your code accesses Orders navigation property for the first time, orders for that customer will be populated from the database.

That's it for now! Keep coding!!


Bipin Joshi is a software consultant, trainer, author and spiritual yoga mentor having 23+ years of experience in software development. He teaches online training courses in ASP.NET Core, Angular, and Design Patterns to individuals and small groups. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Twitter  Facebook  Google+  LinkedIn

Posted On : 29 October 2018


Tags : ASP.NET ASP.NET Core MVC C# Visual Studio


Subscribe to our newsletter

Get monthly email updates about new articles, tutorials, code samples, and how-tos getting added to our knowledge base.