Explicit Loading in Entity Framework Core

Explicit Loading in Entity Framework Core

In this article, I am going to discuss Explicit Loading in Entity Framework (EF) Core with Examples. Please read our previous article, where we discussed 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.

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.

Let us understand this 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’s 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. But 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.

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

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

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

And finally, you need to call the Load method, which will generate and executes the SQL Statement in the database to get the data and fill in the specified reference or collection navigation property of the main entity.

In the next article, I am going to 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 *