4

ビュー モデルをデータベース モデルと同期する必要がある MVC3 アプリケーションがあります。さまざまなオブジェクト間でプロパティをコピーするには、あまりにも多くのコードを記述していることに気付きました。データモデルを単純にサブクラス化できる場合はこれを避けましたが、それがあまりにも制限的であることがわかった場合もあります。

同様の名前を持つプロパティの浅いクローン作成をサポートするために、Object でいくつかの拡張メソッドを開発しましたが、これはかなりうまくいきました。ただし、同じことを達成するためのより効率的な手段があるかどうかは疑問です。したがって、これはピアレビューと、このコードを改善するためのオプションを求めていると思います。

更新:関連するテーブルを明示的に処理する方が良いことがわかりました。IsVirtual をテストすることで、クローン作成中にリレーションが不注意に影響を受けるのを防ぐことができます。更新された CloneMatching メソッドを参照してください。その他は、どのプロパティを更新または除外するかを明示的に示しています。

public static class CustomExtensions
{
   public static T CloneMatching<T, S>(this T target, S source)
       where T : class
       where S : class
    {
        if (source == null)
        {
            return target;
        }
        Type sourceType = typeof(S);
        Type targetType = typeof(T);
        BindingFlags flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;

        PropertyInfo[] properties = sourceType.GetProperties();
        foreach (PropertyInfo sPI in properties)
        {
            PropertyInfo tPI = targetType.GetProperty(sPI.Name,flags);
            if (tPI != null && tPI.PropertyType.IsAssignableFrom(sPI.PropertyType) && !tPI.PropertyType.IsVirtual)
            {
                tPI.SetValue(target, sPI.GetValue(source, null), null);
            }
        }
        return target;
    }

    public static T CloneProperties<T, S>(this T target, S source, string[] propertyNames)
       where T : class
       where S : class
    {
        if (source == null)
        {
            return target;
        }
        Type sourceType = typeof(S);
        Type targetType = typeof(T);
        BindingFlags flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;

        PropertyInfo[] properties = sourceType.GetProperties();
        foreach (PropertyInfo sPI in properties)
        {
            if (propertyNames.Contains(sPI.Name))
            {
                PropertyInfo tPI = targetType.GetProperty(sPI.Name, flags);
                if (tPI != null && tPI.PropertyType.IsAssignableFrom(sPI.PropertyType))
                {
                    tPI.SetValue(target, sPI.GetValue(source, null), null);
                }
            }
        }
        return target;
    }
    public static T CloneExcept<T, S>(this T target, S source, string[] propertyNames)
       where T : class
       where S : class
    {
        if (source == null)
        {
            return target;
        }
        Type sourceType = typeof(S);
        Type targetType = typeof(T);
        BindingFlags flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;

        PropertyInfo[] properties = sourceType.GetProperties();
        foreach (PropertyInfo sPI in properties)
        {
            if (!propertyNames.Contains(sPI.Name))
            {
                PropertyInfo tPI = targetType.GetProperty(sPI.Name, flags);
                if (tPI != null && tPI.PropertyType.IsAssignableFrom(sPI.PropertyType))
                {
                    tPI.SetValue(target, sPI.GetValue(source, null), null);
                }
            }
        }
        return target;
    }
}

これを使用してビュー モデルをデータ モデルにマップする方法の例を次に示します。

DataSession.Quote.CloneProperties(viewModel,
                new[] {"PaymentType","CardHolder","CardHolderZip","CardNumber","CardExp","CVC",
                          "AccountHolder","AccountHolderZip","ABA","Account",
                          "AccuracyAgreement","PrivacyTermsAgreement","ElectronicSignatureAgreement"});
4

1 に答える 1