Reputation: 538
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
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:
UserManager<TUser>
doesn't support including related entities. You would need to use the DbSet
, i.e. context.Users
.
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 JOIN
s.
Upvotes: 2
Reputation: 1577
You can get all the roles of the user using this method.
_userManager.GetRolesAsync(id);
Upvotes: 1