【发布时间】:2017-12-31 15:54:41
【问题描述】:
我正在构建一个 MVC5 Web 应用程序。我使用了身份框架。我正在努力做到这一点,以便每个用户都有一个与他相关联的军队列表。这些将通过复选框在页面上更新。
我已经用这个附加属性扩展了默认的 ApplicationUser 类。
public virtual ICollection<Army> Armies { get; set; }
public ApplicationUser()
{
Armies = new HashSet<Army>();
}
我也有这些领域的陆军课程。陆军表已填充了大约 10 个条目,详细说明了不同的军队。
public class Army
{
public int Id { get; set; }
public String Name { get; set; }
public String IconLocation { get; set; }
public virtual ICollection<ApplicationUser> Users { get; set; }
public Army()
{
Users = new HashSet<ApplicationUser>();
}
}
然后我在 DbContext 中建立了关系
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder
.Entity<ApplicationUser>()
.HasMany(u => u.Armies)
.WithMany(t => t.Users)
.Map(m =>
{
m.ToTable("UserArmies");
m.MapLeftKey("UserId");
m.MapRightKey("ArmyId");
});
}
用户可以在管理用户页面上编辑这些,这些显示为复选框项目。
public class CheckBoxItem
{
public int Id { get; set; }
public String Name { get; set; }
public bool IsChecked { get; set; }
}
控制器调用 PopulateArmyCheckBoxList() 方法将军队变成复选框列表。 (这最初是使用列表完成的,但在我试图解决我的问题时在下面用字典实现。)这部分程序按预期工作,我正确显示我的复选框并勾选相关框。
private List<CheckBoxItem> PopulateArmyCheckBoxList()
{
var userId = User.Identity.GetUserId();
var userArmies = _context.Users.SingleOrDefault(u => u.Id == userId).Armies.ToDictionary(t=>t.Id, t=>t.Name);
var allArmies = _context.Armies.ToDictionary(t=>t.Id, t => t.Name);
var armyCheckBoxList = new List<CheckBoxItem>();
foreach (var army in allArmies)
{
armyCheckBoxList.Add(new CheckBoxItem()
{
Id = army.Key,
Name = army.Value,
IsChecked = false
});
}
foreach(var army in userArmies)
{
var cb = armyCheckBoxList.Find(c => c.Id == army.Key);
if(cb != null)
cb.IsChecked = true;
}
return armyCheckBoxList;
}
viewModel 包含一个用户和一个名为 Armies 的 CheckBoxItem 列表。如果是第一次访问,则 User == null 并且 viewModel 会填充数据。否则它将获取数据并更新用户。
public async Task<ActionResult> Index(IndexViewModel viewModel)
{
var userId = User.Identity.GetUserId();
if (viewModel.User == null)
{
var model = new IndexViewModel
{
User = UserManager.FindById(userId),
Armies = PopulateArmyCheckBoxList()
};
return View(model);
}
var user = UserManager.FindById(userId);
user.UserName = viewModel.User.UserName;
user.Email = viewModel.User.Email;
user.ProfilePictureLocation = SaveProfileImage(user, viewModel.ProfilePicture);
UserManager.Update(user);
ViewBag.StatusMessage = "Your Profile Has Been Updated.";
viewModel.User = UserManager.FindById(User.Identity.GetUserId());
return View(viewModel);
}
最后阶段出现了可怕的错误。我需要更新数据库上的 UserArmies 表。我试图通过在调用 UserManager.Update(user); 之前添加以下代码行来做到这一点;
user.Armies = GetUserArmies(user, viewModel.Armies);
调用以下方法。首先,我得到一个 ID 列表并将其称为 selectedArmies。然后我从数据库中获取军队列表并将其放入 allArmies。 userArmies 是要填充和返回的军队的空白列表。
private List<Army> GetUserArmies(ApplicationUser user, List<CheckBoxItem> armies)
{
var selectedArmies = armies.Where(a => a.IsChecked).Select(a => a.Id).ToList();
var allArmies = _context.Armies.ToList();
var userArmies = new List<Army>();
foreach (var army in selectedArmies)
userArmies.Add(allArmies.Find(t => t.Id == army));
return userArmies;
}
我有 2 个不需要的结果。首先是我现在的状态。 发生错误说 无法定义两个对象之间的关系,因为它们附加到不同的 ObjectContext 对象上
当我从 Army 类中删除 virtual 关键字时,我得到了以下结果,其中 Armies 表首先在新 ID 下复制了 Army 行。然后将新的 UserArmy 保存到新创建的 Exsiting Army 副本下的数据库中。这会导致我的复选框列表加倍。
我哪里出错了?任何帮助将不胜感激。
附加信息 我也有用户文章类使用相同的军队表。这使用非常相似的代码并且可以完美地工作而不会创建重复项。这让我觉得这与唱歌 UserManager 和 _Context
【问题讨论】:
标签: c# entity-framework asp.net-mvc-5 asp.net-identity