Explicit Loading in Entity Framework Core

Explicit Loading in Entity Framework Core

In this article, I will discuss Explicit Loading in Entity Framework (EF) Core with Examples. Please read our previous article discussing Lazy Loading in Entity Framework Core with Examples. At the end of this article, you will understand what is Explicit Loading and how to implement Explicit Loading in the EF Core. We will work with the same example we have worked on so far.

Note: If you are a .NET developer, Entity Framework Core (EF Core) could be a great Object-Relational Mapper (ORM) for you to use. When working with EF Core, loading related data is a common operation, and there are multiple ways to load related data in EF Core. Explicit Loading is one example. The other two approaches are Eager Loading and Lazy Loading

Explicit Loading in Entity Framework Core

Even if Lazy Loading is disabled in Entity Framework Core, it is still possible to lazily load the related entities, but it must be done with an explicit call. Here, we need to explicitly call the Load() method to load the related entities explicitly. That means the EF Core’s Explicit Loading loads related data from the database separately by calling the Load() method.

Explicit loading in Entity Framework Core is a feature that allows us to load related data of an entity into the context on demand. This differs from eager loading (using Include) and lazy loading (where related data is loaded automatically when the navigation property is accessed). Explicit loading gives you control over when and what related data is retrieved, which can be useful for optimizing performance and resource utilization.

Example to Understand Explicit Loading in Entity Framework Core

Let us understand Explicit loading in Entity Framework Core with an Example. First, let us disable the Lazy loading for all the entities by setting the LazyLoadingEnabled property to false within the constructor of the context class. So, first, modify the EFCoreDbContext class as shown below.

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace EFCoreCodeFirstDemo.Entities
{
    public class EFCoreDbContext : DbContext
    {
        //Constructor calling the Base DbContext Class Constructor
        public EFCoreDbContext() : base()
        {
            //Disabling Lazy Loading
            this.ChangeTracker.LazyLoadingEnabled = false;
        }

        //OnConfiguring() method is used to select and configure the data source
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            //To Display the Generated the Database Script
            optionsBuilder.LogTo(Console.WriteLine, LogLevel.Information);

            //Configuring the Connection String
            optionsBuilder.UseSqlServer(@"Server=LAPTOP-6P5NK25R\SQLSERVER2022DEV;Database=EFCoreDB1;Trusted_Connection=True;TrustServerCertificate=True;");
        }

        //OnModelCreating() method is used to configure the model using ModelBuilder Fluent API
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //Use this to configure the model using Fluent API
        }

        //Adding Domain Classes as DbSet Properties
        public virtual DbSet<Course> Courses { get; set; }

        public virtual DbSet<Standard> Standards { get; set; }

        public virtual DbSet<Student> Students { get; set; }

        public virtual DbSet<StudentAddress> StudentAddresses { get; set; }

        public virtual DbSet<Teacher> Teachers { get; set; }
    }
}

Next, modify the Program class Main method as shown below to ensure Lazy Loading is Disabled and it is not loading the related data when we explicitly access the navigation properties.

using EFCoreCodeFirstDemo.Entities;
using Microsoft.EntityFrameworkCore;
namespace EFCoreCodeFirstDemo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var context = new EFCoreDbContext();

                //Loading the particular student data only
                //Here, it will only load the Student Data, no related entities
                Student? student = context.Students.FirstOrDefault(std => std.StudentId == 1);
                Console.WriteLine($"Firstname: {student?.FirstName}, Lastname: {student?.LastName}");
                Console.WriteLine();

                //As Lazy Loading is Disabled so, it will not load the Standard data
                Standard? standard = student?.Standard;
                Console.WriteLine($"StandardName: {standard?.StandardName}, Description: {standard?.Description}");
                Console.WriteLine();

                //As Lazy Loading is Disabled so, it will load the StudentAddress data
                StudentAddress? studentAddress = student?.StudentAddress;
                Console.WriteLine($"AddresLin1 {studentAddress?.Address1}, AddresLin2 {studentAddress?.Address2}");
                Console.WriteLine();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}"); ;
            }
        }
    }
}
Output:

Explicit Loading in Entity Framework (EF) Core with Examples

As you can see in the above output, it is not loading the Standard and Address data of the Student. Now, modify the Main method of the Program class as follows to load the related Standard and Address data explicitly.

using EFCoreCodeFirstDemo.Entities;
namespace EFCoreCodeFirstDemo
{
    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var context = new EFCoreDbContext();

