Beispiel #1
0
        /// <summary>use location from header to generate initial edit and identity</summary>
        /// <param name="entity">entity in added state</param>
        /// <param name="identity">identity as specified in the response header - location header or dataserviceid header.</param>
        /// <param name="editLink">editlink as specified in the response header - location header.</param>
        internal void AttachLocation(object entity, string identity, Uri editLink)
        {
            Debug.Assert(null != entity, "null != entity");
            Debug.Assert(!String.IsNullOrEmpty(identity), "!String.IsNullOrEmpty(identity)");
            Debug.Assert(editLink != null, "editLink != null");

            this.EnsureIdentityToResource();

            // resource.State == EntityState.Added or Unchanged for second pass of media link
            EntityDescriptor resource = this.entityDescriptors[entity];

            // make sure we got the right one - server could override identity and we may be tracking another one already.
            this.ValidateDuplicateIdentity(identity, resource);

            this.DetachResourceIdentity(resource);

            // While processing the response, we need to find out if the given resource was inserted deep
            // If it was, then we need to change the link state from added to unchanged
            if (resource.IsDeepInsert)
            {
                LinkDescriptor end = this.bindings[resource.GetRelatedEnd()];
                end.State = EntityStates.Unchanged;
            }

            resource.Identity = identity; // always attach the identity
            resource.EditLink = editLink;

            // scenario: sucessfully batch (1) add a new entity and (2) delete an existing entity where the new entity has the same identity as deleted entity
            // where the SaveChanges pass1 will now associate existing identity with new entity
            // but pass2 for the deleted entity will not blindly remove the identity that is now associated with the new identity
            this.identityToDescriptor[identity] = resource;
        }
Beispiel #2
0
        /// <summary>
        /// Writes an entity reference link.
        /// </summary>
        /// <param name="binding">The link descriptor.</param>
        /// <param name="requestMessage">The request message used for writing the payload.</param>
        internal void WriteEntityReferenceLink(LinkDescriptor binding, ODataRequestMessageWrapper requestMessage)
#endif
        {
            using (ODataMessageWriter messageWriter = Serializer.CreateMessageWriter(requestMessage, this.requestInfo, false /*isParameterPayload*/))
            {
                EntityDescriptor targetResource = this.requestInfo.EntityTracker.GetEntityDescriptor(binding.Target);

                Uri targetResourceEditLink;
                if (null != targetResource.GetLatestIdentity())
                {
                    // When we write the uri in the payload, we need to make sure that we write the edit
                    // link in the payload, since the request uri is the edit link of the parent entity.
                    // Think of a read/write service - since the uri is the target link to the parent entity
                    // its better that we write the edit link of the child entity in the payload.
                    targetResourceEditLink = targetResource.GetResourceUri(this.requestInfo.BaseUriResolver, false /*queryLink*/);
                }
                else
                {
#if DEBUG
                    Debug.Assert(isBatch, "we should be cross-referencing entities only in batch scenarios");
#endif
                    targetResourceEditLink = UriUtil.CreateUri("$" + targetResource.ChangeOrder.ToString(CultureInfo.InvariantCulture), UriKind.Relative);
                }

                ODataEntityReferenceLink referenceLink = new ODataEntityReferenceLink();
                referenceLink.Url = targetResourceEditLink;
                messageWriter.WriteEntityReferenceLink(referenceLink);
            }
        }
Beispiel #3
0
        /// <summary>Detach existing link</summary>
        /// <param name="existingLink">link to detach</param>
        /// <param name="targetDelete">true if target is being deleted, false otherwise</param>
        internal override void DetachExistingLink(LinkDescriptor existingLink, bool targetDelete)
        {
            // The target can be null in which case we don't need this check
            if (existingLink.Target != null)
            {
                // Identify the target resource for the link
                EntityDescriptor targetResource = this.GetEntityDescriptor(existingLink.Target);

                // Check if there is a dependency relationship b/w the source and target objects i.e. target can not exist without source link
                // Deep insert requires this check to be made but skip the check if the target object is being deleted
                if (targetResource.IsDeepInsert && !targetDelete)
                {
                    EntityDescriptor parentOfTarget = targetResource.ParentForInsert;
                    if (Object.ReferenceEquals(targetResource.ParentEntity, existingLink.Source) &&
                        (parentOfTarget.State != EntityStates.Deleted ||
                         parentOfTarget.State != EntityStates.Detached))
                    {
                        throw new InvalidOperationException(Strings.Context_ChildResourceExists);
                    }
                }
            }

            if (this.TryRemoveLinkDescriptor(existingLink))
            {   // this link may have been previously detached by a detaching entity
                existingLink.State = EntityStates.Detached;
            }
        }
