添加到集合时修改了集合

时间:2013-08-11 04:45:54

标签: c# asp.net-mvc entity-framework collections

尝试添加到集合时获取“Collection was modified”异常

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);
    }
}

问题特别在于“添加”方法。如果我对该部分进行评论,则不会抛出任何异常。重要的是要注意我已经尝试将foreach重写为for循环并在form.Links中添加“ToList()”。在所有情况下都抛出相同的异常。我在网站的其他部分使用这个确切的模式没有问题,这就是为什么这是如此令人沮丧。这也适用于“创建”。该问题仅影响“编辑”操作。

其他相关代码:

[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; }
}

更新

更多信息:添加到集合中......即使在循环之外也会引发相同的错误。这会给任何人一个想法吗?

4 个答案:

答案 0 :(得分: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。这将解决您的问题。

答案 1 :(得分: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);
    }
}

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

答案 2 :(得分:0)

您无法修改您枚举的集合(例如,每个集合)。

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

E.g:

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

可以采用更好的方式,但这显示了错误的要点。您无法更改正在循环的集合。

答案 3 :(得分:0)

不确定究竟是什么负责解决问题,但升级到Visual Studio 2013 Express(来自2010 Professional),并安装ASP.Net 4.5 / IIS8后,即使此应用程序继续以ASP.Net 4.0为目标,我不再遇到问题,原帖中使用的代码按原样运行。

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