Monday, March 30, 2020

Eager Loading in Entity Framework Core

Eager loading loads the data from the main table and the related / dependent tables together during the initial load. To perform eager loading we use the Include() method. Let us consider our sample tables Employee and Department to implement Eager loading.

The Employee table which has a Foreign Key DepartmentId referencing to the Department table. We will load the data from the Employee table and also load the corresponding data from the Department table using Eager Loading.





There are different ways of writing the LINQ query to achieve eager loading, below are the different options.

Using Query Syntax
var employeeList = (from e in _context.Employee.Include("Department") select e).ToList();


Using Method Syntax
var employeeList = _context.Employee.Include("Department").ToList();


Using Lambda Expression Syntax
var employeeList = _context.Employee.Include(e => e.Department).ToList();

All the above queries will return the same result.

When you look at the output of the above queries you will notice that the Navigational properties are nested indefinitely i.e Employee object will have list of Department object and each Department object will have a list of Employee object and so on as an infinite loop. IF you try to access this ActionMethod in Post Man you might also get BAD ARRAY error.

This is because EF Core will automatically fix-up navigation properties, you can end up with cycles in your object graph. Some serialization frameworks do not allow such cycles. For example, Json.NET will throw the following exception if a cycle is encountered. If you are using ASP.NET Core, you can configure Json.NET to ignore cycles that it finds in the object graph. This is done in the ConfigureServices(...) method in Startup.cs.

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc()
.AddJsonOptions(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore)
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

This will help avoid the infinite loop, still the JSON result will have one level of nesting, after applying this fix the output from the above queries will be as follows.

[
    {
        "employeeId": 1,
        "departmentId": 1,
        "name": "Tim",
        "age": 40,
        "city": "London",
        "state": "London",
        "countryId": 2,
        "phone": "1112223333",
        "email": "test@test.com",
        "country": null,
        "department": {
            "departmentId": 1,
            "name": "Information Technology",
            "employee": [
                {
                    "employeeId": 6,
                    "departmentId": 1,
                    "name": "Harry",
                    "age": 34,
                    "city": "Tokyo",
                    "state": "Tokyo",
                    "countryId": 3,
                    "phone": "3342233556",
                    "email": "harry@mail.com",
                    "country": null
                },
                . . .
            ]
        }
    },
. . .
]

If you want to completely avoid this nesting and create a neat JSON then we will have to use our custom ViewModel object and use the Select clause in the LINQ query to trim these nested objects as follows.

       var employeeList = _context.Employee
                                    .Include("Department")
                                    .AsEnumerable()
                                    .Select(e => new EmployeeDetail
                                    {
                                        EmployeeId = e.EmployeeId,
                                        Department = e.Department.Name,
                                        Name = e.Name,
                                        Age = e.Age
                                    }).ToList();

This query will produce a neat JSON response with just the required properties in the response as follows.

[
    {
        "employeeId": 1,
        "department": "Information Technology",
        "name": "Tim",
        "age": 40,
        "country": null
    },
    {
        "employeeId": 3,
        "department": "Accounts",
        "name": "Harry",
        "age": 45,
        "country": null
    }
    . . .
]


Search Flipkart Products:
Flipkart.com

No comments: