我构建了一个MVC5 Web App。我使用过Identity Framework。我试图让它成为每个用户都有一个他与之关联的军队列表。这些将通过复选框在页面上更新。
我已使用此附加属性扩展了默认的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()方法将军队变成复选框列表。 (这最初是使用Lists完成的,但下面用字典实现,而我正试图解决我的问题。)这部分程序按预期工作,我正确显示我的复选框,并勾选相关的方框。
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包含一个User和一个名为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的列表,并称之为选择敌人。然后我从数据库中获取军队列表并将其放入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对象
当我从陆军类中移除虚拟关键字时,我得到以下结果,其中军队表首先复制新Id下的军队行。然后将新的UserArmy保存到新创建的Exsiting Army副本下的数据库中。这会导致我的复选框列表加倍。
我哪里错了?任何帮助将不胜感激。
其他信息 我也有User Article类使用相同的armies表。这使用非常类似的代码并且完美地工作而不会产生重复。这让我觉得它与SingManager和_Context
有关答案 0 :(得分:0)
您需要创建自己的DbContext并覆盖OnModelCreating方法。
public class MyDbContext : DbContext
{
public MyDbContext () : base("YourDefaultConnectionString")
{
// Database Initializer
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Write your own model creation code;
}
}
希望这会给你一个想法。
答案 1 :(得分:0)
我认为已找到答案
我使用UserManager和_context(我自己的DbContext)来访问数据,由于某种原因它无法将数据合并。通过交换我的方法来通过我的DBContext而不是UserManager调用用户我得到了错误并设法解决了问题。