                //Loading the particular student data only
                //Here, it will only load the Student Data, no related entities
                Student? student = context.Students.FirstOrDefault(std => std.StudentId == 1);
                Console.WriteLine($"Firstname: {student?.FirstName}, Lastname: {student?.LastName}");
                Console.WriteLine();

                //Load Standard Explicit using the Load Method
                //If the related Property is a Reference type, 
                //First, call the Reference method by passing the property name that you want to load
                //and then call the Load Method
                if( student != null )
                {
                    //At this point the related Standard Entity is Loaded
                    context.Entry(student).Reference(s => s.Standard).Load();
                }

                //Printing the Standard Data
                if(student?.Standard !=  null )
                {
                    Console.WriteLine("Standard Entity is Loaded");
                    Console.WriteLine($"StandardName: {student.Standard.StandardName}, Description: {student.Standard.Description}");
                    Console.WriteLine();
                }
                else
                {
                    Console.WriteLine("Standard Entity is not Loaded");
                    Console.WriteLine();
                }

                //We have not yet loaded the related StudentAddress Entity
                //Printing the StudentAddress Data
                if (student?.StudentAddress != null)
                {
                    Console.WriteLine("StudentAddress Entity is Loaded");
                    Console.WriteLine($"AddresLin1 {student.StudentAddress.Address1}, AddresLin2 {student.StudentAddress.Address2}");
                    Console.WriteLine();
                }
                else
                {
                    Console.WriteLine("StudentAddress Entity is not Loaded");
                    Console.WriteLine();
                }

                //Loads Courses Collection Explicit using the Load Method
                //If the related Property is a Collection type, 
                //First, call the Collection method by passing the property name that you want to load
                //and then call the Load Method
                if (student != null)
                {
                    // At this point the related Courses Entities are Loaded
                    context.Entry(student).Collection(s => s.Courses).Load();
                }

                //Printing the Courses Data
                if (student?.Courses != null)
                {
                    Console.WriteLine("Courses Entities are Loaded");
                    foreach (var course in student.Courses)
                    {
                        Console.WriteLine($"CourseName: {course.CourseName}");
                    }
                }
                else
                {
                    Console.WriteLine("Courses Entities are not Loaded");
                    Console.WriteLine();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}"); ;
            }
        }
    }
}
Output:

Explicit Loading in Entity Framework Core

As you can see in the above output, it is using Explicit Loading to load the related entities. First, it issues one select statement to fetch the student entity, and then it issues two separate SQL queries to get the related standard and course data. However, it is not loading the Student Address, as we are not explicitly loading this entity.

Understanding the Reference, Collection, Entry, and Load Method

In the above example, we need to understand two statements, i.e., context.Entry(student).Reference(s => s.Standard).Load(); and context.Entry(student).Collection(s => s.Courses).Load();. So, let us proceed and understand these two statements in detail.

  1. context.Entry(student).Reference(s => s.Standard).Load(): If you want to load the related entity data, a reference navigation property of the Main entity, then you need to use this syntax. This statement will generate and execute the SQL query in the database to fetch the related Standard data and fill the data with the Standard reference property of the student object.
  2. context.Entry(student).Collection(s => s.Courses).Load(): If you want to load the related entity data, a collection navigation property of the Main entity, then you need to use this syntax. This statement will generate and execute the SQL query in the database to fetch the related Courses data and fill the data with the Courses Collection property of the student object.

You must pass the main entity instance to the Entry method. In this case, the student instance is our main entity. Then, you must check whether the related entity is a reference or a collection-type navigation property.

Suppose it is a reference navigation property (in our case, Standard is a reference navigation property). In that case, we need to call the Reference method, and you need to specify the Reference Navigation Property name using the string name or the lambda expression. It is recommended to use a lambda expression. If you misspell the property name, you will get a compile-time error.

Suppose it is a collection navigation property (in our case, Courses is a collection navigation property). In that case, we need to use the Collection method, and you need to specify the Collection Navigation Property name using the string name or the lambda expression.

Finally, you need to call the Load method to generate and execute the SQL Statement in the database to get the data and fill in the main entity’s specified reference or collection navigation property.

Advantages and Disadvantages of Explicit Loading in Entity Framework Core

Explicit loading in Entity Framework Core (EF Core) is a technique that provides developers with control over when related data should be fetched from the database. While it can be powerful, it’s essential to understand its pros and cons to use it effectively.

