I want to compare records to see if there are differences between them.
Person
table:
ID Name Address
--------------------------------
1 John Smith 123 A Street
2 John Smith 123 A Street
3 John Smith 234 B Street
Records 1 and 2 are "equal". Records 2 and 3 are "not equal".
I have implemented IEquatable
on model Person
as follows.
public static bool operator ==(Person p1, Person p2)
{
if (System.Object.ReferenceEquals(p1, p2)) return true;
return p1.Equals(p2);
}
public static bool operator !=(Person p1, Person p2)
{
return !(p1== p2);
}
public bool Equals(Person other)
{
if (System.Object.ReferenceEquals(this, other)) return true;
if (Name != other.Name) return false;
if (Address != other.Address) return false;
return true;
}
public override bool Equals(object obj)
{
Person person = obj as Person;
if (person == null) return false;
return Equals(person);
}
public override int GetHashCode()
{
unchecked
{
int hash = (int)2166136261;
hash = hash * 25165843 ^ (Name != null ? Name .GetHashCode() : 0);
hash = hash * 25165843 ^ (Address != null ? Address.GetHashCode() : 0);
return hash;
}
}
The issue is that when the Persons
ICollection from a navigational property is materialized. It is missing records "equal" to each other (ie a single John Smith 123 A Street record is returned). I am guessing this is because by default it considers distinct entities ones that have unique primary keys. By overriding equals it thinks both records are the same entity.
Screenshot showing Addresses
instead of Persons
: (Top is with IEquatable
, bottom is without)
//Addresses Definition (generated code)
public virtual ICollection<Address> Addresses { get; set; }
How can I reconcile EF needing see equality at the object level versus me wanting to see a logical equality?