0

Getting the "Collection was modified" exception when attempting to add to a collection

public void UpdateLinks(EventViewModel form)
{
    var selectedIds = form.Links.Select(r => r.ResourceTypeID).ToList();
    var assignedIds = form.Event.Links.Select(r => r.ResourceTypeID).ToList();
    foreach (var resource in form.Links)
    {
        resource.EventID = form.Event.ID;
        if (!assignedIds.Contains(resource.ResourceTypeID))
            form.Event.Links.Add(resource);
    }
    foreach (var resource in form.Event.Links.ToList())
    {
        if (!selectedIds.Contains(resource.ResourceTypeID))
            form.Event.Links.Remove(resource);
    }
}

The problem is specifically with the "Add" method. If I comment that part out, no exception is thrown. It's important to note that I've already tried re-writing the foreach as a for loop and adding "ToList()" to form.Links. The same exception is thrown in all cases. I use this exact pattern on other parts of the site without issue which is why this is so frustrating. This also works on "Create". The problem only affects the "Edit" action.

Other relevant code:

[HttpPost]
public ActionResult Edit(EventViewModel form, HttpPostedFileBase[] eventFiles)
{
    if (ModelState.IsValid)
    {
        eventsService.UpdateEvent(form.Event);
        eventsService.UpdateManufacturerTags(form);
        eventsService.UpdateFiles(form, eventFiles);
        eventsService.UpdateLinks(form);
        eventsService.Save();
        return RedirectToAction("Details", new { id = form.Event.ID });
    }
    return View(form);
}

public class EventViewModel : ContentLeftViewModel
{
    public Event Event { get; set; }
    public string[] SelectedManufacturers { get; set; }
    public MultiSelectList Manufacturers { get; set; }
    public IList<EventResource> Files { get; set; }
    public IList<EventResource> Links { get; set; }

    public EventViewModel()
    {
        SelectedManufacturers = new string[0];
        Files = new List<EventResource>();
        Links = new List<EventResource>();
    }
}

public class Event
{
    [Key]
    public int ID { get; set; }

    [Required]
    public string Title { get; set; }

    [Required]
    [DisplayName("Start Time")]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:M/d/yyyy h:mm tt}")]
    public DateTime? StartTime { get; set; }

    [Required]
    [DisplayName("End Time")]
    [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:M/d/yyyy h:mm tt}")]
    public DateTime? EndTime { get; set; }

    public string Venue { get; set; }

    public string Address { get; set; }

    public string City { get; set; }

    public string State { get; set; }

    public string Zip { get; set; }

    [AllowHtml]
    [DataType(DataType.MultilineText)]
    public string Description { get; set; }

    [DisplayName("Registration Link")]
    public string RegistrationUrl { get; set; }

    public virtual IList<Manufacturer> Manufacturers { get; set; }

    public virtual IList<EventResource> Files { get; set; }

    public virtual IList<EventResource> Links { get; set; }

    //public IEnumerable<EventResource> Resources
    //{
    //    get { return Files.Concat(Links); }
    //}

    public string StartDate
    {
        get { return StartTime.Value.ToShortDateString(); }
    }

    public string StartTimeOnly
    {
        get { return StartTime.Value.ToShortTimeString(); }
    }

    public string EndDate
    {
        get { return EndTime.Value.ToShortDateString(); }
    }

    public string EndTimeOnly
    {
        get { return EndTime.Value.ToShortTimeString(); }
    }

    public Event()
    {
        Manufacturers = new List<Manufacturer>();
        Files = new List<EventResource>();
        Links = new List<EventResource>();
    }
}

public class EventResource
{
    [Key, Column(Order = 0)]
    public int EventID { get; set; }

    [Key, Column(Order = 1)]
    public int ResourceTypeID { get; set; }

    [Key, Column(Order = 2)]
    public string Path { get; set; }

    public virtual Event Event { get; set; }

    public virtual ResourceType Type { get; set; }
}

UPDATE

Some more info: Adding to the collection at all... even outside of a loop throws the same error. Does that give anyone an idea?

4

4 回答 4

0

您可以在添加条目之前使用 LINQ 过滤掉条目。

public void UpdateLinks(EventViewModel form)
{
    var selectedIds = form.Links.Select(r => r.ResourceTypeID).ToArray();
    var assignedIds = form.Event.Links.Select(r => r.ResourceTypeID).ToArray();
    foreach (var resource in form.Links
        .Where(r=> !assignedIds.Contain(r.ResourceTypeID)).ToArray())
    {
        resource.EventID = form.Event.ID;
        form.Event.Links.Add(resource);
    }
    foreach (var resource in form.Event.Links
        .Where(r=> !selectedIds.Contain(r.ResourceTypeID)).ToArray())
    {
        form.Event.Links.Remove(resource);
    }
}

在这两种方法中,我们都是在枚举和添加之前过滤资源。您不能同时枚举和添加。

于 2013-08-11T07:17:25.900 回答
0

您不能修改正在枚举的集合(例如,对于每个集合)。

您需要循环一次以获取要添加和/或删除的项目,然后在第一个循环之外的第二个循环中添加或删除所有这些项目。

例如:

Dim coll = New List(of String)({"1", "2", "3", "4", "6"})
dim coll2 = New List(of String)({"5", "8", "9", "2"})

Dim removeItems as new list(of String)()

For Each item in coll
 For Each item2 in coll2
  If item2 = item
    removeItems.Add(item)
  end if
 Next item2
Next item

' remove the items gathered
For each itemToRemove in removeItems
 coll.Remove(itemToRemove)
Next itemToRemove

它可以做得更好,但这显示了错误的要点。您无法更改正在循环的集合。

于 2013-08-12T21:55:08.020 回答
0

不知道究竟是什么负责解决这个问题,但在升级到 Visual Studio 2013 Express(从 2010 Professional)并安装 ASP.Net 4.5/IIS8 之后,即使这个应用程序继续以 ASP.Net 4.0 为目标,我也是不再遇到此问题,原始帖子中使用的代码按原样工作。

也许这是由 ASP.Net 框架的某个构建或旧版本的 IIS 引起的?

于 2013-08-15T20:15:49.620 回答
0

试试这个:

var lsEvents = form.Event.Links.ToList();
foreach (var resource in form.Links)
{
    resource.EventID = form.Event.ID;
    if (!assignedIds.Contains(resource.ResourceTypeID))
        lsEvents.Add(resource);
}
foreach (var resource in form.Event.Links)
{
    if (!selectedIds.Contains(resource.ResourceTypeID))
        lsEvents.Remove(resource);
}

并按lsEvents要求使用。这将解决您的问题。

于 2013-08-11T05:07:46.557 回答