-
Notifications
You must be signed in to change notification settings - Fork 931
Description
My application code contains a method that looks like this (simplified):
public bool ContainsLoadedEntityEqualTo(object entity)
{
return session
.GetSessionImplementation()
.PersistenceContext
.EntityEntries
.Keys
.Cast<object>()
.Contains(entity);
}session.GetSessionImplementation().PersistenceContext.EntityEntries is of type NHibernate.Util.IdentityMap.
The private field IdentityMap.map is of type NHibernate.Util.SequencedHashMap.
IdentityMap.Keys, which forwards to SequencedHashMap.Keys, is of type NHibernate.Util.SequencedHashMap.KeyCollection.
In some rare cases enumerating this SequencedHashMap.KeyCollection throws this exception:
System.InvalidOperationException: Enumerator was modified
at NHibernate.Util.SequencedHashMap.OrderedEnumerator.MoveNext()
at System.Linq.Enumerable.<CastIterator>d__97`1.MoveNext()
at System.Linq.Enumerable.Contains[TSource](IEnumerable`1 source, TSource value, IEqualityComparer`1 comparer)
at System.Linq.Enumerable.Contains[TSource](IEnumerable`1 source, TSource value)
at MyClass.ContainsLoadedEntityEqualTo(object entity)
So the Contains call iterates over EntityEntries.Keys and that throws an exception in SequencedHashMap.OrderedEnumerator.MoveNext().
I've also tried to add a ToList call before the Contains call but that doesn't change anything other than the call stack showing ToList instead of Contains.
This is the code that throws:
nhibernate-core/src/NHibernate/Util/SequencedHashMap.cs
Lines 686 to 691 in e15822d
| public bool MoveNext() | |
| { | |
| if (_parent._modCount != _expectedModCount) | |
| { | |
| throw new InvalidOperationException("Enumerator was modified"); | |
| } |
I don't know how to reproduce this. I've never seen the exception in my dev environment, only in log files from the production system.
As a quick and ugly workaround I tried to wrap the call in a try-catch-block which retries a few times if it fails. But that doesn't fix it. If the first iteration throws the exception, then any further iteration throws too. That's also why I think that this is not a timing/threading problem.
Could it be that iterating over EntityEntries.Keys somehow sometimes triggers lazy loading that then modifies the EntityEntries collection?
I don't know with which NHibernate version I first saw that exception. But it was at least back with version 5.5.2.
I haven't deployed NHibernate 5.6.0 yet, but I can confirm that I also saw the exception with 5.5.3.
I've found the bugs #1216 and #3355 which might be related. But while the exception and the exact source are the same, the call stack is different for me.