private static string GetErrorMessageForValidation(ChangeSetEntry changeSetEntry)
 {
     return string.Format(
         CultureInfo.CurrentCulture,
         "Validation failed for the entity '{0}' with one or more errors: {1}.",
         changeSetEntry.Entity.GetType(),
         string.Join(", ", changeSetEntry.ValidationErrors.Select(vri => ErrorUtility.GetErrorMessageForValidation(vri))));
 }
Пример #2
0
        /// <summary>
        /// Returns a map of composition members to associated child operations for the specified
        /// entity, caching the results.
        /// </summary>
        /// <param name="entity">The entity to get associated changes for.</param>
        /// <returns>The map of child changes.</returns>
        private Dictionary <PropertyDescriptor, IEnumerable <ChangeSetEntry> > GetAssociatedChanges(object entity)
        {
            // first check our cache to see if we've already computed the associated changes
            // for the specified entity.
            Dictionary <PropertyDescriptor, IEnumerable <ChangeSetEntry> > associatedChanges = null;

            if (this._associatedChangesMap == null)
            {
                this._associatedChangesMap = new Dictionary <object, Dictionary <PropertyDescriptor, IEnumerable <ChangeSetEntry> > >();
            }
            else if (this._associatedChangesMap.TryGetValue(entity, out associatedChanges))
            {
                return(associatedChanges);
            }

            // compute the associated changes for the specified entity
            Dictionary <int, ChangeSetEntry> entityOperationMap = this._changeSetEntries.ToDictionary(p => p.Id);

            associatedChanges = new Dictionary <PropertyDescriptor, IEnumerable <ChangeSetEntry> >();
            IEnumerable <PropertyDescriptor> compositionMembers =
                TypeDescriptor.GetProperties(entity.GetType()).Cast <PropertyDescriptor>()
                .Where(p => p.Attributes[typeof(CompositionAttribute)] != null);

            foreach (PropertyDescriptor compositionMember in compositionMembers)
            {
                // first get any current child operations
                List <ChangeSetEntry> associatedChangesList = new List <ChangeSetEntry>();
                ChangeSetEntry        changeSetEntry        = this._changeSetEntries.Single(p => p.Entity == entity);
                if (changeSetEntry.Associations != null)
                {
                    if (changeSetEntry.Associations.ContainsKey(compositionMember.Name))
                    {
                        int[] associatedIds = changeSetEntry.Associations[compositionMember.Name];
                        IEnumerable <ChangeSetEntry> childOperations = associatedIds.Select(p => entityOperationMap[p]);
                        associatedChangesList.AddRange(childOperations);
                    }
                }

                // next get any child delete operations
                if (changeSetEntry.OriginalAssociations != null)
                {
                    if (changeSetEntry.OriginalAssociations.ContainsKey(compositionMember.Name))
                    {
                        int[] originalAssociatedIds = changeSetEntry.OriginalAssociations[compositionMember.Name];
                        IEnumerable <ChangeSetEntry> deletedChildOperations = originalAssociatedIds
                                                                              .Select(p => entityOperationMap[p])
                                                                              .Where(p => p.Operation == DomainOperation.Delete);
                        associatedChangesList.AddRange(deletedChildOperations);
                    }
                }

                associatedChanges[compositionMember] = associatedChangesList;
            }

            this._associatedChangesMap[entity] = associatedChanges;

            return(associatedChanges);
        }
Пример #3
0
        private void VerifyExistsInChangeset(object entity)
        {
            ChangeSetEntry entry = this._changeSetEntries.FirstOrDefault(p => object.ReferenceEquals(entity, p.Entity));

            if (entry == null)
            {
                throw new ArgumentException(Resource.ChangeSet_ChangeSetEntryNotFound, "entity");
            }
        }
Пример #4
0
        /// <summary>
        /// Recursively orders the specified operation and all child operations, adding them to the
        /// <paramref name="orderedOperations"/> list.
        /// </summary>
        /// <param name="operation">The operation to order.</param>
        /// <param name="operationChildMap">Map of operation to child operations.</param>
        /// <param name="orderedOperations">The list of ordered operations.</param>
        private void OrderOperations(ChangeSetEntry operation, Dictionary <ChangeSetEntry, List <ChangeSetEntry> > operationChildMap, List <ChangeSetEntry> orderedOperations)
        {
            // first add the operation
            orderedOperations.Add(operation);

            // recursively add all its children
            List <ChangeSetEntry> childOps;

            if (!operationChildMap.TryGetValue(operation, out childOps))
            {
                return;
            }
            foreach (ChangeSetEntry childOperation in childOps)
            {
                this.OrderOperations(childOperation, operationChildMap, orderedOperations);
            }
        }
