0

I already have a database which contains identity user tables (AspNetUser, AspRole,...). I am using DB first to generate Models, I've configured every necessary services in program.cs. The project ran well until I start using services (ex: UserManager<AppUser>) related to Identity. It caused a lot of exceptions (un-countable). I asked AI and googled a lot but seems the hope has lost.

Here is all the models were generated: Entity Models

Program.cs configuration: Configuration

Here are some of the exceptions, i found a post that had the same issue but did not work for me: View detail here

  1. cannot use table 'appuserroles' for entity type 'appuserrole' since it is being used for entity type 'appuserrole (dictionary<string, object>)' and potentially other entity types, but there is no linking relationship. add a foreign key to 'appuserrole' on the primary key properties and pointing to the primary key on another entity type mapped to 'appuserroles'.

  2. Npgsql.PostgresException (0x80004005): 42P01: relation "AppUser" does not exist.

  3. System.InvalidOperationException: Cannot use table 'AppRoleClaims' for entity type 'IdentityRoleClaim<Guid>' since it is being used for entity type 'AppRoleClaim' and potentially other entity types, but there is no linking relationship. Add a foreign key to 'IdentityRoleClaim<Guid>' on the primary key properties and pointing to the primary key on another entity type mapped to 'AppRoleClaims'.

Here is my Database Context:

public partial class MyUserContext : IdentityDbContext<AspNetUser, IdentityRole<Guid>, Guid>
{
    public MyUserContext()
    {
    }

    public MyUserContext(DbContextOptions<MyUserContext> 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)
        => optionsBuilder.UseSqlServer("server=(local);database=MyUser;Trusted_Connection=True;TrustServerCertificate=True;uid=sa;pwd=T@n12345678901;");

    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.Id).ValueGeneratedNever();
            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.Id).ValueGeneratedNever();
            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.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.HasOne(d => d.User).WithMany(p => p.AspNetUserTokens).HasForeignKey(d => d.UserId);
        });

        OnModelCreatingPartial(modelBuilder);
    }

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

2 Answers 2

0

If you have based your code on an example, they are not using an explicit entity for tables like AspNetUserRole, so you should not try and declare one. These tables are joining tables for many-to-many relationships and are optional in many cases.

To fix your issue, remove the entity declarations for these joining entities like AspNetUserRole. Your mappings are already catering for the joining table.

For instance your code here:

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");
                });

This is declaring the relationship between the User and Role to the AspNetUserRoles table but mapping it as a basic Dictionary rather than an explicit entity class. The explicit class is not needed, but you could adjust the mapping to use it. In either case you don't need DbSets declared for many-to-many joining tables, simply let EF work these out where your entities should be using User.Roles and Role.Users respectively.

Sign up to request clarification or add additional context in comments.

Comments

0

After randomly configured in the OnModelCreating(), i finally resolved all exceptions.

  1. Map all the identity classes to Database tables (map to table's name)

modelBuilder.Entity<IdentityRole<Guid>>().ToTable("AspNetRoles"); modelBuilder.Entity<IdentityUserRole<Guid>>().ToTable("AspNetUserRoles"); modelBuilder.Entity<IdentityUserLogin<Guid>>().ToTable("AspNetUserLogins"); modelBuilder.Entity<IdentityUserToken<Guid>>().ToTable("AspNetTokens"); modelBuilder.Entity<IdentityUserClaim<Guid>>().ToTable("AspNetUserTokens"); modelBuilder.Entity<AspNetUser>().ToTable("AspNetUsers"); // This line is important, remove it will cause the 2nd exception (I don't know why)

  1. Map the generated classes (AspNetRole, AspNetUserToken,...) to non-exsited table name. This is the most essential to avoid Identity and AspNet refer to the same table and cause the 3rd exceptions. Ex: modelBuilder.Entity<AspNetRole>().ToTable("random table name here")

1 Comment

BTW, you are allowed to tick your answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.