ABP框架7.1修改IdentityUser列后数据种子器报错求助
我使用ABP Framework 7.1搭配Angular UI,在DbContext中对IdentityUser的两个列重命名并设为必填:
builder.Entity<IdentityUser>(b => { b.Property(x => x.Name).IsRequired().HasColumnName("FirstName"); b.Property(x => x.Surname).IsRequired().HasColumnName("LastName"); });
创建迁移并更新数据库后,列名已成功修改,但运行数据种子器时报错:
Cannot insert null into column name LastName, table AbpUsers, the column does not allow nulls.
我尝试自定义Identity种子器:
[Dependency(ReplaceServices = true)] public class CustomIdentityDataSeederContributor : IdentityDataSeeder { public CustomIdentityDataSeederContributor( IUnitOfWorkManager unitOfWorkManager, IGuidGenerator guidGenerator, IIdentityRoleRepository roleRepository, IIdentityUserRepository userRepository, ILookupNormalizer lookupNormalizer, IdentityUserManager userManager, IdentityRoleManager roleManager, ICurrentTenant currentTenant, IOptions<IdentityOptions> identityOptions, IdentityUserManager identityUserManager) : base(guidGenerator, roleRepository, userRepository, lookupNormalizer, userManager, roleManager, currentTenant, identityOptions) { } public override async Task<IdentityDataSeedResult> SeedAsync(string adminEmail, string adminPassword, Guid? tenantId = null) { var result = new IdentityDataSeedResult(); Check.NotNullOrWhiteSpace(adminEmail, nameof(adminEmail)); Check.NotNullOrWhiteSpace(adminPassword, nameof(adminPassword)); string adminUserName = "custom"; if (adminEmail == "admin@abp.io") { return result; } if (tenantId != Guid.Empty && tenantId != null) { adminUserName = "custom2"; if (adminEmail == "custom@Custom.com") { adminEmail = "custom2@Custom.com"; } } using (CurrentTenant.Change(tenantId)) { //"admin" user var adminUser = await UserRepository.FindByNormalizedUserNameAsync( LookupNormalizer.NormalizeName(adminUserName) ); if (adminUser != null) { return result; } adminUser = new IdentityUser( GuidGenerator.Create(), adminUserName, adminEmail, tenantId ) { //This should be first name and lastname Name = adminUserName, Surname = "surname" }; (await UserManager.CreateAsync(adminUser, adminPassword)).CheckErrors(); result.CreatedAdminUser = true; //"admin" role const string adminRoleName = "admin"; var adminRole = await RoleRepository.FindByNormalizedNameAsync(LookupNormalizer.NormalizeName(adminRoleName)); if (adminRole == null) { adminRole = new IdentityRole( GuidGenerator.Create(), adminRoleName, tenantId ) { IsStatic = true, IsPublic = true }; (await RoleManager.CreateAsync(adminRole)).CheckErrors(); result.CreatedAdminRole = true; } (await UserManager.AddToRoleAsync(adminUser, adminRoleName)).CheckErrors(); return result; } } }
注意IdentityUser的属性还是Name和Surname而非新列名,ABP内部类未修改。我还在MigrationService的SeedDataAsync方法里添加了LastName属性:
private async Task SeedDataAsync(Tenant tenant = null) { Logger.LogInformation($"Executing {(tenant == null ? "host" : tenant.Name + " tenant")} database seed..."); await _dataSeeder.SeedAsync(new DataSeedContext(tenant?.Id) .WithProperty(IdentityDataSeedContributor.AdminEmailPropertyName, IdentityDataSeedContributor.AdminEmailDefaultValue) .WithProperty(IdentityDataSeedContributor.AdminPasswordPropertyName, IdentityDataSeedContributor.AdminPasswordDefaultValue) .WithProperty("LastName", "Test") ); }
但仍报相同错误,该如何解决?
1. 修复自定义种子器的构造函数依赖
你的自定义种子器构造函数多传入了一个IdentityUserManager identityUserManager参数,与基类构造函数的参数列表不匹配,导致ABP无法正确替换默认的IdentityDataSeeder服务,默认种子器仍在执行(默认逻辑不会给Surname赋值,导致数据库LastName列空值)。
修改构造函数,移除多余的参数:
public CustomIdentityDataSeederContributor( IGuidGenerator guidGenerator, IIdentityRoleRepository roleRepository, IIdentityUserRepository userRepository, ILookupNormalizer lookupNormalizer, IdentityUserManager userManager, IdentityRoleManager roleManager, ICurrentTenant currentTenant, IOptions<IdentityOptions> identityOptions) : base(guidGenerator, roleRepository, userRepository, lookupNormalizer, userManager, roleManager, currentTenant, identityOptions) { }
2. 调整种子器的邮箱判断逻辑
代码中if (adminEmail == "admin@abp.io") return result;的判断会跳过默认admin用户的创建,如果数据库中不存在该用户,后续其他逻辑可能尝试创建它并触发空值错误。要么移除该判断,要么确保该邮箱对应的用户已提前存在,或者在判断分支内补充赋值逻辑。
3. 验证数据库约束与旧数据
确认AbpUsers表的FirstName和LastName列确实已设置非空约束,并且表中旧数据(如果存在)已填充这两个列的值,避免遗留空值记录触发约束错误。
4. 显式提交UnitOfWork(可选)
在自定义种子器的SeedAsync方法末尾,显式调用UnitOfWork的保存方法,确保数据被正确提交:
await UnitOfWorkManager.Current.SaveChangesAsync();
(需要在构造函数中注入IUnitOfWorkManager并保存为类字段)
5. 重置迁移与数据库(可选)
若问题仍存在,可删除现有迁移记录,重新生成迁移并更新数据库,同时清空AbpUsers表数据,让种子器从头执行。
内容的提问来源于stack exchange,提问作者Jesus

