2013-08-11 4 views
0

Получение «Коллекция была изменена» исключение при попытке добавить к коллекцииКоллекция была изменена при добавлении в коллекцию

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 и добавить «ToList()» в form.Links. Такое же исключение выбрасывается во всех случаях. Я использую этот точный шаблон на других частях сайта без проблем, поэтому это так расстраивает. Это также работает над «Создать». Проблема влияет только на действие «Изменить».

Другое соответствующий код:

[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

Некоторые подробнее: Добавление к коллекции вообще ... даже вне цикла бросает ту же ошибку. Это дает кому-то идею?

+0

Не рекомендуется изменять коллекцию, когда вы выполняете итерацию через foreach.see, если простой для цикла подходит для цели. –

+0

. Каждая коллекция .Net генерирует исключение, если вы попытаетесь изменить его во время итерации через него - не если это цикл для каждого цикла, или если вы получили итератор и делаете это «вручную» (в цикле for или while). Попробуйте использовать For-Loop, как предложено выше, или создайте временную коллекцию с данными, которые вы хотите удалить или добавить впоследствии. – peter

+0

В других частях сайта я успешно использовал одно и то же решение для разных типов объектов. Вы правы, но добавляете «ToList()», чтобы создать новый список, чтобы избежать этой проблемы в этих других случаях. Я попробую предложения ниже. –

ответ

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 в соответствии с требованиями. Это исправит вашу проблему.

+0

С помощью этого метода вам также необходимо установить form.Event.Links в lsEvents, если вы действительно хотите, чтобы изменения отражались в модели. Как только вы это сделаете, вы получите одно и то же исключение. Довольно застрял на этом! –

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

В обоих методах мы фильтруем ресурсы перед перечислением и добавлением. Вы не можете перечислять и добавлять одновременно.

+0

Пройден этот выстрел, но при этом было исключено одно и то же исключение –

+0

Попробуйте теперь с ToList, изменено на ToArray –

+0

Не имеет значения –

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 

Это можно сделать лучший способ, но это показывает суть ошибки. Вы не можете изменить собираемую вами коллекцию.

+0

Пробовал это и тот же foreach (var resource in form.Links) { ресурс.EventID = form.Event.ID; if (! AssignIds.Contains (resource.ResourceTypeID)) addedLinks.Add (ресурс); } Еогеасп (вар ресурс в form.Event.Links.ToList()) { если removedLinks.Add (ресурс) (selectedIds.Contains (resource.ResourceTypeID)!); } удаленLinks.ForEach (r => form.Event.Links.Remove (r)); добавилLinks.ForEach (r => form.Event.Links.Add (r)); –

0

Не уверен, что именно было ответственным за решение проблемы, но после обновления до Visual Studio 2013 Express (с 2010 Professional) и установки с ним ASP.Net 4.5/IIS8, хотя это приложение продолжает нацеливаться на ASP.Net 4.0, я больше не испытываю проблемы, и код, используемый в исходном сообщении, работает как есть.

Возможно, это было вызвано определенной сборкой структуры ASP.Net или более старой версией IIS?

Смежные вопросы