如何避免AspNetUsers、AspNetRoles和AspNetUserRoles生成Discriminator字段
嘿,我来帮你搞定这个Identity扩展的问题!
核心问题梳理
你遇到的本质问题是:EF Core对非抽象基类的继承默认会采用**TPH(单表继承)**策略,它需要一个鉴别器字段来区分基类和派生类的实例。哪怕你完全不想使用IdentityUser/IdentityRole这些基类本身,也得明确告诉EF Core:你只认自己的派生类,别给基类留空间。
具体解决步骤
咱们一步步来,从类定义到DbContext配置全覆盖:
1. 先确认你的派生类定义
确保你的自定义类正确继承自Identity的基类,比如:
// 自定义用户类 public class AppUser : IdentityUser { // 你的自定义属性 public string DisplayName { get; set; } } // 自定义角色类 public class AppRole : IdentityRole { // 你的自定义角色属性 public string RoleDescription { get; set; } } // 自定义用户-角色关联类(注意泛型参数要和主键类型匹配,这里用string) public class AppUserRole : IdentityUserRole<string> { // 你的自定义关联属性 public DateTime AssignedAt { get; set; } }
2. 关键:替换IdentityDbContext的泛型参数
这一步很多人容易忽略!默认的IdentityDbContext用的是Identity的基类,你必须把它替换成你的自定义类,这样EF和Identity框架才会正确识别你的派生类:
public class AppDbContext : IdentityDbContext< AppUser, // 替换为你的自定义用户类 AppRole, // 替换为你的自定义角色类 string, // 主键类型(通常是string) IdentityUserClaim<string>, // 没扩展的话用基类就行 AppUserRole, // 替换为你的自定义用户-角色关联类 IdentityUserLogin<string>, // 没扩展用基类 IdentityRoleClaim<string>, // 没扩展用基类 IdentityUserToken<string> // 没扩展用基类 > { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } // 接下来配置OnModelCreating protected override void OnModelCreating(ModelBuilder builder) { // 一定要先调用基类方法!不然Identity的默认配置(主键、关系、索引)会丢失 base.OnModelCreating(builder); // 配置自定义用户:指定鉴别器,明确只映射AppUser builder.Entity<AppUser>(b => { b.HasDiscriminator<string>("UserType") .HasValue<AppUser>("ApplicationUser"); // 给派生类指定唯一鉴别器值 b.ToTable("Users"); // 可选:自定义表名,替换默认的AspNetUsers }); // 配置自定义角色 builder.Entity<AppRole>(b => { b.HasDiscriminator<string>("RoleType") .HasValue<AppRole>("ApplicationRole"); b.ToTable("Roles"); // 可选:自定义表名,替换默认的AspNetRoles }); // 配置自定义用户-角色关联 builder.Entity<AppUserRole>(b => { b.HasDiscriminator<string>("UserRoleType") .HasValue<AppUserRole>("ApplicationUserRole"); b.ToTable("UserRoles"); // 可选:自定义表名,替换默认的AspNetUserRoles // 可选:给自定义属性加配置,比如默认值 b.Property(ur => ur.AssignedAt) .HasDefaultValueSql("GETUTCDATE()"); }); } }
3. 核心原理说明
- 为什么要配置鉴别器?哪怕基类不是抽象的,EF Core默认会认为你可能同时使用基类和派生类实例,所以需要鉴别器来区分。咱们通过
HasValue<AppUser>("ApplicationUser")明确告诉EF:只有这个值对应的派生类是有效的,基类不会被实例化。 - 替换
IdentityDbContext的泛型参数是重中之重:这会让Identity框架在处理登录、授权等逻辑时,直接使用你的自定义类,而不是默认的IdentityUser,从根源上避免类型冲突。
常见错误排查
如果还是遇到问题,检查这几点:
- 有没有忘记调用
base.OnModelCreating(builder)?这会导致Identity的默认关系配置丢失,引发各种奇怪的错误。 - 派生类的主键类型是否和基类一致?比如
IdentityUser默认主键是string,你的AppUser别改成int。 - 迁移时有没有生成正确的鉴别器字段?可以通过
Add-Migration命令查看生成的迁移文件,确认鉴别器字段已添加。
内容的提问来源于stack exchange,提问作者jmogera
相关产品推荐
相关产品推荐

