-1

I was trying to delete a record that was not saved in DB it throws the following exception

Error occurred. Collection was modified; enumeration operation might not execute

I can't understand why i get this error message only when try to delete that record is in memory, i don't have issue to delete a record that saved in the back end.

here is the code throws exception.

 public bool DeleteVegetationZone(ref Assessment objAssessment, int VegetationZoneIDToDelete, string UserFullname, ref string ErrorMessage)
    {
        string RowFilter = @"VegetationZoneID=" + Convert.ToString(VegetationZoneIDToDelete);
        Assessment.tblVegetationZoneRow[] VegetationZoneRows = (Assessment.tblVegetationZoneRow[])objAssessment.tblVegetationZone.Select(RowFilter);
        if ((VegetationZoneRows != null) && (VegetationZoneRows.Length != 0))
        {
            if (VegetationZoneRows.Length == 1)
            {
                if (VegetationZoneRows[0].VegetationZoneID > 0)
                {
                    VegetationZoneRows[0].UpdatedBySystemUser = UserFullname;
                    VegetationZoneRows[0].SaveType = (int)EnumCollection.SaveType.RemoveOnly;
                }
                else
                {
                    VegetationZoneRows[0].Delete();
                    objAssessment.AcceptChanges();
                }
                //Delete the child records                    
                //tblTransect
                foreach (Assessment.tblTransectRow TransectRow in objAssessment.tblTransect.Rows)
                {
                    if (TransectRow.VegetationZoneID == VegetationZoneIDToDelete)
                        DeleteVegTransectPlot(ref objAssessment, TransectRow.TransectID, UserFullname, ref ErrorMessage);
                }

                //tblManagementZone
                foreach (Assessment.tblManagementZoneRow ManagementZoneRow in objAssessment.tblManagementZone.Rows)
                {
                    if (ManagementZoneRow.VegetationZoneID == VegetationZoneIDToDelete)
                        DeleteManagementZone(ref objAssessment, ManagementZoneRow.ManagementZoneID, UserFullname, ref ErrorMessage);
                }

                //tblThreatenedSpeciesSubzone

                foreach (Assessment.tblThreatenedSpeciesSubzoneRow ThreatenedSpeciesSubzoneRow in objAssessment.tblThreatenedSpeciesSubzone.Rows)
                {
                    if (ThreatenedSpeciesSubzoneRow.VegetationZoneID == VegetationZoneIDToDelete)
                        DeleteThreatenedSpeciesSubzone(ref objAssessment, ThreatenedSpeciesSubzoneRow.ThreatenedSpeciesZoneID, UserFullname, ref ErrorMessage);
                }

                UpdateSpeciesGeoHabitatSurveyTime(ref objAssessment, UserFullname, ref ErrorMessage);
            }
            else
            {
                //Cannot have more than one row with same key
                ErrorMessage = "Error: More than one record found - Vegetation zone ID = " + Convert.ToString(VegetationZoneIDToDelete);
                return false;
            }
        }
        else
        {
            //Must have at least one row with same key
            ErrorMessage = "Error: Record not found - Vegetation zone ID = " + Convert.ToString(VegetationZoneIDToDelete);
            return false;
        }
        return true;
    }

exception thrown at

 foreach (Assessment.tblThreatenedSpeciesSubzoneRow ThreatenedSpeciesSubzoneRow in objAssessment.tblThreatenedSpeciesSubzone.Rows)
                {
                    if (ThreatenedSpeciesSubzoneRow.VegetationZoneID == VegetationZoneIDToDelete)
                        DeleteThreatenedSpeciesSubzone(ref objAssessment, ThreatenedSpeciesSubzoneRow.ThreatenedSpeciesZoneID, UserFullname, ref ErrorMessage);
                }
Usher
  • 2,146
  • 9
  • 43
  • 81
  • types are not clear, what is the type of Assessment.tblThreatenedSpeciesSubzoneRow and what function DeleteThreatenedSpeciesSubzone does ? – mfarouk Oct 16 '14 at 08:09
  • already i looked at that post but i can't help myself with that answer, thats the reason i posted here. – Usher Oct 16 '14 at 08:10
  • It's never a great idea to remove items from a collection *during* iteration because it can break the enumerator. Reason being indexes/positions of items will all change, however, if you work your way *backwards* you can remove safely as the positions of the items won't change. – James Oct 16 '14 at 08:11
  • The two answers you received here basically repeat what is being stated in the duplicate, bu then tailored to your code. That should work. If not, show your `DeleteThreatenedSpeciesSubzone` code. – CodeCaster Oct 16 '14 at 08:11
  • @CodeCaster, the answers are not helping me much, it doesn't row[i] or Tolist either. – Usher Oct 16 '14 at 09:58

2 Answers2

1

Change the loop from foreach to equivalent for:

// Note reversed order of the for loop
for (int i = objAssessment.tblThreatenedSpeciesSubzone.Rows.Count - 1; i >= 0; --i) {
  Assessment.tblThreatenedSpeciesSubzoneRow ThreatenedSpeciesSubzoneRow = 
    objAssessment.tblThreatenedSpeciesSubzone.Row[i];

  if (ThreatenedSpeciesSubzoneRow.VegetationZoneID == VegetationZoneIDToDelete)
    DeleteThreatenedSpeciesSubzone(ref objAssessment, ThreatenedSpeciesSubzoneRow.ThreatenedSpeciesZoneID, UserFullname, ref ErrorMessage);
}

Since you can't modify collection within foreach loop but you can do it within for one.

Edit: when Row[i] is not supported, you can emulate it via Linq:

var list = objAssessment.tblThreatenedSpeciesSubzone.Rows.ToList(); // <- Linq    

for (int i = list.Count - 1; i >= 0; --i) {
  Assessment.tblThreatenedSpeciesSubzoneRow ThreatenedSpeciesSubzoneRow = 
    list[i];

  if (ThreatenedSpeciesSubzoneRow.VegetationZoneID == VegetationZoneIDToDelete)
    DeleteThreatenedSpeciesSubzone(ref objAssessment, ThreatenedSpeciesSubzoneRow.ThreatenedSpeciesZoneID, UserFullname, ref ErrorMessage);
}
Dmitry Bychenko
  • 180,369
  • 20
  • 160
  • 215
  • @Dimitry , unfortunately it doesn't like Row[i], updated my code in full. – Usher Oct 16 '14 at 10:01
  • @Usher: if direct `Row[i]` is unwanted, you can try creating a copy/cache of items via `.ToList()` – Dmitry Bychenko Oct 16 '14 at 10:34
  • Thank Dmitry, i do have system.Linq but when i use your code i got this exception @Error 5 'System.Data.DataRowCollection' does not contain a definition for 'ToList' and no extension method 'ToList' accepting a first argument of type 'System.Data.DataRowCollection' could be found (are you missing a using directive or an assembly reference?) – Usher Oct 16 '14 at 20:17
0

In your foreach loop should look like :

foreach (Assessment.tblThreatenedSpeciesSubzoneRow ThreatenedSpeciesSubzoneRow in objAssessment.tblThreatenedSpeciesSubzone.Rows.ToList())

This occurs as your trying to modify the collection when it is being used.

adityaswami89
  • 573
  • 6
  • 15
  • As explained above when you are looping through a collection and you are modifying the same collection , you will get this error. – adityaswami89 Oct 16 '14 at 08:11
  • I still cant get why this was down voted :0/ – adityaswami89 Oct 16 '14 at 08:13
  • Not mine thumb down, but perhaps idea of creating another collection by calling linq `.ToList()` is not obvious. Or because it's an answer in the linked question. – Sinatr Oct 16 '14 at 08:26
  • i have row collect and its not showing an option to use .ToList () anyway – Usher Oct 16 '14 at 09:52
  • did you add reference to System.Linq ?? – adityaswami89 Oct 16 '14 at 10:04
  • @adityaswami89 i did ,still no luck – Usher Oct 16 '14 at 20:13
  • The main problem is you are trying to delete a particular record which is still getting parsed through the collection. My suggestion is that : You keep a property called as CanDeleted in ThreatenedSpiecesSubzoneRow and just assign CanDelete = true in your method. After parsing try to delete all the records whose CanDelete == true. You cannot at anytime modify the collection when it is being used.Kindly let me know if this helps. – adityaswami89 Oct 17 '14 at 03:52