Beispiel #4
0
        /// <summary>response materialization has an identity to attach to the inserted object</summary>
        /// <param name="entityDescriptorFromMaterializer">entity descriptor containing all the information about the entity from the response.</param>
        /// <param name="metadataMergeOption">mergeOption based on which EntityDescriptor will be merged.</param>
        internal override void AttachIdentity(EntityDescriptor entityDescriptorFromMaterializer, MergeOption metadataMergeOption)
        {   // insert->unchanged
            Debug.Assert(entityDescriptorFromMaterializer != null, "entityDescriptorFromMaterializer != null");

            this.EnsureIdentityToResource();

            // resource.State == EntityState.Added or Unchanged for second pass of media link
            EntityDescriptor trackedEntityDescriptor = this.entityDescriptors[entityDescriptorFromMaterializer.Entity];

            // make sure we got the right one - server could override identity and we may be tracking another one already.
            this.ValidateDuplicateIdentity(entityDescriptorFromMaterializer.Identity, trackedEntityDescriptor);

            this.DetachResourceIdentity(trackedEntityDescriptor);

            // While processing the response, we need to find out if the given resource was inserted deep
            // If it was, then we need to change the link state from added to unchanged
            if (trackedEntityDescriptor.IsDeepInsert)
            {
                LinkDescriptor end = this.bindings[trackedEntityDescriptor.GetRelatedEnd()];
                end.State = EntityStates.Unchanged;
            }

            trackedEntityDescriptor.Identity = entityDescriptorFromMaterializer.Identity; // always attach the identity
            AtomMaterializerLog.MergeEntityDescriptorInfo(trackedEntityDescriptor, entityDescriptorFromMaterializer, true /*mergeInfo*/, metadataMergeOption);
            trackedEntityDescriptor.State = EntityStates.Unchanged;

            // scenario: sucessfully (1) delete an existing entity and (2) add a new entity where the new entity has the same identity as deleted entity
            // where the SaveChanges pass1 will now associate existing identity with new entity
            // but pass2 for the deleted entity will not blindly remove the identity that is now associated with the new identity
            this.identityToDescriptor[entityDescriptorFromMaterializer.Identity] = trackedEntityDescriptor;
        }
Beispiel #5
0
 internal bool IsRelatedEntity(LinkDescriptor related)
 {
     if (this.entity != related.Source)
     {
         return(this.entity == related.Target);
     }
     return(true);
 }
Beispiel #6
0
 internal void AddedLink(MaterializerEntry source, string propertyName, object target)
 {
     if (this.Tracking && (ShouldTrackWithContext(source) && ShouldTrackWithContext(target, this.responseInfo.MaxProtocolVersion)))
     {
         LinkDescriptor item = new LinkDescriptor(source.ResolvedObject, propertyName, target, EntityStates.Added);
         this.links.Add(item);
     }
 }
Beispiel #7
0
 private static void HandleResponsePost(LinkDescriptor linkDescriptor)
 {
     if ((EntityStates.Added != linkDescriptor.State) && ((EntityStates.Modified != linkDescriptor.State) || (linkDescriptor.Target == null)))
     {
         System.Data.Services.Client.Error.ThrowBatchUnexpectedContent(InternalError.LinkNotAddedState);
     }
     linkDescriptor.State = EntityStates.Unchanged;
 }
