/// <summary> /// Copies the changed property values from the underlying entity (accessible via <see cref="GetInstance()" />) /// to the <paramref name="original"/> entity recursively. /// </summary> /// <param name="original">The entity to be updated.</param> public void CopyChangedValues(T original) { if (original == null) { throw Error.ArgumentNull(nameof(original)); } // Delta parameter type cannot be derived type of original // to prevent unrecognizable information from being applied to original resource. if (!_structuredType.IsAssignableFrom(original.GetType())) { throw Error.Argument(nameof(original), SRResources.DeltaTypeMismatch, _structuredType, original.GetType()); } RuntimeHelpers.EnsureSufficientExecutionStack(); // For regular non-structural properties at current level. PropertyAccessor <T>[] propertiesToCopy = _changedProperties.Intersect(_updatableProperties).Select(s => _allProperties[s]).ToArray(); foreach (PropertyAccessor <T> propertyToCopy in propertiesToCopy) { propertyToCopy.Copy(_instance, original); } CopyChangedDynamicValues(original); // For nested resources. foreach (string nestedResourceName in _deltaNestedResources.Keys) { // Patch for each nested resource changed under this T. dynamic deltaNestedResource = _deltaNestedResources[nestedResourceName]; dynamic originalNestedResource = null; if (!TryGetPropertyRef(original, nestedResourceName, out originalNestedResource)) { throw Error.Argument(nestedResourceName, SRResources.DeltaNestedResourceNameNotFound, nestedResourceName, original.GetType()); } if (originalNestedResource == null) { // When patching original target of null value, directly set nested resource. dynamic deltaObject = _deltaNestedResources[nestedResourceName]; dynamic instance = deltaObject.GetInstance(); // Recursively patch up the instance with the nested resources. deltaObject.CopyChangedValues(instance); _allProperties[nestedResourceName].SetValue(original, instance); } else { // Recursively patch the subtree. bool isDeltaType = DeltaHelper.IsDeltaOfT(deltaNestedResource.GetType()); Contract.Assert(isDeltaType, nestedResourceName + "'s corresponding value should be Delta<T> type but is not."); deltaNestedResource.CopyChangedValues(originalNestedResource); } } }
/// <inheritdoc/> public override bool TryGetPropertyValue(string name, out object value) { if (name == null) { throw Error.ArgumentNull("name"); } if (_dynamicDictionaryPropertyinfo != null) { if (_dynamicDictionaryCache == null) { _dynamicDictionaryCache = GetDynamicPropertyDictionary(_dynamicDictionaryPropertyinfo, _instance, create: false); } if (_dynamicDictionaryCache != null && _dynamicDictionaryCache.TryGetValue(name, out value)) { return(true); } } if (this._deltaNestedResources.ContainsKey(name)) { // If this is a nested resource, get the value from the dictionary of nested resources. object deltaNestedResource = _deltaNestedResources[name]; Contract.Assert(deltaNestedResource != null, "deltaNestedResource != null"); Contract.Assert(DeltaHelper.IsDeltaOfT(deltaNestedResource.GetType())); // Get the Delta<{NestedResourceType}>._instance using Reflection. FieldInfo field = deltaNestedResource.GetType().GetField("_instance", BindingFlags.NonPublic | BindingFlags.Instance); Contract.Assert(field != null, "field != null"); value = field.GetValue(deltaNestedResource); return(true); } else { // try to retrieve the value of property. PropertyAccessor <T> cacheHit; if (_allProperties.TryGetValue(name, out cacheHit)) { value = cacheHit.GetValue(_instance); return(true); } } value = null; return(false); }
/// <summary> /// Attempts to get the value of the nested Property called <paramref name="name"/> from the underlying resource. /// <remarks> /// Only properties that exist on Entity can be retrieved. /// Only modified nested properties can be retrieved. /// The nested Property type will be <see cref="IDelta"/> of its defined type. /// </remarks> /// </summary> /// <param name="name">The name of the nested Property</param> /// <param name="value">The value of the nested Property</param> /// <returns><c>True</c> if the Property was found and is a nested Property</returns> internal bool TryGetNestedPropertyValue(string name, out object value) { if (name == null) { throw Error.ArgumentNull(nameof(name)); } if (!_deltaNestedResources.ContainsKey(name)) { value = null; return(false); } // This is a nested resource, the value returned must be an IDelta<T> // from the dictionary of nested resources to allow the traversal of // hierarchies of Delta<T>. object deltaNestedResource = _deltaNestedResources[name]; Contract.Assert(deltaNestedResource != null, "deltaNestedResource != null"); Contract.Assert(DeltaHelper.IsDeltaOfT(deltaNestedResource.GetType())); value = deltaNestedResource; return(true); }