/// <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; } } }