【问题标题】:EF Core 2.0 Identity - Adding navigation propertiesEF Core 2.0 Identity - 添加导航属性
【发布时间】:2017-08-24 13:55:21
【问题描述】:

在 EF Core 2.0 中,Identity 导航属性默认是不包含的,所以升级后我添加了。所以对于 User 和 Role 之间的多对多关系,以及 Role 和 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 表和UserId1AspNetUserRoles 表添加了一个额外的RoleId1 键,并且所有get 查询实际上都使用新键而不是RoleIdUserId,它们也存在。

【问题讨论】:

标签: c# mysql postgresql entity-framework-core


【解决方案1】:

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

所以我做了以下操作:

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。所以,我根据Add IdentityUser POCO Navigation Properties添加了以下内容。

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 导航属性的线索。

【讨论】:

  • 感谢您非常彻底的回答。我刚刚遇到了这个问题,听从了您的建议,现在可以开始了!
【解决方案2】:

我遇到了同样的问题,在我的情况下,问题是因为我在OnModelCreating 的底部调用了base.OnModelCreating(builder)。将base.OnModelCreating(builder) 移到最顶部解决了这个问题(没有重复的列和 FK)。

感谢GitHub issue

【讨论】:

    【解决方案3】:

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

    你必须告诉 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);
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-04
      • 2018-02-03
      • 2018-10-22
      • 2018-10-10
      • 1970-01-01
      • 2019-08-06
      • 2023-03-21
      相关资源
      最近更新 更多