英文:
ASP.NET Core Identity, load user's claims when pulling a user from the database
问题
如果你的数据库上下文继承自IdentityDbContext<User>,那么你的上下文会获得像UserClaims和RoleClaims这样的属性。可以使用以下方式获取用户的声明...
User jim = await Context.Users.SingleAsync(u => u.Name == "Jim");
List<IdentityUserClaim<string>> claims = await Context
  .UserClaims
  .Where(c => c.UserId == jim.Id)
  .ToListAsync();
然而,这种方法似乎有些繁琐。我本来希望能够像下面这样操作...
User jim = await Context.Users
  .Include(u => u.UserClaims)
  .SingleAsync(u => u.Name == "Jim");
然而,这个代码不会编译。如果你将它更改为包含 u.Claims,那么它会编译,但会抛出异常... "InvalidOperationException: 表达式'u.Claims'在'Include'操作内无效,因为它不表示属性访问:'t => t.MyProperty'"
我理解这一点,即User实体没有Claims导航属性(虽然我不确定Intellisense是如何捕捉到Claims属性的),但我感到惊讶的是,在设置Identity时为什么没有提供这个功能。
我是否漏掉了什么,还是必须进行两次数据库调用才能获取用户和声明?
英文:
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?
答案1
得分: 1
是的,你说得对,它默认没有导航属性。
你可以尝试按照这个文档添加导航属性:
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 =>
    {
        // 每个用户可以有多个用户声明
        b.HasMany(e => e.Claims)
            .WithOne()
            .HasForeignKey(uc => uc.UserId)
            .IsRequired();
    });
}
英文:
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();
        });
    }
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论