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

执行EF迁移报错:IdentityUserRole<string>需定义主键

报错原因:IdentityUserRole缺少主键定义

问题描述

我在Blazor服务端项目中继承IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>,并在OnModelCreating方法中调用了base.OnModelCreating(modelBuilder),但执行dotnet ef migrations add IntitialMigration命令时出现错误:

The entity type 'IdentityUserRole' requires a primary key to be defined

原代码

using MyBlazorApp.Server.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;

namespace MyBlazorApp.Server.Data
{
    public class ApplicationDbContext : IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }        

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

            modelBuilder.Entity<ApplicationUser>()
                .Property(e => e.firstName)
                .HasMaxLength(250);

            modelBuilder.Entity<ApplicationUser>()
                .Property(e => e.lastName)
                .HasMaxLength(250);

            modelBuilder.Entity<ApplicationUser>()
                .Property(e => e.isLdapLogin);

            modelBuilder.Entity<ApplicationUser>()
                .Property(e => e.isMFAforce);

            modelBuilder.Entity<ApplicationUser>()
                .Property(e => e.apiKey);

            modelBuilder.Entity<ApplicationUser>()
                .Property(e => e.IsEnabled);

            //Seeding a  'Administrator' role to AspNetRoles table
            var arId = "dffc6dd5-b145-41e9-a861-c87ff673e9ca";
            modelBuilder.Entity<IdentityRole>().HasData(
                new IdentityRole
                {
                    Id = arId,
                    Name = "Admins",
                    NormalizedName = "ADMINS".ToUpper(),
                    ConcurrencyStamp = arId
                }
            ); ;
            var urId = "f8a527ac-d7f6-4d9d-aca6-46b2261b042b";
            modelBuilder.Entity<IdentityRole>().HasData(
                new IdentityRole
                {
                    Id = urId,
                    Name = "Users",
                    NormalizedName = "USERS".ToUpper(),
                    ConcurrencyStamp = urId
                }
            ); ;

            //a hasher to hash the password before seeding the user to the db
            var hasher = new PasswordHasher<IdentityUser>();

            //Seeding the Admin User to AspNetUsers table
            modelBuilder.Entity<ApplicationUser>().HasData(
                new ApplicationUser
                {
                    Id = new Guid("6fbfb682-568c-4f5b-a298-85937ca4f7f3"), // primary key
                    UserName = "super.admin",
                    NormalizedUserName = "SUPER.ADMIN",
                    PasswordHash = hasher.HashPassword(null, "7ugVUczrm7"),
                    firstName = "Super",
                    lastName = "Admin",
                    Email = "super.admin@local.app",
                    NormalizedEmail = "SUPER.ADMIN@LOCAL.APP",
                    EmailConfirmed = true,
                    isMFAforce = 0,
                    isLdapLogin = 0
                }
            );

            List<IdentityUserRole<string>> UserRoles = new List<IdentityUserRole<string>>();
            UserRoles.Add(new IdentityUserRole<string>
            {
                RoleId = "dffc6dd5-b145-41e9-a861-c87ff673e9ca",
                UserId = "6fbfb682-568c-4f5b-a298-85937ca4f7f3"
            });
            modelBuilder.Entity<IdentityUserRole<string>>().HasData(UserRoles);
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            base.OnConfiguring(optionsBuilder);
        }

    }
}

报错原因分析

你的DbContext明确使用Guid类型作为主键(继承IdentityDbContext<ApplicationUser, IdentityRole<Guid>, Guid>),但代码中存在多处类型不匹配:

  1. 种子角色数据使用IdentityRole(默认是string主键),而非IdentityRole<Guid>,导致EF Core识别的角色类型与上下文配置不一致。
  2. 密码哈希器使用PasswordHasher<IdentityUser>(默认string主键),而非对应Guid主键的PasswordHasher<ApplicationUser>或PasswordHasher<IdentityUser<Guid>>。
  3. 用户角色关联数据使用IdentityUserRole<string>,但上下文并未注册该类型,EF Core无法读取其主键配置(上下文默认注册的是IdentityUserRole<Guid>),因此抛出缺少主键的错误。

修正方案

将所有涉及Identity的泛型类型统一为Guid版本:

1. 修正角色种子数据

//Seeding a  'Administrator' role to AspNetRoles table
var arId = Guid.Parse("dffc6dd5-b145-41e9-a861-c87ff673e9ca");
modelBuilder.Entity<IdentityRole<Guid>>().HasData(
    new IdentityRole<Guid>
    {
        Id = arId,
        Name = "Admins",
        NormalizedName = "ADMINS".ToUpper(),
        ConcurrencyStamp = arId.ToString()
    }
);
var urId = Guid.Parse("f8a527ac-d7f6-4d9d-aca6-46b2261b042b");
modelBuilder.Entity<IdentityRole<Guid>>().HasData(
    new IdentityRole<Guid>
    {
        Id = urId,
        Name = "Users",
        NormalizedName = "USERS".ToUpper(),
        ConcurrencyStamp = urId.ToString()
    }
);

2. 修正密码哈希器

var hasher = new PasswordHasher<ApplicationUser>();

3. 修正用户角色关联数据

List<IdentityUserRole<Guid>> UserRoles = new List<IdentityUserRole<Guid>>();
UserRoles.Add(new IdentityUserRole<Guid>
{
    RoleId = Guid.Parse("dffc6dd5-b145-41e9-a861-c87ff673e9ca"),
    UserId = Guid.Parse("6fbfb682-568c-4f5b-a298-85937ca4f7f3")
});
modelBuilder.Entity<IdentityUserRole<Guid>>().HasData(UserRoles);

修正后,所有Identity相关类型与上下文的Guid主键配置保持一致,EF Core能正确识别各实体的主键,即可正常生成迁移。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 15:50:40