Frantisek Pastorek
Frantisek Pastorek

Reputation: 538

Load object from table with id as foreign key

i have define users with UserRole type Role as foreing key of another table. Entiti framework auto transformed name UserRole to UserRoleId with type integer (Id). Its ok. But i have UserRoleId = 2 in table User table preview and when i trying get user by Id:

var user = await _userManager.FindByIdAsync(id);

so parameter UserRole is null user preview from debuging.

Application user:

public class ApplicationUser : IdentityUser
{
    public int PriorityLevel { get; set; }
    public Role UserRole { get; set; }
    public string ForName { get; set; }
    public string LastName { get; set; }
    public string Mobile { get; set; }
    public string WorkPlace { get; set; }
    public string Notice { get; set; }
}

Must i use some entity framework command for load UserRole as type Role? Or can i get UserRoleId from table?

Thanks for any advice.

Upvotes: 3

Views: 4515

Answers (2)

Chris Pratt
Chris Pratt

Reputation: 239240

You tagged your question with Entity Framework, but just in case, I'll cover Entity Framework Core, as well, since they diverge slightly on this.

Entity Framework supports lazy-loading, but importantly, the property must be virtual to enable that, i.e.:

public virtual Role UserRole { get; set; }

EF adds the logic necessary to do lazy-load the property by deriving a dynamic "proxy" class from your entity and overriding the property. Since non-virtual properties cannot be overridden, this logic is not added to properties without virtual. Without virtual, navigation properties will not be loaded automatically, and will remain null, whether there's associations in the database or not.

Entity Framework Core does not support lazy-loading at all, so adding virtual will not help you.

In either case, you should really be eager-loading, instead. This is done by adding Include to your query. However, you have two problems there:

  1. UserManager<TUser> doesn't support including related entities. You would need to use the DbSet, i.e. context.Users.

  2. You cannot use Include with Find (or any of the Find-related methods), as it has logic that is incompatible with doing joins. Namely, Find attempts to pull the entity from the context cache without doing a query at all, if possible, and as such, cannot guarantee that navigation properties can be included. As a result, you will have to switch to something like SingleOrDefault.

var user = await context.Users.Include(x => x.UserRole).SingleOrDefault(x => x.Id == id);

With that, UserRole should now actually have a value.

Alternatively, you should be able to explicitly-load UserRole:

var user = await _userManager.FindByIdAsync(id);
context.Entry(user).Reference(s => s.UserRole).Load();

This methodology is the same in both Entity Framework and Entity Framework Core. However it was only introduced into EF Core in 1.1, so be cognizant of the version you're running. The one downside here is that this will result in (potentially) two queries. Again, since the Find methods attempt to retrieve from the context cache, it's possible you'll avoid a query there, but the entity is not in the cache, it will take two queries: one for the user and one for the related role. However, that would have been the case as well with lazy-loading. Only eagerly-loading allows the queries to be combined using JOINs.

Upvotes: 2

shujaat siddiqui
shujaat siddiqui

Reputation: 1577

You can get all the roles of the user using this method.

_userManager.GetRolesAsync(id);

Upvotes: 1

Related Questions