Nick Orlowski
Nick Orlowski

Reputation: 115

EF Core 3.1.4 Navigation property returning null in One-To-One relationship

I am having a problem where a navigation property is always returning null in a One-to-One relationship in EF Core 3.1.4.

My models are structured like so:

    public class UserCredential
    {
        public Guid Id { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public byte[] Salt { get; set; }
        public bool IsLocked { get; set; }
        public bool IsDeleted { get; set; }   
        public DateTime CreatedDate { get; set; }
        public DateTime? ModifiedDate { get; set; }
        public DateTime? DeletedDate { get; set; }

        public UserProfile UserProfile { get; set; }
    }

    public class UserProfile
    {
        public Guid Id { get; set; }
        public string FirstName { get; set; }
        public string MiddleName { get; set; }
        public string LastName { get; set; }
        public string Suffix { get; set; }
        public bool IsDeleted { get; set; }
        public List<Address> Addresses {get;set;}
        public DateTime DOB { get; set; }
        public DateTime CreatedDate { get; set; }
        public DateTime? ModifiedDate { get; set; }
        public DateTime? DeletedDate { get; set; }

        public Guid UserCredentialId { get; set; }
        public UserCredential UserCredential { get; set; }
    }

Based off what I understand, that should have been enough for EF Core to infer the One-To-One relationship. But it didnt work so I defined the relationshup in my dbContext like so:

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            builder.Entity<UserProfile>(entity =>
            {
                entity.HasOne(up => up.UserCredential)
                    .WithOne(uc => uc.UserProfile)
                    .HasForeignKey<UserProfile>( up => up.UserCredentialId);
            });
        }

I checked the db and there is a foreign key from UserProfile -> UserCredentials defined in the table. Likewise both tables have Id as a primary key.

If I post data to a "addUser" endpoint it will be added correctly in the db.

{
    "username": "test3",
    "password": "password123",
    "UserProfile":{
        "FirstName": "John",
        "LastName": "Doe"
    }
}

Db Screenshot

However "UserProfile" in my model is always null.

System.NullReferenceException: 'Object reference not set to an instance of an object.' IronCarp.Identity.Models.UserCredential.UserProfile.get returned null.

I'm using a repository to interact with the db and the method that is returning my data/model seems simple enough.

        private async Task<UserCredential> GetUserCredentials(string username)
        {
            return await context.UserCredentials.Where(u => u.Username == username).FirstOrDefaultAsync();
        }

Any help is appreciated, I am not sure what I am missing, thanks!

Upvotes: 3

Views: 1071

Answers (2)

ms87
ms87

Reputation: 17492

For me this issue was happening intermittently in my integration tests.

It turned out because I was mistakenly registering the EF Core DbContext as Transient and not Scoped:

Services.AddDbContext<SubscriptionsContext>(
            options => options.UseNpgsql(appConfig.DatabaseConnectionString,
                optionsBuilder => optionsBuilder.EnableRetryOnFailure(3)), ServiceLifetime.Transient);

Should be:

Services.AddDbContext<SubscriptionsContext>(
            options => options.UseNpgsql(appConfig.DatabaseConnectionString,
                optionsBuilder => optionsBuilder.EnableRetryOnFailure(3)), ServiceLifetime.Scoped);

If you look at the default parameter on the AddDbContext() extension method, it's always Scoped:

enter image description here

Upvotes: 0

nitinsingh9x
nitinsingh9x

Reputation: 696

try to include navigation property in linkq, try something like this:

private async Task<UserCredential> GetUserCredentials(string username)
        {
            return await context.UserCredentials.Include(x => x.UserProfile).Where(u => u.Username == username).FirstOrDefaultAsync();
        }

Upvotes: 4

Related Questions