Search code examples
c#entity-framework-coremigration

How to get rid of shadow properties (UserId1) in EF Core 6 during Migration. Using ONLY attributes (no Fluent API if that's real)


During the migration, the shadow properties UserId1 and RoleId1 are created:

The foreign key property 'ApplicationUserRole.RoleId1' was created in shadow state because a conflicting property with the simple name 'RoleId' exists in the entity type, but is either not mapped, is already used for another relationship, or is incompatible with the associated primary key type. See https://aka.ms/efcore-relationships for information on mapping relationships in EF Core.
The foreign key property 'ApplicationUserRole.UserId1' was created in shadow state because a conflicting property with the simple name 'UserId' exists in the entity type, but is either not mapped, is already used for another relationship, or is incompatible with the associated primary key type. See https://aka.ms/efcore-relationships for information on mapping relationships in EF Core.

Of course I can use Fluent to get rid of the problem:

builder.Entity<ApplicationUserRole>()
    .HasOne(ur => ur.User)
    .WithMany(u => u.UserRoles)
    .HasForeignKey(ur => ur.UserId);

But I only need to use ATTRIBUTES.

class ApplicationUser (IdentityUser)

[Table("AspNetUsers")]

public class ApplicationUser : IdentityUser<int>
{
    [Key]
    [PersonalData]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public override int Id { get; set; }
    [NotMapped]
    public virtual ICollection<ApplicationUserClaim> Claims { get; set; }
    [NotMapped]
    public virtual ICollection<ApplicationUserLogin> Logins { get; set; }
    [NotMapped]
    public virtual ICollection<ApplicationUserToken> Tokens { get; set; }
    [NotMapped]
    [InverseProperty("User")]
    public virtual ICollection<ApplicationUserRole> UserRoles { get; set; }
}

Class ApplicationUserRole ( IdentityUserRole )

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.AspNetCore.Identity;

namespace OnlineStore.Entities;

[Table("AspNetUserRoles")]
public class ApplicationUserRole : IdentityUserRole<int>
{
    [Key]
    public override int UserId { get; set; }
    
    
    public virtual ApplicationUser User { get; set; } = null!;
    
    [ForeignKey(nameof(RoleId))]
    public virtual ApplicationRole Role { get; set; } = null!;
}

ApplicationContex

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using OnlineStore.Entities;

namespace OnlineStore.Contexts;

public class ApplicationContext
    : IdentityDbContext<ApplicationUser, ApplicationRole, int, ApplicationUserClaim,       ApplicationUserRole, ApplicationUserLogin, ApplicationRoleClaim, ApplicationUserToken>
{
    public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options)
    {
    }

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

        var roles = new ApplicationRole[]
        {
            new ApplicationRole(ApplicationRole.User, 1),
            new ApplicationRole(ApplicationRole.Admin, 2),
        };

        builder.Entity<ApplicationRole>().HasData(roles);

        builder.Entity<ApplicationUserRole>()
            .HasOne(ur => ur.User)
            .WithMany(u => u.UserRoles)
            .HasForeignKey(ur => ur.UserId);
    }
}

I managed to do it through Fluent, but only through attributes.


Solution

  • After a few tries I decided to see if something contained base.OnModelCreating(builder) of the ApplicationContext class and it did, so I decided to delete that line and it worked for me. Maybe this is a bad decision, but it helped me!