Getting 'IdentityUserLogin<string>' requires a primary key error when saving new user

Stefan Gunel 0 Reputation points
2023-05-21T21:50:23.3766667+00:00

I work on an ASP.NET Core 7 Web API project with ASP.NET Core Identity.

I wanted to run code-first at the beginning of my project but I skipped because I had no idea how to create foreign key among my models with the AspNetUsers table.

So I chose to run database-first instead.

I migrate the Identity models first, then I create the remaining tables in SMSS. Next I run Scaffold-DbContext to get the models and the new context.

My problem is that when I try to save a new user to the database, I get the error:

System.InvalidOperationException: The entity type 'IdentityUserLogin' requires a primary key to be defined. If you intend to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types

My context looks like this:


public partial class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
    {
    }

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    public virtual DbSet<AspNetUsers> AspNetUsers { get; set; }

    public virtual DbSet<Comment> Comment { get; set; }
    public virtual DbSet<ReactionType> ReactionType { get; set; }
    public virtual DbSet<Video> Video { get; set; }
    public virtual DbSet<VideoReaction> VideoReaction { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<AspNetUsers>(entity =>
        {
            entity.HasIndex(e => e.NormalizedUserName, "UserNameIndex")
                .IsUnique()
                .HasFilter("([NormalizedUserName] IS NOT NULL)");
        });

        modelBuilder.Entity<Comment>(entity =>
        {
            entity.Property(e => e.Inserted).HasDefaultValueSql("(getdate())");

            entity.HasOne(d => d.User).WithMany(p => p.Comment)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_Comment_AspNetUsers");

            entity.HasOne(d => d.Video).WithMany(p => p.Comment)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_Comment_Video");
        });

        modelBuilder.Entity<ReactionType>(entity =>
        {
            entity.Property(e => e.Inserted).HasDefaultValueSql("(getdate())");
        });

        modelBuilder.Entity<Video>(entity =>
        {
            entity.Property(e => e.VideoId).HasDefaultValueSql("(newid())");
            entity.Property(e => e.Inserted).HasDefaultValueSql("(getdate())");

            entity.HasOne(d => d.User).WithMany(p => p.Video)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_Video_AspNetUsers");
        });

        modelBuilder.Entity<VideoReaction>(entity =>
        {
            entity.Property(e => e.Inserted).HasDefaultValueSql("(getdate())");

            entity.HasOne(d => d.ReactionType).WithMany(p => p.VideoReaction)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_VideoReaction_ReactionType");

            entity.HasOne(d => d.User).WithMany(p => p.VideoReaction)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_VideoReaction_AspNetUsers");

            entity.HasOne(d => d.Video).WithMany(p => p.VideoReaction)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_VideoReaction_Video");
        });

        OnModelCreatingPartial(modelBuilder);
    }

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

When I search for the error message, the only solution I find is that the code below could solve the error. But in my case the code doesn't solve the error.

base.OnModelCreating(builder);

I tried with and still get the error:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<AspNetUsers>(entity =>
    {
        entity.HasIndex(e => e.NormalizedUserName, "UserNameIndex")
            .IsUnique()
            .HasFilter("([NormalizedUserName] IS NOT NULL)");
    });

    modelBuilder.Entity<Comment>(entity =>
    {
        entity.Property(e => e.Inserted).HasDefaultValueSql("(getdate())");

        entity.HasOne(d => d.User).WithMany(p => p.Comment)
            .OnDelete(DeleteBehavior.ClientSetNull)
            .HasConstraintName("FK_Comment_AspNetUsers");

        entity.HasOne(d => d.Video).WithMany(p => p.Comment)
            .OnDelete(DeleteBehavior.ClientSetNull)
            .HasConstraintName("FK_Comment_Video");
    });
...
Developer technologies | ASP.NET | ASP.NET Core
Developer technologies | .NET | Other
{count} votes

5 answers

