EF Core 6中如何播种带规范化字段的Identity角色与用户数据?
解决Identity角色/用户播种时规范化属性(NormalizedName等)为null的问题
在使用Microsoft.AspNetCore.Identity.EntityFrameworkCore v6.0.8和Microsoft.EntityFrameworkCore v6.0.8播种Identity角色与用户时,即使手动指定了NormalizedName、NormalizedUserName等规范化属性的值,数据库中这些字段始终为null。现有代码如下:
public class AppDbContext : IdentityDbContext<User, Role, int> { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { builder.Entity<Role>().HasData(new Role { Id = 1, Name = "SystemAdmin", NormalizedName = "SYSTEMADMIN" }); base.OnModelCreating(builder); } }
问题原因
Identity的base.OnModelCreating(builder)方法会自动为NormalizedName、NormalizedUserName、NormalizedEmail等规范化属性配置值生成策略(ValueGeneratedOnAddOrUpdate),这会让EF Core认为这些值由系统自动生成,从而忽略你在HasData中手动指定的固定值。
解决方案
方案1:调整代码顺序(推荐)
将base.OnModelCreating(builder)的调用移至种子数据配置之前,让Identity完成默认配置后,再通过HasData覆盖规范化属性的固定值:
public class AppDbContext : IdentityDbContext<User, Role, int> { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { // 先执行Identity的默认配置 base.OnModelCreating(builder); // 配置角色种子数据 builder.Entity<Role>().HasData(new Role { Id = 1, Name = "SystemAdmin", NormalizedName = "SYSTEMADMIN", ConcurrencyStamp = Guid.NewGuid().ToString() // 需指定并发戳,避免Identity验证报错 }); // 配置用户种子数据示例 builder.Entity<User>().HasData(new User { Id = 1, UserName = "admin@example.com", NormalizedUserName = "ADMIN@EXAMPLE.COM", Email = "admin@example.com", NormalizedEmail = "ADMIN@EXAMPLE.COM", EmailConfirmed = true, PasswordHash = GetHashedPassword(), // 使用加密后的密码 SecurityStamp = Guid.NewGuid().ToString(), ConcurrencyStamp = Guid.NewGuid().ToString() }); } // 生成加密密码的辅助方法 private string GetHashedPassword() { var hasher = new PasswordHasher<User>(); return hasher.HashPassword(null, "YourSecurePassword123!"); } }
注意:
- 必须为角色和用户指定
ConcurrencyStamp(可用Guid.NewGuid().ToString()生成),否则Identity会因为并发戳验证失败拒绝数据。 - 用户的
PasswordHash不能直接写明文,必须使用PasswordHasher生成加密后的哈希值。
方案2:手动移除值生成策略
如果无法调整代码顺序,可以手动移除规范化属性的自动生成配置,让EF Core使用你指定的固定值:
public class AppDbContext : IdentityDbContext<User, Role, int> { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { builder.Entity<Role>().HasData(new Role { Id = 1, Name = "SystemAdmin", NormalizedName = "SYSTEMADMIN", ConcurrencyStamp = Guid.NewGuid().ToString() }); base.OnModelCreating(builder); // 移除角色NormalizedName的自动生成配置 builder.Entity<Role>() .Property(r => r.NormalizedName) .ValueGeneratedNever(); // 若需要配置用户,同样移除对应属性的自动生成 builder.Entity<User>() .Property(u => u.NormalizedUserName) .ValueGeneratedNever(); builder.Entity<User>() .Property(u => u.NormalizedEmail) .ValueGeneratedNever(); } }
内容的提问来源于stack exchange,提问作者devklick
相关产品推荐
相关产品推荐

