Esempio n. 1
0
        /// <summary>
        /// Tracks the SaveChanges method.
        /// </summary>
        /// <param name="data">The data service context data on which to apply state transition.</param>
        /// <param name="options">The options.</param>
        /// <param name="response">The response.</param>
        /// <param name="cachedOperationsFromResponse">The individual operation respones, pre-enumerated and cached.</param>
        /// <param name="tracker">The entity data change tracker to use</param>
        public static void TrackSaveChanges(this DataServiceContextData data, SaveChangesOptions options, DSClient.DataServiceResponse response, IEnumerable <DSClient.OperationResponse> cachedOperationsFromResponse, IEntityDescriptorDataChangeTracker tracker)
        {
            ExceptionUtilities.CheckArgumentNotNull(data, "data");
            ExceptionUtilities.CheckArgumentNotNull(response, "response");
            ExceptionUtilities.CheckArgumentNotNull(cachedOperationsFromResponse, "cachedOperationsFromResponse");
            ExceptionUtilities.CheckArgumentNotNull(tracker, "tracker");

            // Check options and response consistency
            if ((options & SaveChangesOptions.ContinueOnError) == 0)
            {
                ExceptionUtilities.Assert(response.Count(r => r.Error != null) == 0, "Check save changes options and response consistency: no errors in the response when ContinueOnError is off.");
            }

            // because some links will not have separate requests, we need to keep track of all link changes
            var allPendingLinkChanges = data.GetOrderedChanges().OfType <LinkDescriptorData>().ToList();

            // go through the pending changes and update the states based on whether the request succeeded
            foreach (DSClient.ChangeOperationResponse changeResponse in cachedOperationsFromResponse)
            {
                DescriptorData       descriptorData;
                LinkDescriptorData   linkDescriptorData   = null;
                StreamDescriptorData streamDescriptorData = null;
                var entityDescriptor = changeResponse.Descriptor as DSClient.EntityDescriptor;
                if (entityDescriptor != null)
                {
                    descriptorData = data.GetEntityDescriptorData(entityDescriptor.Entity);
                }
                else
                {
                    var linkDescriptor = changeResponse.Descriptor as DSClient.LinkDescriptor;
                    if (linkDescriptor != null)
                    {
                        linkDescriptorData = data.GetLinkDescriptorData(linkDescriptor.Source, linkDescriptor.SourceProperty, linkDescriptor.Target);
                        descriptorData     = linkDescriptorData;
                        allPendingLinkChanges.Remove(linkDescriptorData);
                    }
                    else
                    {
                        // for stream descriptors, we need to find the parent descriptor, then get the stream descriptor data from it
                        var streamDescriptor = (DSClient.StreamDescriptor)changeResponse.Descriptor;

                        entityDescriptor     = streamDescriptor.EntityDescriptor;
                        streamDescriptorData = data.GetStreamDescriptorData(entityDescriptor.Entity, streamDescriptor.StreamLink.Name);
                        descriptorData       = streamDescriptorData;
                    }
                }

                // don't update states for responses that indicate failure
                if (changeResponse.Error != null)
                {
                    continue;
                }

                // because the request succeeded, make the corresponding updates to the states
                if (descriptorData.State == EntityStates.Deleted ||
                    (linkDescriptorData != null &&
                     linkDescriptorData.State == EntityStates.Modified &&
                     linkDescriptorData.SourceDescriptor.State == EntityStates.Deleted))
                {
                    data.RemoveDescriptorData(descriptorData);
                }
                else
                {
                    // for non-deleted descriptors, we need to update states based on the headers
                    var entityDescriptorData = descriptorData as EntityDescriptorData;
                    if (entityDescriptorData != null)
                    {
                        if (entityDescriptorData.IsMediaLinkEntry && entityDescriptorData.DefaultStreamState == EntityStates.Modified)
                        {
                            entityDescriptorData.DefaultStreamDescriptor.UpdateFromHeaders(changeResponse.Headers);
                            entityDescriptorData.DefaultStreamState = EntityStates.Unchanged;
                        }
                        else
                        {
                            if (entityDescriptorData.IsMediaLinkEntry && entityDescriptorData.DefaultStreamState == EntityStates.Added)
                            {
                                entityDescriptorData.DefaultStreamState = EntityStates.Unchanged;
                            }

                            // because there might have been a reading-entity event for this entity, we need to apply the headers through the tracker
                            tracker.TrackUpdateFromHeaders(entityDescriptorData, changeResponse.Headers);

                            // ensure that all updates are applied before moving to the next response
                            tracker.ApplyPendingUpdates(entityDescriptorData);

                            entityDescriptorData.ParentForInsert         = null;
                            entityDescriptorData.ParentPropertyForInsert = null;
                            entityDescriptorData.InsertLink = null;
                        }
                    }
                    else if (streamDescriptorData != null)
                    {
                        streamDescriptorData.UpdateFromHeaders(changeResponse.Headers);
                    }

                    descriptorData.State = EntityStates.Unchanged;
                }
            }

            // go through each link change that did not have an assocatiated response and update its state
            foreach (var linkDescriptorData in allPendingLinkChanges.OfType <LinkDescriptorData>())
            {
                if (linkDescriptorData.State == EntityStates.Added || linkDescriptorData.State == EntityStates.Modified)
                {
                    linkDescriptorData.State = EntityStates.Unchanged;
                }
            }
        }
        /// <summary>
        /// Tracks the SaveChanges method.
        /// </summary>
        /// <param name="data">The data service context data on which to apply state transition.</param>
        /// <param name="options">The options.</param>
        /// <param name="response">The response.</param>
        /// <param name="cachedOperationsFromResponse">The individual operation respones, pre-enumerated and cached.</param>
        /// <param name="tracker">The entity data change tracker to use</param>
        public static void TrackSaveChanges(this DataServiceContextData data, SaveChangesOptions options, DSClient.DataServiceResponse response, IEnumerable<DSClient.OperationResponse> cachedOperationsFromResponse, IEntityDescriptorDataChangeTracker tracker)
        {
            ExceptionUtilities.CheckArgumentNotNull(data, "data");
            ExceptionUtilities.CheckArgumentNotNull(response, "response");
            ExceptionUtilities.CheckArgumentNotNull(cachedOperationsFromResponse, "cachedOperationsFromResponse");
            ExceptionUtilities.CheckArgumentNotNull(tracker, "tracker");

            // Check options and response consistency
            if ((options & SaveChangesOptions.ContinueOnError) == 0)
            {
                ExceptionUtilities.Assert(response.Count(r => r.Error != null) == 0, "Check save changes options and response consistency: no errors in the response when ContinueOnError is off.");
            }

            // because some links will not have separate requests, we need to keep track of all link changes
            var allPendingLinkChanges = data.GetOrderedChanges().OfType<LinkDescriptorData>().ToList();

            // go through the pending changes and update the states based on whether the request succeeded
            foreach (DSClient.ChangeOperationResponse changeResponse in cachedOperationsFromResponse)
            {
                DescriptorData descriptorData;
                LinkDescriptorData linkDescriptorData = null;
                StreamDescriptorData streamDescriptorData = null;
                var entityDescriptor = changeResponse.Descriptor as DSClient.EntityDescriptor;
                if (entityDescriptor != null)
                {
                    descriptorData = data.GetEntityDescriptorData(entityDescriptor.Entity);
                }
                else
                {
                    var linkDescriptor = changeResponse.Descriptor as DSClient.LinkDescriptor;
                    if (linkDescriptor != null)
                    {
                        linkDescriptorData = data.GetLinkDescriptorData(linkDescriptor.Source, linkDescriptor.SourceProperty, linkDescriptor.Target);
                        descriptorData = linkDescriptorData;
                        allPendingLinkChanges.Remove(linkDescriptorData);
                    }
                    else
                    {
#if WINDOWS_PHONE
                        throw new TaupoNotSupportedException("Stream Descriptors are not supported on Windows Phone");
#else
                        // for stream descriptors, we need to find the parent descriptor, then get the stream descriptor data from it                        
                        var streamDescriptor = (DSClient.StreamDescriptor)changeResponse.Descriptor;
                        
                        entityDescriptor = streamDescriptor.EntityDescriptor;
                        streamDescriptorData = data.GetStreamDescriptorData(entityDescriptor.Entity, streamDescriptor.StreamLink.Name);
                        descriptorData = streamDescriptorData;
#endif
                    }
                }

                // don't update states for responses that indicate failure
                if (changeResponse.Error != null)
                {
                    continue;
                }

                // because the request succeeded, make the corresponding updates to the states
                if (descriptorData.State == EntityStates.Deleted ||
                        (linkDescriptorData != null &&
                        linkDescriptorData.State == EntityStates.Modified &&
                        linkDescriptorData.SourceDescriptor.State == EntityStates.Deleted))
                {
                    data.RemoveDescriptorData(descriptorData);
                }
                else
                {
                    // for non-deleted descriptors, we need to update states based on the headers
                    var entityDescriptorData = descriptorData as EntityDescriptorData;
                    if (entityDescriptorData != null)
                    {
                        if (entityDescriptorData.IsMediaLinkEntry && entityDescriptorData.DefaultStreamState == EntityStates.Modified)
                        {
                            entityDescriptorData.DefaultStreamDescriptor.UpdateFromHeaders(changeResponse.Headers);
                            entityDescriptorData.DefaultStreamState = EntityStates.Unchanged;
                        }
                        else
                        {
                            if (entityDescriptorData.IsMediaLinkEntry && entityDescriptorData.DefaultStreamState == EntityStates.Added)
                            {
                                entityDescriptorData.DefaultStreamState = EntityStates.Unchanged;
                            }

                            // because there might have been a reading-entity event for this entity, we need to apply the headers through the tracker
                            tracker.TrackUpdateFromHeaders(entityDescriptorData, changeResponse.Headers);

                            // ensure that all updates are applied before moving to the next response
                            tracker.ApplyPendingUpdates(entityDescriptorData);

                            entityDescriptorData.ParentForInsert = null;
                            entityDescriptorData.ParentPropertyForInsert = null;
                            entityDescriptorData.InsertLink = null;
                        }
                    }
                    else if (streamDescriptorData != null)
                    {
                        streamDescriptorData.UpdateFromHeaders(changeResponse.Headers);
                    }

                    descriptorData.State = EntityStates.Unchanged;
                }
            }

            // go through each link change that did not have an assocatiated response and update its state
            foreach (var linkDescriptorData in allPendingLinkChanges.OfType<LinkDescriptorData>())
            {
                if (linkDescriptorData.State == EntityStates.Added || linkDescriptorData.State == EntityStates.Modified)
                {
                    linkDescriptorData.State = EntityStates.Unchanged;
                }
            }
        }