In C#, how do you construct an entity comparator? (with example code of first attempt)

.net c# comparison entity-framework performance

Question

Possible Duplicate:
What is the best way to compare two entity framework entities?

I want to know the most efficient way of comparing two entities of the same type.

One entity is created from an xml file by hand ( ie new instance and manually set properties) and the other is retvied from my object context.

I want to know if the property values are the same in each instance.

My first thoughts are to generate a hash of the property values from each object and compare the hashes, but there might be another way, or a built in way?

Any suggestions would be welcome.

Many thanks,

James

UPDATE

I came up with this:

static class ObjectComparator<T>
{
    static bool CompareProperties(T newObject, T oldObject)
    {
        if (newObject.GetType().GetProperties().Length != oldObject.GetType().GetProperties().Length)
        {
            return false;
        }
        else
        {
            var oldProperties = oldObject.GetType().GetProperties();

            foreach (PropertyInfo newProperty in newObject.GetType().GetProperties())
            {
                try
                {
                    PropertyInfo oldProperty = oldProperties.Single<PropertyInfo>(pi => pi.Name == newProperty.Name);

                    if (newProperty.GetValue(newObject, null) != oldProperty.GetValue(oldObject, null))
                    {
                        return false;
                    }
                }
                catch
                {
                    return false;
                }
            }

            return true;
        }
    }
}

I haven't tested it yet, it is more of a food for thought to generate some more ideas from the group.

One thing that might be a problem is comparing properties that have entity values themselves, if the default comparator compares on object reference then it will never be true. A possible fix is to overload the equality operator on my entities so that it compares on entity ID.

1
4
5/23/2017 11:55:42 AM

Accepted Answer

As is the code will not do what you are expecting.

Try this simple test:


class A {
    public int Id { get; set; }
    public string Name { get; set; }
}

class B : A {
    public DateTime BirthDate { get; set; }
}

class ObjectComparer {
    public static void Show() {
        A a = new A();
        B b = new B();
        A a1 = new A();

        Console.WriteLine(ObjectComparator.CompareProperties(a, b));
        Console.WriteLine(ObjectComparator.CompareProperties(b, a));
        Console.WriteLine(ObjectComparator.CompareProperties(a, a1));
    }
}

You would expect it to return

false

false

true

but it returns

false

false

false

try changing the inner if to look like:


if (!object.Equals(newProperty.GetValue(newObject, null), oldProperty.GetValue(oldObject, null))) { 
       return false; 
} 

You can also save some time in the case a and a1 both reference the same object by checking that in the begining of the method.


static class ObjectComparator { 
    public static bool CompareProperties(T newObject, T oldObject) {
        if (object.Equals(newObject, oldObject)) {
            return true;
        }
        if (newObject.GetType().GetProperties().Length != oldObject.GetType().GetProperties().Length) { 
            return false; 
        } 
        else { 
            var oldProperties = oldObject.GetType().GetProperties(); 
            foreach (PropertyInfo newProperty in newObject.GetType().GetProperties()) { 
                try { 
                    PropertyInfo oldProperty = oldProperties.Single(pi => pi.Name == newProperty.Name); 
                    if (!object.Equals(newProperty.GetValue(newObject, null), oldProperty.GetValue(oldObject, null))) { 
                        return false; 
                    } 
                } 
                catch { 
                    return false; 
                } 
            } 
            return true; 
        } 
    } 
}

If you are concered with performance, you can cache the return of Type.GetProperties into a local variable during the lifetime of the method, since Reflection does not do that by itself at least up to version 3.5 SP1. In doing that you will drop GetProperties calls from four to two.

If you are only expecting to compare objects of exactly the same type (or put another way not compare between base and derived instances), you can further reduce the calls of GetProperties to one.

Hope this helps.

5
8/8/2009 8:04:02 PM

Popular Answer

I would do something like this

static class ObjectComparator<T>
{
    public static bool CompareProperties(T newObject, T oldObject)
    {
        if (Equals(newObject, oldObject))
        {
            return true;
        }
        PropertyInfo[] newProps = newObject.GetType().GetProperties();
        PropertyInfo[] oldProps = oldObject.GetType().GetProperties();

        if (newProps.Length != oldProps.Length)
        {
            return false;
        }

        foreach (PropertyInfo newProperty in newProps)
        {
            PropertyInfo oldProperty = oldProps.SingleOrDefault(pi => pi.Name == newProperty.Name);
            if (oldProperty == null)
                return false;

            object newval = newProperty.GetValue(newObject, null);
            object oldval = oldProperty.GetValue(oldObject, null);

            if (!Equals(newval, oldval))
                return false;
        }
        return true;
    }
}


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow