Support of POCO entities with custom Equals and GetHashCode implementations

EF6 will support POCO entities that have custom Equals or GetHashCode implementations. EF will instead use the default implementations. This is a continuation of efforts to have less requirements on the entity classes and to support a fairly common way of implementing the DDD aggregate pattern.

However there are some caveats:

  • You should still follow the guidelines (Eric Lippert has a great post on this) for implementing Equals and GetHashCode
  • If your hashcode/equality algorithm cannot guarantee immutability and uniqueness at all times then you need to make sure that your collection navigation properties use reference equality for comparisons. For HashSet<T> pass System.Data.Entity.Infrastructure.ObjectReferenceEqualityComparer to the constructor (or create your own reference-based equality comparer, something like the snippet below should work). Do not use List<T> as it will always use the overridden Equals method for methods like Remove.
    public class Category
    {
        public Category()
        {
            Products = new HashSet<Product>(new ObjectReferenceEqualityComparer());
        }

        public string CategoryId { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Product> Products { get; set; }
    }
    [Serializable]
    public sealed class ObjectReferenceEqualityComparer : IEqualityComparer<object>
    {
        bool IEqualityComparer<object>.Equals(object x, object y)
        {
            return ReferenceEquals(x, y);
        }

        int IEqualityComparer<object>.GetHashCode(object obj)
        {
            return RuntimeHelpers.GetHashCode(obj);
        }
    }
  • Data binding through the Local property uses ObservableCollection which relies on the overridden Equals implementations. Make sure that in this case Equals only returns true if the key values are equal and that the key values are immutable at least during the data binding lifetime.

Last edited Apr 24, 2013 at 5:27 PM by ajcvickers, version 4

Comments

AndriySvyryd Aug 1, 2013 at 12:15 AM 
In most cases EF will ignore custom Equals and GetHashCode when it stores and compares the objects internally.

Even previously EF wouldn't return different instances for an object with the same key.

Whether to use on not to use custom comparison is now up to your scenario as this change makes EF behavior independent of Equals and GetHashCode implementation.

FuriCuri Jul 6, 2013 at 12:48 PM 
I don't understand the text: you're saying that EF will support enities with custom Equals and GetHashCode, but then you say that EF will use default implementation. So basically EF will ignore any custom Equals and GetHashCode methods?

More importantly should - should we still use our custom base entity class for comparison entites by Id and custome ValueObject base class for comparison immutable value objects by their property values? Or EF will do it by default, meaning two different entity objects instances with the same key will be equal (==) without any custom code written? And the same goes with value objects? Or we still have to use our custom comparison implementation in base classes (like in NHibernate)?