解决EF Core中ApplicationUserClaim.UserId1影子状态外键错误
使用组件
- Microsoft.EntityFrameworkCore.SqlServer 8.0
- Microsoft.AspNetCore.Identity.EntityFrameworkCore 8.0
核心背景
直接执行以下代码会失败:
var usersClaims = await applicationDbContext.UserClaims.Include(uc=>uc.User).ToListAsync();
原因是默认的IdentityUserClaim没有内置User导航属性,IdentityUser也没有ICollection<ApplicationUserClaim>类型的Claims属性。因此自定义了ApplicationUser和ApplicationUserClaim类,并在ApplicationDbContext中引用这些自定义类:
IdentityDbContext<ApplicationUser, ..., ApplicationUserClaim,...>
自定义代码实现
ApplicationUser类
public class ApplicationUser : IdentityUser<string> { [Column(TypeName = "varchar(100)")] [MaxLength(100)] public string FirstName { get; set; } = string.Empty; [Column(TypeName = "varchar(100)")] [MaxLength(100)] public string LastName { get; set; } = string.Empty; public string FullName => $"{FirstName} {LastName}"; [Required] public bool Enabled { get; set; } = true; public virtual ICollection<ApplicationUserClaim> Claims { get; set; } = new List<ApplicationUserClaim>(); }
ApplicationUserClaim类
public class ApplicationUserClaim : IdentityUserClaim<string> { [ForeignKey("User")] public override string UserId { get; set; } = null!; public virtual ApplicationUser User { get; set; } = null!; }
ApplicationDbContext配置
ApplicationDbContext : IdentityDbContext< ApplicationUser, IdentityRole<string>, string, ApplicationUserClaim, IdentityUserRole<string>, IdentityUserLogin<string>, IdentityRoleClaim<string>, IdentityUserToken<string>> ... protected override void OnModelCreating(ModelBuilder modelBuilder) { ... modelBuilder.Entity<ApplicationUserClaim>(entity => { entity.HasOne(uc => uc.User) .WithMany(u => u.Claims) .HasForeignKey(uc => uc.UserId); }); ... }
问题现象
执行迁移并更新数据库后,EF Core重复创建了AspNetUsers与AspNetUserClaims的一对多关系,同时出现以下错误:
Microsoft.EntityFrameworkCore.Model.Validation[10625] 外键属性'ApplicationUserClaim.UserId1'已在影子状态中创建,因为实体类型中存在名为'UserId'的冲突属性,但该属性未映射、已用于其他关系或与关联主键类型不兼容。
原因分析
Identity框架已经默认配置了AspNetUsers和AspNetUserClaims之间的一对多关系。当你自定义导航属性后,又在OnModelCreating中手动重复配置关系时,EF Core会将其识别为全新的关系,进而创建额外的外键UserId1,最终导致关系重复和属性冲突。
解决方法
- 移除
ApplicationUserClaim中对UserId的重写和[ForeignKey]特性——基类IdentityUserClaim<TKey>已定义UserId属性,且Identity框架已默认配置该外键关联。 - 移除
OnModelCreating中手动添加的ApplicationUserClaim关系配置,让Identity的默认配置生效,EF Core会自动将自定义导航属性关联到默认外键上。
修改后的ApplicationUserClaim类:
public class ApplicationUserClaim : IdentityUserClaim<string> { public virtual ApplicationUser User { get; set; } = null!; }
调整后,EF Core不会创建重复外键,User和Claims导航属性可正确关联到默认的UserId外键,你也能正常使用Include(uc=>uc.User)加载关联用户数据。
内容的提问来源于stack exchange,提问作者Will

