Entity Framework 4 - Association Notification

I ran into some difficulties with EF 4, foreign keys, and INotifyPropertyChanged / partial methods open to scalar properties.

Hope you can help me find the right way to do this.

Image I have a Customer object with * .. 1 with a country entity.

Now, I obviously would like to be able to:

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

... but I don’t necessarily need the CountryKey property.

I am creating an Association in EF with the right power in an .edmx designer. I do not want to "add foreign key properties" in the dialog box.

This leaves me with the generated class without partial OnCountryChanging and OnCountryChanged.

Then I try to add foreign key properties, and now I have OnCountryKeyChanging and 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 "CountryKey" "". WPF.

: ?

  • ViewModel, ""?
  • T4?
  • , ?

, WPF/EF ViewModel.

+3
1

" " , , . ViewModel dynamicobject, , , ..

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

All Articles