如何正确扩展 IdentityUser 以保存每个用户的集合
How to correctly extend IdentityUser to save collections for each user
我希望用户能够 select 从 MultiSelectList 下拉列表中选择多项技能。我能够将每个用户的多种技能 selections 保存到数据库中,但我发现如果我删除一个用户的技能选项,并且我使用以前保存过相同技能的不同用户登录他的 selections,该用户和所有其他拥有类似技能选项的用户都会被删除。
所以我很清楚。假设用户 A 保存了这些技能 ["C#", "Python", "Java"]。用户B当前当前保存的技能为["C++","Scala"]。然后用户 B 登录并决定添加他刚刚学习的 C#。一旦他更新了个人资料,他的 selection 就变成了这个 ["C++","Scala", "C#"]。 C# 将从用户 A 的 selections 中删除,因此它变为 ["Python", "Java"].
这是我的习惯IdentityUser
class.
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; }
}
这就是我在控制器中保存技能 selection 的方式。
[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);
}
}
更新 - 我如何删除 selections
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);
}
}
你应该创建一个像 UserSkills
一样的 class,它有 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);
}
}
我希望用户能够 select 从 MultiSelectList 下拉列表中选择多项技能。我能够将每个用户的多种技能 selections 保存到数据库中,但我发现如果我删除一个用户的技能选项,并且我使用以前保存过相同技能的不同用户登录他的 selections,该用户和所有其他拥有类似技能选项的用户都会被删除。
所以我很清楚。假设用户 A 保存了这些技能 ["C#", "Python", "Java"]。用户B当前当前保存的技能为["C++","Scala"]。然后用户 B 登录并决定添加他刚刚学习的 C#。一旦他更新了个人资料,他的 selection 就变成了这个 ["C++","Scala", "C#"]。 C# 将从用户 A 的 selections 中删除,因此它变为 ["Python", "Java"].
这是我的习惯IdentityUser
class.
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; }
}
这就是我在控制器中保存技能 selection 的方式。
[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);
}
}
更新 - 我如何删除 selections
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);
}
}
你应该创建一个像 UserSkills
一样的 class,它有 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);
}
}