Пример #5
0
        /// <summary>
        /// Returns the original unmodified entity for the provided <paramref name="clientEntity"/>.
        /// </summary>
        /// <remarks>
        /// Note that only members marked with <see cref="RoundtripOriginalAttribute"/> will be set
        /// in the returned instance.
        /// </remarks>
        /// <typeparam name="TEntity">The entity type.</typeparam>
        /// <param name="clientEntity">The client modified entity.</param>
        /// <returns>The original unmodified entity for the provided <paramref name="clientEntity"/>.</returns>
        /// <exception cref="ArgumentNullException">if <paramref name="clientEntity"/> is null.</exception>
        /// <exception cref="ArgumentException">if <paramref name="clientEntity"/> is not in the change set.</exception>
        public TEntity GetOriginal <TEntity>(TEntity clientEntity) where TEntity : class
        {
            if (clientEntity == null)
            {
                throw new ArgumentNullException("clientEntity");
            }

            ChangeSetEntry entry = this._changeSetEntries.FirstOrDefault(p => object.ReferenceEquals(p.Entity, clientEntity));

            if (entry == null)
            {
                throw new ArgumentException(Resource.ChangeSet_ChangeSetEntryNotFound);
            }

            if (entry.Operation == DomainOperation.Insert)
            {
                throw new InvalidOperationException(Resource.ChangeSet_OriginalNotValidForInsert);
            }

            return((TEntity)entry.OriginalEntity);
        }
Пример #6
0
        public static ChangeSetEntry GetCustomUpdateChangeSetEntry(OperationContext context, Expression expression, object original)
        {
            context.OperationName = Utility.GetNameFromLambda(expression);
            IEnumerable<object> parameterValues = Utility.GetParametersFromLambda(expression);
            object entity = parameterValues.First();

            ChangeSetEntry changeSetEntry = new ChangeSetEntry(Utility.DefaultChangeSetEntryId, entity, original, DomainOperation.Update);

            DomainOperationEntry domainOperationEntry = context.DomainServiceDescription.GetCustomMethod(entity.GetType(), context.OperationName);
            if (domainOperationEntry == null)
            {
                throw new InvalidOperationException(string.Format(
                    CultureInfo.CurrentCulture,
                    Resources.NoCustomUpdateOperation,
                    context.OperationName,
                    context.DomainServiceDescription.DomainServiceType));
            }
            changeSetEntry.EntityActions = new EntityActionCollection
            {
                { context.OperationName, parameterValues.Skip(1).ToArray() },
            };

            return changeSetEntry;
        }
Пример #7
0
        /// <summary>
        /// Reorders the specified changeset operations to respect compositional hierarchy ordering
        /// rules. For compositional hierarchies, all parent operations are ordered before operations
        /// on their children, recursively.
        /// </summary>
        /// <param name="changeSetEntries">The changeset operations to order.</param>
        /// <returns>The ordered operations.</returns>
        private IEnumerable <ChangeSetEntry> OrderChangeset(IEnumerable <ChangeSetEntry> changeSetEntries)
        {
            Dictionary <int, ChangeSetEntry> cudOpIdMap = changeSetEntries.ToDictionary(p => p.Id);
            Dictionary <ChangeSetEntry, List <ChangeSetEntry> > operationChildMap = new Dictionary <ChangeSetEntry, List <ChangeSetEntry> >();

            // we group by entity type so we can cache per Type computations and lookups
            bool hasComposition = false;

            foreach (var group in changeSetEntries.GroupBy(p => p.Entity.GetType()))
            {
                IEnumerable <PropertyDescriptor> compositionMembers = TypeDescriptor.GetProperties(group.Key).Cast <PropertyDescriptor>().Where(p => p.Attributes[typeof(CompositionAttribute)] != null).ToArray();

                // foreach operation in the changeset, identify all child operations
                // and add them to a map of operation to child operations
                foreach (ChangeSetEntry operation in group)
                {
                    foreach (PropertyDescriptor compositionMember in compositionMembers)
                    {
                        hasComposition = true;

                        // add any current associations
                        List <int> childIds = new List <int>();
                        if (operation.Associations != null)
                        {
                            if (operation.Associations.ContainsKey(compositionMember.Name))
                            {
                                childIds.AddRange(operation.Associations[compositionMember.Name]);
                            }
                        }

                        // add any original associations
                        if (operation.OriginalAssociations != null)
                        {
                            if (operation.OriginalAssociations.ContainsKey(compositionMember.Name))
                            {
                                childIds.AddRange(operation.OriginalAssociations[compositionMember.Name]);
                            }
                        }

                        // foreach identified child operation, set the parent
                        // and build the composition maps
                        foreach (int id in childIds.Distinct())
                        {
                            // find the operation corresponding to the child entry
                            ChangeSetEntry childOperation = null;
                            if (!cudOpIdMap.TryGetValue(id, out childOperation))
                            {
                                continue;
                            }

                            // set the parent of this operation
                            if (childOperation.ParentOperation != null)
                            {
                                // an child operation can only have a single parent
                                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resource.ChangeSet_ChildHasMultipleParents, childOperation.Id));
                            }
                            childOperation.ParentOperation = operation;

                            // add the current operation to the list of child operations
                            // for the current operation
                            List <ChangeSetEntry> currChildOps;
                            if (!operationChildMap.TryGetValue(operation, out currChildOps))
                            {
                                currChildOps = new List <ChangeSetEntry>();
                                operationChildMap[operation] = currChildOps;
                            }
                            currChildOps.Add(childOperation);
                        }
                    }
                }
            }

            if (!hasComposition)
            {
                // there were no compositions, so leave the original changeset
                // as is
                return(changeSetEntries);
            }

            // For each "root" operation with no child operations, recursively add
            // all child operations in a recursive preorder traversal from each root
            List <ChangeSetEntry>        orderedOperations = new List <ChangeSetEntry>();
            IEnumerable <ChangeSetEntry> rootOperations    = changeSetEntries.Where(p => p.ParentOperation == null);

            foreach (ChangeSetEntry operation in rootOperations)
            {
                this.OrderOperations(operation, operationChildMap, orderedOperations);
            }

            // now add any remaining operations
            return(orderedOperations.Union(changeSetEntries).ToArray());
        }