Advantages of Explicit Loading in Entity Framework Core:
  • Control: With Explicit Loading in EF Core, we have full control over when to load the related data from the database. So we can decide when to hit the database to retrieve the related entities, optimizing performance and memory usage.
  • Efficiency: Useful when you need related data conditionally or in a specific part of your application, avoiding the upfront cost of loading unnecessary data.
  • Flexibility: You can combine explicit loading with additional LINQ queries to filter or sort the related data.
  • Optimized Data Retrieval: With Explicit Loading in EF Core, we can load data only when we need the related data, which will reduce unnecessary data fetches from the database and improve performance, especially in scenarios where the related data isn’t always required.
  • Minimized Initial Payload: When retrieving a primary entity, related entities are not immediately retrieved, making the initial data fetch faster, especially when dealing with large amounts of data.
Disadvantages of Explicit Loading in Entity Framework Core:
  • Complexity: Managing when and what to load can be complex for developers. They must remember to call explicit loads to avoid null references or missing data.
  • Multiple Database Roundtrips: Each explicit database load results in a separate database call. This can result in multiple round trips to the database, which can affect the performance of your application when dealing with a large number of related entities.
  • Avoid N+1 Queries Problem: Avoid the N+1 queries problem, where you execute one query to fetch the main entities and then N additional queries for related entities. This can be mitigated by the well-thought-out use of explicit loading in combination with appropriate query batching.
  • Lack of Transparency: It can be confusing and lead to errors for developers unfamiliar with the codebase to determine when or if related data is loaded.
  • Maintenance Overhead: Tracking where explicit loads occur cannot be easy as the application grows. Developers may need to modify loading strategies as requirements change.
Explicit Loading vs. Lazy Loading vs. Eager Loading in Entity Framework Core:

In Entity Framework Core (EF Core), three primary strategies are available for loading related data: Explicit Loading, Lazy Loading, and Eager Loading. Each approach has its advantages and disadvantages. Let us proceed and try to understand the differences between these three approaches and when to use which approach in application development.

Explicit Loading:

How it works: After fetching the main entity, we need to call the Load method to load related data.

Advantages:
  1. Full control over when to fetch the related data.
  2. Ability to conditionally load related data from the database.
Disadvantages:
  1. Multiple database roundtrips can affect the performance of your application.
  2. Increased complexity: developers must remember to load related data by explicitly calling the Load method.
Lazy Loading:

How it works: Related data is loaded automatically when we first access the main entity’s navigation property for the first time.

Advantages:
  1. Transparent and automatic; no need to write extra code to load related data.
  2. Data is loaded only when needed.

Disadvantages:

  1. This can result in the “N+1 Query Problem,” where accessing properties in a loop can generate many unexpected queries.
  2. Due to multiple database round trips, this can also lead to performance issues if not used carefully.
  3. Requires additional setup in EF Core, such as installing a separate package and modifying navigation properties to be virtual.
Eager Loading:

How it works: Related data is loaded upfront using methods like Include and ThenInclude.

Advantages:
  1. Data is loaded in a single roundtrip, which can be more efficient in many scenarios.
  2. It indicates which related data will be fetched, providing transparency.
Disadvantages:
  1. It might fetch more data than necessary if not used properly.
  2. Initial queries can be heavier, fetching all related data at a time, even if some data isn’t needed immediately.
When to use Which Approach:

Explicit Loading: If you want complete control over when to fetch the related data depending on conditions or logic in your code, then you should use EF Core Explicit Loading to load Related Entities.

Lazy Loading: When you want to minimize upfront data retrieval and are okay with fetching related data on the fly, you can use EF Core Lazy Loading to load Related Entities.

Eager Loading: If you know the related data you need and want to fetch everything at once, then you need to use EF Core Eager Loading to load Related Entities.

In Real-time Applications, you might use a combination of these strategies based on the specific needs and performance characteristics of different components of your application. It is important to understand each approach to make well-informed decisions. It is also important to keep track of and analyze your database queries to ensure that you achieve the desired performance and behavior.

In the next article, I will discuss Default Conventions in Entity Framework Core with Examples. In this article, I try to explain Explicit Loading in Entity Framework Core with Examples, and I hope you enjoyed this Explicit Loading in EF Core with Examples article. Please give your valuable feedback and suggestions about this article.

Leave a Reply

Your email address will not be published. Required fields are marked *