Beispiel #8
0
 internal void ApplyToContext()
 {
     if (this.Tracking)
     {
         foreach (KeyValuePair <string, ODataEntry> pair in this.identityStack)
         {
             MaterializerEntry entry    = MaterializerEntry.GetEntry(pair.Value);
             bool             mergeInfo = (entry.CreatedByMaterializer || (entry.ResolvedObject == this.insertRefreshObject)) || entry.ShouldUpdateFromPayload;
             EntityDescriptor trackedEntityDescriptor = this.responseInfo.EntityTracker.InternalAttachEntityDescriptor(entry.EntityDescriptor, false);
             MergeEntityDescriptorInfo(trackedEntityDescriptor, entry.EntityDescriptor, mergeInfo, this.mergeOption);
             if (mergeInfo && ((this.responseInfo.MergeOption != MergeOption.PreserveChanges) || (trackedEntityDescriptor.State != EntityStates.Deleted)))
             {
                 trackedEntityDescriptor.State = EntityStates.Unchanged;
             }
         }
         foreach (LinkDescriptor descriptor2 in this.links)
         {
             if (EntityStates.Added == descriptor2.State)
             {
                 if ((EntityStates.Deleted == this.responseInfo.EntityTracker.GetEntityDescriptor(descriptor2.Target).State) || (EntityStates.Deleted == this.responseInfo.EntityTracker.GetEntityDescriptor(descriptor2.Source).State))
                 {
                     this.responseInfo.EntityTracker.DetachExistingLink(descriptor2, false);
                 }
                 else
                 {
                     this.responseInfo.EntityTracker.AttachLink(descriptor2.Source, descriptor2.SourceProperty, descriptor2.Target, this.mergeOption);
                 }
             }
             else
             {
                 if (EntityStates.Modified == descriptor2.State)
                 {
                     object target = descriptor2.Target;
                     if (MergeOption.PreserveChanges == this.mergeOption)
                     {
                         LinkDescriptor descriptor3 = this.responseInfo.EntityTracker.GetLinks(descriptor2.Source, descriptor2.SourceProperty).SingleOrDefault <LinkDescriptor>();
                         if ((descriptor3 != null) && (descriptor3.Target == null))
                         {
                             goto Label_0233;
                         }
                         if (((target != null) && (EntityStates.Deleted == this.responseInfo.EntityTracker.GetEntityDescriptor(target).State)) || (EntityStates.Deleted == this.responseInfo.EntityTracker.GetEntityDescriptor(descriptor2.Source).State))
                         {
                             target = null;
                         }
                     }
                     this.responseInfo.EntityTracker.AttachLink(descriptor2.Source, descriptor2.SourceProperty, target, this.mergeOption);
                 }
                 else
                 {
                     this.responseInfo.EntityTracker.DetachExistingLink(descriptor2, false);
                 }
                 Label_0233 :;
             }
         }
     }
 }
Beispiel #9
0
 protected Uri CreateRequestRelativeUri(LinkDescriptor binding)
 {
     if (binding.IsSourcePropertyCollection && (EntityStates.Added != binding.State))
     {
         EntityDescriptor entityDescriptor = this.RequestInfo.EntityTracker.GetEntityDescriptor(binding.Target);
         Uri uri = DataServiceContext.GenerateEditLinkRelativeUri(binding.SourceProperty, entityDescriptor.Entity, this.RequestInfo.MaxProtocolVersion);
         return(Util.CreateUri("$links" + '/' + CommonUtil.UriToString(uri), UriKind.Relative));
     }
     return(Util.CreateUri("$links" + '/' + binding.SourceProperty, UriKind.Relative));
 }
Beispiel #10
0
 internal void AddLink(LinkDescriptor linkDescriptor)
 {
     try
     {
         this.bindings.Add(linkDescriptor, linkDescriptor);
     }
     catch (ArgumentException)
     {
         throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Context_RelationAlreadyContained);
     }
 }
Beispiel #11
0
        /// <summary>
        /// Invoke this method to notify the log that a link was removed
        /// from a collection.
        /// </summary>
        /// <param name="source">
        /// Instance with the collection from which <paramref name="target"/>
        /// was removed.
        /// </param>
        /// <param name="propertyName">Property name for collection.</param>
        /// <param name="target">Object which was removed.</param>
        internal void RemovedLink(MaterializerEntry source, string propertyName, object target)
        {
            Debug.Assert(source.Entry != null || source.ForLoadProperty, "source != null || source.ForLoadProperty");
            Debug.Assert(propertyName != null, "propertyName != null");

            if (IsEntity(source) && IsEntity(target, this.clientEdmModel))
            {
                Debug.Assert(this.Tracking, "this.Tracking -- otherwise there's an 'if' missing (it happens to be that the assert holds for all current callers");
                LinkDescriptor item = new LinkDescriptor(source.ResolvedObject, propertyName, target, EntityStates.Detached);
                this.links.Add(item);
            }
        }
        /// <summary>
        /// Invoke this method to notify the log that a link was removed
        /// from a collection.
        /// </summary>
        /// <param name="source">
        /// Instance with the collection from which <paramref name="target"/>
        /// was removed.
        /// </param>
        /// <param name="propertyName">Property name for collection.</param>
        /// <param name="target">Object which was removed.</param>
        internal void RemovedLink(AtomEntry source, string propertyName, object target)
        {
            Debug.Assert(source != null, "source != null");
            Debug.Assert(propertyName != null, "propertyName != null");

            if (ShouldTrackWithContext(source) && ShouldTrackWithContext(target))
            {
                Debug.Assert(this.Tracking, "this.Tracking -- otherwise there's an 'if' missing (it happens to be that the assert holds for all current callers");
                LinkDescriptor item = new LinkDescriptor(source.ResolvedObject, propertyName, target, EntityStates.Detached);
                this.links.Add(item);
            }
        }
