调用RoleManager.RoleExistsAsync()引发Discriminator列不存在异常
这个问题确实和你自定义的ApplicationRole继承IdentityRole直接相关,我来给你拆解下原因和解决办法:
问题根源
当你自定义ApplicationRole继承自IdentityRole时,EF Core默认会采用**TPH(表每层次继承)**的映射策略——简单说就是把基类和子类的数据都存在同一个表(默认是AspNetRoles)里,通过自动添加的Discriminator列来区分这条数据是属于IdentityRole还是你的ApplicationRole。如果你的数据库表中没有这个Discriminator列,EF Core在查询时就会抛出这个找不到列的异常。
具体解决步骤
1. 确认DbContext的继承配置
首先要确保你的项目DbContext是继承自IdentityDbContext<ApplicationUser, ApplicationRole, string>,而不是默认的IdentityDbContext(默认的会用IdentityRole作为角色类型)。示例代码如下:
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string> { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } }
2. 添加数据库迁移并更新
配置好DbContext后,需要通过EF Core迁移来在AspNetRoles表中添加Discriminator列:
- 打开终端或者Package Manager Console,运行以下命令:
执行后,EF Core会自动在# 添加迁移文件 Add-Migration AddDiscriminatorColumnToRoles # 更新数据库 Update-DatabaseAspNetRoles表中创建Discriminator列,后续存储角色时会自动填充标识值(比如ApplicationRole)。
3. (可选)如果不想用TPH策略,改用TPT
如果你希望基类和子类的数据分开存储,可以配置**TPT(表每类型)**策略,让IdentityRole和ApplicationRole分别对应不同的表。在DbContext的OnModelCreating方法中添加配置:
protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); // 配置TPT:基类存AspNetRoles,子类存ApplicationRoles builder.Entity<IdentityRole>().ToTable("AspNetRoles"); builder.Entity<ApplicationRole>().ToTable("ApplicationRoles"); }
配置完成后同样需要运行迁移和更新数据库,这时候会生成两个独立的角色表。
4. 检查Startup.cs中的Identity配置
最后确认Startup.cs里的Identity服务配置是使用你的自定义用户和角色类型:
services.AddIdentity<ApplicationUser, ApplicationRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders();
不要出现混用IdentityRole和ApplicationRole的情况,否则也会导致映射异常。
内容的提问来源于stack exchange,提问作者user6728767

