Miina (@minepupper) is fixing them bugs

EF Core returns null for a Navigation property

Reading Time: 4 minutes.

This article describes how to fix a situation, where you can’t use any of the navigation properties of your Entity Framework Core entities, since they are all null, despite data being in the database for sure.

So, another day, another error. This time I can’t blame SharePoint, since I just messed up with ASP.NET Core and Entity Framework Core. :)

Symptoms

No matter what I’d do, I was getting null values for my navigation properties on my entities. They’d would always be null during runtime despite the columns having proper values in the database. Does this sound like utter and moonspeak? Well, easier to show the code!

So I had something like this in my Site.cs model:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
 
namespace ...Models
{
    public class Site : BaseEntity
    {
        [Key]
        public int SiteId { get; set; }
 
        [Required]
        [MaxLength(500)]
        public string SiteUrl { get; set; }
 
        public string UserName { get; set; }
 
        [InverseProperty("PrimarySite")]
        public virtual ICollection<ApplicationUser> PrimaryUsers { get; set; }
    }
}

And this in my ApplicationUser class:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
 
namespace ...Models
{
    public class ApplicationUser : IdentityUser
    {
        public string LastLoginProvider { get; set; }
        public DateTime? LastLoginDate { get; set; }
        public string UserAgent { get; set; }
        public string IpAddress { get; set; }
        public string FullName { get; set; }
        public DateTime? CreatedAt { get; set; }
 
        [ForeignKey("SiteId")]
        public virtual Site PrimarySite { get; set; }
 
    }
}

And in my controller, the navigation property for an instance of ApplicationUser would always be null, so the PrimarySite could not be accessed – even though I could verify from the database, that the foreign key is indeed populated!

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
 
namespace ...Controllers
{
    public class SitesController : Controller
    {
        private readonly ApplicationDbContext _db;
        private readonly SignInManager _signInManager;
        private readonly UserManager _userManager;
        private readonly ILogger _logger;
 
        public SitesController(UserManager userManager, SignInManager signInManager, ILogger logger, ApplicationDbContext db)
        {
            _signInManager = signInManager;
            _userManager = userManager;
            _logger = logger;
            _db = db;
        }
 
        [Authorize]
        [Route("[controller]/[action]")]
        public IActionResult UpdateSelection()
        {
            var user = _userManager.GetUserAsync(HttpContext.User).Result;
 
            var siteViewModel = new SiteViewModel();
 
            // The following line would always be null - no matter what data DB has
            if (user.PrimarySite != null) siteViewModel.ParseValues(user.PrimarySite);
 
            return View(siteViewModel);
        }
 
        // Rest of the implementation omitted
 
    }
}

Every time and for every entity, user.PrimarySite was always null. The following call, for example, would always throw an exception:

siteViewModel.ParseValues(user.PrimarySite);

This is frustrating – I tried quite a few different things, but couldn’t get it to populate even by explicitly requesting the navigation property by running .Include(p => p.PrimarySite);

I was getting flabbergasted. Is this issue something that’s broken in Entity Framework for .NET Core? This isn’t how it works in Entity Framework with “classic” .NET Framework!

But wait: I have been struggling with lazy loading sometimes before. And that was actually the reason here as well!

Problem: Lazy Loading is messing with my Navigation properties

By default, EFCore loads Navigation properties lazily – which means, that unless they’re explicitly requested or loaded beforehand, they won’t be populated. But this time, even explicit loading (adding .Include(PropertyName) in the command) didn’t help. What do?

Well, I guess my issue was that I didn’t actually have lazy loading configured. So I was apparently using it without configuring it. Not sure how I ended up with this mess, but at this point it made sense to properly configure it. But how?

How to configure Lazy Loading on entity Framework Core?

First of all, you need to add this NuGet package (should be enough for any ASP.NET Core 2+ project):

Microsoft.EntityFrameworkCore.Proxies

See below – I got the 2.1.1 version (since my application was that version as well).

Microsoft.EntityFrameworkCore.Procies NuGet package.
Microsoft.EntityFrameworkCore.Procies NuGet package.

Then you need to make all of your navigation properties virtual, like so:

Navigation properties need to always be virtual when using Lazy Loading, so that EF Core can overwrite then with proxies during runtime execution.
Navigation properties need to always be virtual when using Lazy Loading, so that EF Core can overwrite then with proxies during runtime execution.

And finally, you need to configure it in your Startup.cs’s ConfigureServices() like this (of course, replace the DefaultConnection with your connection string’s name):

services.AddDbContext(options =&gt; options.UseLazyLoadingProxies().UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

And you should be good! Your navigation properties should be loaded during runtime.

Antti K. Koskela

Antti Koskela is a proud digital native nomadic millennial full stack developer (is that enough funny buzzwords? That's definitely enough funny buzzwords!), who works as a Solutions Architect for Valo Intranet, the product that will make you fall in love with your intranet. Working with the global partner network, he's responsible for the success of Valo deployments happening all around the world.

He's been a developer from 2004 (starting with PHP and Java), and he's been bending and twisting SharePoint into different shapes since MOSS. Nowadays he's not only working on SharePoint, but also on .NET projects, Azure, Office 365 and a lot of other stuff.

This is his personal professional (e.g. professional, but definitely personal) blog.
mm

Leave a Reply

avatar
5000
  Subscribe  
Notify of