0

I am working in visual studio 2017, i created a web with this properties:

asp.net

mvc

individual User Account

But i changed the model of AspNetUser:

In Models:

ApplicationUser (add)
    {
        ...
        [ForeignKey]
        [InverseProperty("ApplicationUser")]
        public virtual UserProfile UserProfile {get; set;}
    }

UserProfile
    {
        ...
        [InverseProperty("UserProfile")]
        public virtual ApplicationUser ApplicationUser {get; set;}
        [ForeignKey]
        [InverseProperty("UserProfile")]
        public virtual UserImage {get; set;} 
    }

UserImage
    {
        ...
        [InverseProperty("UserImage")]
        public virtual UserProfile {get; set;}    
    }

Later i do a migration in nuget console, when in my view save my user with their profile, this work fine (i did a check in my db), but, when i try to get the user's profile is null.

I used this code. In my controller AccountController for my view UpdateUser i put this

private readonly UserManager<ApplicationUser> _userManager;

public AccountController(..., UserManager<ApplicationUser> userManager) {
    this._userManager = userManager;
     ....
}

public async Task<IActionResult> UpdateUser() {
    ApplicationUser currentUser = await _userManager.GetUserAsync(User);
    ...
}

Now, when my controller in the function UpdateUser do action await _userManager.GetUserAsync(User), this load not open the related table UserProfile because of that the field UserProfile in currentUser is null. In asp.net 5 i can load this profile using HttpContext.GetOwinContext<applicationDbContext>() but aspnetcore don't has this

How i can do that (or What do I have to change so that the function GetUserAsync(User) load the user and their profile automatically)?

1 Answer 1

3

EF Core does not support lazy-loading. As a result, navigation properties like your UserProfile will be null unless you either eagerly or explicitly load them. Eager loading is achieved by utilizing Include with your query. However, UserManager affords you no opportunity for that. As a result, you would need to do an explicit load after getting the user:

var currentUser = await _userManager.GetUserAsync(User);
await context.Entry(currentUser).Reference(x => x.UserProfile).LoadAsync();

Alternatively, you can actually pull the user from your context. You don't have to use UserManager. It just makes some things easier.

var currentUser = await context.Users.Include(x => x.UserProfile).SingleOrDefault(x => x.Id == User.Identity.GetUserId());

However, it should be noted that UserProfile should go away entirely. One of the whole points of Identity is to give you an extensible user object. If you need your user to have an image, add an image property directly on ApplicationUser. Having a separate profile object is just another join that has to be made for no reason. The only reason ASP.NET Membership had a UserProfile was because User was not extensible.

Sign up to request clarification or add additional context in comments.

3 Comments

I used UserProfile not only for user's image, i put anothers fields in this table. Thanks for your answer.
That was just an example. All properties that apply to a "user" should be directly on ApplicationUser. You don't need a separate UserProfile entity.
ApplicationUser with imageType, image(byte[]), imageName, birthdate and any others is very ugly for me. And in the future if AspNetUser change (normal updates that asp makes) you will not have big problems with this migration in your app. But i repeat you "Thanks a lot for your answer!!"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.