Beispiel #13
0
        internal static LinkDescriptor RestoreState(
            LinkDescriptorState state, Dictionary <Guid, EntityDescriptor> idToEntityDescriptor)
        {
            var linkDescriptor = new LinkDescriptor(
                idToEntityDescriptor[state.SourceDescriptorId].Entity,
                state.SourceProperty,
                idToEntityDescriptor[state.TargetDescriptorId].Entity);

            linkDescriptor.RestoreState((DescriptorState)state);

            return(linkDescriptor);
        }
Beispiel #14
0
 /// <summary>
 /// Add the given link to the link descriptor collection
 /// </summary>
 /// <param name="linkDescriptor">link descriptor to add</param>
 /// <exception cref="InvalidOperationException">throws argument exception if the link already exists</exception>
 internal void AddLink(LinkDescriptor linkDescriptor)
 {
     Debug.Assert(linkDescriptor != null, "linkDescriptor != null");
     try
     {
         this.EnsureLinkBindings();
         this.bindings.Add(linkDescriptor, linkDescriptor);
     }
     catch (ArgumentException)
     {
         throw Error.InvalidOperation(Strings.Context_RelationAlreadyContained);
     }
 }
Beispiel #15
0
        internal LinkDescriptor DetachReferenceLink(object source, string sourceProperty, object target, MergeOption linkMerge)
        {
            LinkDescriptor existingLink = this.GetLinks(source, sourceProperty).FirstOrDefault <LinkDescriptor>();

            if (existingLink != null)
            {
                if (((target == existingLink.Target) || (linkMerge == MergeOption.AppendOnly)) || ((MergeOption.PreserveChanges == linkMerge) && (EntityStates.Modified == existingLink.State)))
                {
                    return(existingLink);
                }
                this.DetachExistingLink(existingLink, false);
            }
            return(null);
        }
Beispiel #16
0
        /// <summary>
        /// attach the link with the given source, sourceProperty and target.
        /// </summary>
        /// <param name="source">source entity of the link.</param>
        /// <param name="sourceProperty">name of the property on the source entity.</param>
        /// <param name="target">target entity of the link.</param>
        /// <param name="linkMerge">merge option to be used to merge the link if there is an existing link.</param>
        internal override void AttachLink(object source, string sourceProperty, object target, MergeOption linkMerge)
        {
            LinkDescriptor relation = new LinkDescriptor(source, sourceProperty, target, this.model);
            LinkDescriptor existing = this.TryGetLinkDescriptor(source, sourceProperty, target);

            if (existing != null)
            {
                switch (linkMerge)
                {
                case MergeOption.AppendOnly:
                    break;

                case MergeOption.OverwriteChanges:
                    relation = existing;
                    break;

                case MergeOption.PreserveChanges:
                    if ((EntityStates.Added == existing.State) ||
                        (EntityStates.Unchanged == existing.State) ||
                        (EntityStates.Modified == existing.State && null != existing.Target))
                    {
                        relation = existing;
                    }

                    break;

                case MergeOption.NoTracking:     // public API point should throw if link exists
                    throw Error.InvalidOperation(Strings.Context_RelationAlreadyContained);
                }
            }
            else
            {
                if (this.model.GetClientTypeAnnotation(this.model.GetOrCreateEdmType(source.GetType())).GetProperty(sourceProperty, false).IsEntityCollection ||
                    (null == (existing = this.DetachReferenceLink(source, sourceProperty, target, linkMerge))))
                {
                    this.AddLink(relation);
                    this.IncrementChange(relation);
                }
                else if (!((MergeOption.AppendOnly == linkMerge) ||
                           (MergeOption.PreserveChanges == linkMerge && EntityStates.Modified == existing.State)))
                {
                    // AppendOnly doesn't change state or target
                    // OverWriteChanges changes target and state
                    // PreserveChanges changes target if unchanged, leaves modified target and state alone
                    relation = existing;
                }
            }

            relation.State = EntityStates.Unchanged;
        }
