If your database context inherits from IdentityDbContext<User>
, then your context gets properties like UserClaims
and RoleClaims
. These can be used to get (say) a user's claims as follows...
User jim = await Context.Users.SingleAsync(u => u.Name == "Jim");
List<IdentityUserClaim<string>> claims = await Context
.UserClaims
.Where(c => c.UserId == jim.Id)
.ToListAsync();
However, this seems somewhat clunky. I would have expected to be able to do the following...
User jim = await Context.Users
.Include(u => u.UserClaims)
.SingleAsync(u => u.Name == "Jim");
However this doesn't compile. If you change it to include u.Claims
then it compiles, but throws an exception... "InvalidOperationException: The expression 'u.Claims' is invalid inside an 'Include' operation, since it does not represent a property access: 't => t.MyProperty'"
Now I understand this, in that the User
entity doesn't have a Claims
navigation property (although I'm not sure where Intellisense picks up the Claims
property), but I'm surprised that this isn't something provided when you set up Identity.
Am I missing something here, or do I have to make two database calls to get the user and claims?
Yes,you are right, it doesn't have navigation property by default.
You could try follow this document to add the navigation property yourself:
public class ApplicationUser : IdentityUser
{
public virtual ICollection<IdentityUserClaim<string>> Claims { get; set; }
}
Dbcontext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>(b =>
{
// Each User can have many UserClaims
b.HasMany(e => e.Claims)
.WithOne()
.HasForeignKey(uc => uc.UserId)
.IsRequired();
});
}