private void ParseObject(NodeContext nodeContext, EntityAspect targetAspect) {
// backingStore will be null if not allowed to overwrite the entity.
var backingStore = (targetAspect == null) ? null : targetAspect.BackingStore;
var dict = (IDictionary<String, JToken>)nodeContext.Node;
var structuralType = nodeContext.StructuralType;
// needs to be the current namingConvention
var nc = _mappingContext.EntityManager.MetadataStore.NamingConvention;
dict.ForEach(kvp => {
var key = nc.ServerPropertyNameToClient(kvp.Key, structuralType);
var prop = structuralType.GetProperty(key);
if (prop != null) {
if (prop.IsDataProperty) {
if (backingStore != null) {
var dp = (DataProperty)prop;
if (dp.IsComplexProperty) {
var newCo = (IComplexObject)kvp.Value.ToObject(dp.ClrType);
var co = (IComplexObject)backingStore[key];
var coBacking = co.ComplexAspect.BackingStore;
newCo.ComplexAspect.BackingStore.ForEach(kvp2 => {
coBacking[kvp2.Key] = kvp2.Value;
});
} else {
var val = kvp.Value;
if (val.Type == JTokenType.Null && dp.ClrType != typeof(String) && !TypeFns.IsNullableType(dp.ClrType)) {
// this can only happen if the client is nonnullable but the server is nullable.
backingStore[key] = dp.DefaultValue;
} else if (dp.IsEnumType || (dp.DataType.ClrType == typeof(TimeSpan))) {
backingStore[key] = val.ToObject(dp.ClrType, _customSerializer);
} else {
var newValue = val.ToObject(dp.ClrType);
if (dp.IsForeignKey && targetAspect != null) {
var oldValue = targetAspect.GetValue(key);
backingStore[key] = newValue;
targetAspect.UpdateRelated(dp, newValue, oldValue);
// Above is like next line but with fewer side effects
// targetAspect.SetValue(key, val.ToObject(dp.ClrType));
} else {
backingStore[key] = newValue;
}
}
}
}
} else {
// prop is a ComplexObject
var np = (NavigationProperty)prop;
if (kvp.Value.HasValues) {
NodeContext newContext;
if (np.IsScalar) {
var nestedOb = (JObject)kvp.Value;
newContext = new NodeContext() { Node = nestedOb, ObjectType = prop.ClrType, StructuralProperty = np };
var entity = (IEntity)CreateAndPopulate(newContext);
if (backingStore != null) backingStore[key] = entity;
} else {
var nestedArray = (JArray)kvp.Value;
var navSet = (INavigationSet)TypeFns.CreateGenericInstance(typeof(NavigationSet<>), prop.ClrType);
nestedArray.Cast<JObject>().ForEach(jo => {
newContext = new NodeContext() { Node = jo, ObjectType = prop.ClrType, StructuralProperty = np };
var entity = (IEntity)CreateAndPopulate(newContext);
navSet.Add(entity);
});
// add to existing nav set if there is one otherwise just set it.
object tmp;
if (backingStore.TryGetValue(key, out tmp)) {
var backingNavSet = (INavigationSet)tmp;
navSet.Cast<IEntity>().ForEach(e => backingNavSet.Add(e));
} else {
navSet.NavigationProperty = np;
navSet.ParentEntity = targetAspect.Entity;
backingStore[key] = navSet;
}
}
} else {
// do nothing
//if (!np.IsScalar) {
// return TypeFns.ConstructGenericInstance(typeof(NavigationSet<>), prop.ClrType);
//} else {
// return null;
//}
}
}
} else {
if (backingStore != null) backingStore[key] = kvp.Value.ToObject<Object>();
}
});
}