C#でエンティティ比較子を書く方法(最初の試みのコード例)

.net c# comparison entity-framework performance

質問

可能な重複:
2つのエンティティフレームワークエンティティを比較するための最良の方法は何ですか?

同じ種類の2つのエンティティを比較する最も効率的な方法を知りたいです。

一方のエンティティは手動でxmlファイルから作成され(すなわち、新しいインスタンスと手動で設定されたプロパティ)、もう一方は私のオブジェクトコンテキストから返されます。

各インスタンスでプロパティ値が同じかどうかを知りたいです。

私の最初の考えは、各オブジェクトからプロパティ値のハッシュを生成し、ハッシュを比較することですが、別の方法があるのでしょうか。

任意の提案は大歓迎です。

どうもありがとう、

ジェームズ

更新

私はこれを思い付きました:

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;
        }
    }
}

私はまだそれをテストしていません、それはグループからいくつかのより多くのアイデアを生成するための思考のためのより食品です。

問題になる可能性があることの1つは、エンティティ値自体を持つプロパティを比較することです。デフォルトのコンパレータがオブジェクト参照を比較すると、それは決して真になりません。考えられる解決策は、エンティティIDを比較するように、私のエンティティの等価演算子をオーバーロードすることです。

受け入れられた回答

コードはあなたが期待していることをしないでしょう。

この簡単なテストを試してください。


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));
    }
}

あなたはそれが戻ってくると期待するでしょう

本当の

しかしそれは戻る

次のようになるようにインナーを変更してみてください。


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

aとa1の両方が同じオブジェクトを参照している場合は、メソッドの開始時にそれをチェックすることで時間を節約することもできます。


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; 
        } 
    } 
}

パフォーマンスに悩んでいるのであれば、Reflectionはそれ自体では少なくともバージョン3.5 SP1まではそれを行わないので、メソッドの有効期間中にType.GetPropertiesの戻り値をローカル変数にキャッシュできます。そうすることであなたは4から2にGetProperties呼び出しを落とすでしょう。

まったく同じ型のオブジェクトを比較することを期待しているだけの場合(または基本インスタンスと派生インスタンスの間で比較しない場合)、GetPropertiesの呼び出しを1つに減らすことができます。

お役に立てれば。


人気のある回答

私はこのようなことをするだろう

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

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