Пример #8
0
 public static ChangeSet CreateChangeSet(ChangeSetEntry entry)
 {
     return new ChangeSet(new[] { entry });
 }
 private static string GetErrorMessageForConflicts(ChangeSetEntry changeSetEntry)
 {
     return string.Format(
         CultureInfo.CurrentCulture,
         "There are conflicts for one or more members on the entity '{0}': {1}.",
         changeSetEntry.Entity.GetType(),
         string.Join(", ", changeSetEntry.ConflictMembers));
 }
        /// <summary>
        /// Helper method performs a submit operation against a given proxy instance.
        /// </summary>
        /// <param name="domainService">The type of <see cref="DomainService"/> to perform this query operation against.</param>
        /// <param name="context">The current context.</param>
        /// <param name="domainServiceInstances">The list of tracked <see cref="DomainService"/> instances that any newly created
        /// <see cref="DomainServices"/> will be added to.</param>
        /// <param name="currentOriginalEntityMap">The mapping of current and original entities used with the utility <see cref="DomainServiceProxy.AssociateOriginal"/> method.</param>
        /// <param name="entity">The entity being submitted.</param>
        /// <param name="operationName">The name of the submit operation. For CUD operations, this can be null.</param>
        /// <param name="parameters">The submit operation parameters.</param>
        /// <param name="domainOperation">The type of submit operation.</param>
        /// <exception cref="ArgumentNullException">if <paramref name="context"/> is null.</exception>
        /// <exception cref="ArgumentNullException">if <paramref name="entity"/> is null.</exception>
        /// <exception cref="OperationException">if operation errors are thrown during execution of the submit operation.</exception>
        public static void Submit(Type domainService, DomainServiceContext context, IList<DomainService> domainServiceInstances, IDictionary<object, object> currentOriginalEntityMap, object entity, string operationName, object[] parameters, DomainOperation domainOperation)
        {
            context = new DomainServiceContext(context, DomainOperationType.Submit);
            DomainService service = CreateDomainServiceInstance(domainService, context, domainServiceInstances);

            object originalEntity = null;
            currentOriginalEntityMap.TryGetValue(entity, out originalEntity);

            // if this is an update operation, regardless of whether original
            // values have been specified, we need to mark the operation as
            // modified
            bool hasMemberChanges = domainOperation == DomainOperation.Update;

            // when custom methods are invoked, the operation type
            // is Update
            if (domainOperation == DomainOperation.Custom)
            {
                domainOperation = DomainOperation.Update;
            }

            ChangeSetEntry changeSetEntry = new ChangeSetEntry(1, entity, originalEntity, domainOperation);
            changeSetEntry.HasMemberChanges = hasMemberChanges;
            if (!string.IsNullOrEmpty(operationName))
            {
                changeSetEntry.EntityActions = new List<Serialization.KeyValue<string, object[]>>(); 
                changeSetEntry.EntityActions.Add(new Serialization.KeyValue<string, object[]>(operationName, parameters));
            }

            ChangeSet changeSet = new ChangeSet(new[] { changeSetEntry });

            service.Submit(changeSet);

            if (changeSetEntry.HasError)
            {
                throw new OperationException(Resource.DomainServiceProxy_OperationError, changeSetEntry.ValidationErrors);
            }
        }