Beispiel #17
0
        protected Uri CreateRequestUri(EntityDescriptor sourceResource, LinkDescriptor binding)
        {
            Uri      uri;
            LinkInfo linkInfo = null;

            if (sourceResource.TryGetLinkInfo(binding.SourceProperty, out linkInfo) && ((uri = linkInfo.AssociationLink) != null))
            {
                if (binding.IsSourcePropertyCollection && (EntityStates.Deleted == binding.State))
                {
                    EntityDescriptor entityDescriptor = this.RequestInfo.EntityTracker.GetEntityDescriptor(binding.Target);
                    uri = DataServiceContext.AppendKeysToUri(uri.AbsoluteUri, entityDescriptor.Entity, UriKind.Absolute, this.RequestInfo.MaxProtocolVersion);
                }
                return(uri);
            }
            return(Util.CreateUri(sourceResource.GetResourceUri(this.RequestInfo.BaseUriResolver, false), this.CreateRequestRelativeUri(binding)));
        }
Beispiel #18
0
 protected static string GetLinkHttpMethod(LinkDescriptor link)
 {
     if (!link.IsSourcePropertyCollection)
     {
         if (link.Target == null)
         {
             return("DELETE");
         }
         return("PUT");
     }
     if (EntityStates.Deleted == link.State)
     {
         return("DELETE");
     }
     return("POST");
 }
Beispiel #19
0
        internal void AttachLocation(object entity, string identity, Uri editLink)
        {
            this.EnsureIdentityToResource();
            EntityDescriptor descriptor = this.entityDescriptors[entity];

            this.ValidateDuplicateIdentity(identity, descriptor);
            this.DetachResourceIdentity(descriptor);
            if (descriptor.IsDeepInsert)
            {
                LinkDescriptor descriptor2 = this.bindings[descriptor.GetRelatedEnd(this.maxProtocolVersion)];
                descriptor2.State = EntityStates.Unchanged;
            }
            descriptor.Identity = identity;
            descriptor.EditLink = editLink;
            this.identityToDescriptor[identity] = descriptor;
        }
        /// <summary>
        /// Invoke this method to notify the log that a new link was
        /// added to a collection.
        /// </summary>
        /// <param name="source">
        /// Instance with the collection to which <paramref name="target"/>
        /// was added.
        /// </param>
        /// <param name="propertyName">Property name for collection.</param>
        /// <param name="target">Object which was added.</param>
        internal void AddedLink(AtomEntry source, string propertyName, object target)
        {
            Debug.Assert(source != null, "source != null");
            Debug.Assert(propertyName != null, "propertyName != null");

            if (!this.Tracking)
            {
                return;
            }

            if (ShouldTrackWithContext(source) && ShouldTrackWithContext(target))
            {
                LinkDescriptor item = new LinkDescriptor(source.ResolvedObject, propertyName, target, EntityStates.Added);
                this.links.Add(item);
            }
        }
Beispiel #21
0
        /// <summary>
        /// Invoke this method to notify the log that a new link was
        /// added to a collection.
        /// </summary>
        /// <param name="source">
        /// Instance with the collection to which <paramref name="target"/>
        /// was added.
        /// </param>
        /// <param name="propertyName">Property name for collection.</param>
        /// <param name="target">Object which was added.</param>
        internal void AddedLink(MaterializerEntry source, string propertyName, object target)
        {
            Debug.Assert(source.Entry != null || source.ForLoadProperty, "source != null || source.ForLoadProperty");
            Debug.Assert(propertyName != null, "propertyName != null");

            if (!this.Tracking)
            {
                return;
            }

            if (IsEntity(source) && IsEntity(target, this.clientEdmModel))
            {
                LinkDescriptor item = new LinkDescriptor(source.ResolvedObject, propertyName, target, EntityStates.Added);
                this.links.Add(item);
            }
        }
