// Called via reflection public virtual Task <TResult> ExecuteTypedAsync <TEntity, TRefEntity, TResult>(IRef <TRefEntity> entityRef, MemberInfo memberInfo, string rowKeyRef, string partitionKeyRef, TEntity value, IDictionary <string, EntityProperty> dictionary, AzureTableDriverDynamic repository, Func <Func <Task>, TResult> onSuccessWithRollback, Func <TResult> onFailure) where TRefEntity : IReferenceable { var rowKey = entityRef.StorageComputeRowKey(); var partitionKey = entityRef.StorageComputePartitionKey(rowKey); return(repository.UpdateAsync <TRefEntity, TResult>(rowKey, partitionKey, async(entity, saveAsync) => { var referencedEntityType = typeof(TRefEntity); var fieldToModifyFieldInfo = referencedEntityType .GetFields() .Select( field => { return field .GetAttributesInterface <IPersistInAzureStorageTables>() .Where(attr => attr.Name == this.ReferenceProperty) .First( (attr, next) => field, () => default(FieldInfo)); }) .Where(v => !v.IsDefaultOrNull()) .First(); var valueToMutate = fieldToModifyFieldInfo.GetValue(entity); var valueToMutateType = valueToMutate.GetType(); if (valueToMutateType.IsSubClassOfGeneric(typeof(IRefs <>))) { var references = valueToMutate as IReferences; var idsOriginal = references.ids; var rowKeyId = Guid.Parse(rowKeyRef); if (idsOriginal.Contains(rowKeyId)) { return onSuccessWithRollback(() => 1.AsTask()); } var ids = idsOriginal .Append(rowKeyId) .Distinct() .ToArray(); var refsInstantiatable = typeof(Refs <>) .MakeGenericType(valueToMutateType.GenericTypeArguments.First().AsArray()); var valueMutated = Activator.CreateInstance(refsInstantiatable, ids.AsArray()); fieldToModifyFieldInfo.SetValue(ref entity, valueMutated); var result = await saveAsync(entity); Func <Task> rollback = async() => { bool rolled = await repository.UpdateAsync <TRefEntity, bool>(rowKey, partitionKey, async(entityRollback, saveRollbackAsync) => { fieldToModifyFieldInfo.SetValue(ref entityRollback, valueToMutate); await saveRollbackAsync(entityRollback); return true; }, () => false); }; return onSuccessWithRollback(rollback); } return onFailure(); }, onFailure)); }