Bad Dub
Bad Dub

Reputation: 1593

ASP.NET Core Identity User Claims Architecture

I am manually moving my ASP.NET MVC app running on .NET Framework 4.6 project to ASP.NET Core 6.0 and having issues when I try and run the application.

Right now I am getting this error:

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.'

It seems that my database configuration is incorrect somewhere. This is what I have so far (cut down for handiness).

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 entity:

public class User : IdentityUser
{
    public int Id { get; set; }
    public string Username { get; set; }
}

I have tried adding the following to the User entity and updating its associated OnModelCreating configuration.

User entity attempt:

public virtual ICollection<AspNetUserClaim> AspNetUserClaims { get; set; } = new HashSet<AspNetUserClaim>();

DbContext OnModelCreating attempt:

entity.HasMany(x => x.AspNetUserClaims)
    .WithOne()
    .HasForeignKey(x => x.UserId)
    .IsRequired()
    .OnDelete(DeleteBehavior.Cascade);

Upvotes: 1

Views: 271

Answers (1)

Brando Zhang
Brando Zhang

Reputation: 27987

According to the error message, you could find you want to set User' Id property as foreign key with User's UserId.

Since the UserId is the string, the Id is int, this is the reason why it throw this error.

To solve this issue, I suggest you could try to modify the user id's type to string.

public class User : IdentityUser
{
    public string Id { get; set; }
    public string Username { get; set; }
}

Upvotes: 1

Related Questions