Beispiel #22
0
        internal void AttachIdentity(EntityDescriptor entityDescriptorFromMaterializer, MergeOption metadataMergeOption)
        {
            this.EnsureIdentityToResource();
            EntityDescriptor descriptor = this.entityDescriptors[entityDescriptorFromMaterializer.Entity];

            this.ValidateDuplicateIdentity(entityDescriptorFromMaterializer.Identity, descriptor);
            this.DetachResourceIdentity(descriptor);
            if (descriptor.IsDeepInsert)
            {
                LinkDescriptor descriptor2 = this.bindings[descriptor.GetRelatedEnd(this.maxProtocolVersion)];
                descriptor2.State = EntityStates.Unchanged;
            }
            descriptor.Identity = entityDescriptorFromMaterializer.Identity;
            AtomMaterializerLog.MergeEntityDescriptorInfo(descriptor, entityDescriptorFromMaterializer, true, metadataMergeOption);
            descriptor.State = EntityStates.Unchanged;
            this.identityToDescriptor[entityDescriptorFromMaterializer.Identity] = descriptor;
        }
Beispiel #23
0
 internal void DetachExistingLink(LinkDescriptor existingLink, bool targetDelete)
 {
     if (existingLink.Target != null)
     {
         EntityDescriptor entityDescriptor = this.GetEntityDescriptor(existingLink.Target);
         if (entityDescriptor.IsDeepInsert && !targetDelete)
         {
             EntityDescriptor parentForInsert = entityDescriptor.ParentForInsert;
             if (object.ReferenceEquals(entityDescriptor.ParentEntity, existingLink.Source) && ((parentForInsert.State != EntityStates.Deleted) || (parentForInsert.State != EntityStates.Detached)))
             {
                 throw new InvalidOperationException(System.Data.Services.Client.Strings.Context_ChildResourceExists);
             }
         }
     }
     if (this.TryRemoveLinkDescriptor(existingLink))
     {
         existingLink.State = EntityStates.Detached;
     }
 }
Beispiel #24
0
        protected ODataRequestMessageWrapper CreateRequest(LinkDescriptor binding)
        {
            if (binding.ContentGeneratedForSave)
            {
                return(null);
            }
            EntityDescriptor entityDescriptor = this.RequestInfo.EntityTracker.GetEntityDescriptor(binding.Source);
            EntityDescriptor descriptor2      = (binding.Target != null) ? this.RequestInfo.EntityTracker.GetEntityDescriptor(binding.Target) : null;
            Uri requestUri = null;

            if (entityDescriptor.GetLatestIdentity() == null)
            {
                if (!this.IsBatch)
                {
                    binding.ContentGeneratedForSave = true;
                    throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Context_LinkResourceInsertFailure, entityDescriptor.SaveError);
                }
                Uri uri = this.CreateRequestRelativeUri(binding);
                requestUri = Util.CreateUri("$" + entityDescriptor.ChangeOrder.ToString(CultureInfo.InvariantCulture) + "/" + CommonUtil.UriToString(uri), UriKind.Relative);
            }
            else
            {
                if ((!this.IsBatch && (descriptor2 != null)) && (descriptor2.GetLatestIdentity() == null))
                {
                    binding.ContentGeneratedForSave = true;
                    throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Context_LinkResourceInsertFailure, descriptor2.SaveError);
                }
                requestUri = this.CreateRequestUri(entityDescriptor, binding);
            }
            ODataRequestMessageWrapper requestMessage = this.CreateRequestMessage(requestUri, GetLinkHttpMethod(binding));

            if (this.IsBatch)
            {
                requestMessage.SetHeader("Content-ID", binding.ChangeOrder.ToString(CultureInfo.InvariantCulture));
            }
            if ((EntityStates.Added == binding.State) || ((EntityStates.Modified == binding.State) && (binding.Target != null)))
            {
                requestMessage.SetHeader("Content-Type", "application/xml");
            }
            WebUtil.SetOperationVersionHeaders(requestMessage, Util.DataServiceVersion1, this.RequestInfo.MaxProtocolVersionAsVersion);
            return(requestMessage);
        }
Beispiel #25
0
        protected bool CreateChangeData(int index, ODataRequestMessageWrapper requestMessage)
        {
            Descriptor descriptor = this.ChangedEntries[index];

            if (descriptor.DescriptorKind == DescriptorKind.Entity)
            {
                EntityDescriptor entityDescriptor = (EntityDescriptor)descriptor;
                descriptor.ContentGeneratedForSave = true;
                return(this.CreateRequestData(entityDescriptor, requestMessage));
            }
            descriptor.ContentGeneratedForSave = true;
            LinkDescriptor binding = (LinkDescriptor)descriptor;

            if ((EntityStates.Added != binding.State) && ((EntityStates.Modified != binding.State) || (binding.Target == null)))
            {
                return(false);
            }
            this.CreateRequestData(binding, requestMessage);
            return(true);
        }
