简体   繁体   English

EF Core 2.0 Identity - 添加导航属性

[英]EF Core 2.0 Identity - Adding navigation properties

In EF Core 2.0 Identity navigation properties are not included by default, so after upgrading, I added them.在 EF Core 2.0 中,默认情况下不包含身份导航属性,因此在升级后,我添加了它们。 So for Many-To-Many relationship between User and Role, and One-To-Many relationship between Role and RoleClaim, I added following navigation properties:因此,对于 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;}
}

Surprisingly it adds an additional RoleId1 key to AspNetRoleClaims table and UserId1 to AspNetUserRoles tables and all the get queries actually use new keys instead of RoleId and UserId which are also present.令人惊讶的是增加了一个额外RoleId1关键AspNetRoleClaims表和UserId1AspNetUserRoles表和所有实际使用新的密钥,而不是GET查询RoleIdUserId同样存在。

I do not know why, there are not these useful navigation properties.不知道为什么,没有这些有用的导航属性。 I want to list users with their roles.我想列出用户及其角色。

So I did the follow:所以我做了以下事情:

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

This creates the navigation, but it creates additional columns like RoleId1 and Discriminator .这会创建导航,但会创建其他列,如RoleId1Discriminator So, I added the following according to Add IdentityUser POCO Navigation Properties .所以,我根据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);
}

But I still have both columns RoleId1 and Discriminator .但我仍然有两列RoleId1Discriminator After that, I replace with the new ApplicationRole class in ApplicationDbContext, DI configuration service and DB seed.之后,我用 ApplicationDbContext、DI 配置服务和 DB 种子中的新 ApplicationRole 类替换。

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

Also, I could navigate and get the first name of role.此外,我可以导航并获取角色的名字。

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

I hope this give you a clue for Claims navigation property.我希望这能给你一个关于Claims导航属性的线索。

I've encountered the same issue, in my case the problem was caused because I had put the call to base.OnModelCreating(builder) at the bottom of OnModelCreating .我遇到同样的问题,在我的情况的问题造成的,因为我已经把电话给base.OnModelCreating(builder)在底部OnModelCreating Moving base.OnModelCreating(builder) at the very top solved the issue (no duplicate columns and FKs).在最顶部移动base.OnModelCreating(builder)解决了这个问题(没有重复的列和 FK)。

在此处输入图片说明

Thanks to this GitHub issue感谢这个GitHub 问题

I encountered with same issue and this is solution.我遇到了同样的问题,这是解决方案。

You have to tell Ef on which navigation property you are going to have OneToMany Relation.您必须告诉 Ef 您将拥有 OneToMany Relation 的导航属性。

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

You can Also specify navigation property in string like您还可以在字符串中指定导航属性,例如

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM