Reputation: 33938
I've been getting this exception out in the field. I don't understand how the collection can be modified while iterating. I copy everything to local variables at the start of the method.
public void Flush() {
var tempEntities = attachedEntities.Select(item => item).ToList();
attachedEntities.Clear();
var tempEntitiesToDelete = entitiesToDelete.Select(item => item).ToList();
entitiesToDelete.Clear();
foreach (var attachedEntity in tempEntities) {
var isTransient = (bool)GetPrivateField(attachedEntity.GetType(), attachedEntity, "isTransient");
if (isTransient)
db.Insert(attachedEntity);
else
db.Update(attachedEntity);
}
foreach (var entity in tempEntitiesToDelete)
db.Delete(entity);
}
Stack Trace
System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.Collections.Generic.List`1 Enumerator[Compass.Mobile.Core.DataAccess.IEntity].VerifyState () [0x00000] in <filename unknown>:0
at System.Collections.Generic.List`1 Enumerator[Compass.Mobile.Core.DataAccess.IEntity].MoveNext () [0x00000] in <filename unknown>:0
at System.Linq.Enumerable <CreateSelectIterator>c__Iterator1D`2[Compass.Mobile.Core.DataAccess.IEntity,Compass.Mobile.Core.DataAccess.IEntity].MoveNext () [0x00000] in <filename unknown>:0
at System.Collections.Generic.List`1[Compass.Mobile.Core.DataAccess.IEntity].AddEnumerable (IEnumerable`1 enumerable) [0x00000] in <filename unknown>:0
at System.Collections.Generic.List`1[Compass.Mobile.Core.DataAccess.IEntity]..ctor (IEnumerable`1 collection) [0x00000] in <filename unknown>:0
at System.Linq.Enumerable.ToList[TSource] (IEnumerable`1 source) [0x00000] in <filename unknown>:0
at Compass.Mobile.Core.DataAccess.Session.Flush () [0x00000] in <filename unknown>:0
at Compass.Mobile.Core.DataAccess.Session.Commit () [0x00000] in <filename unknown>:0
at Compass.Mobile.Core.Bootstrap.CommandBus.Flush () [0x00000] in <filename unknown>:0
Upvotes: 2
Views: 14186
Reputation: 268293
Judging by the stack trace, it's not failing inside your foreach
(or enumerating tempEntities
which is a plain list) but inside one of ToList
calls, when Select
iterator's underlying list checks its state before moving on to next item.
This line in your stack trace makes me believe so:
at System.Linq.Enumerable <CreateSelectIterator>c__Iterator1D`2[Compass.Mobile.Core.DataAccess.IEntity,Compass.Mobile.Core.DataAccess.IEntity].MoveNext () [0x00000] in <filename unknown>:0
Your foreach loop variable is just a list, so it doesn't go through Select
. This leads me to believe that either attachedEntities
or entitiesToDelete
change while you're doing Select
over them:
/* Failing here... */
var tempEntities = attachedEntities.Select(item => item).ToList();
attachedEntities.Clear();
/* ...or here*/
var tempEntitiesToDelete = entitiesToDelete.Select(item => item).ToList();
entitiesToDelete.Clear();
/* ...but not here! */
foreach (var attachedEntity in tempEntities) {
// ...
}
It could very well be a concurrency issue.
By the way, you really don't need Select (item => item)
, it would just be an identity projection.
Upvotes: 2
Reputation: 50728
Replace this:
foreach (var entity in tempEntitiesToDelete)
db.Delete(entity);
With:
for (var i = tempEntitiesToDelete.Count - 1; i >= 0; i--)
db.Delete(tempEntitiesToDelete[i]);
I had this problem when I tried to delete while looping through; it was trying to modify the list of items. Therefore, looping backward fixed it for me.
Upvotes: 3