Link ASP.Net 身份 table 到用户详细信息 table
Link ASP.Net Identity table to a user detail table
我正在尝试 link 我的身份用户 table 到我创建的用于跟踪其他用户信息的用户详细信息 table。该用户详细信息 table 称为 UserProfile。
我遇到了这个 link 但它在 .NET Core 2.1 中不起作用:
这是我目前拥有的:
public class ApplicationUser : IdentityUser
{
[Key]
public override string Id { get; set; }
[ForeignKey("Id")]
public virtual UserProfile UserProfile { get; set; }
}
[Table("UserProfile")]
public class UserProfile
{
[Key, ForeignKey("User")]
public string UserId { get; set; } // UserId (Primary key)
public string UserName { get; set; } // UserName
public string FirstName { get; set; } // FirstName
public string LastName { get; set; } // LastName
//[ForeignKey("Id")]
public virtual ApplicationUser User { get; set; }
}
然而,在我调用的代码的其他地方:
var user = await _userMgr.FindByNameAsync(model.UserName);
并且user.UserProfile为空。
我试过很多数据标注的组合甚至流利api都无济于事
modelBuilder.Entity<ApplicationUser>()
.HasOne(c => c.UserProfile)
.WithOne(t => t.User)
.HasForeignKey<UserProfile>(b => b.UserId);
我也试过打开延迟加载,但那甚至无法加载 属性。
有谁知道如何在 .Net Core 2.1 中执行此操作?
谢谢
您的主要问题只是 UserManager
没有包含相关实体的功能,例如您的 UserProfile
。因此,您有两个选择:
直接使用您的上下文。然后,您可以在对数据库的一次查询中立即加载 UserProfile
和 ApplicationUser
实例:
var user = await _context.Users.Include(x => x.UserProfile).SingleOrDefaultAsync(x => x.UserName == model.UserName);
您可以显式加载相关的 UserProfile
。但是,这将导致额外的查询,总共有两个:一个用于获取用户,一个用于获取相关配置文件:
await _context.Entry(user).Reference(x => x.UserProfile).LoadAsync();
但是,坦率地说,您根本不应该 UserProfile
。 ASP.NET 身份不同于 ASP.NET 会员资格。对于后者,您必须有一个单独的 UserProfile
,因为 Membership 中的 "user" 不可扩展。在 Identity 中,用户 是 可扩展的,因此如果您想要关于它的其他个人资料信息,只需将其添加到 class:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; } // FirstName
public string LastName { get; set; } // LastName
}
请注意,我在这里也修剪了很多杂物。覆盖 Id
然后让它自动实现是没有意义的。此外,您显然不需要 UserProfile
中的 UserName
属性 因为 IdentityUser
已经有了,这当然意味着您的 ApplicationUser
也有.
更新
用户数据的保存方式不一定会影响它是否可以声明。换句话说,您不必按字面意义将数据保存为声明即可访问它作为声明。只需从 UserClaimsPrincipalFactory<TUser>
派生,覆盖 CreateAsync
,然后将其注册为作用域的服务集合。
public class MyClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
public MyClaimsPrincipalFactory(UserManager<TUser> userManager, IOptions<IdentityOptions> optionsAccessor)
: base(userManager, optionsAccessor)
{
}
public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
var principal = await base.CreateAsync(user);
((ClaimsIdentity)principal.Identity).AddClaims(new[]
{
new Claim(ClaimTypes.GivenName, user.FirstName),
new Claim(ClaimTypes.Surname, user.LastName),
// etc.
});
return principal;
}
}
然后在 ConfigureServices
:
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, MyClaimsPrincipalFactory>();
我正在尝试 link 我的身份用户 table 到我创建的用于跟踪其他用户信息的用户详细信息 table。该用户详细信息 table 称为 UserProfile。
我遇到了这个 link 但它在 .NET Core 2.1 中不起作用:
这是我目前拥有的:
public class ApplicationUser : IdentityUser
{
[Key]
public override string Id { get; set; }
[ForeignKey("Id")]
public virtual UserProfile UserProfile { get; set; }
}
[Table("UserProfile")]
public class UserProfile
{
[Key, ForeignKey("User")]
public string UserId { get; set; } // UserId (Primary key)
public string UserName { get; set; } // UserName
public string FirstName { get; set; } // FirstName
public string LastName { get; set; } // LastName
//[ForeignKey("Id")]
public virtual ApplicationUser User { get; set; }
}
然而,在我调用的代码的其他地方:
var user = await _userMgr.FindByNameAsync(model.UserName);
并且user.UserProfile为空。
我试过很多数据标注的组合甚至流利api都无济于事
modelBuilder.Entity<ApplicationUser>()
.HasOne(c => c.UserProfile)
.WithOne(t => t.User)
.HasForeignKey<UserProfile>(b => b.UserId);
我也试过打开延迟加载,但那甚至无法加载 属性。
有谁知道如何在 .Net Core 2.1 中执行此操作?
谢谢
您的主要问题只是 UserManager
没有包含相关实体的功能,例如您的 UserProfile
。因此,您有两个选择:
直接使用您的上下文。然后,您可以在对数据库的一次查询中立即加载
UserProfile
和ApplicationUser
实例:var user = await _context.Users.Include(x => x.UserProfile).SingleOrDefaultAsync(x => x.UserName == model.UserName);
您可以显式加载相关的
UserProfile
。但是,这将导致额外的查询,总共有两个:一个用于获取用户,一个用于获取相关配置文件:await _context.Entry(user).Reference(x => x.UserProfile).LoadAsync();
但是,坦率地说,您根本不应该 UserProfile
。 ASP.NET 身份不同于 ASP.NET 会员资格。对于后者,您必须有一个单独的 UserProfile
,因为 Membership 中的 "user" 不可扩展。在 Identity 中,用户 是 可扩展的,因此如果您想要关于它的其他个人资料信息,只需将其添加到 class:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; } // FirstName
public string LastName { get; set; } // LastName
}
请注意,我在这里也修剪了很多杂物。覆盖 Id
然后让它自动实现是没有意义的。此外,您显然不需要 UserProfile
中的 UserName
属性 因为 IdentityUser
已经有了,这当然意味着您的 ApplicationUser
也有.
更新
用户数据的保存方式不一定会影响它是否可以声明。换句话说,您不必按字面意义将数据保存为声明即可访问它作为声明。只需从 UserClaimsPrincipalFactory<TUser>
派生,覆盖 CreateAsync
,然后将其注册为作用域的服务集合。
public class MyClaimsPrincipalFactory : UserClaimsPrincipalFactory<ApplicationUser>
{
public MyClaimsPrincipalFactory(UserManager<TUser> userManager, IOptions<IdentityOptions> optionsAccessor)
: base(userManager, optionsAccessor)
{
}
public async override Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
{
var principal = await base.CreateAsync(user);
((ClaimsIdentity)principal.Identity).AddClaims(new[]
{
new Claim(ClaimTypes.GivenName, user.FirstName),
new Claim(ClaimTypes.Surname, user.LastName),
// etc.
});
return principal;
}
}
然后在 ConfigureServices
:
services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, MyClaimsPrincipalFactory>();