ASP.NET Core 3.1 EF Core:无法移除NormalizedName唯一索引,需创建联合索引
解决ASP.NET Core 3.1中IdentityRole联合唯一索引替换默认NormalizedName唯一索引的问题
问题原因
ASP.NET Identity框架默认会为IdentityRole<TKey>的NormalizedName属性创建唯一索引,仅通过builder.HasIndex(c => c.NormalizedName).IsUnique(false)无法覆盖或移除这个默认索引,导致迁移仅生成新的联合索引,未修改原有唯一约束。
解决方案
1. 移除默认索引并重新配置
在ApplicationRole的实体配置中,先移除Identity默认创建的NormalizedName唯一索引,再按需添加非唯一索引和联合唯一索引:
public void Configure(EntityTypeBuilder<ApplicationRole> builder) { // 移除Identity默认的NormalizedName唯一索引 var normalizedNameIndex = builder.Metadata.FindIndex(nameof(ApplicationRole.NormalizedName)); if (normalizedNameIndex != null) { builder.Metadata.RemoveIndex(normalizedNameIndex); } // 可选:保留NormalizedName的非唯一索引(若无需单独索引可删除此行) builder.HasIndex(c => c.NormalizedName).IsUnique(false); // 添加多属性联合唯一索引 builder.HasIndex(c => new { c.NormalizedName, c.SupplierId, c.CustomerId }).IsUnique(true); }
2. 生成迁移并更新数据库
执行以下命令生成包含索引修改的迁移脚本:
Add-Migration UpdateRoleUniqueIndex
随后更新数据库:
Update-Database
3. 同步应用层验证逻辑
由于默认的RoleValidator会验证NormalizedName的唯一性,需确保自定义的TenantRoleValidator验证联合属性的唯一性,避免应用层与数据库层约束不一致:
public class TenantRoleValidator : RoleValidator<ApplicationRole> { private readonly ApplicationDbContext _context; public TenantRoleValidator(ApplicationDbContext context, IdentityErrorDescriber errors = null) : base(errors) { _context = context; } public override async Task<IdentityResult> ValidateAsync(RoleManager<ApplicationRole> manager, ApplicationRole role) { var result = await base.ValidateAsync(manager, role); // 验证NormalizedName+SupplierId+CustomerId的组合唯一性 var existingRole = await _context.Roles .FirstOrDefaultAsync(r => r.NormalizedName == role.NormalizedName && r.SupplierId == role.SupplierId && r.CustomerId == role.CustomerId && r.Id != role.Id); if (existingRole != null) { result = IdentityResult.Failed(new IdentityError { Code = "DuplicateRoleCombination", Description = "同一NormalizedName、SupplierId和CustomerId组合的角色已存在。" }); } return result; } }
内容的提问来源于stack exchange,提问作者Tariq Hajeer
相关产品推荐
相关产品推荐

