迁移.NET Framework MVC到ASP.NET Core 6.0遇Identity用户声明错误
问题:ASP.NET Core 6.0迁移中的Identity实体类型不兼容错误
System.InvalidOperationException: 'The relationship from 'IdentityUserClaim' to 'User' with foreign key properties {'UserId' : string} cannot target the primary key {'Id' : int} because it is not compatible. Configure a principal key or a set of foreign key properties with compatible types for this relationship.'
错误原因
自定义User实体继承了默认主键为string的IdentityUser,但手动声明了int类型的Id属性,导致User主键类型变为int;而AspNetUserClaim等关联实体的UserId仍配置为string类型,两者类型不匹配,引发外键关联错误。
相关代码
DbContext
public class DbContext : IdentityDbContext<User> { protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<AspNetRole>(entity => { entity.HasIndex(e => e.Name, "RoleNameIndex") .IsUnique() .HasFillFactor(80); entity.Property(e => e.Id).HasMaxLength(128); entity.Property(e => e.Name) .IsRequired() .HasMaxLength(256); }); modelBuilder.Entity<AspNetUser>(entity => { entity.HasIndex(e => e.UserName, "UserNameIndex") .IsUnique() .HasFillFactor(80); entity.Property(e => e.Id).HasMaxLength(128); entity.Property(e => e.Email).HasMaxLength(256); entity.Property(e => e.LockoutEndDateUtc).HasColumnType("datetime"); entity.Property(e => e.UserName) .IsRequired() .HasMaxLength(256); entity.HasMany(d => d.Roles) .WithMany(p => p.Users) .UsingEntity<Dictionary<string, object>>( "AspNetUserRole", l => l.HasOne<AspNetRole>().WithMany().HasForeignKey("RoleId").HasConstraintName("FK_dbo.AspNetUserRoles_dbo.AspNetRoles_RoleId"), r => r.HasOne<AspNetUser>().WithMany().HasForeignKey("UserId").HasConstraintName("FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId"), j => { j.HasKey("UserId", "RoleId").HasName("PK_dbo.AspNetUserRoles"); j.ToTable("AspNetUserRoles"); j.HasIndex(new[] { "RoleId" }, "IX_RoleId").HasFillFactor(80); j.HasIndex(new[] { "UserId" }, "IX_UserId").HasFillFactor(80); j.IndexerProperty<string>("UserId").HasMaxLength(128); j.IndexerProperty<string>("RoleId").HasMaxLength(128); }); }); modelBuilder.Entity<AspNetUserClaim>(entity => { entity.HasIndex(e => e.UserId, "IX_UserId") .HasFillFactor(80); entity.Property(e => e.UserId) .IsRequired() .HasMaxLength(128); entity.HasOne(d => d.User) .WithMany(p => p.AspNetUserClaims) .HasForeignKey(d => d.UserId) .HasConstraintName("FK_dbo.AspNetUserClaims_dbo.AspNetUsers_UserId"); }); modelBuilder.Entity<AspNetUserLogin>(entity => { entity.HasKey(e => new { e.LoginProvider, e.ProviderKey, e.UserId }) .HasName("PK_dbo.AspNetUserLogins"); entity.HasIndex(e => e.UserId, "IX_UserId") .HasFillFactor(80); entity.Property(e => e.LoginProvider).HasMaxLength(128); entity.Property(e => e.ProviderKey).HasMaxLength(128); entity.Property(e => e.UserId).HasMaxLength(128); entity.HasOne(d => d.User) .WithMany(p => p.AspNetUserLogins) .HasForeignKey(d => d.UserId) .HasConstraintName("FK_dbo.AspNetUserLogins_dbo.AspNetUsers_UserId"); }); modelBuilder.Entity<User>(entity => { entity.ToTable("User"); }); } }
User实体
public class User : IdentityUser { public int Id { get; set; } public string Username { get; set; } }
已尝试的修改
User实体修改
public virtual ICollection<AspNetUserClaim> AspNetUserClaims { get; set; } = new HashSet<AspNetUserClaim>();
DbContext的OnModelCreating修改
entity.HasMany(x => x.AspNetUserClaims) .WithOne() .HasForeignKey(x => x.UserId) .IsRequired() .OnDelete(DeleteBehavior.Cascade);
解决方案
1. 修正User实体的继承关系
继承IdentityUser<int>指定主键类型为int,无需手动声明Id属性(基类已包含):
public class User : IdentityUser<int> { public string Username { get; set; } public virtual ICollection<AspNetUserClaim> AspNetUserClaims { get; set; } = new HashSet<AspNetUserClaim>(); }
2. 修正DbContext的继承与配置
使用IdentityDbContext<User, IdentityRole<int>, int>匹配主键类型,并更新所有关联实体的主键/外键类型配置:
public class YourDbContext : IdentityDbContext<User, IdentityRole<int>, int> { // 构造函数(根据依赖注入方式调整) public YourDbContext(DbContextOptions<YourDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { // 先调用基类方法确保Identity默认配置生效 base.OnModelCreating(modelBuilder); modelBuilder.Entity<AspNetRole>(entity => { entity.HasIndex(e => e.Name, "RoleNameIndex") .IsUnique() .HasFillFactor(80); // 移除string类型的Id长度配置,改为int类型主键 // entity.Property(e => e.Id).HasMaxLength(128); entity.Property(e => e.Name) .IsRequired() .HasMaxLength(256); }); modelBuilder.Entity<AspNetUser>(entity => { entity.HasIndex(e => e.UserName, "UserNameIndex") .IsUnique() .HasFillFactor(80); // 移除string类型的Id长度配置 // entity.Property(e => e.Id).HasMaxLength(128); entity.Property(e => e.Email).HasMaxLength(256); entity.Property(e => e.LockoutEndDateUtc).HasColumnType("datetime"); entity.Property(e => e.UserName) .IsRequired() .HasMaxLength(256); entity.HasMany(d => d.Roles) .WithMany(p => p.Users) .UsingEntity<Dictionary<string, object>>( "AspNetUserRole", l => l.HasOne<AspNetRole>().WithMany().HasForeignKey("RoleId").HasConstraintName("FK_dbo.AspNetUserRoles_dbo.AspNetRoles_RoleId"), r => r.HasOne<AspNetUser>().WithMany().HasForeignKey("UserId").HasConstraintName("FK_dbo.AspNetUserRoles_dbo.AspNetUsers_UserId"), j => { j.HasKey("UserId", "RoleId").HasName("PK_dbo.AspNetUserRoles"); j.ToTable("AspNetUserRoles"); j.HasIndex(new[] { "RoleId" }, "IX_RoleId").HasFillFactor(80); j.HasIndex(new[] { "UserId" }, "IX_UserId").HasFillFactor(80); // 改为int类型的外键配置 j.IndexerProperty<int>("UserId"); j.IndexerProperty<int>("RoleId"); }); }); modelBuilder.Entity<AspNetUserClaim>(entity => { entity.HasIndex(e => e.UserId, "IX_UserId") .HasFillFactor(80); // 移除string类型的UserId长度配置,改为int类型 entity.Property(e => e.UserId) .IsRequired(); entity.HasOne(d => d.User) .WithMany(p => p.AspNetUserClaims) .HasForeignKey(d => d.UserId) .HasConstraintName("FK_dbo.AspNetUserClaims_dbo.AspNetUsers_UserId"); }); modelBuilder.Entity<AspNetUserLogin>(entity => { entity.HasKey(e => new { e.LoginProvider, e.ProviderKey, e.UserId }) .HasName("PK_dbo.AspNetUserLogins"); entity.HasIndex(e => e.UserId, "IX_UserId") .HasFillFactor(80); entity.Property(e => e.LoginProvider).HasMaxLength(128); entity.Property(e => e.ProviderKey).HasMaxLength(128); // 改为int类型的UserId entity.Property(e => e.UserId) .IsRequired(); entity.HasOne(d => d.User) .WithMany(p => p.AspNetUserLogins) .HasForeignKey(d => d.UserId) .HasConstraintName("FK_dbo.AspNetUserLogins_dbo.AspNetUsers_UserId"); }); modelBuilder.Entity<User>(entity => { entity.ToTable("User"); }); } }
3. 修正AspNetUserClaim等关联实体的UserId类型
确保AspNetUserClaim的UserId为int类型:
public class AspNetUserClaim { // 其他属性保持不变 public int UserId { get; set; } public User User { get; set; } }
通过以上修改,统一所有Identity相关实体的主键与外键类型为int,即可解决类型不兼容的关联错误。
内容的提问来源于stack exchange,提问作者Bad Dub
相关产品推荐
相关产品推荐

