protected object LoadObject(IObjectGraph source, Dictionary <object, object> parsedObjects) { if (!source.IsAnonymous) { var instance = source.GetInstance(); if (instance is IEntity) { instance = GetCopyInContextOrAttach(instance as IEntity); } LoadIncludes(source, instance, parsedObjects); return(instance); } else { //Anonymous Types var anonType = source.GetInstanceType(); var ctor = anonType.GetConstructors().Single(); var deserializedIncludes = new Dictionary <PropertyInfo, object>(); foreach (var property in source.GetPropertiesNeedingContextBinding()) { if (!TypesUtil.IsNonPrimitiveCollection(property.PropertyType)) { var propertyValue = LoadObject(source.GetObjectGraphForProperty(property), parsedObjects); deserializedIncludes.Add(property, propertyValue); } else { var collectionItems = source.GetObjectGraphForCollection(property) .Select(itemInfo => LoadObject(itemInfo, parsedObjects)).ToList(); var propertyValue = MakeEnumerable(property.PropertyType, collectionItems); deserializedIncludes.Add(property, propertyValue); } } var ctorArgs = deserializedIncludes.Select(kvp => kvp.Value).ToArray(); return(Activator.CreateInstance(anonType, ctorArgs)); } }
protected void LoadIncludes(IObjectGraph source, object instance, Dictionary <object, object> parsedObjects) { if (parsedObjects.ContainsKey(instance)) { return; } //Add it to the parsed objects list, so that we can avoid going through circular relationships. parsedObjects.Add(instance, null); if (source.IsCollection) { var sourceCollection = source.GetSourceCollection(); var ctr = 0; foreach (var item in (instance as IEnumerable)) { LoadIncludes(sourceCollection[ctr++], item, parsedObjects); } } else { foreach (var property in source.GetPropertiesNeedingContextBinding()) { if (!TypesUtil.IsNonPrimitiveCollection(property.PropertyType)) { //If the instance is an Entity, we treat property setting differently. // This is because setters will automatically trigger Reverse Reference setters. if (instance is IEntity) { var propValFromSource = source.GetPropertyValue(property); var loadedValue = property.GetValue(instance); //If the property is already loaded in our current instance, we should not touch it. // Yet, if they (current instance and the source) refer to the same value, we should attach includes. //If they are NOT the same, we do nothing. (Since the user changed the property, can't overwrite.) if (IsPropertyLoadedOnEntity(instance, property)) { if (loadedValue != null && loadedValue is IEntity && ((IEntity)loadedValue).IsEquivalent((IEntity)propValFromSource)) { LoadIncludes(source.GetObjectGraphForProperty(property), loadedValue, parsedObjects); } } //Property is not loaded on the current instance. Go ahead and add it via Materialization methods. else { if (source.GetPropertyValue(property) != null) { var propertyValue = LoadObject(source.GetObjectGraphForProperty(property), parsedObjects); var intermediateContainer = GetBackingContainerForProperty(instance as IEntity, property); intermediateContainer.MaterializationAddReference((propertyValue as IEntity)._getIntermediateEntity()); } } } //Instance is not an IEntity, we can just set the property value. else { if (source.GetPropertyValue(property) != null) { var propertyValue = LoadObject(source.GetObjectGraphForProperty(property), parsedObjects); property.SetValue(instance, propertyValue); } } } //This property is a collection. else { var entityList = source.GetObjectGraphForCollection(property) .Select(collItemSource => LoadObject(collItemSource, parsedObjects)).ToList(); if (IsManyToMany(property)) { //Many-to-Many collection can only exist in Entities, hence the cast. AddToManyToManyCollection((IEntity)instance, property, entityList); } else { SetEnumerableProperty(instance, property, MakeEnumerable(property.PropertyType, entityList)); } } } } }