【问题标题】:MVC5 - ManytoMany Using ApplicationUser Adds new Rows instead of using Existing Ones / Or Throws ErrorMVC5 - 多对多使用 ApplicationUser 添加新行而不是使用现有行/或引发错误
【发布时间】: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


    【解决方案1】:

    您需要创建自己的 DbContext 并覆盖 OnModelCreating 方法。

    public class MyDbContext : DbContext 
    { 
        public MyDbContext () : base("YourDefaultConnectionString")
        {           
            // Database Initializer 
        }
         protected override void OnModelCreating(DbModelBuilder modelBuilder)
         {
           // Write your own model creation code;  
         }
    }
    

    希望这会给你一个想法。

    【讨论】:

    • 我已经按照我提供的原始代码所示完成了这项工作?这就是我使用 Fluent API 完善我的关系的地方?我将更改我的帖子以更清楚地显示被覆盖的方法。如果我还没有添加其他内容,您能否进一步提示?
    【解决方案2】:

    我想它找到了答案

    我使用 UserManager 和 _context(我自己的 DbContext)来访问数据,由于某种原因它无法合并数据。通过交换我的方法以通过我的 DBContext 而不是 UserManager 调用用户,我绕过了错误并设法解决了问题。

    【讨论】:

      猜你喜欢
      • 2016-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-31
      • 2021-08-24
      相关资源
      最近更新 更多