ASP.NET Core添加用户到角色时触发IdentityUserRole参数异常求助
我在尝试将新用户添加到角色时遇到了以下异常:
ArgumentException: Entity type 'IdentityUserRole
' is defined with a single key property, but 2 values were passed to the 'DbSet.Find' method.
异常触发在这行代码:
userManager.AddToRoleAsync(user, "Admin");
以下是Startup类中的CreateRoles方法代码:
private async Task CreateRoles(IServiceProvider serviceProvider) { //adding custom roles var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole<int>>>(); var userManager = serviceProvider.GetRequiredService<UserManager<UserEntity>>(); string[] roleNames = { "Admin", "Manager", "User" }; IdentityResult roleResult; foreach (var roleName in roleNames) { //creating the roles and seeding them to the database var roleExist = await roleManager.RoleExistsAsync(roleName); if (!roleExist) { roleResult = await roleManager.CreateAsync( new IdentityRole<int> { Name = roleName, NormalizedName = roleName.ToUpper() }); } } //creating a super user who could maintain the web app var poweruser = new UserEntity { UserName = Configuration["AdminUserName"], Email = Configuration["AdminUserEmail"], Password = Configuration["AdminUserPassword"], ResidendceId = int.Parse(Configuration["AdminUserCountryId"]) }; string UserPassword = Configuration["AdminUserPassword"]; UserEntity user = await userManager.FindByEmailAsync(Configuration["AdminUserEmail"]); if (user == null) { var createPowerUser = await userManager.CreateAsync(poweruser); user = poweruser; } var adminRoleList = await userManager.GetUsersInRoleAsync("Admin"); if (user != null && !adminRoleList.Any(u => u.Email == user.Email)) { //here we tie the new user to the "Admin" role await userManager.AddToRoleAsync(user, "Admin"); } }
请问该如何解决这个问题?
这个问题的核心是你的用户角色关联表没有被正确配置复合主键。默认情况下,ASP.NET Identity的IdentityUserRole<int>实体是用UserId和RoleId作为复合主键的,但如果你的DbContext里没明确告诉EF Core这一点,它就会误以为这张表只有一个主键,而AddToRoleAsync内部调用Find方法时会传入两个主键值,自然就抛出参数不匹配的异常了。
你可以按下面的步骤逐步修复:
在DbContext中配置
IdentityUserRole<int>的复合主键
打开你的DbContext类,找到OnModelCreating方法,添加如下配置:protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // 明确配置用户角色关联表的复合主键 modelBuilder.Entity<IdentityUserRole<int>>() .HasKey(ur => new { ur.UserId, ur.RoleId }); }确认
UserEntity的继承关系正确
确保你的自定义用户实体UserEntity是继承自IdentityUser<int>的,这样才能和基于int类型主键的角色系统兼容:public class UserEntity : IdentityUser<int> { // 你的自定义属性,比如ResidendceId等 public int ResidendceId { get; set; } }检查DbContext的泛型参数是否正确
你的DbContext需要继承IdentityDbContext并指定正确的泛型参数,确保用户、角色、主键类型都匹配:public class YourDbContext : IdentityDbContext<UserEntity, IdentityRole<int>, int> { public YourDbContext(DbContextOptions<YourDbContext> options) : base(options) { } // 你项目中的其他DbSet和配置 }
完成这些配置后,根据需要重新生成并应用数据库迁移(如果用Code First的话),再运行代码,AddToRoleAsync就能正常执行了。本质上就是让EF Core清楚知道用户角色关联表的主键结构,避免参数匹配错误。
内容的提问来源于stack exchange,提问作者Canale