Sort by: Most helpful
  1. Stefan Gunel 0 Reputation points
    2023-05-22T16:47:42.14+00:00

    Hi @Anonymous ,

    Here is my ApplicationUser:

    using Microsoft.AspNetCore.Identity;
    
    namespace VideoSocialApp.Infrastructure.Identity
    {
        public class ApplicationUser : IdentityUser
        {
            public string FirstName { get; set; }
            public string LastName { get; set; }
            public bool? ShowFullName { get; set; }
            public string? ProfilePicture { get; set; }
            public DateTime? ProfilePictureUpdated { get; set; }
            public DateTime? LastLoggedIn { get; set; }
            public DateTime? PasswordLastChanged { get; set; }
            public bool? IsActive { get; set; }
    
            public string? RefreshToken { get; set; }
            public DateTime RefreshTokenExpiryTime { get; set; }
        }
    }
    
    0 comments No comments

  2. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

  3. Anonymous
    2023-05-23T07:10:00.17+00:00

    Hi,@Stefan Gunel,I tried as you mentioned and reproduced the error

    I think you've messed up the dbcontext for Db-first & Code-first

    And the following tables are necessary for your ApplicationUser

    User's image

    For code first solution,you could try with the dbcontext as below:

    public  class ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
        
        public virtual DbSet<SomeEntity>SomeEntity { get; set; }
        // other DbSets here......
        
        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
    
        }
    
    }
    
    
    
    public class ApplicationUser : IdentityUser
    {
      .......
    public SomeEntity SomeEntity { get; set; } = default!;
    }
    

    other DbSets such as DbSet<AspNetUsers> AspNetUsers has been defined in parent class so you don't have to define it again,also the entity has been configured in parent class's OnModelCreating method ,if you want to keep the configration,just call base.OnModelCreating(builder) in child class(If you forget to call it it child class,the primary key for AspNetUserLogin won't be configured and you would get the error)

    here's the source codes related:

    builder.Entity<TUserLogin>(b =>
            {
                b.HasKey(l => new { l.LoginProvider, l.ProviderKey });
                if (maxKeyLength > 0)
                {
                    b.Property(l => l.LoginProvider).HasMaxLength(maxKeyLength);
                    b.Property(l => l.ProviderKey).HasMaxLength(maxKeyLength);
                }
                b.ToTable("AspNetUserLogins");
            });
    

    And the Scaffolded dbcontext on my side:

    public partial class Identity0523Context : DbContext
    {
        public Identity0523Context()
        {
        }
    
        public Identity0523Context(DbContextOptions<Identity0523Context> options)
            : base(options)
        {
        }
    
        public virtual DbSet<AspNetRole> AspNetRoles { get; set; }
    
        public virtual DbSet<AspNetRoleClaim> AspNetRoleClaims { get; set; }
    
        public virtual DbSet<AspNetUser> AspNetUsers { get; set; }
    
        public virtual DbSet<AspNetUserClaim> AspNetUserClaims { get; set; }
    
        public virtual DbSet<AspNetUserLogin> AspNetUserLogins { get; set; }
    
        public virtual DbSet<AspNetUserToken> AspNetUserTokens { get; set; }
    
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    #warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
            => optionsBuilder.UseSqlServer("connectstr");
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<AspNetRole>(entity =>
            {
                entity.HasIndex(e => e.NormalizedName, "RoleNameIndex")
                    .IsUnique()
                    .HasFilter("([NormalizedName] IS NOT NULL)");
    
                entity.Property(e => e.Name).HasMaxLength(256);
                entity.Property(e => e.NormalizedName).HasMaxLength(256);
            });
    
            modelBuilder.Entity<AspNetRoleClaim>(entity =>
            {
                entity.HasIndex(e => e.RoleId, "IX_AspNetRoleClaims_RoleId");
    
                entity.HasOne(d => d.Role).WithMany(p => p.AspNetRoleClaims).HasForeignKey(d => d.RoleId);
            });
            
    
    
            modelBuilder.Entity<AspNetUser>(entity =>
            {
                entity.HasIndex(e => e.NormalizedEmail, "EmailIndex");
    
                entity.HasIndex(e => e.NormalizedUserName, "UserNameIndex")
                    .IsUnique()
                    .HasFilter("([NormalizedUserName] IS NOT NULL)");
    
                entity.Property(e => e.Email).HasMaxLength(256);
                entity.Property(e => e.NormalizedEmail).HasMaxLength(256);
                entity.Property(e => e.NormalizedUserName).HasMaxLength(256);
                entity.Property(e => e.UserName).HasMaxLength(256);
    
                entity.HasMany(d => d.Roles).WithMany(p => p.Users)
                    .UsingEntity<Dictionary<string, object>>(
                        "AspNetUserRole",
                        r => r.HasOne<AspNetRole>().WithMany().HasForeignKey("RoleId"),
                        l => l.HasOne<AspNetUser>().WithMany().HasForeignKey("UserId"),
                        j =>
                        {
                            j.HasKey("UserId", "RoleId");
                            j.ToTable("AspNetUserRoles");
                            j.HasIndex(new[] { "RoleId" }, "IX_AspNetUserRoles_RoleId");
                        });
            });
    
            modelBuilder.Entity<AspNetUserClaim>(entity =>
            {
                entity.HasIndex(e => e.UserId, "IX_AspNetUserClaims_UserId");
    
                entity.HasOne(d => d.User).WithMany(p => p.AspNetUserClaims).HasForeignKey(d => d.UserId);
            });
    
            modelBuilder.Entity<AspNetUserLogin>(entity =>
            {
                entity.HasKey(e => new { e.LoginProvider, e.ProviderKey });
    
                entity.HasIndex(e => e.UserId, "IX_AspNetUserLogins_UserId");
    
                entity.Property(e => e.LoginProvider).HasMaxLength(128);
                entity.Property(e => e.ProviderKey).HasMaxLength(128);
    
                entity.HasOne(d => d.User).WithMany(p => p.AspNetUserLogins).HasForeignKey(d => d.UserId);
            });
    
            modelBuilder.Entity<AspNetUserToken>(entity =>
            {
                entity.HasKey(e => new { e.UserId, e.LoginProvider, e.Name });
    
                entity.Property(e => e.LoginProvider).HasMaxLength(128);
                entity.Property(e => e.Name).HasMaxLength(128);
    
                entity.HasOne(d => d.User).WithMany(p => p.AspNetUserTokens).HasForeignKey(d => d.UserId);
            });
    
            OnModelCreatingPartial(modelBuilder);
        }
    
        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    }
    
    
    
    

    You missed the required Entities to describe ApplicationUser/IdentityUser and when you try this line

    var result = await _userManager.CreateAsync(user, Input.Password);

    You would got error,I recommand you just try code-first approach with the dbcontext I've shown and follow this document to customize Identity


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,

    RuikaiFeng

    0 comments No comments

  4. Stefan Gunel 0 Reputation points
    2023-05-23T23:09:39.6233333+00:00

    Thank you so much for your help. Really appreciate it.

    Now I understand where I have gone wrong. It was not a good idea to mix Code and Database first.

    I run Clean Architecture in my project. I have Application, Domain, Infrastructure and Presentation layers.

    In the Infrastructure layer I have Identity settings incl. ApplicationUser.

    If I'm going to run Code First. How can I use ApplicationUser/AspNetUsers in my Domain layer if I would like to foreign key my models? This is because the Doamin layer has no reference to any layer.

    That's why I mixed up Code & Database first. Had no idea how to solve it. Searched but couldn't find anything about this.

    Hope I'm not bothering you with the problem.

    Thanks again for the help.


  5. Stefan Gunel 0 Reputation points
    2023-05-29T22:40:09.6466667+00:00

    Hello @Anonymous

    I have now tried it too. Getting the same error and not working.

    I think I'll give up now.

    Thank you for all your help and time.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.