I had a similar problem with EF were I wanted to convert a query returned list, into a class property's dictionary equivalent. Very similar to how you want to have LeaveEntitlementDetails
wrapped by LeveEntitlementStore
For example:
class A
{
[NotMapped()]
public Dictionary<int, DataType> Data {get; set}
//refers to Data.Values
public ICollection<DataType> DataAsList {get; set}
}
Where I wanted DataAsList
to essentially wrap Data.Values
After a lot of trial and error, I discovered that EF, for collections (maybe more) alters through the getter's returned value (rather than the setter).
I.e. when initializing from my db:
var pollquery=From bb In DBM.Dbi.DataTable.Includes("DataAsList")
Where bb.Id = id
Select bb;
ClassA objInstance = pollquery.First();
ClassA.DataAsList
's setter was never being called, but the getter was during EF's internal construction of my object.... Conclusion: EF is using a reference retrieved from the getter of property ClassA.DataAsList
, and adding objects to it.
So I wrapped my getter's return value for DataAsList
in an ObservableCollection and added a handler for CollectionChanged args and sure enough, my handler for CollectionChanged was picking up .Add
calls.
So heres my hackaround-workaround:
class A : INotifyPropertyChanged
{
//So we can let EF know a complex property has changed
public event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged;
//here's our actual data, rather than an auto property, we use an explicit member definition so we can call PropertyChanged when Data is changed
private Dictionary<int, DataType> m_data = new Dictionary<int, DataType>();
//not mapped property as it's not mapped to a column in EF DB
[NotMapped()]
public Dictionary<int, DataType> Data {
get { return m_data; }
set {
m_data = value;
//now call PropertyChanged for our Front (so EF will know it's been changed)
if (PropertyChanged != null) {
PropertyChanged(this, new PropertyChangedEventArgs("DataAsList"));
}
}
}
//this is our front for the data, that we use in EF to map data to
[DebuggerHidden()]
public ICollection<DataType> DataAsList {
get {
ObservableCollection<DataType> ob = new ObservableCollection<DataType>(Data.Values());
ob.CollectionChanged += Handles_entryListChanged;
return ob;
}
set {
//clear any existing data, as EF is trying to set the collections value
Data.Clear();
//this is how, in my circumstance, i converted my object into the dictionary from an internal obj.Id property'
foreach (DataType entry in value) {
entryions.Add(entry.id, entry);
}
}
}
//This will now catch wind of any changes EF tries to make to our DataAsList property
public void Handles_entryListChanged(object sender, NotifyCollectionChangedEventArgs e)
{
//Debugger.Break()
switch (e.Action) {
case NotifyCollectionChangedAction.Add:
foreach (DataType entry in e.NewItems) {
m_data.Add(entry.Id, entry);
}
break;
default:
Debugger.Break();
break;
}
}
}
Note the Magic is the:
public ICollection<DataType> DataAsList {
get {
ObservableCollection<DataType> ob = new ObservableCollection<DataType>(Data.Values());
ob.CollectionChanged += Handles_entryListChanged;
return ob;
}
where we subscribe to any changes made to the returned list and Handles_entryListChanged
where we handle and essentially replicate any changes made.