In my code, I initially cache existing objects of my entity DataEntry
in form of a ConcurrentDictionary
. From parallel tasks, I try to read pre-cached data entries. If none exists, I want to create a new one.
ConcurrentDictionary<string, DataEntry> dataEntryDict = new ConcurrentDictionary<string, DataEntry>(
await db.DataEntries
.Where(de => allObjIDs.Contains(de.PAObjID))
.IncludeOptimized(de => de.WorkSchedules)
.ToDictionaryAsync(a => a.PAObjID, a => a)
);
var allDataEntryNumbers = new ConcurrentHashSet<DataEntryStruct>();
await Task.WhenAll(allDataEntryNumbers.Batch(20).Select(async workOrderBatch => {
var gwoResp = await MyServiceCall();
foreach (dsyWorkOrder01TtyWorkOrder currDetail in gwoResp.dsyWorkOrder01) {
// Get or create element
DataEntry currentEntry = dataEntryDict.GetOrAdd(
currDetail.Obj,
key => {
var newDe = new DataEntry();
db.DataEntries.Add(newDe); // This seems to be the line, where the exception is thrown
return newDe;
}
);
// Set regular fields
currentEntry.ApplyTtyWorkOrder(currDetail, resourceDict);
}
}
If I call that (simplified) code, I get the error message from the title. But not always. The method can be called from the UI, which works in 100 % of the cases, but it can also be called from a background worker, which triggers every night.
This resulted in the following error:
Full import failed with a/an InvalidOperationException. Collection was modified; enumeration operation may not execute.
at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) at System.Collections.Generic.Dictionary
2.ValueCollection.Enumerator.MoveNext() at System.Data.Entity.Core.Objects.ObjectStateManager.GetEntityEntriesForDetectChanges(Dictionary
2 entityStore, List1& entries) at System.Data.Entity.Core.Objects.ObjectStateManager.GetEntityEntriesForDetectChanges() at System.Data.Entity.Core.Objects.ObjectStateManager.DetectChanges() at System.Data.Entity.Internal.InternalContext.DetectChanges(Boolean force) at System.Data.Entity.Internal.Linq.InternalSet
1.ActOnSet(Action action, EntityState newState, Object entity, String methodName) at System.Data.Entity.Internal.Linq.InternalSet1.Add(Object entity)
1.Add(TEntity entity) at Namespace.Import.ImportScheduler.<>c__DisplayClass9_1.b__16(String key) in C:\Users\Reichelt\source\repos\path\Import\FullImport.cs:line 295 at System.Collections.Concurrent.ConcurrentDictionary
at System.Data.Entity.DbSet2.GetOrAdd(TKey key, Func
2 valueFactory) at Namespace.Import.ImportScheduler.<>c__DisplayClass9_3.<b__5>d.MoveNext() in C:\Users\Reichelt\source\repos\path\Import\FullImport.cs:line 0 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Namespace.Import.ImportScheduler.d__9.MoveNext() in C:\Users\Reichelt\source\repos\path\Import\FullImport.cs:line 323
So you have any idea what's going wrong in this case?