Beispiel #26
0
 internal void WriteEntityReferenceLink(LinkDescriptor binding, ODataRequestMessageWrapper requestMessage)
 {
     using (ODataMessageWriter writer = CreateMessageWriter(requestMessage, this.requestInfo))
     {
         Uri resourceUri;
         EntityDescriptor entityDescriptor = this.requestInfo.EntityTracker.GetEntityDescriptor(binding.Target);
         if (entityDescriptor.GetLatestIdentity() != null)
         {
             resourceUri = entityDescriptor.GetResourceUri(this.requestInfo.BaseUriResolver, false);
         }
         else
         {
             resourceUri = Util.CreateUri("$" + entityDescriptor.ChangeOrder.ToString(CultureInfo.InvariantCulture), UriKind.Relative);
         }
         ODataEntityReferenceLink link = new ODataEntityReferenceLink {
             Url = resourceUri
         };
         writer.WriteEntityReferenceLink(link);
     }
 }
Beispiel #27
0
        internal void AttachLink(object source, string sourceProperty, object target, MergeOption linkMerge)
        {
            LinkDescriptor linkDescriptor = new LinkDescriptor(source, sourceProperty, target, this.maxProtocolVersion);
            LinkDescriptor descriptor2    = this.TryGetLinkDescriptor(source, sourceProperty, target);

            if (descriptor2 != null)
            {
                switch (linkMerge)
                {
                case MergeOption.OverwriteChanges:
                    linkDescriptor = descriptor2;
                    break;

                case MergeOption.PreserveChanges:
                    if (((EntityStates.Added == descriptor2.State) || (EntityStates.Unchanged == descriptor2.State)) || ((EntityStates.Modified == descriptor2.State) && (descriptor2.Target != null)))
                    {
                        linkDescriptor = descriptor2;
                    }
                    break;

                case MergeOption.NoTracking:
                    throw System.Data.Services.Client.Error.InvalidOperation(System.Data.Services.Client.Strings.Context_RelationAlreadyContained);
                }
            }
            else
            {
                ClientEdmModel model = ClientEdmModel.GetModel(this.maxProtocolVersion);
                if (model.GetClientTypeAnnotation(model.GetOrCreateEdmType(source.GetType())).GetProperty(sourceProperty, false).IsEntityCollection || ((descriptor2 = this.DetachReferenceLink(source, sourceProperty, target, linkMerge)) == null))
                {
                    this.AddLink(linkDescriptor);
                    this.IncrementChange(linkDescriptor);
                }
                else if ((linkMerge != MergeOption.AppendOnly) && ((MergeOption.PreserveChanges != linkMerge) || (EntityStates.Modified != descriptor2.State)))
                {
                    linkDescriptor = descriptor2;
                }
            }
            linkDescriptor.State = EntityStates.Unchanged;
        }
