【问题标题】:EF6 Collection was modified; enumeration operation may not execute修改了 EF6 集合;枚举操作可能无法执行
【发布时间】:2017-05-29 22:02:38
【问题描述】:

我需要将 adin 用户添加到他们不存在的表(和子表)中。

我有以下代码引发错误:“集合已修改;枚举操作可能无法执行。”在“_userPrefsContext.UserRecs.Add(userRec);”行上

var allUserRecs = _userPrefsContext.UserRecs.ToList();

        foreach (string adminUser in adminUsers.Where(x => x.Length > 0))
        {
            domain = adminUser.Split('\\')[0];
            login = adminUser.Split('\\')[1];

            var userRec = new Domain.UserPrefs.BamUser()
            {
                AdLogonDomain = domain,
                AdLogonId = login,
                UserViews = colUserView
            };

            if (allUserRecs.Where(x => x.AdLogonDomain == domain
                                    && x.AdLogonId == login).Count() == 0)
            {
                //don't currently have a user rec for this login so create one
                _userPrefsContext.UserRecs.Add(userRec);
            }
        }
        _userPrefsContext.SaveChanges();

我在 SO 上看到过类似的帖子,但在每种情况下,他们似乎都在迭代他们正在添加的集合。就我而言,我只是想遍历一个字符串列表。

我哪里做错了?

现在编辑成如下(还是一样的错误):

            List<string> adminUsers = WebConfigurationManager.AppSettings["AdminUsers"].Split(';').ToList();
        adminUsers = adminUsers.Where(x => x.Length > 0).ToList();

        string domain = "", login = "";
        string userViewString = Helpers.ViewNames.UserView.ToString();

        int viewId = _userPrefsContext.ViewRecs.Where(x => x.Name == userViewString).Select(x => x.BamViewId).Single();

        Domain.UserPrefs.UserView userView = new Domain.UserPrefs.UserView()
        {
            BamViewId = viewId
        };

        List<Domain.UserPrefs.UserView> colUserView = new List<Domain.UserPrefs.UserView>();
        colUserView.Add(userView);

        var allUserRecs = _userPrefsContext.UserRecs.ToList();
        string[] users = new string[adminUsers.Count()];
        int y = 0;
        foreach(string user in adminUsers)
        {
            users[y] = user;
            y++;
        }

        int total = adminUsers.Count;
        for (var i = 0; i < total; i++)
        {

            domain = users[i].Split('\\')[0];
            login = users[i].Split('\\')[1];

            if (allUserRecs.Where(x => x.AdLogonDomain == domain
                                    && x.AdLogonId == login).Count() == 0)
            {
                //don't currently have a user rec for this login so create one
                _userPrefsContext.UserRecs.Add(new Domain.UserPrefs.BamUser()
                {
                    AdLogonDomain = domain,
                    AdLogonId = login,
                    UserViews = colUserView
                });
            }
        }
        _userPrefsContext.SaveChanges();

【问题讨论】:

  • 我只是想遍历一个字符串列表 - adminUsers.Where(x =&gt; x.Length &gt; 0) 绝对是不是一个列表
  • 很好发现 - 谢谢

标签: entity-framework entity-framework-6


【解决方案1】:

UserViews 定义为域实体如下:

public virtual ICollection<UserView> UserViews { get; set; }

为了完成这项工作,我改变了

var userRec = new Domain.UserPrefs.BamUser()
            {
                AdLogonDomain = domain,
                AdLogonId = login,
                UserViews = colUserView
            };

var userRec = new Domain.UserPrefs.BamUser() { AdLogonDomain = domain, AdLogonId = login, UserViews = colUserView.ToList() };

说实话,我不知道为什么需要 .ToList() - 如果有人这样做,那么我认为解释可能对许多人有帮助!

【讨论】:

    【解决方案2】:

    仅供参考 最好使用 any 替换 countany 工作速度比计数快得多。 使用此代码

     if (!allUserRecs.any(x => x.AdLogonDomain == domain                                   && x.AdLogonId == login))
                {
                    //don't currently have a user rec for this login so create one
                    _userPrefsContext.UserRecs.Add(new Domain.UserPrefs.BamUser()
                    {
                        AdLogonDomain = domain,
                        AdLogonId = login,
                        UserViews = colUserView
                    });
                }
    

    替换

    if (allUserRecs.Where(x => x.AdLogonDomain == domain
                                        && x.AdLogonId == login).Count() == 0)
                {
                    //don't currently have a user rec for this login so create one
                    _userPrefsContext.UserRecs.Add(new Domain.UserPrefs.BamUser()
                    {
                        AdLogonDomain = domain,
                        AdLogonId = login,
                        UserViews = colUserView
                    });
                }
    

    【讨论】:

      【解决方案3】:

      问题是您有一个列表,然后您在 foreach 中运行 where 子句。这意味着它必须在每次运行时重新查询列表,但如果您在运行期间修改了列表,现在查询可能是错误的。

      这将是一个更好的解决方案:

      var allUserRecs = _userPrefsContext.UserRecs.Where(x => x.Length > 0).ToList();
      
          foreach (string adminUser in adminUsers)
          {
              domain = adminUser.Split('\\')[0];
              login = adminUser.Split('\\')[1];
      
              var userRec = new Domain.UserPrefs.BamUser()
              {
                  AdLogonDomain = domain,
                  AdLogonId = login,
                  UserViews = colUserView
              };
      
              if (allUserRecs.Where(x => x.AdLogonDomain == domain
                                      && x.AdLogonId == login).Count() == 0)
              {
                  //don't currently have a user rec for this login so create one
                  _userPrefsContext.UserRecs.Add(userRec);
              }
          }
          _userPrefsContext.SaveChanges();
      

      【讨论】:

      • 恐怕这没有帮助。请参阅最新版本的编辑,我已经尝试了所有我能想到的方法来消除对使用 foreach 进行迭代的任何依赖 - 可怕的黑客攻击,但需要找出导致错误的原因!
      猜你喜欢
      • 1970-01-01
      • 2012-04-13
      • 1970-01-01
      • 1970-01-01
      • 2015-06-17
      • 2020-02-07
      • 1970-01-01
      相关资源
      最近更新 更多