.NET Core/Entity Framework Core中从UserRoles表提取自定义字段的实现咨询
.NET Core/Entity Framework Core中从UserRoles表提取自定义字段的实现咨询
嗨,看起来你已经完成了EF Core Identity模型的自定义,给UserRole关联关系添加了自定义字段,现在想要在用户登录后提取这些字段并传递给应用对吧?我来帮你梳理下实现步骤:
首先先把你给出的自定义实体类补全并整理好:
public class ApplicationUser: IdentityUser { public virtual ICollection<ApplicationUserRole> UserRoles { get; set; } = null!; public string? UserCode { get; set; } public string? UserExternalCode1 { get; set; } public string? UserExternalCode2 { get; set; } public string? UserExternalCode3 { get; set; } public Guid? EmployeeTypeId { get; set; } public EmployeeType? EmployeeType { get; set; } = null!; } public class ApplicationUserRole: IdentityUserRole<string> { public Guid? LineId { get; set; } public Line? Line { get; set; } = null!; public Guid? TerritoryId { get; set; } public Territory? Territory { get; set; } = null!; }
接下来是关键的配置和提取步骤:
1. 确保DbContext正确配置自定义UserRole实体
首先要在你的ApplicationDbContext里注册ApplicationUserRole,并且配置好它的复合主键(因为IdentityUserRole<TKey>默认是UserId+RoleId的复合主键),同时配置导航属性的关联:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole<string>, string, IdentityUserClaim<string>, ApplicationUserRole, IdentityUserLogin<string>, IdentityRoleClaim<string>, IdentityUserToken<string>> { public DbSet<ApplicationUserRole> ApplicationUserRoles { get; set; } public DbSet<Line> Lines { get; set; } public DbSet<Territory> Territories { get; set; } public DbSet<EmployeeType> EmployeeTypes { get; set; } public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); // 配置ApplicationUserRole的复合主键 builder.Entity<ApplicationUserRole>(ur => { ur.HasKey(r => new { r.UserId, r.RoleId }); // 配置与Line的关联 ur.HasOne(ur => ur.Line) .WithMany() .HasForeignKey(ur => ur.LineId) .OnDelete(DeleteBehavior.Restrict); // 配置与Territory的关联 ur.HasOne(ur => ur.Territory) .WithMany() .HasForeignKey(ur => ur.TerritoryId) .OnDelete(DeleteBehavior.Restrict); }); } }
2. 用户登录后提取自定义UserRole字段
当用户登录成功后,你可以通过UserManager获取用户对象,并且显式Include自定义的UserRoles集合以及关联的实体,这样就能拿到那些自定义字段了:
方式一:使用UserManager获取用户并包含关联数据
private readonly UserManager<ApplicationUser> _userManager; private readonly IHttpContextAccessor _httpContextAccessor; public YourService(UserManager<ApplicationUser> userManager, IHttpContextAccessor httpContextAccessor) { _userManager = userManager; _httpContextAccessor = httpContextAccessor; } public async Task<List<ApplicationUserRole>> GetUserCustomRoleData() { var currentUser = await _userManager.GetUserAsync(_httpContextAccessor.HttpContext.User); if (currentUser == null) { throw new UnauthorizedAccessException("用户未登录"); } // 显式加载UserRoles以及关联的Line和Territory await _userManager.Context.Entry(currentUser) .Collection(u => u.UserRoles) .Query() .Include(ur => ur.Line) .Include(ur => ur.Territory) .LoadAsync(); // 现在currentUser.UserRoles里就包含了所有自定义字段和关联实体 return currentUser.UserRoles.ToList(); }
方式二:直接通过DbContext查询
如果你更倾向于直接查询数据库,也可以这样做:
public async Task<List<ApplicationUserRole>> GetUserCustomRoleData(string userId) { return await _dbContext.ApplicationUserRoles .Include(ur => ur.Line) .Include(ur => ur.Territory) .Where(ur => ur.UserId == userId) .ToListAsync(); }
3. 将自定义字段传递给应用的建议
如果需要在整个应用中都能便捷访问这些字段,可以考虑在用户登录时把关键的自定义字段添加到Claims中,这样后续可以通过User.Claims直接获取:
// 在登录逻辑中(比如Login方法) var user = await _userManager.FindByEmailAsync(model.Email); var userRoles = await _dbContext.ApplicationUserRoles .Include(ur => ur.Line) .Where(ur => ur.UserId == user.Id) .ToListAsync(); var claims = new List<Claim> { new Claim(ClaimTypes.NameIdentifier, user.Id), // 添加自定义字段到Claims new Claim("LineId", userRoles.FirstOrDefault()?.LineId.ToString() ?? string.Empty), new Claim("TerritoryName", userRoles.FirstOrDefault()?.Territory?.Name ?? string.Empty) }; // 创建ClaimsIdentity并完成登录 var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme); await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
这样之后,在任何需要的地方都可以通过User.FindFirstValue("LineId")来获取对应的自定义字段值了。
备注:内容来源于stack exchange,提问作者stefano
相关产品推荐
相关产品推荐

