.NET 8 EF Core在IdentityUserRole表中鉴别器值异常求助
你的问题出在ASP.NET Core 8中Identity DbContext泛型参数与AddIdentity注册的类型不匹配,导致EF Core对IdentityUserRole<string>实体的鉴别器值产生混淆。
具体原因
你在Program.cs中注册的是AddIdentity<ApplicationUser, ApplicationRole>(自定义角色类型),但ApplicationDbContext继承的是IdentityDbContext<ApplicationUser>(默认使用IdentityRole作为角色类型)。这种不匹配使得EF Core在插入用户角色时使用IdentityUserRole<string>的鉴别器,但查询时却期望匹配ApplicationUserRole(框架内部因泛型参数冲突产生的错误类型推断)。
修复步骤
1. 修正ApplicationDbContext的泛型继承
将ApplicationDbContext继承的泛型参数明确指定为你的自定义用户和角色类型,确保与AddIdentity的注册一致:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string>, IApplicationDbContext { // 构造函数(根据你的依赖注入方式调整) public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { // 必须调用base方法,确保Identity的默认映射逻辑生效 base.OnModelCreating(builder); // 自定义Identity表名(移除重复的ApplicationClaim映射) builder.Entity<ApplicationUser>(x => { x.ToTable("ApplicationUser"); }); builder.Entity<ApplicationRole>(x => { x.ToTable("ApplicationRole"); }); builder.Entity<IdentityUserClaim<string>>(x => { x.ToTable("ApplicationClaim"); }); builder.Entity<IdentityUserLogin<string>>(x => { x.ToTable("ApplicationUserLogin"); }); builder.Entity<IdentityUserToken<string>>(x => { x.ToTable("ApplicationUserToken"); }); builder.Entity<IdentityRoleClaim<string>>(x => { x.ToTable("ApplicationRoleClaim"); }); builder.Entity<IdentityUserRole<string>>(x => { x.ToTable("ApplicationUserRole"); x.HasKey(z => new { z.RoleId, z.UserId }); }); } }
2. 移除不必要的鉴别器列(可选)
如果你不需要鉴别器列,可以在IdentityUserRole<string>的映射中显式关闭它:
builder.Entity<IdentityUserRole<string>>(x => { x.ToTable("ApplicationUserRole"); x.HasKey(z => new { z.RoleId, z.UserId }); // 关闭鉴别器列 x.HasDiscriminator().IsRequired(false); });
3. 更新数据库
执行EF Core迁移,确保数据库表结构与修正后的实体映射一致:
Add-Migration FixUserRoleDiscriminator Update-Database
为什么.NET 6/7没问题?
ASP.NET Core 8对Identity与EF Core的集成逻辑做了严格调整,要求DbContext的泛型参数必须与AddIdentity注册的用户/角色类型完全匹配,否则会触发类型推断错误,导致鉴别器值不匹配。而.NET 6/7的框架逻辑相对宽松,未强制这种匹配,因此未出现该问题。
内容的提问来源于stack exchange,提问作者John81