Beispiel #28
0
        /// <summary>
        /// find and detach link for reference property
        /// </summary>
        /// <param name="source">source entity</param>
        /// <param name="sourceProperty">source entity property name for target entity</param>
        /// <param name="target">target entity</param>
        /// <param name="linkMerge">link merge option</param>
        /// <returns>true if found and not removed</returns>
        internal LinkDescriptor DetachReferenceLink(object source, string sourceProperty, object target, MergeOption linkMerge)
        {
            Debug.Assert(sourceProperty.IndexOf('/') == -1, "sourceProperty.IndexOf('/') == -1");

            LinkDescriptor existing = this.GetLinks(source, sourceProperty).FirstOrDefault();

            if (null != existing)
            {
                if ((target == existing.Target) ||
                    (MergeOption.AppendOnly == linkMerge) ||
                    (MergeOption.PreserveChanges == linkMerge && EntityStates.Modified == existing.State))
                {
                    return(existing);
                }

                // Since we don't support deep insert on reference property, no need to check for deep insert.
                this.DetachExistingLink(existing, false);
                Debug.Assert(!this.Links.Any(o => (o.Source == source) && (o.SourceProperty == sourceProperty)), "only expecting one");
            }

            return(null);
        }
        /// <summary>Applies all accumulated changes to the associated data context.</summary>
        /// <remarks>The log should be cleared after this method successfully executed.</remarks>
        internal void ApplyToContext()
        {
            Debug.Assert(
                this.mergeOption != MergeOption.OverwriteChanges || this.foundEntriesWithMedia.Count == 0,
                "mergeOption != MergeOption.OverwriteChanges || foundEntriesWithMedia.Count == 0 - we only use the 'entries-with-media' lookaside when we're not in overwrite mode, otherwise we track everything through identity stack");

            if (!this.Tracking)
            {
                return;
            }

            foreach (KeyValuePair <String, AtomEntry> entity in this.identityStack)
            {
                AtomEntry entry = entity.Value;
                if (entry.CreatedByMaterializer ||
                    entry.ResolvedObject == this.insertRefreshObject ||
                    entry.ShouldUpdateFromPayload)
                {
                    // Create a new descriptor and try to attach, if one already exists, get the existing reference instead.
                    EntityDescriptor descriptor = new EntityDescriptor(entity.Key, entry.QueryLink, entry.EditLink, entry.ResolvedObject, null, null, null, entry.ETagText, EntityStates.Unchanged);
                    descriptor = this.context.InternalAttachEntityDescriptor(descriptor, false);

                    // we should always reset descriptor's state to Unchanged (old v1 behaviour)
                    descriptor.State = EntityStates.Unchanged;

                    this.ApplyMediaEntryInformation(entry, descriptor);
                    descriptor.ServerTypeName = entry.TypeName;
                }
                else
                {
                    // Refresh the entity state indirectly by calling TryGetEntity.
                    EntityStates state;
                    this.context.TryGetEntity(entity.Key, entry.ETagText, this.mergeOption, out state);
                }
            }

            // Regardless of the merge mode, media link information should
            // always be applied to the context.
            foreach (AtomEntry entry in this.foundEntriesWithMedia.Values)
            {
                Debug.Assert(entry.ResolvedObject != null, "entry.ResolvedObject != null -- otherwise it wasn't found");
                EntityDescriptor descriptor = this.context.GetEntityDescriptor(entry.ResolvedObject);
                this.ApplyMediaEntryInformation(entry, descriptor);
            }

            foreach (LinkDescriptor link in this.links)
            {
                if (EntityStates.Added == link.State)
                {
                    // Added implies collection
                    if ((EntityStates.Deleted == this.context.GetEntityDescriptor(link.Target).State) ||
                        (EntityStates.Deleted == this.context.GetEntityDescriptor(link.Source).State))
                    {
                        this.context.DeleteLink(link.Source, link.SourceProperty, link.Target);
                    }
                    else
                    {
                        this.context.AttachLink(link.Source, link.SourceProperty, link.Target, this.mergeOption);
                    }
                }
                else if (EntityStates.Modified == link.State)
                {
                    // Modified implies reference
                    object target = link.Target;
                    if (MergeOption.PreserveChanges == this.mergeOption)
                    {
                        LinkDescriptor end = this.context.GetLinks(link.Source, link.SourceProperty).FirstOrDefault();
                        if (null != end && null == end.Target)
                        {
                            // leave the SetLink(link.Source, link.SourceProperty, null)
                            continue;
                        }

                        if ((null != target) && (EntityStates.Deleted == this.context.GetEntityDescriptor(target).State) ||
                            (EntityStates.Deleted == this.context.GetEntityDescriptor(link.Source).State))
                        {
                            target = null;
                        }
                    }

                    this.context.AttachLink(link.Source, link.SourceProperty, target, this.mergeOption);
                }
                else
                {
                    // detach link
                    Debug.Assert(EntityStates.Detached == link.State, "not detached link");
                    this.context.DetachLink(link.Source, link.SourceProperty, link.Target);
                }
            }
        }
Beispiel #30
0
 /// <summary>
 /// Remove the link from the list of tracked link descriptors.
 /// </summary>
 /// <param name="linkDescriptor">link to be removed.</param>
 /// <returns>true if the link was tracked and now removed, otherwise returns false.</returns>
 internal bool TryRemoveLinkDescriptor(LinkDescriptor linkDescriptor)
 {
     this.EnsureLinkBindings();
     return(this.bindings.Remove(linkDescriptor));
 }