代码之家  ›  专栏  ›  技术社区  ›  Ben_jamin

MVC5-许多使用ApplicationUser的用户添加新行,而不是使用现有行/或抛出错误

  •  0
  • Ben_jamin  · 技术社区  · 8 年前

    我正在构建一个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上下文有关

    2 回复  |  直到 8 年前
        1
  •  0
  •   Sayem    8 年前

    您需要创建自己的DbContext并重写OnModelCreating方法。

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

    希望这能给你一个想法。

        2
  •  0
  •   Ben_jamin    8 年前

    我认为它已经找到了答案

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