3

EF 4、外部キー、および INotifyPropertyChanged / スカラー プロパティ用に公開された部分メソッドでいくつかの問題に直面しています。

これを行う正しい方法を見つけるのを手伝ってくれることを願っています。

Image Country エンティティと *..1 の関係を持つ Customer エンティティがあります。

今、私は明らかにできるようにしたいと思います:

var customer = new Customer();
customer.Country = [...]

...しかし、CountryKey プロパティは必ずしも必要ではありません。

.edmx デザイナーで正しいカーディナリティを使用して、EF で関連付けを作成します。ダイアログで「外部キーのプロパティを追加」しないことを選択しました。

これにより、部分的な OnCountryChanging と OnCountryChanged のない生成されたクラスが残ります。

次に、外部キー プロパティを追加しようとすると、OnCountryKeyChanging と OnCountryKeyChanged が作成されました。

ただし、生成されたコードは次のようになります。

/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Int64 CountryKey
{
    get
    {
        return _CountryKey;
    }
    set
    {
        OnCountryKeyChanging(value);
        ReportPropertyChanging("CountryKey");
        _CountryKey = StructuralObject.SetValidValue(value);
        ReportPropertyChanged("CountryKey");
        OnCountryKeyChanged();
    }
}
private global::System.Int64 _CountryKey;
partial void OnCountryKeyChanging(global::System.Int64 value);
partial void OnCountryKeyChanged();

生成されたコードからわかるように、PropertyChanged 通知は "Country" ではなく "CountryKey" で発生します。これにより、WPF でのデータ バインディングが困難になります。

私の質問は次のとおりです。どうすればこれを回避できますか?

  • オブジェクトをViewModelでラップし、プロパティの変更をリッスンして、「キー」部分を削除しますか?
  • T4 テンプレートを変更しますか?
  • または、まだ表示されていない 3 番目のオプションはありますか?

ViewModel で各 Model プロパティをラップせずに WPF / EF を試しているので、ここで何か提案をいただければ幸いです。

4

1 に答える 1

0

「ベスト プラクティス」のアプローチは、ビューモデルでモデルを装飾し、必要に応じてモデル プロパティを公開することです。おそらくプロパティマッピングなどを使用して、動的オブジェクトを使用した気の利いた作業で汎用ViewModelを作成できます。

public class DynamicViewModel : DynamicObject, INotifyPropertyChanged, IDisposable
{
    public event PropertyChangedEventHandler PropertyChanged;

    private static readonly Dictionary<Type, Tuple<Dictionary<string, PropertyInfo>, Dictionary<string, string>>> typeDictionary = new Dictionary<Type, Tuple<Dictionary<string, PropertyInfo>, Dictionary<string, string>>>();

    private readonly Dictionary<string, object> additionalProperties = new Dictionary<string, object>();

    private readonly object underlyingObject;
    public object UnderlyingObject
    {
        get
        {
            return underlyingObject;
        }
    }

    private readonly Type type;

    /// <summary>
    /// constructor which takes a model for which it will be extensing its perceived properties
    /// </summary>
    /// <param name="underlyingObject">the underlying object</param>
    public DynamicViewModel(IBindableRfqViewModel underlyingObject) : this(underlyingObject, new Dictionary<string, string>())
    {

    }

    /// <summary>
    /// constructor which takes a model for which it will be extensing its perceived properties as well as a property map
    /// </summary>
    /// <param name="underlyingObject">the underlying object</param>
    /// <param name="propertyMap">a string/string dictionary, where the key is a property on the underlying object, and the value is the name of the dynamic property to be used as a binding target</param>
    public DynamicViewModel(IBindableRfqViewModel underlyingObject, Dictionary<string, string> propertyMap)
    {
        this.underlyingObject = underlyingObject;
        if (underlyingObject is INotifyPropertyChanged)
        {
            ((INotifyPropertyChanged)underlyingObject).PropertyChanged += OnUnderlyingPropertyChanged;
        }

        type = underlyingObject.GetType();
        if (typeDictionary.ContainsKey(type))
        {
            return;
        }
        lock (typeDictionary)
        {
            if (typeDictionary.ContainsKey(type))
            {
                return;
            }
            var forwardPropertyMap = propertyMap;
            var typeProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).ToDictionary(p => p.Name, p => p);
            typeDictionary.Add(type, Tuple.Create(typeProperties,forwardPropertyMap));
        }
    }

    private void OnUnderlyingPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        this.OnPropertyChanged(e.PropertyName);
    }

    private bool TryGetProperty(string name, out object result)
    {
        try
        {
            var propertyData = typeDictionary[type];
            var modelProperty = name;
            if (propertyData.Item2.ContainsKey(name))
            {
                modelProperty = propertyData.Item2[name];
            }
            if (propertyData.Item1.ContainsKey(modelProperty))
            {
                result = propertyData.Item1[modelProperty].GetValue(underlyingObject, null);
                return true;
            }

            if (additionalProperties.ContainsKey(name))
            {
                result = additionalProperties[name];
                return true;
            }

            result = null;
            return true;
        }
        catch (Exception ex)
        {
            result = null;
            return false;
        }
    }

    /// <summary>
    /// <see cref="DynamicObject.TryGetMember" />
    /// </summary>
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        return this.TryGetProperty(binder.Name, out result);
    }

    /// <summary>
    /// <see cref="DynamicObject.TryGetIndex" />
    /// </summary>
    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
    {
        return this.TryGetProperty(indexes[0].ToString(), out result);
    }

    private bool TrySetProperty(string name, object value)
    {
        try
        {
            var propertyData = typeDictionary[type];
            var modelProperty = name;
            if (propertyData.Item2.ContainsKey(name))
            {
                modelProperty = propertyData.Item2[name];
            }
            if (propertyData.Item1.ContainsKey(modelProperty))
            {
                propertyData.Item1[modelProperty].SetValue(underlyingObject, value, null);
            }
            else
            {
                if (!additionalProperties.ContainsKey(name))
                {
                    additionalProperties.Add(name, new object());
                }
                additionalProperties[name] = value;
            }

            this.OnPropertyChanged(name);
            return true;
        }
        catch (Exception ex)
        {
            return false;
        }

    }

    /// <summary>
    /// <see cref="DynamicObject.TrySetMember" />
    /// </summary>
    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        return this.TrySetProperty(binder.Name, value);
    }

    /// <summary>
    /// <see cref="DynamicObject.TrySetIndex" />
    /// </summary>
    public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
    {
        return indexes.Length == 0 || this.TrySetProperty(indexes[0].ToString(), value);
    }

    private void OnPropertyChanged(string propName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propName));
        }
    }

    /// <summary>
    /// IDisposable implementation
    /// </summary>
    public void Dispose()
    {
        if (underlyingObject is INotifyPropertyChanged)
        {
            ((INotifyPropertyChanged)underlyingObject).PropertyChanged -= OnUnderlyingPropertyChanged;
        }
        if (underlyingObject is IDisposable)
        {
            ((IDisposable)underlyingObject).Dispose();
        }
    }
}
于 2012-04-25T10:13:57.813 に答える