You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET 6 Identity中添加导航属性且不生成Discriminator列

解决.NET 6 Identity中自定义UserRole添加导航属性时生成Discriminator列的问题

问题背景

我在使用.NET 6开发API项目,采用Identity组件。初始定义的User和Role类如下:

public class ApplicationUser : IdentityUser<int> {
    public virtual ICollection<IdentityUserRole<int>> Roles { get; } = new List<IdentityUserRole<int>>();        
}
public class ApplicationRole : IdentityRole<int> {
    public virtual ICollection<IdentityUserRole<int>> Users { get; } = new List<IdentityUserRole<int>>();
}

对应的生成表结构(AspNetUserRoles)如下:

migrationBuilder.CreateTable(
    name: "AspNetUserRoles",
    schema: "ancid",
    columns: table => new
    {
        UserId = table.Column<int>(type: "int", nullable: false),
        RoleId = table.Column<int>(type: "int", nullable: false)
    },
    constraints: table =>
    {
        //...
    });

此时从ApplicationUser只能导航到IdentityUserRole<int>获取RoleId,无法直接获取角色名称。于是我自定义了ApplicationUserRole并添加导航属性,修改后的类:

public class ApplicationUserRole : IdentityUserRole<int> {
    public virtual ApplicationUser User { get; }
    public virtual ApplicationRole Role { get; }
}
public class ApplicationUser : IdentityUser<int> {
    public virtual ICollection<ApplicationUserRole> Roles { get; } = new List<ApplicationUserRole>();        
}
public class ApplicationRole : IdentityRole<int> {
    public virtual ICollection<ApplicationUserRole> Users { get; } = new List<ApplicationUserRole>();
}

但生成的迁移会自动为AspNetUserRoles表添加Discriminator列:

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.AddColumn<string>(
        name: "Discriminator",
        schema: "ancid",
        table: "AspNetUserRoles",
        type: "nvarchar(max)",
        nullable: false,
        defaultValue: "");
}

即使删除迁移目录重新生成初始迁移,该列依然存在,而AspNetUsers和AspNetRoles表没有这个问题。需要实现添加导航属性但不生成Discriminator列的目标。

解决方案

1. 在DbContext中显式配置实体映射

在继承自IdentityDbContext的DbContext类中,重写OnModelCreating方法,显式指定ApplicationUserRole对应的表,并告知EF Core这是该表的唯一实体类型,不需要鉴别器:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    // 配置ApplicationUserRole映射到AspNetUserRoles表,关闭鉴别器
    modelBuilder.Entity<ApplicationUserRole>(b =>
    {
        b.HasKey(r => new { r.UserId, r.RoleId });
        b.ToTable("AspNetUserRoles", "ancid"); // 指定表名和schema,和之前一致
        
        // 显式配置导航属性关联
        b.HasOne(r => r.User)
            .WithMany(u => u.Roles)
            .HasForeignKey(r => r.UserId)
            .IsRequired();

        b.HasOne(r => r.Role)
            .WithMany(r => r.Users)
            .HasForeignKey(r => r.RoleId)
            .IsRequired();
    });
}

2. 确保IdentityDbContext使用自定义的UserRole类型

在DbContext的继承声明中,明确指定自定义的ApplicationUserRole作为泛型参数,让EF Core默认使用你的自定义类型而非基类IdentityUserRole<int>:

public class YourDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, int, 
    IdentityUserClaim<int>, ApplicationUserRole, IdentityUserLogin<int>,
    IdentityRoleClaim<int>, IdentityUserToken<int>>
{
    public YourDbContext(DbContextOptions<YourDbContext> options) : base(options)
    {
    }
}

3. 重新生成迁移

删除现有的迁移文件和开发环境数据库,执行以下命令重新生成初始迁移并更新数据库:

dotnet ef migrations add InitialCreate
dotnet ef database update

此时生成的迁移中不会再出现Discriminator列,同时ApplicationUser和ApplicationRole可以通过ApplicationUserRole的导航属性直接关联获取相关数据。


内容的提问来源于stack exchange,提问作者tschmit

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 16:25:25