【问题标题】:Add Collection to user object in ASP.NET Core with Identity使用标识将集合添加到 ASP.NET Core 中的用户对象
【发布时间】:2019-03-01 08:19:21
【问题描述】:

我在玩 EF Core 和 ASP.NET Core 时偶然发现了以下问题。 我想以列表的形式向用户对象添加一些额外的数据。问题是列表永远不会更新。

这是我的 DbContext:

public class ApplicationDbContext : IdentityDbContext<HostUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {
    }
}

现在是我的用户对象:

public class HostUser : IdentityUser
{
    [PersonalData]
    public ICollection<GuestUser> GuestUsers { get; set; }
}

这是在控制器中添加一个新的 GuestUser:

[HttpPost]
    public async Task<IActionResult> Post([FromBody]GuestUser userToInsert)
    {
        if (userToInsert == null)
        {
            return BadRequest();
        }

        var currentUser = await GetCurrentUserAsync();
        if (currentUser == null)
        {
            return Forbid();
        }

        if(currentUser.GuestUsers?.Any(user => user.Id == userToInsert.Id) ?? false)
        {
            return BadRequest();
        }

        if(currentUser.GuestUsers == null)
        {
            currentUser.GuestUsers = new List<GuestUser>();
        }

        currentUser.GuestUsers.Add(userToInsert);
        await userManager.UpdateAsync(currentUser);

        return Ok();
    }

我的问题是这是否是一个完全错误的方法,我必须在 DbContext 中添加一个 GuestUser 的 DbSet 并将其映射到用户。 如果是这种情况,我不知道如何实现这一点。 注意:这里的GuestUser不是另一个IdentityUser,它是本地用户数据

【问题讨论】:

    标签: c# asp.net-core entity-framework-core asp.net-core-identity


    【解决方案1】:

    这可能是这样的:

    实体:

    public class HostUser : IdentityUser
    {
        public virtual ICollection<GuestUser> GuestUsers { get; set; }
    }
    
    public class GuestUser
    {
        public int HostUserId { get; set; }
        public virtual HostUser HostUser { get; set; }
    }
    

    数据库上下文:

    public class ApplicationDbContext : IdentityDbContext<HostUser>
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
    
        public DbSet<GuestUser> GuestUsers { get; set; }
    
        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
    
            builder.Entity<HostUser>(
                typeBuilder =>
                {
                    typeBuilder.HasMany(host => host.GuestUsers)
                        .WithOne(guest => guest.HostUser)
                        .HasForeignKey(guest => guest.HostUserId)
                        .IsRequired();
    
                    // ... other configuration is needed
                });
    
            builder.Entity<GuestUser>(
                typeBuilder =>
                {
                    typeBuilder.HasOne(guest => guest.HostUser)
                        .WithMany(host => host.GuestUsers)
                        .HasForeignKey(guest => guest.HostUserId)
                        .IsRequired();
    
                    // ... other configuration is needed
                });
        }
    }
    

    控制器动作:

    [HttpPost]
    public async Task<IActionResult> Post([FromBody] GuestUser userToInsert)
    {
        // All checks and validation ...
    
        // You can get the current user ID from the user claim for instance
        int currentUserId = int.Parse(User.FindFirst(Claims.UserId).Value);
    
        // _context is your ApplicationDbContext injected via controller constructor DI 
        userToInsert.HostUserId = currentUserId;
    
        // Save new guest user associated with the current host user
        _context.GuestUsers.Add(userToInsert);
        await _context.SaveChangesAsync();
    
        // If you need to get the current user with all guests
        List<HostUser> currentUser = await _context.Users.Include(host => host.GuestUsers).ToListAsync();
    
        return Ok(currentUser);
    }
    

    这里我提供了完整的代码 - how to configure custom Identity based DB context(所有需要的自定义类都继承自 IdentityDbContext 使用的基类)。

    【讨论】:

      【解决方案2】:

      有两个问题。

      1.首先你应该将ViewModel与实体分开(不要将GuestUser作为参数的web/api方法传递)

      2.那么正如您提到的,您应该在DbContext 中声明GuestUserDBSet 并将其映射到用户表。

      定义您的自定义用户实体

      public class ApplicationUser : IdentityUser
      {
          public string CustomTag { get; set; }
      }
      

      声明您的自定义 DbContext

      接下来使用这个类型作为上下文的通用参数:

      public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
      {
          public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
              : base(options)
          {
          }
      
          protected override void OnModelCreating(ModelBuilder modelBuilder)
          {
              base.OnModelCreating(modelBuilder);
      
              modelBuilder.Entity<ApplicationUser>(b =>
              {
                  // Each User can have many UserClaims
                  b.HasMany(e => e.Claims)
                      .WithOne()
                      .HasForeignKey(uc => uc.UserId)
                      .IsRequired();
              });
          }
      }
      

      更新 ConfigureServices 以使用新的 ApplicationUser 类:

      services.AddDefaultIdentity<ApplicationUser>()
          .AddEntityFrameworkStores<ApplicationDbContext>();
      

      如果您有任何其他问题,请告诉我。

      【讨论】:

      • 好的,所以我应该为“GuestUser”创建一个 DTO 并在 api 方法中实例化“GuestUser”?如果你能给我一个很好的映射示例,因为我对 EF Core 的经验为零
      • 是的,就是这样,我正在为你准备一个例子,我会在5分钟后修改这个答案。
      • 我不确定我是否完全理解它。所以 CustomTag 应该是 GuestUsere.Claims (在 OnModelCreating 方法中)应该是 e .GuestUser 在我的情况下?我看不到额外的 DbSet 应该映射到哪里
      猜你喜欢
      • 2018-07-29
      • 2022-11-30
      • 2014-12-09
      • 2023-03-10
      • 1970-01-01
      • 2019-01-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多