We occasionally see this exception in our logs, but can't figure out how to reproduce it under test:
System.NullReferenceException: Object reference not set to an instance of an object.
at System.Data.Objects.EntityEntry.DetectChangesInProperty(Int32 ordinal, Boolean detectOnlyComplexProperties, Boolean detectOnly)
at System.Data.Objects.EntityEntry.DetectChangesInProperties(Boolean detectOnlyComplexProperties)
at System.Data.Objects.ObjectStateManager.DetectChangesInScalarAndComplexProperties(IList1 entries)
1.Find(Object[] keyValues)
at System.Data.Objects.ObjectStateManager.DetectChanges()
at System.Data.Entity.Internal.InternalContext.DetectChanges(Boolean force)
at System.Data.Entity.Internal.Linq.InternalSet
at
The failing method System.Data.Objects.EntityEntry.DetectChangesInProperty(Int32 ordinal, Boolean detectOnlyComplexProperties, Boolean detectOnly)
decompiles with dotPeek (plus my comments) to:
private bool DetectChangesInProperty(
int ordinal,
bool detectOnlyComplexProperties,
bool detectOnly)
{
bool changeDetected = false;
// possible System.NullReferenceException on _cacheTypeMetadata
StateManagerMemberMetadata managerMemberMetadata = this._cacheTypeMetadata.Member(ordinal);
// possible System.NullReferenceException on managerMemberMetadata (if a null entry exists in _members[])
object obj1 = managerMemberMetadata.GetValue(this._wrappedEntity.Entity);
if (managerMemberMetadata.IsComplex)
{
if (this.State != EntityState.Deleted)
{
object complexObjectSnapshot = this.GetComplexObjectSnapshot(this.Entity, ordinal);
if (this.DetectChangesInComplexType(managerMemberMetadata, managerMemberMetadata, obj1, complexObjectSnapshot, ref changeDetected, detectOnly))
{
this.CheckForDuplicateComplexObjects(obj1);
if (!detectOnly)
{
((IEntityChangeTracker) this).EntityMemberChanging(managerMemberMetadata.CLayerName);
// possible System.NullReferenceException on _cache
this._cache.ChangingOldValue = complexObjectSnapshot;
((IEntityChangeTracker) this).EntityMemberChanged(managerMemberMetadata.CLayerName);
}
this.UpdateComplexObjectSnapshot(managerMemberMetadata, this.Entity, ordinal, obj1);
if (!changeDetected)
this.DetectChangesInComplexType(managerMemberMetadata, managerMemberMetadata, obj1, complexObjectSnapshot, ref changeDetected, detectOnly);
}
}
}
else if (!detectOnlyComplexProperties)
{
object obj2;
// possible System.NullReferenceException on _wrappedEntity
this.FindOriginalValue(managerMemberMetadata, this._wrappedEntity.Entity, out obj2);
object originalValue = ((StateManagerValue) obj2).originalValue;
// possible System.NullReferenceException on object
if (!object.Equals(obj1, originalValue))
{
changeDetected = true;
if (managerMemberMetadata.IsPartOfKey)
{
// static so no possible System.NullReferenceException
if (!ByValueEqualityComparer.Default.Equals(obj1, originalValue))
throw EntityUtil.CannotModifyKeyProperty(managerMemberMetadata.CLayerName);
}
else if (this.State != EntityState.Deleted && !detectOnly)
{
((IEntityChangeTracker) this).EntityMemberChanging(managerMemberMetadata.CLayerName);
((IEntityChangeTracker) this).EntityMemberChanged(managerMemberMetadata.CLayerName);
}
}
}
return changeDetected;
}
There are several places where a NullReferenceException
could be thrown, and I can't begin to guess. If we knew how to reliably reproduce the problem I could step through, but I don't. So far, this is all I have.
We have a large ASP.NET website solution with dozens of repositories which all use the same type of DbContext. We haven't implemented instance-per-request yet, but we know we have to. It'll take us several weeks to do it. We think this is the cause of the exception. In the meantime we have various approaches to newing up DbContext: per method call (expensive), now being replaced by (less expensive but also-smelly) service locators, with a bit of Autofac (still not instance per request because of that being incompatible with our version of MVC plus async
).
We want to figure out how to reproduce this error reliably, so that we can know that instance-per-request has actually fixed the problem. So the underlying question is not "how do we fix this", but "how do we reproduce it"? And to answer that, I'm curious as to how this exception is actually happening.