Quantcast
Channel: Entity Framework
Viewing all articles
Browse latest Browse all 10318

Commented Issue: EF requires that entity classes don't override GetHashCode [1005]

$
0
0
It looks like EF (I'm working with code-first style) requires that the poco entity classes not override GetHashCode(). I didn't see that in the documentation, and even if documented, it does not seem like a good idea, and the error that occurs is not good, making it difficult to figure out what is going on.

EntityEntry.cs uses a Dictionary<object, ...> _originalValues to keep track of each object's original property values. That Dictionary uses GetHashCode() (presumably followed by Equals() for collisions) to keep track of objects. But users can override GetHashCode with their own implementation, often to achieve value semantics (where the hash code of an object represents the values the object stores (like String) rather than the object's identity). This breaks EntityEntry.cs's dictionary because for value semantics the hash code changes when the object is updated, and thus EntityEntry can't find the original property values.

In a debug build this scenario hits the assert that says "Original value not found even after snapshot."

Without that assert I get an error: "The property 'Id' is part of the object's key information and cannot be modified." where Id is the first property in the object. I did not track down why this error occurs, but it doesn't seem to point to the fundamental cause.

I hit a similar issue first in EF 5, then got the EF 6 source on 2013-03-31 via git clone to see if it also happens in EF 6. The error is different in 6 but I believe it is a similar fundamental issue. In EF5 it happens when using a complex type inside the entity class, and the error is:
"The entity of type 'Foo' references the same complex object of type 'Bar' more than once. Complex objects cannot be referenced multiple times by the same entity."

If EntityEntry.cs needs to keep track of objects it needs to not use GetHashCode() which can be overridden by the user. One possibility is to use ConditionalWeakTable for _originalValues, but there are ramifications that would need to be understood. I tried that and it solved the problem, but I'm not sure about all the ramifications of the change, including perf and lifetimes of objects. Another alternative is a custom dictionary that uses System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode() and Object.ReferenceEquals() to avoid depending on the user's Equals() and GetHashCode() implementations.
Comments: Code change looks good, and I verified that it fixes my particular scenario.

Viewing all articles
Browse latest Browse all 10318

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>