我正在构建一个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()方法将军队转换为复选框列表。(这最初是使用列表完成的,但在我尝试修复问题时,下面使用dictionary实现。)程序的这一部分按预期工作,我正确显示了我的复选框,并勾选了相关的复选框。
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的复选框项目列表。如果是第一次访问,则用户==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);
}
最后一个阶段是一切都大错特错的地方。我需要更新数据库中的userarms表。在调用UserManager之前,我尝试通过添加以下代码行来实现这一点。更新(用户);
user.Armies = GetUserArmies(user, viewModel.Armies);
调用以下方法。首先,我得到一个Id列表,并将其称为selectedArmies。然后我从数据库中取出一份军队名单,放在allArmies中。用户军队是要填写和返回的军队的空白列表。
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;
}
我有两个不想要的结果。第一个是我现在的状况。
出现以下错误:
无法定义这两个对象之间的关系,因为它们附加到不同的ObjectContext对象
当我从Army类中删除virtual关键字时,我会得到以下结果,其中Army表首先在新Id下复制Army行,然后将新UserArmy保存到现有Army的新创建副本下的数据库中。这将导致我的复选框列表加倍。
我哪里做错了?任何帮助都将不胜感激。
其他信息
我还有一个用户文章类,它使用相同的armies表。这使用了非常相似的代码,并且在不创建重复代码的情况下可以完美地工作。这让我觉得很重要这与sing UserManager和\u上下文有关