I manage a publicly available WPF app which uses Entity Framework 6.1 (model-first ObjectContext) and a SQLite database.
The number one crash log (according to HockeyApp) for my app is the following (with pointers to my app's code marked ****):
System.InvalidOperationException: The property 'Id' is part of the object's key information and cannot be modified.
at System.Data.Entity.Core.Objects.EntityEntry.VerifyEntityValueIsEditable(StateManagerTypeMetadata typeMetadata, Int32 ordinal, String memberName)
at System.Data.Entity.Core.Objects.EntityEntry.GetAndValidateChangeMemberInfo(String entityMemberName, Object complexObject, String complexObjectMemberName, StateManagerTypeMetadata& typeMetadata, String& changingMemberName, Object& changingObject)
at System.Data.Entity.Core.Objects.EntityEntry.EntityMemberChanging(String entityMemberName, Object complexObject, String complexObjectMemberName)
at System.Data.Entity.Core.Objects.EntityEntry.EntityMemberChanging(String entityMemberName)
at System.Data.Entity.Core.Objects.ObjectStateEntry.System.Data.Entity.Core.Objects.DataClasses.IEntityChangeTracker.EntityMemberChanging(String entityMemberName)
at System.Data.Entity.Core.Objects.DataClasses.EntityObject.ReportPropertyChanging(String property)
****
at MyNamespace.MyApp.MyEntity.set_Id(Int64 value) in C:\MyPath\MyApp\EfGeneratedEntities.cs
****
at lambda_method(Closure , Object , Object )
at System.Data.Entity.Core.Objects.DelegateFactory.SetValue(EdmProperty property, Object target, Object value)
at System.Data.Entity.Core.Objects.StateManagerMemberMetadata.SetValue(Object userObject, Object value)
at System.Data.Entity.Core.Objects.Internal.LightweightEntityWrapper`1.SetCurrentValue(EntityEntry entry, StateManagerMemberMetadata member, Int32 ordinal, Object target, Object value)
at System.Data.Entity.Core.Objects.EntityEntry.SetCurrentEntityValue(StateManagerTypeMetadata metadata, Int32 ordinal, Object userObject, Object newValue)
at System.Data.Entity.Core.Objects.ObjectStateEntryDbUpdatableDataRecord.SetRecordValue(Int32 ordinal, Object value)
at System.Data.Entity.Core.Mapping.Update.Internal.PropagatorResult.SetServerGenValue(Object value)
at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.BackPropagateServerGen(List`1 generatedValues)
at System.Data.Entity.Core.Mapping.Update.Internal.UpdateTranslator.Update()
at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.<Update>b__2(UpdateTranslator ut)
at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update[T](T noChangesResult, Func`2 updateFunction)
at System.Data.Entity.Core.EntityClient.Internal.EntityAdapter.Update()
at System.Data.Entity.Core.Objects.ObjectContext.<SaveChangesToStore>b__d()
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
at System.Data.Entity.Core.Objects.ObjectContext.<>c__DisplayClassb.<SaveChangesInternal>b__8()
at System.Data.Entity.Infrastructure.DefaultExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChanges()
****
at MyNamespace.MyApp.MyContext.OnMyEvent() in C:\MyPath\MyApp\MyContext.cs
****
I have not been able to reproduce this crash, and so I have not been able to attempt to fix it. I would love to get it sorted.
I understand the crash message. But my app is not doing anything that should cause this. The MyEntity.Id
property is an entity key (with StoreGeneratedPattern
= Identity
) and I never manually set the Id
value. I never manually mark an entity as modified. My SQLite DB does not have any triggers or anything else that could mess with EF's interpretation of DB-generated identity values. I really can't see how this crash could happen, and I can't make it happen myself - inserts of new entities work just fine for me.
I of course don't expect anyone to read this post and come up with the solution, but I'm hoping somebody can lead me in the right direction.
What non-obvious reasons could cause this crash to happen?
I'm sure I'll be asked for source code, but there's really not much to it. In the culprit code I simply create a MyEntity
object, set some property values, add it to context, and call SaveChanges()
. That's it. As I said, it works just fine in my testing and for 99% of customer usage. But I get several crash reports like this every day and I'd love to put an end to them.
---- UPDATE ----
I think it's worth pointing out that the MyEntity.set_Id(Int64 value)
in the stack trace is clearly part of Entity Framework's key/identity value retrieval (see lines around PropagatorResult.SetServerGenValue(Object value)
, etc.). This is not my code setting the Id
, it's EF.
Looking the Entity Framework source code, this exception is thrown when trying to set an entity key value for an entity not in the Added
state:
// Key fields are only editable if the entry is the `Added` state.
if (member.IsPartOfKey
&& State != EntityState.Added)
{
throw new InvalidOperationException(Strings.ObjectStateEntry_CannotModifyKeyProperty(memberName));
}
So could the issue be that MyEntity is somehow being put into an alternate state (e.g. Modified
) before SaveChanges()
(or during SaveChanges()
but before identity value retrieval)?
How could that happen? As I mentioned, I am not manually setting the state anywhere.