【问题标题】:How to correctly extend IdentityUser to save collections for each user如何正确扩展 IdentityUser 以保存每个用户的集合
【发布时间】:2020-11-17 03:15:26
【问题描述】:

我希望用户能够从 MultiSelectList 下拉列表中选择多个技能。我能够将每个用户的多个技能选择保存到数据库中,但我发现如果我删除一个用户的技能选项,并且我使用之前在他的选择中保存了相同技能的不同用户登录,它会已为此用户和所有其他保存了类似技能选项的用户删除。

所以我很清楚。假设用户 A 保存了这些技能 [“C#”、“Python”、“Java”]。用户 B 当前保存的技能是 ["C++","Scala"]。用户 B 然后登录并决定添加他刚刚学习的 C#。一旦他更新了他的个人资料并且他的选择变成了这个[“C++”,“Scala”,“C#”]。 C# 会从用户 A 的选择中删除,因此它变为 ["Python", "Java"]。

这是我自定义的IdentityUser 类。

public class ApplicationUser : IdentityUser
{
    public ApplicationUser()
    {
        Skills = new List<Skill>();
    }
    public string Location { get; set; }
    public virtual ICollection<Skill> Skills { get; set; }
}

这是技能模型。

public class Skill
{
    public int SkillId { get; set; }
    public string SkillType { get; set; }
}

这就是我在控制器中保存技能选择的方式。

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Profile(ProfileViewModel profileModel)
{
    var user = await _userManager.GetUserAsync(User);

    if (user == null)
    {
        return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
    }
    if (ModelState.IsValid)
    {
        if (user.Location != profileModel.Location) user.Location = profileModel.Location;

        if (profileModel.SelectedSkillIds != null)
        {
            List<Skill> tempSkills = new List<Skill> { };
            foreach (var skillID in profileModel.SelectedSkillIds)
            {
                user.Skills.Add(_context.Skills.FirstOrDefault(x => x.SkillId == skillID));
                var skill = _context.Skills.Find(skillID);
                if (skill != null)
                {
                    user.Skills.Add(skill);
                    tempSkills.Add(skill);
                }
                var allSkills = _context.Skills.ToList();
                var skillsToRemove = allSkills.Except(tempSkills);
                foreach (var sk in skillsToRemove)
                {
                    user.Skills.Remove(sk);
                }
            }
            await _userManager.UpdateAsync(user);
            await _signInManager.RefreshSignInAsync(user);
            return RedirectToAction("Profile", "Account");
        }
        return View(profileModel);
    }
}

更新 - 我如何删除选择

if (profileModel.SelectedSkillIds != null)
{
    List<UserSkill> tempSkills = new List<UserSkill> { };
    foreach (var skillID in profileModel.SelectedSkillIds)
    {
        var skill = _context.Skills.Find(skillID);
        if (skill != null)
        {
            var userskill = new UserSkill { AppUserId = user.Id, SkillId = skill.SkillId };
            user.UserSkills.Add(userskill);
            tempSkills.Add(userskill);
        }
    var allSkills = _context.UserSkills.ToList();
    var skillsToRemove = allSkills.Except(tempSkills);
    foreach (var sk in skillsToRemove)
    {
        user.UserSkills.Remove(sk); 
    }
}

【问题讨论】:

    标签: c# asp.net asp.net-mvc asp.net-core asp.net-mvc-4


    【解决方案1】:

    您应该创建一个像UserSkills 这样的类,它具有UserId 和SkillId,在这种情况下,任何用户都可以拥有多种技能,并且任何技能都可以用于许多用户。见many-to-many,1,2

    你应该把你的模型改成这个

    public class ApplicationUser : IdentityUser
    {
        public ApplicationUser()
        {
            Skills = new List<Skill>();
        }
        public string Location { get; set; }
        public virtual ICollection<UserSkills> Skills { get; set; }
    }
    public class Skill
    {
        public int SkillId { get; set; }
        public string SkillType { get; set; }
        public virtual ICollection<UserSkills> Skills { get; set; }
    }
    public class UserSkills
    {
        public int Id { get; set }
        public int UserId { get; set }
        public int SkillId { get; set }
        public Skill Skill { get; set; }
        public ApplicationUser User { get; set; }
    }
    
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Profile(ProfileViewModel profileModel)
    {
        var user = await _userManager.GetUserAsync(User);
    
        if (user == null)
        {
            return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
        }
        if (ModelState.IsValid)
        {
            if (user.Location != profileModel.Location) user.Location = profileModel.Location;
    
            if (profileModel.SelectedSkillIds != null)
            {
                List<Skill> tempSkills = new List<Skill> { };
                foreach (var sk in user.UserSkills)
                {
                   user.UserSkills.Remove(sk);
                }
                foreach (var skillID in profileModel.SelectedSkillIds)
                {
                    var userSkills = new UserSkill { UserId = user.Id, SkillId = skillID };
                    user.UserSkills.Add(userSkills);
                }
                await _userManager.UpdateAsync(user);
                await _signInManager.RefreshSignInAsync(user);
                return RedirectToAction("Profile", "Account");
            }
            return View(profileModel);
        }
    }
    

    然后将UserSkills 添加到您的DbContext

    public DbSet<Skill> Skills { get; set; }
    public DbSet<UserSkill> UserSkills { get; set; }
    

    最后在package manager console中使用Add-Migration和Update-DataBase

    其他选项

    您可以在控制器中注入DbContext 并在UserSkill 表中添加UserSkills 数据

    private readonly YourDbContext _dbContext;
    public UserController(YourDbContext dbContext)
    {
        _dbContext = dbContext;
    }
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Profile(ProfileViewModel profileModel)
    {
        var user = await _userManager.GetUserAsync(User);
    
        if (user == null)
        {
            return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
        }
        if (ModelState.IsValid)
        {
            if (user.Location != profileModel.Location) user.Location = profileModel.Location;
    
            if (profileModel.SelectedSkillIds != null)
            {
                var userSkillsForDelete = _dbContext.UserSkills.Where(a => a.UserId == user.Id).ToList();//<-- NOTE THIS
                foreach (var sk in userSkillsForDelete)
                {
                   //user.UserSkills.Remove(sk);
                   _dbContext.UserSkills.Remove(sk);<--NOTE THIS
                }
                foreach (var skillID in profileModel.SelectedSkillIds)
                {
                    var userSkills = new UserSkill { UserId = user.Id, SkillId = skillID };
                   _dbContext.UserSkills.Add(userSkills);<--NOTE THIS
                }
                await _userManager.UpdateAsync(user);
                await _signInManager.RefreshSignInAsync(user);
                return RedirectToAction("Profile", "Account");
            }
            return View(profileModel);
        }
    }
    
    

    【讨论】:

    • 嗨。这些值没有被保存,因此我无法填充下拉列表。这是我添加到我的上下文public DbSet&lt;Skill&gt; Skills。
    • 现在工作正常。新问题是,由于一些奇怪的原因,如果我从下拉列表中删除一些选择,它们不会更新。我只能添加。
    • 更新:我现在可以删除选择。我已经更新了我如何在问题中实现这一点,但我仍然不明白为什么你删除现有选择的方法不起作用。如果您想通了,我将不胜感激。
    • @QudusGiwa 您可以使用user.userSkills 获取所有用户技能。但你应该包括UserSkill这样的数据await _userManager.Users.Include(a =&gt; a.UserSkills).FirstOrDefaultAsync(a =&gt; a.Id == user.Id)
    • 我明白了。感谢您的帮助):
    猜你喜欢
    • 1970-01-01
    • 2021-04-29
    • 1970-01-01
    • 1970-01-01
    • 2013-12-23
    • 2016-11-05
    • 1970-01-01
    • 1970-01-01
    • 2017-03-24
    相关资源
    最近更新 更多