EF Core 2.0 Identity - 添加导航属性

9
在EF Core 2.0中,默认情况下不包括Identity导航属性,因此在升级后,我添加了它们。因此,在用户和角色之间的多对多关系以及角色和RoleClaim之间的一对多关系中,我添加了以下导航属性:
public class User : IdentityUser
{
    [Required]
    public string Name { get; set; }

    public virtual ICollection<IdentityUserRole<string>> Roles { get; set; }
}

public class Role : IdentityRole
{
    [Required]
    public string Name { get; set; }

    public virtual ICollection<IdentityRoleClaim<string>> Claims { get; set;}
}

令人惊讶的是,它在AspNetRoleClaims表中添加了一个额外的RoleId1键,在AspNetUserRoles表中添加了UserId1键,并且所有的查询都实际使用新键而不是已经存在的RoleIdUserId


请参见此主题的答案 https://dev59.com/wVYN5IYBdhLWcg3wO18v#47772406 - YodasMyDad
3个回答

11

我不知道为什么,没有这些有用的导航属性。我想列出用户及其角色。

所以我做了以下操作:

public class ApplicationUser : IdentityUser
{
    public virtual ICollection<ApplicationUserRole> UserRoles { get; } = new List<ApplicationUserRole>();
}

public class ApplicationUserRole : IdentityUserRole<string>
{
    public virtual ApplicationUser User { get; set; }
    public virtual ApplicationRole Role { get; set; }
}

public class ApplicationRole : IdentityRole<string>
{
    public ApplicationRole(){ }

    public ApplicationRole(string roleName)
        : base(roleName)
    {
    }

    public virtual ICollection<ApplicationUserRole> UserRoles { get; } = new List<ApplicationUserRole>();
}

这将创建导航,但它会创建其他列,如 RoleId1Discriminator。所以,根据添加 IdentityUser POCO 导航属性,我添加了以下内容。

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

    builder.Entity<ApplicationUser>()
        .HasMany(e => e.UserRoles)
        .WithOne()
        .HasForeignKey(e => e.UserId)
        .IsRequired()
        .OnDelete(DeleteBehavior.Cascade);

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

    builder.Entity<ApplicationUserRole>()
        .HasOne(e => e.Role)
        .WithMany(e => e.UserRoles)
        .HasForeignKey(e => e.RoleId);
}

但是我仍然拥有两个列RoleId1Discriminator。之后,我在ApplicationDbContext中使用新的ApplicationRole类替换,DI配置服务和DB种子。

public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string, IdentityUserClaim<string>
    , ApplicationUserRole, IdentityUserLogin<string>, IdentityRoleClaim<string>, IdentityUserToken<string>>
{
    ...
}

public void ConfigureServices(IServiceCollection services)
{
   ...
   services.AddIdentity<ApplicationUser, ApplicationRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
   ...
}

public DbInitializer(
        ApplicationDbContext context,
        UserManager<ApplicationUser> userManager,
        RoleManager<ApplicationRole> roleManager)
    {
        _context = context;
        _userManager = userManager;
        _roleManager = roleManager;
    }

public async void Initialize()
    {
        _context.Database.EnsureCreated();

        if (!_context.Roles.Any(r => r.Name == SharedConstants.Role.ADMINISTRATOR))
            await _roleManager.CreateAsync(new ApplicationRole(SharedConstants.Role.ADMINISTRATOR));
    }            

另外,我可以导航并获取角色的名字。

ctx.Users.Select(e => new
            {
                e.Id,
                e.UserName,
                e.Email,
                e.PhoneNumber,
                Roles = e.UserRoles.Select(i => i.Role.Name).ToList()
            }).ToList();

我希望这可以给你关于 Claims 导航属性的一个线索。


非常感谢您提供如此详尽的答案。我刚刚遇到了这个问题,按照您的建议去做,现在一切都很好! - Arian Kulp

7
我遇到了相同的问题,原因是我在 OnModelCreating 的底部调用了 base.OnModelCreating(builder)。将 base.OnModelCreating(builder) 移至顶部解决了该问题(没有重复的列和 FK)。

enter image description here

感谢这个 GitHub issue

2
这对我解决了问题。@UUHHIVS 对“设置”有一个很好的答案。然而,上面的答案才是解决我的问题的方法^^ - jward01
1
老话题,但也解决了我的问题,非常感谢! - Junior Silva

0

我遇到了同样的问题,这是解决方案。

你必须告诉Ef你将在哪个导航属性上拥有OneToMany关系。

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


        CreateUserModel(modelBuilder.Entity<User>());
        CreateRoleModel(modelBuilder.Entity<Role>());

    }


    private void CreateRoleModel(EntityTypeBuilder<Role> entityTypeBuilder)
    {
        entityTypeBuilder.HasMany(role => role.UserRoles).
            WithOne(**e=> e.Role**).
            HasForeignKey(userRole => userRole.RoleId).
            IsRequired()
            .OnDelete(DeleteBehavior.Cascade);
    }

    private void CreateUserModel(EntityTypeBuilder<User> entityTypeBuilder)
    {
        entityTypeBuilder.HasMany(user => user.UserRoles).
            WithOne(**e=>e.User**).
            HasForeignKey(userRole => userRole.UserId).
            IsRequired()
            .OnDelete(DeleteBehavior.Cascade);
    }

您还可以像字符串一样指定导航属性

private void CreateRoleModel(EntityTypeBuilder<Role> entityTypeBuilder)
    {
        entityTypeBuilder.HasMany(role => role.UserRoles).
            WithOne(**"Role"**).
            HasForeignKey(userRole => userRole.RoleId).
            IsRequired()
            .OnDelete(DeleteBehavior.Cascade);
    }

    private void CreateUserModel(EntityTypeBuilder<User> entityTypeBuilder)
    {
        entityTypeBuilder.HasMany(user => user.UserRoles).
            WithOne(**"User"**).
            HasForeignKey(userRole => userRole.UserId).
            IsRequired()
            .OnDelete(DeleteBehavior.Cascade);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接