我正在构建一个MVC5 Web App。我使用了身份框架。我正在尝试使每个用户都有一个与他关联的军队列表。这些将通过复选框在页面上更新。
我已经用这个附加属性扩展了默认的 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;
}
视图模型包含一个用户和一个称为军队的复选框项列表。如果是首次访问,则用户 == null 和视图模型填充数据。否则,它将获取数据并更新用户。
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);
}
最后阶段是一切都出了可怕的错误。我需要更新数据库上的用户军队表。我尝试通过在调用UserManager.Update(user)之前添加以下代码行来做到这一点;
user.Armies = GetUserArmies(user, viewModel.Armies);
它调用以下方法。首先,我得到一个 Id 的列表,并称它为 selectedArmyies。然后我从数据库中获取军队列表并将其放入所有军队中。用户军队是一个空白的军队列表,需要填写和返回。
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 关键字时,我反而得到以下结果,其中 Armyies 表首先在新 ID 下复制 Army 行。然后将新的用户军队保存到数据库中,在新创建的现有军队副本下。然后,这会导致我的复选框列表加倍。
我哪里出错了?任何帮助将不胜感激。
附加信息 我也有用户文章类使用相同的军队表。这使用非常相似的代码,并且无需创建重复项即可完美运行。这让我觉得这与唱用户管理器和_Context有关
您需要创建自己的 DbContext 并覆盖 OnModelCreate 方法。
public class MyDbContext : DbContext
{
public MyDbContext () : base("YourDefaultConnectionString")
{
// Database Initializer
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Write your own model creation code;
}
}
希望这会给你一个想法。
我认为它已经找到了答案
我正在使用UserManager和_context(我自己的DbContext)来访问数据,由于某种原因,它无法控制数据。通过交换我的方法通过我的DBContext而不是UserManager调用用户,我绕过了错误并设法解决了问题。