/// <summary>
        /// Instantiates a new Serializer class and calls WriteEntry method on it.
        /// </summary>
        /// <param name="dataServiceContext"></param>
        /// <returns></returns>
        private static Person SetupSerializerAndCallWriteEntry(DataServiceContext dataServiceContext)
        {
            Person person = new Person();
            Address address = new Address();
            Car car1 = new Car();
            person.Cars.Add(car1);
            person.HomeAddress = address;

            dataServiceContext.AttachTo("Cars", car1);
            dataServiceContext.AttachTo("Addresses", address);

            var requestInfo = new RequestInfo(dataServiceContext);
            var serializer = new Serializer(requestInfo);
            var headers = new HeaderCollection();
            var clientModel = new ClientEdmModel(ODataProtocolVersion.V4);
            var entityDescriptor = new EntityDescriptor(clientModel);
            entityDescriptor.State = EntityStates.Added;
            entityDescriptor.Entity = person;
            var requestMessageArgs = new BuildingRequestEventArgs("POST", new Uri("http://www.foo.com/Northwind"), headers, entityDescriptor, HttpStack.Auto);
            var linkDescriptors = new LinkDescriptor[] { new LinkDescriptor(person, "Cars", car1, clientModel), new LinkDescriptor(person, "HomeAddress", address, clientModel) };
            var odataRequestMessageWrapper = ODataRequestMessageWrapper.CreateRequestMessageWrapper(requestMessageArgs, requestInfo);

            serializer.WriteEntry(entityDescriptor, linkDescriptors, odataRequestMessageWrapper);
            return person;
        }
        /// <summary>
        /// Instantiates a new Serializer class and calls WriteEntry method on it.
        /// </summary>
        /// <param name="dataServiceContext"></param>
        /// <returns></returns>
        private static Person SetupSerializerAndCallWriteEntry(DataServiceContext dataServiceContext)
        {
            Person  person  = new Person();
            Address address = new Address();
            Car     car1    = new Car();

            person.Cars.Add(car1);
            person.HomeAddress = address;

            dataServiceContext.AttachTo("Cars", car1);
            dataServiceContext.AttachTo("Addresses", address);

            var requestInfo      = new RequestInfo(dataServiceContext);
            var serializer       = new Serializer(requestInfo);
            var headers          = new HeaderCollection();
            var clientModel      = new ClientEdmModel(ODataProtocolVersion.V4);
            var entityDescriptor = new EntityDescriptor(clientModel);

            entityDescriptor.State  = EntityStates.Added;
            entityDescriptor.Entity = person;
            var requestMessageArgs         = new BuildingRequestEventArgs("POST", new Uri("http://www.foo.com/Northwind"), headers, entityDescriptor, HttpStack.Auto);
            var linkDescriptors            = new LinkDescriptor[] { new LinkDescriptor(person, "Cars", car1, clientModel), new LinkDescriptor(person, "HomeAddress", address, clientModel) };
            var odataRequestMessageWrapper = ODataRequestMessageWrapper.CreateRequestMessageWrapper(requestMessageArgs, requestInfo);

            serializer.WriteEntry(entityDescriptor, linkDescriptors, odataRequestMessageWrapper);
            return(person);
        }
예제 #3
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;
            trackedEntityDescriptor.PropertiesToSerialize.Clear();

            // scenario: successfully (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;
        }
예제 #4
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 OData-EntityId header.</param>
        /// <param name="editLink">editlink as specified in the response header - location header.</param>
        internal void AttachLocation(object entity, Uri identity, Uri editLink)
        {
            Debug.Assert(entity != null, "null != entity");
            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: successfully 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;
        }
예제 #5
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;
            }
        }
예제 #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);
     }
 }
예제 #7
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);
     }
 }
예제 #8
0
        /// <summary>
        /// Gets string representation of the specified link descriptor.
        /// </summary>
        /// <param name="linkDescriptor">The link descriptor.</param>
        /// <returns>The string representation of the specified link descriptor.</returns>
        public static string ToTraceString(this LinkDescriptor linkDescriptor)
        {
            ExceptionUtilities.CheckArgumentNotNull(linkDescriptor, "linkDescriptor");

            return(string.Format(
                       CultureInfo.InvariantCulture,
                       "{{ State = {0}, Source = {{ {1} }}, SourceProperty = '{2}', Target = {{ {3} }} }}",
                       linkDescriptor.State,
                       linkDescriptor.Source,
                       linkDescriptor.SourceProperty,
                       linkDescriptor.Target == null ? "null" : linkDescriptor.Target));
        }
예제 #9
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);
            }
        }
예제 #10
0
            private string ToTraceString(LinkDescriptor descriptor)
            {
                ExceptionUtilities.Assert(descriptor != null, "descriptor cannot be null.");

                return(string.Format(
                           CultureInfo.InvariantCulture,
                           "{{ State = {0}, Source = {{ Identity = {1} }}, SourceProperty = '{2}', Target = {{ {3} }} }}",
                           descriptor.State,
                           this.context.GetEntityDescriptor(descriptor.Source).Identity,
                           descriptor.SourceProperty,
                           descriptor.Target == null ? "null" : "Identity = " + this.context.GetEntityDescriptor(descriptor.Target).Identity));
            }
예제 #11
0
        private void ApplicationStartup(object sender, StartupEventArgs e)
        {
            var destinationPath = Path.GetDirectoryName(e.Args[0]);
            var linkDescriptor  = new LinkDescriptor {
                DestinationPath = destinationPath
            };
            var initialStep  = new LinkTypeWizardStep(linkDescriptor);
            var wizardWindow = new WizardWindow("Создание ссылки", initialStep);

            MainWindow = wizardWindow;
            MainWindow.Show();
        }
예제 #12
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);
     }
 }
        public void SerializeEnity_NullableEnumProperty()
        {
            MyEntity1 myEntity1 = new MyEntity1()
            {
                ID                 = 2,
                MyColorValue       = null,
                MyFlagsColorValue  = MyFlagsColor.Blue,
                ComplexValue1Value = new ComplexValue1()
                {
                    MyColorValue = MyColor.Green, MyFlagsColorValue = MyFlagsColor.Red
                },
                MyFlagsColorCollection1 = new List <MyFlagsColor>()
                {
                    MyFlagsColor.Blue, MyFlagsColor.Red, MyFlagsColor.Red
                },
                MyColorCollection = new List <MyColor?> {
                    MyColor.Green, null
                }
            };

            DataServiceContext dataServiceContext = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));

            dataServiceContext.EnableAtom = true;
            dataServiceContext.Format.UseAtom();
            dataServiceContext.AttachTo("MyEntitySet1", myEntity1);

            var requestInfo      = new RequestInfo(dataServiceContext);
            var serializer       = new Serializer(requestInfo);
            var headers          = new HeaderCollection();
            var clientModel      = new ClientEdmModel(ODataProtocolVersion.V4);
            var entityDescriptor = new EntityDescriptor(clientModel);

            entityDescriptor.State  = EntityStates.Added;
            entityDescriptor.Entity = myEntity1;
            var requestMessageArgs         = new BuildingRequestEventArgs("POST", new Uri("http://www.foo.com/Northwind"), headers, entityDescriptor, HttpStack.Auto);
            var linkDescriptors            = new LinkDescriptor[] { };
            var odataRequestMessageWrapper = ODataRequestMessageWrapper.CreateRequestMessageWrapper(requestMessageArgs, requestInfo);

            serializer.WriteEntry(entityDescriptor, linkDescriptors, odataRequestMessageWrapper);

            // read result:
            MemoryStream stream = (MemoryStream)(odataRequestMessageWrapper.CachedRequestStream.Stream);

            stream.Position = 0;

            string payload = (new StreamReader(stream)).ReadToEnd();

            payload = Regex.Replace(payload, "<updated>[^<]*</updated>", "");
            payload.Should().Be(
                "{\"ComplexValue1Value\":{\"MyColorValue\":\"Green\",\"MyFlagsColorValue\":\"Red\",\"StringValue\":null},\"ID\":2,\"MyColorCollection\":[\"Green\",null],\"MyColorValue\":null,\"MyFlagsColorCollection1\":[\"Blue\",\"Red\",\"Red\"],\"MyFlagsColorValue\":\"Blue\"}");
        }
예제 #14
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 ((existing.State == EntityStates.Added) ||
                        (existing.State == EntityStates.Unchanged) ||
                        (existing.State == EntityStates.Modified && existing.Target != null))
                    {
                        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, UndeclaredPropertyBehavior.ThrowException).IsEntityCollection ||
                    ((existing = this.DetachReferenceLink(source, sourceProperty, target, linkMerge)) == null))
                {
                    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;
        }
예제 #15
0
        private void VerifyDescriptor(DescriptorData expected, Descriptor actual, int responseOrder)
        {
            EntityDescriptorData entityDescriptorData = expected as EntityDescriptorData;
            LinkDescriptorData   linkDescriptorData   = expected as LinkDescriptorData;
            StreamDescriptorData streamDescriptorData = expected as StreamDescriptorData;

            if (entityDescriptorData != null)
            {
                EntityDescriptor entityDescriptor = actual as EntityDescriptor;
                this.Assert.IsNotNull(entityDescriptor, GetVerificationFailureMessage(responseOrder, "Unexpected descriptor type:\r\nExpected: {0}\r\nActual:   {1}\r\nExpected descriptor data: {2}.", typeof(EntityDescriptor).Name, actual.GetType().Name, entityDescriptorData));

                this.Assert.AreSame(
                    entityDescriptorData.Entity,
                    entityDescriptor.Entity,
                    GetVerificationFailureMessage(responseOrder, "Entity verification failed for the entity descriptor data: {0}.", expected));
            }
            else if (linkDescriptorData != null)
            {
                LinkDescriptor linkDescriptor = actual as LinkDescriptor;
                this.Assert.IsNotNull(linkDescriptor, GetVerificationFailureMessage(responseOrder, "Unexpected descriptor type:\r\nExpected: {0}\r\nActual:   {1}\r\nExpected descriptor data: {2}.", typeof(LinkDescriptor).Name, actual.GetType().Name, linkDescriptorData));

                bool notMatch = linkDescriptorData.SourceDescriptor.Entity != linkDescriptor.Source ||
                                (linkDescriptorData.TargetDescriptor == null && linkDescriptor.Target != null) ||
                                (linkDescriptorData.TargetDescriptor != null && linkDescriptorData.TargetDescriptor.Entity != linkDescriptor.Target) ||
                                linkDescriptorData.SourcePropertyName != linkDescriptor.SourceProperty;

                this.Assert.IsFalse(notMatch, GetVerificationFailureMessage(responseOrder, "Link verification failed.\r\nExpected: {0}\r\nActual:   {1}", linkDescriptorData, linkDescriptor.ToTraceString()));
            }
            else
            {
#if WINDOWS_PHONE
                throw new TaupoNotSupportedException("StreamDescriptors are not supported on Windows Phone");
#else
                ExceptionUtilities.CheckObjectNotNull(streamDescriptorData, "Expected was not an entity, link, or stream descriptor: {0}", expected);

                StreamDescriptor streamDescriptor = actual as StreamDescriptor;

                this.Assert.IsNotNull(streamDescriptor, GetVerificationFailureMessage(responseOrder, "Unexpected descriptor type:\r\nExpected: {0}\r\nActual:   {1}\r\nExpected descriptor data: {2}.", typeof(StreamDescriptor).Name, actual.GetType().Name, streamDescriptorData));

                this.Assert.AreEqual(streamDescriptorData.State.ToProductEnum(), streamDescriptor.State, GetVerificationFailureMessage(responseOrder, "Stream descriptor state verification failed."));
                this.Assert.AreEqual(streamDescriptorData.Name, streamDescriptor.StreamLink.Name, GetVerificationFailureMessage(responseOrder, "Stream descriptor name verification failed."));
                this.Assert.AreEqual(streamDescriptorData.ETag, streamDescriptor.StreamLink.ETag, GetVerificationFailureMessage(responseOrder, "Stream descriptor etag verification failed."));
                this.Assert.AreEqual(streamDescriptorData.ContentType, streamDescriptor.StreamLink.ContentType, GetVerificationFailureMessage(responseOrder, "Stream descriptor content type verification failed."));
                this.Assert.AreEqual(streamDescriptorData.EditLink, streamDescriptor.StreamLink.EditLink, GetVerificationFailureMessage(responseOrder, "Stream descriptor edit link verification failed."));
                this.Assert.AreEqual(streamDescriptorData.SelfLink, streamDescriptor.StreamLink.SelfLink, GetVerificationFailureMessage(responseOrder, "Stream descriptor self link verification failed."));
#endif
            }
        }
        public void SerializeEnity_TwoNavigationLinksInJsonFormat()
        {
            var person = new Person
            {
                ID   = 100,
                Name = "Bing",
            };

            var car1 = new Car {
                ID = 1001
            };
            var car2 = new Car {
                ID = 1002
            };

            DataServiceContext dataServiceContext = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));

            dataServiceContext.AttachTo("Persons", person);
            dataServiceContext.AttachTo("Cars", car1);
            dataServiceContext.AttachTo("Cars", car2);
            dataServiceContext.AddLink(person, "Cars", car1);
            dataServiceContext.AddLink(person, "Cars", car2);

            var requestInfo      = new RequestInfo(dataServiceContext);
            var serializer       = new Serializer(requestInfo);
            var headers          = new HeaderCollection();
            var clientModel      = new ClientEdmModel(ODataProtocolVersion.V4);
            var entityDescriptor = new EntityDescriptor(clientModel);

            entityDescriptor.State    = EntityStates.Added;
            entityDescriptor.Entity   = person;
            entityDescriptor.EditLink = new Uri("http://www.foo.com/custom");
            var requestMessageArgs         = new BuildingRequestEventArgs("POST", new Uri("http://www.foo.com/Northwind"), headers, entityDescriptor, HttpStack.Auto);
            var linkDescriptors            = new LinkDescriptor[] { new LinkDescriptor(person, "Cars", car1, clientModel), new LinkDescriptor(person, "Cars", car2, clientModel) };
            var odataRequestMessageWrapper = ODataRequestMessageWrapper.CreateRequestMessageWrapper(requestMessageArgs, requestInfo);

            serializer.WriteEntry(entityDescriptor, linkDescriptors, odataRequestMessageWrapper);

            // read result:
            MemoryStream stream = (MemoryStream)(odataRequestMessageWrapper.CachedRequestStream.Stream);

            stream.Position = 0;

            string payload = (new StreamReader(stream)).ReadToEnd();

            payload.Should().Be(
                "{\"ID\":100,\"Name\":\"Bing\",\"[email protected]\":[\"http://www.odata.org/service.svc/Cars(1001)\",\"http://www.odata.org/service.svc/Cars(1002)\"]}");
        }
예제 #17
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);
            }
        }
예제 #18
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 (existing != null)
            {
                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);
        }
        private string SerializeEntity <T>(string entitySetName, T entityObject)
        {
            this.context.AddObject(entitySetName, entityObject);
            var requestInfo      = new RequestInfo(this.context);
            var serializer       = new Serializer(requestInfo);
            var headers          = new HeaderCollection();
            var entityDescriptor = new EntityDescriptor(this.clientEdmModel);

            entityDescriptor.State  = EntityStates.Added;
            entityDescriptor.Entity = entityObject;
            var requestMessageArgs         = new BuildingRequestEventArgs("POST", new Uri("http://tempuri.org"), headers, entityDescriptor, HttpStack.Auto);
            var odataRequestMessageWrapper = ODataRequestMessageWrapper.CreateRequestMessageWrapper(requestMessageArgs, requestInfo);
            var linkDescriptors            = new LinkDescriptor[0];

            serializer.WriteEntry(entityDescriptor, linkDescriptors, odataRequestMessageWrapper);

            var stream       = (MemoryStream)odataRequestMessageWrapper.CachedRequestStream.Stream;
            var streamReader = new StreamReader(stream);
            var body         = streamReader.ReadToEnd();

            return(body);
        }
예제 #20
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 targetReferenceLink = targetResource.GetLatestIdentity();

                if (targetReferenceLink == null)
                {
#if DEBUG
                    Debug.Assert(isBatch, "we should be cross-referencing entities only in batch scenarios");
#endif
                    targetReferenceLink = UriUtil.CreateUri("$" + targetResource.ChangeOrder.ToString(CultureInfo.InvariantCulture), UriKind.Relative);
                }

                ODataEntityReferenceLink referenceLink = new ODataEntityReferenceLink();
                referenceLink.Url = targetReferenceLink;
                messageWriter.WriteEntityReferenceLink(referenceLink);
            }
        }
예제 #21
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;
        }
예제 #22
0
    // Introduce 90-degree angle vertices to the lines if they're not fully straight
    void FixLines()
    {
        // Straight line tolerance expressed as maximum vertical offset between two vertices of the line
        const float verticalTolerance = 10.0f;

        const float connectorPadding = 20.0f;

        LineRenderer[] lines = lineCanvas.GetComponentsInChildren <LineRenderer>();
        foreach (LineRenderer line in lines)
        {
            LinkDescriptor linkDesc   = line.GetComponent <LinkDescriptor>();
            Vector2        finalPoint = line.GetPosition(1);

            if (Mathf.Abs(line.GetPosition(0).y - finalPoint.y) > verticalTolerance)
            {
                RectTransform prevTransform = linkDesc.prev.GetComponent <RectTransform>(), nextTransform = linkDesc.next.GetComponent <RectTransform>();
                Rect          prevRect = prevTransform.rect, nextRect = nextTransform.rect;
                bool          isFirstBodyNodeLink = (linkDesc.prev.GetComponent <CodeBlock>() && linkDesc.prev.GetComponent <CodeBlock>().FirstBodyNodeObject == linkDesc.next.gameObject) || (linkingNodes && linkingNodeMode == LinkingMode.FirstBodyNode && prevTransform.gameObject == linkingNodesObjects[0] && nextTransform.name == "previewNode");
                if (prevTransform.localPosition.x + prevRect.width + connectorPadding < nextTransform.localPosition.x)
                {
                    line.positionCount = 4 - (isFirstBodyNodeLink ? 1 : 0);
                    int i = 1;
                    if (isFirstBodyNodeLink)
                    {
                        line.SetPosition(i++, new Vector2((prevTransform.localPosition.x), finalPoint.y));
                    }
                    else
                    {
                        line.SetPosition(i++, new Vector2((nextTransform.localPosition.x - nextRect.width / 2.0f) - connectorPadding, line.GetPosition(0).y));
                        line.SetPosition(i++, new Vector2((nextTransform.localPosition.x - nextRect.width / 2.0f) - connectorPadding, finalPoint.y));
                    }

                    // If we're rendering link preview, make it point to the rect center so that it aligns with the cursor
                    if (nextTransform.name == "previewNode")
                    {
                        line.SetPosition(i++, new Vector2(nextTransform.localPosition.x, finalPoint.y));
                    }
                    else
                    {
                        line.SetPosition(i++, new Vector2((nextTransform.localPosition.x - nextRect.width / 2.0f), finalPoint.y));
                    }
                }
                else
                {
                    line.positionCount = 6 - (isFirstBodyNodeLink ? 1 : 0);
                    int i = 1;
                    if (isFirstBodyNodeLink)
                    {
                        line.SetPosition(i++, new Vector2((prevTransform.localPosition.x), (prevTransform.localPosition.y + nextTransform.localPosition.y) / 2.0f));
                    }
                    else
                    {
                        line.SetPosition(i++, new Vector2((prevTransform.localPosition.x + prevRect.width / 2.0f) + connectorPadding, line.GetPosition(0).y));
                        line.SetPosition(i++, new Vector2((prevTransform.localPosition.x + prevRect.width / 2.0f) + connectorPadding, (prevTransform.localPosition.y + nextTransform.localPosition.y) / 2.0f));
                    }
                    line.SetPosition(i++, new Vector2((nextTransform.localPosition.x - nextRect.width / 2.0f) - connectorPadding, (prevTransform.localPosition.y + nextTransform.localPosition.y) / 2.0f));
                    line.SetPosition(i++, new Vector2((nextTransform.localPosition.x - nextRect.width / 2.0f) - connectorPadding, finalPoint.y));

                    // If we're rendering link preview, make it point to the rect center so that it aligns with the cursor
                    if (nextTransform.name == "previewNode")
                    {
                        line.SetPosition(i++, new Vector2(nextTransform.localPosition.x, finalPoint.y));
                    }
                    else
                    {
                        line.SetPosition(i++, new Vector2((nextTransform.localPosition.x - nextRect.width / 2.0f), finalPoint.y));
                    }
                }
            }
        }
    }
예제 #23
0
 internal bool TryRemoveLinkDescriptor(LinkDescriptor linkDescriptor)
 {
     return this.bindings.Remove(linkDescriptor);
 }
예제 #24
0
 public LinkDescriptorWrapper(LinkDescriptor ed)
 {
     this.State          = ed.State;
     this.SourceProperty = ed.SourceProperty;
     //this.Entity = ed.Entity;
 }
예제 #25
0
    // Update is called once per frame
    void Update()
    {
        Vector3[] corners = { Vector3.zero, Vector3.zero, Vector3.zero, Vector3.zero };

        // Get screen-space rectangle of the node
        rectTransform.GetWorldCorners(corners);
        Rect    nodeRect = new Rect(corners[0], corners[2] - corners[0]);
        Vector2 pointer  = Input.mousePosition;

        UpdateHUD(pointer, nodeRect);

        // Drag if LMB held down and inside the node rectangle
        if (Input.GetKeyDown(KeyCode.Mouse0) && nodeRect.Contains(pointer) || isDragged)
        {
            Drag(pointer);
        }
        if (Input.GetKeyUp(KeyCode.Mouse0))
        {
            isDragged          = false;
            nodeAlreadyDragged = false;
        }

        // Have previewNode follow the mouse
        // This is used to show a preview of the node connection as the user is moving the mouse to the next/firstBody node
        if (name == "previewNode")
        {
            rectTransform.SetPositionAndRotation(pointer, Quaternion.identity);
        }

        // Check if this Draggable isn't part of another node and isn't the previewNode.
        if (transform.parent == owner.elementContainer.transform && name != "previewNode")
        {
            // Linking nodes

            // coords of the point needed to be right-clicked in order to select a firstBodyNode
            Vector2 firstBodyHook = new Vector2(nodeRect.xMin + nodeRect.width / 2.0f, nodeRect.yMax);
            Vector2 nextHook      = new Vector2(nodeRect.xMax, nodeRect.yMin + nodeRect.height / 2.0f);

            if (!owner.linkingNodes && clueHud.hoveredNode == gameObject)
            {
                if (Vector2.Distance(pointer, firstBodyHook) < Vector2.Distance(pointer, nextHook))
                {
                    clueHud.potentialLinkingMode = EditorProgram.LinkingMode.FirstBodyNode;
                }
                else
                {
                    clueHud.potentialLinkingMode = EditorProgram.LinkingMode.NextNode;
                }
            }

            if (Input.GetKeyUp(KeyCode.Mouse1) && nodeRect.Contains(pointer))
            {
                if (!owner.linkingNodes)
                {
                    // Make sure we're not trying to link FROM ProgramEnd
                    if (GetComponent <ProgramEnd>() == null)
                    {
                        // Deteremining the right LinkingMode for CodeBlocks
                        if (GetComponent <CodeBlock>() != null)
                        {
                            // Check if it's node A and not node B
                            if (owner.linkingNodesObjects[0] == null)
                            {
                                if (Vector2.Distance(pointer, firstBodyHook) < Vector2.Distance(pointer, nextHook))
                                {
                                    owner.linkingNodeMode = EditorProgram.LinkingMode.FirstBodyNode;
                                }
                                else
                                {
                                    owner.linkingNodeMode = EditorProgram.LinkingMode.NextNode;
                                }
                            }
                        }
                        // By default, non-CodeBlocks have NextNode linkingmode
                        else
                        {
                            owner.linkingNodeMode = EditorProgram.LinkingMode.NextNode;
                        }

                        owner.linkingPreviewLine = new GameObject(
                            $"{(owner.linkingNodeMode == EditorProgram.LinkingMode.NextNode ? "nextNode" : "firstBody")}:{gameObject.name}->previewNode",
                            new Type[] { typeof(LineRenderer), typeof(LinkDescriptor) }
                            );
                        owner.linkingPreviewLine.transform.SetParent(owner.lineCanvas.transform, false);
                        LinkDescriptor linkDesc = owner.linkingPreviewLine.GetComponent <LinkDescriptor>();
                        linkDesc.prev = gameObject;
                        linkDesc.next = owner.linkingPreviewNode;
                        LineRenderer lineRenderer = owner.linkingPreviewLine.GetComponent <LineRenderer>();
                        lineRenderer.material      = EditorProgram.lineMaterial;
                        lineRenderer.useWorldSpace = false;

                        owner.linkingNodes           = true;
                        owner.linkingNodesObjects[0] = gameObject;
                    }
                }
                else
                {
                    owner.linkingNodesObjects[1] = gameObject;
                    owner.LinkCurrentlySelectedObjects();
                }
            }

            // Other events: Deleting node
            if (Input.GetKeyDown(KeyCode.Delete) && nodeRect.Contains(pointer) && GetComponent <NodeBase>() && !owner.editingNodeProperty && !GetComponent <ProgramEnd>() && !GetComponent <ProgramStart>())
            {
                clueHud.SetCurrentPrompt(null, null);
                GetComponent <NodeBase>().DeleteNode();
            }

            if (GetComponent <NodeBase>())
            {
                if (!owner.editingNodeProperty && owner.EditorActive && !GetComponent <ProgramStart>() && !GetComponent <ProgramEnd>() && !owner.choosingFunctionCall && !owner.choosingNode)
                {
                    if (nodeRect.Contains(pointer))
                    {
                        if (owner.nodeClipboard)
                        {
                            clueHud.CopyPasteNodePrompt.SetActive(true);
                            clueHud.CopyNodePrompt.SetActive(false);
                            clueHud.PasteNodePrompt.SetActive(false);
                        }
                        else
                        {
                            clueHud.CopyPasteNodePrompt.SetActive(false);
                            clueHud.CopyNodePrompt.SetActive(true);
                            clueHud.PasteNodePrompt.SetActive(false);
                        }
                    }
                    else if (clueHud.hoveredNode == gameObject)
                    {
                        if (owner.nodeClipboard)
                        {
                            clueHud.CopyPasteNodePrompt.SetActive(false);
                            clueHud.CopyNodePrompt.SetActive(false);
                            clueHud.PasteNodePrompt.SetActive(true);
                        }
                        else
                        {
                            clueHud.CopyPasteNodePrompt.SetActive(false);
                            clueHud.CopyNodePrompt.SetActive(false);
                            clueHud.PasteNodePrompt.SetActive(false);
                        }
                    }
                    else if (clueHud.hoveredNode == null)
                    {
                        if (owner.nodeClipboard)
                        {
                            clueHud.CopyPasteNodePrompt.SetActive(false);
                            clueHud.CopyNodePrompt.SetActive(false);
                            clueHud.PasteNodePrompt.SetActive(true);
                        }
                        else
                        {
                            clueHud.CopyPasteNodePrompt.SetActive(false);
                            clueHud.CopyNodePrompt.SetActive(false);
                            clueHud.PasteNodePrompt.SetActive(false);
                        }
                    }
                }

                if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl))
                {
                    // Other events: Copying a node
                    if (Input.GetKeyDown(KeyCode.C) && !owner.editingNodeProperty && nodeRect.Contains(pointer) && !GetComponent <ProgramStart>() && !GetComponent <ProgramEnd>())
                    {
                        owner.nodeClipboard = gameObject;

                        clueHud.CopyPasteNodePrompt.SetActive(true);
                        clueHud.CopyNodePrompt.SetActive(false);
                        clueHud.PasteNodePrompt.SetActive(false);
                    }
                    // Other events: Pasting a node
                    else if (Input.GetKeyDown(KeyCode.V) && !owner.editingNodeProperty && owner.nodeClipboard == gameObject)
                    {
                        GameObject copy     = owner.AddNode(owner.nodeClipboard, (pointer.x), pointer.y);
                        NodeBase   copyNode = copy.GetComponent <NodeBase>();
                        copyNode.NextNodeObject = null;
                        copyNode.nextNode       = null;
                        copyNode.PrevNodeObject = null;
                        copyNode.prevNode       = null;
                        copyNode.ownerLoop      = null;

                        if (copyNode.GetComponent <LogicalBlock>())
                        {
                            copyNode.GetComponent <LogicalBlock>().firstBodyNode       = null;
                            copyNode.GetComponent <LogicalBlock>().FirstBodyNodeObject = null;
                        }

                        int guidStartIndex = copy.name.IndexOf("-");
                        copy.name = copy.name.Replace("(Clone)", "");
                        copy.name = copy.name.Substring(0, guidStartIndex <= 0 ? copy.name.Length : guidStartIndex) + copy.GetInstanceID();
                    }
                }
            }
        }

        // Double-click: usually this is editing a node
        if (Input.GetKeyUp(KeyCode.Mouse0) && nodeRect.Contains(pointer))
        {
            clickCounter++;
            timeSinceClick = 0.0f;
        }
        if (clickCounter >= 2)
        {
            if (transform.parent != owner)
            {
                DoubleClick();
            }
            clickCounter = 0;
        }
        if (timeSinceClick > doubleClickAllowedTime)
        {
            clickCounter = 0;
        }

        timeSinceClick += Time.deltaTime;

        lastFramePointer = pointer;
    }
예제 #26
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));
 }
예제 #27
0
 internal override void DetachExistingLink(LinkDescriptor existingLink, bool targetDelete)
 {
     DetachExistingLinkAction(existingLink, targetDelete);
 }
예제 #28
0
 internal bool IsRelatedEntity(LinkDescriptor related)
 {
     if (this.entity != related.Source)
     {
         return (this.entity == related.Target);
     }
     return true;
 }
예제 #29
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>
 /// <param name="isBatch">True if batch, false otherwise.</param>
 internal void WriteEntityReferenceLink(LinkDescriptor binding, ODataRequestMessageWrapper requestMessage, bool isBatch)
예제 #30
0
        /// <summary>
        /// Validates that the link descriptor source and target have identities.
        /// </summary>
        /// <param name="binding">The binding.</param>
        /// <param name="sourceResource">The source resource.</param>
        /// <param name="targetResource">The target resource.</param>
        private static void ValidateLinkDescriptorSourceAndTargetHaveIdentities(LinkDescriptor binding, EntityDescriptor sourceResource, EntityDescriptor targetResource)
        {
            Debug.Assert(!binding.ContentGeneratedForSave, "already saved link");

            // In non-batch scenarios, the source should always have an identity
            if (null == sourceResource.GetLatestIdentity())
            {
                binding.ContentGeneratedForSave = true;
                Debug.Assert(EntityStates.Added == sourceResource.State, "expected added state");
                throw Error.InvalidOperation(Strings.Context_LinkResourceInsertFailure, sourceResource.SaveError);
            }

            if (null != targetResource && null == targetResource.GetLatestIdentity())
            {
                binding.ContentGeneratedForSave = true;
                Debug.Assert(EntityStates.Added == targetResource.State, "expected added state");
                throw Error.InvalidOperation(Strings.Context_LinkResourceInsertFailure, targetResource.SaveError);
            }
        }
예제 #31
0
파일: Serializer.cs 프로젝트: nickchal/pash
 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);
     }
 }
예제 #32
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);
            }
        }
 internal bool IsRelatedEntity(LinkDescriptor related)
 {
     return this.entity == related.Source || this.entity == related.Target;
 }
예제 #34
0
        /// <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()
        {
            if (!this.Tracking)
            {
                return;
            }

            foreach (KeyValuePair <Uri, ODataResource> entity in this.identityStack)
            {
                // Try to attach the entity descriptor got from materializer, if one already exists, get the existing reference instead.
                MaterializerEntry entry = MaterializerEntry.GetEntry(entity.Value);

                bool mergeEntityDescriptorInfo = entry.CreatedByMaterializer ||
                                                 entry.ResolvedObject == this.insertRefreshObject ||
                                                 entry.ShouldUpdateFromPayload;

                // Whenever we merge the data, only at those times will be merge the links also
                EntityDescriptor descriptor = this.entityTracker.InternalAttachEntityDescriptor(entry.EntityDescriptor, false /*failIfDuplicated*/);
                AtomMaterializerLog.MergeEntityDescriptorInfo(descriptor, entry.EntityDescriptor, mergeEntityDescriptorInfo, this.mergeOption);

                if (mergeEntityDescriptorInfo)
                {
                    // In AtomMaterializer.TryResolveFromContext, we set AtomEntry.ShouldUpdateFromPayload to true
                    // when even MergeOption is PreserveChanges and entityState is Deleted. But in that case, we cannot
                    // set the entity state to Unchanged, hence need to workaround that one scenario
                    if (this.mergeOption != MergeOption.PreserveChanges || descriptor.State != EntityStates.Deleted)
                    {
                        // we should always reset descriptor's state to Unchanged (old v1 behavior)
                        descriptor.State = EntityStates.Unchanged;
                        descriptor.PropertiesToSerialize.Clear();
                    }
                }
            }

            foreach (LinkDescriptor link in this.links)
            {
                if (EntityStates.Added == link.State)
                {
                    // Added implies collection
                    this.entityTracker.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)
                    {
                        // GetLinks looks up the existing link using just the SourceProperty, the declaring server type name is not significant here.
                        LinkDescriptor end = this.entityTracker.GetLinks(link.Source, link.SourceProperty).SingleOrDefault();
                        if (end != null && end.Target == null)
                        {
                            // leave the SetLink(link.Source, link.SourceProperty, null)
                            continue;
                        }

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

                    this.entityTracker.AttachLink(link.Source, link.SourceProperty, target, this.mergeOption);
                }
                else
                {
                    // detach link
                    Debug.Assert(EntityStates.Detached == link.State, "not detached link");
                    this.entityTracker.DetachExistingLink(link, false);
                }
            }
        }
예제 #35
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;
 }
예제 #36
0
        /// <summary>
        /// Invoke this method to notify the log that a link was set on
        /// a property.
        /// </summary>
        /// <param name="source">Entry for source object.</param>
        /// <param name="propertyName">Name of property set.</param>
        /// <param name="target">Target object.</param>
        internal void SetLink(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))
            {
                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.Modified);
                this.links.Add(item);
            }
        }
예제 #37
0
 /// <summary>is the entity the same as the source or target entity</summary>
 /// <param name="related">related end</param>
 /// <returns>true if same as source or target entity</returns>
 internal bool IsRelatedEntity(LinkDescriptor related)
 {
     return((this.entity == related.Source) || (this.entity == related.Target));
 }
예제 #38
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 targetReferenceLink = targetResource.GetLatestIdentity();

                if (targetReferenceLink == null)
                {
#if DEBUG
                    Debug.Assert(isBatch, "we should be cross-referencing entities only in batch scenarios");
#endif
                    targetReferenceLink = UriUtil.CreateUri("$" + targetResource.ChangeOrder.ToString(CultureInfo.InvariantCulture), UriKind.Relative);
                }

                ODataEntityReferenceLink referenceLink = new ODataEntityReferenceLink();
                referenceLink.Url = targetReferenceLink;
                messageWriter.WriteEntityReferenceLink(referenceLink);
            }
        }
        public void SerializeEnity_EnumProperty()
        {
            MyEntity1 myEntity1 = new MyEntity1()
            {
                ID                 = 2,
                MyColorValue       = MyColor.Yellow,
                MyFlagsColorValue  = MyFlagsColor.Blue,
                ComplexValue1Value = new ComplexValue1()
                {
                    MyColorValue = MyColor.Green, MyFlagsColorValue = MyFlagsColor.Red
                },
                MyFlagsColorCollection1 = new List <MyFlagsColor>()
                {
                    MyFlagsColor.Blue, MyFlagsColor.Red, MyFlagsColor.Red
                },
                MyColorCollection = new List <MyColor?>()
            };

            DataServiceContext dataServiceContext = new DataServiceContext(new Uri("http://www.odata.org/service.svc"));

            dataServiceContext.EnableAtom = true;
            dataServiceContext.Format.UseAtom();
            dataServiceContext.AttachTo("MyEntitySet1", myEntity1);

            var requestInfo = new RequestInfo(dataServiceContext);
            var serializer  = new Serializer(requestInfo);
            var headers     = new HeaderCollection();

            headers.SetHeader("Content-Type", "application/atom+xml;odata.metadata=minimal");
            var clientModel      = new ClientEdmModel(ODataProtocolVersion.V4);
            var entityDescriptor = new EntityDescriptor(clientModel);

            entityDescriptor.State  = EntityStates.Added;
            entityDescriptor.Entity = myEntity1;
            var requestMessageArgs         = new BuildingRequestEventArgs("POST", new Uri("http://www.foo.com/Northwind"), headers, entityDescriptor, HttpStack.Auto);
            var linkDescriptors            = new LinkDescriptor[] { };
            var odataRequestMessageWrapper = ODataRequestMessageWrapper.CreateRequestMessageWrapper(requestMessageArgs, requestInfo);

            serializer.WriteEntry(entityDescriptor, linkDescriptors, odataRequestMessageWrapper);

            // read result:
            MemoryStream stream = (MemoryStream)(odataRequestMessageWrapper.CachedRequestStream.Stream);

            stream.Position = 0;

            string payload = (new StreamReader(stream)).ReadToEnd();

            payload = Regex.Replace(payload, "<updated>[^<]*</updated>", "");
            payload.Should().Be(
                "<?xml version=\"1.0\" encoding=\"utf-8\"?><entry xmlns=\"http://www.w3.org/2005/Atom\" " +
                "xmlns:d=\"http://docs.oasis-open.org/odata/ns/data\" xmlns:m=\"http://docs.oasis-open.org/odata/ns/metadata\" " +
                "xmlns:georss=\"http://www.georss.org/georss\" xmlns:gml=\"http://www.opengis.net/gml\">" +
                "<id />" +
                "<title />" +
                //"<updated>2013-11-11T19:29:54Z</updated>" +
                "<author><name /></author>" +
                "<content type=\"application/xml\">" +
                "<m:properties>" +
                "<d:ComplexValue1Value>" +
                "<d:MyColorValue m:type=\"#AstoriaUnitTests.TDD.Tests.Client.ODataWriterWrapperUnitTests_MyColor\">Green</d:MyColorValue>" +
                "<d:MyFlagsColorValue m:type=\"#AstoriaUnitTests.TDD.Tests.Client.ODataWriterWrapperUnitTests_MyFlagsColor\">Red</d:MyFlagsColorValue>" +
                "<d:StringValue m:null=\"true\" />" +
                "</d:ComplexValue1Value>" +
                "<d:ID m:type=\"Int64\">2</d:ID>" +
                "<d:MyColorCollection />" +
                "<d:MyColorValue m:type=\"#AstoriaUnitTests.TDD.Tests.Client.ODataWriterWrapperUnitTests_MyColor\">Yellow</d:MyColorValue>" +
                "<d:MyFlagsColorCollection1>" +
                "<m:element m:type=\"#AstoriaUnitTests.TDD.Tests.Client.ODataWriterWrapperUnitTests+MyFlagsColor\">Blue</m:element>" +
                "<m:element m:type=\"#AstoriaUnitTests.TDD.Tests.Client.ODataWriterWrapperUnitTests+MyFlagsColor\">Red</m:element>" +
                "<m:element m:type=\"#AstoriaUnitTests.TDD.Tests.Client.ODataWriterWrapperUnitTests+MyFlagsColor\">Red</m:element>" +
                "</d:MyFlagsColorCollection1>" +
                "<d:MyFlagsColorValue m:type=\"#AstoriaUnitTests.TDD.Tests.Client.ODataWriterWrapperUnitTests_MyFlagsColor\">Blue</d:MyFlagsColorValue>" +
                "</m:properties>" +
                "</content>" +
                "</entry>");
        }
예제 #40
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;
        }
예제 #41
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";
 }
예제 #42
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);
 }
예제 #43
0
 internal bool IsRelatedEntity(LinkDescriptor related)
 {
     return ((this.entity == related.Source) || (this.entity == related.Target));
 }
예제 #44
0
        /// <summary>Handle changeset response.</summary>
        /// <param name="linkDescriptor">headers of changeset response</param>
        private static void HandleResponsePost(LinkDescriptor linkDescriptor)
        {
            if (!((EntityStates.Added == linkDescriptor.State) || (EntityStates.Modified == linkDescriptor.State && null != linkDescriptor.Target)))
            {
                Error.ThrowBatchUnexpectedContent(InternalError.LinkNotAddedState);
            }

            linkDescriptor.State = EntityStates.Unchanged;
        }
예제 #45
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 abstract void DetachExistingLink(LinkDescriptor existingLink, bool targetDelete);
예제 #46
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(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);
            }
        }
예제 #47
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;
     }
 }
예제 #48
0
        /// <summary>
        /// Invoke this method to notify the log that a link was set on
        /// a property.
        /// </summary>
        /// <param name="source">Entry for source object.</param>
        /// <param name="propertyName">Name of property set.</param>
        /// <param name="target">Target object.</param>
        internal void SetLink(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))
            {
                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.Modified);
                this.links.Add(item);
            }
        }
예제 #49
0
        private static Uri AppendTargetEntityKeyIfNeeded(Uri linkUri, LinkDescriptor binding, EntityDescriptor targetResource)
        {
            // To delete from a collection, we need to append the key.
            // For example: if the navigation property name is "Purchases" and the resource type is Order with key '1', then this method will generate 'baseuri/Purchases(1)'
            if (!binding.IsSourcePropertyCollection || EntityStates.Deleted != binding.State)
            {
                return linkUri;
            }

            Debug.Assert(targetResource != null, "targetResource != null");
            StringBuilder builder = new StringBuilder();
            builder.Append(UriUtil.UriToString(linkUri));
            builder.Append(UriHelper.QUESTIONMARK + XmlConstants.HttpQueryStringId + UriHelper.EQUALSSIGN + targetResource.Identity);
            return UriUtil.CreateUri(builder.ToString(), UriKind.RelativeOrAbsolute);
        }
예제 #50
0
 internal override void DetachExistingLink(LinkDescriptor existingLink, bool targetDelete)
 {
     DetachExistingLinkAction(existingLink, targetDelete);
 }
예제 #51
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>
 /// <param name="isBatch">True if batch, false otherwise.</param>
 internal void WriteEntityReferenceLink(LinkDescriptor binding, ODataRequestMessageWrapper requestMessage, bool isBatch)
예제 #52
0
        /// <summary>
        /// Generate a request for the given link.
        /// </summary>
        /// <param name="binding">Instance of LinkDescriptor.</param>
        /// <param name="requestMessage">Instance of IODataRequestMessage to be used to generate the payload.</param>
        private void CreateRequestData(LinkDescriptor binding, ODataRequestMessageWrapper requestMessage)
        {
            Debug.Assert(
                (binding.State == EntityStates.Added) ||
                (binding.State == EntityStates.Modified && null != binding.Target),
                "This method must be called only when a binding is added or put");
#if DEBUG
            Debug.Assert(!Util.IsBatchWithSingleChangeset(this.Options) || this.IsBatchRequest, "If this.Options.IsBatchWithSingleChangeset() is true, this.IsBatchRequest must also be true.");
            this.SerializerInstance.WriteEntityReferenceLink(binding, requestMessage, Util.IsBatchWithSingleChangeset(this.Options));
#else
            this.SerializerInstance.WriteEntityReferenceLink(binding, requestMessage);
#endif
        }
예제 #53
0
        public static DataServiceResponse SaveChanges(DataServiceContext context, SaveChangesOptions options, SaveChangesMode saveMode)
        {
            IList <EntityDescriptor> entites         = (from e in context.Entities where e.State != EntityStates.Unchanged select e).ToArray();
            IList <LinkDescriptor>   links           = (from e in context.Links where e.State != EntityStates.Unchanged select e).ToArray();
            IList <StreamDescriptor> streams         = context.Entities.SelectMany(e => e.StreamDescriptors).Where(s => s.State != EntityStates.Unchanged).ToArray();
            IList <EntityDescriptor> deletedEntities = (from e in entites where e.State == EntityStates.Deleted select e).ToArray();
            IList <LinkDescriptor>   deletedLinks    = (from e in links where e.State == EntityStates.Deleted select e).ToArray();

            DataServiceResponse response = null;

            switch (saveMode)
            {
            case SaveChangesMode.Synchronous:
                response = context.SaveChanges(options);
                break;

            case SaveChangesMode.AsyncWaitOnAsyncWaitHandle:
            {
                IAsyncResult async = context.BeginSaveChanges(options, null, null);
                if (!async.CompletedSynchronously)
                {
                    Assert.IsTrue(async.AsyncWaitHandle.WaitOne(new TimeSpan(0, 0, TestConstants.MaxTestTimeout), false), "BeginSaveChanges {0} timeout", options);
                }

                Assert.IsTrue(async.IsCompleted);
                response = context.EndSaveChanges(async);
                break;
            }

            case SaveChangesMode.AsyncCallback:
            {
                SaveChangesCallback callback = new SaveChangesCallback();
                IAsyncResult        async    = context.BeginSaveChanges(options, callback.CallbackMethod, new object[] { options, context });

                Assert.IsTrue(callback.Finished.WaitOne(new TimeSpan(0, 0, TestConstants.MaxTestTimeout), false), "BeginSaveChanges {0} Asyncallback timeout", options);
                Assert.IsTrue(async.IsCompleted);

                if (null != callback.CallbackFailure)
                {
                    Assert.IsNull(callback.CallbackResult, callback.CallbackFailure.ToString());
                    throw callback.CallbackFailure;
                }

                response = (DataServiceResponse)callback.CallbackResult;
                break;
            }

            default:
                Assert.Fail("shouldn't be here");
                break;
            }

            int entityIndex = 0;
            int linkIndex   = 0;
            int streamIndex = 0;

            if (options == SaveChangesOptions.BatchWithSingleChangeset)
            {
                Assert.AreEqual <int>(response.BatchStatusCode, (int)HttpStatusCode.Accepted, "Expecting 202 as the status code for batch requests");
                Assert.IsTrue(response.BatchHeaders["Content-Type"].StartsWith("multipart/mixed; boundary=batchresponse_"), "expecting content type to be multipart mixed with a boundary value");
                Assert.IsTrue(response.IsBatchResponse, "Expecting response to be batch response");
            }
            else
            {
                Assert.AreEqual <int>(response.BatchStatusCode, -1, "expecting status code to be zero");
                Assert.IsTrue(response.BatchHeaders.Count == 0, "expecting no header information");
                Assert.IsFalse(response.IsBatchResponse, "expecting this to be non batch response");
            }

            foreach (ChangeOperationResponse changeset in response)
            {
                EntityStates state;
                bool         wasDeletedState;

                if (changeset.Descriptor is EntityDescriptor)
                {
                    EntityDescriptor tor = (EntityDescriptor)changeset.Descriptor;
                    state           = tor.State;
                    wasDeletedState = deletedEntities.Contains(tor);

                    // for MLE, more than one request can be sent for the same entity descriptor
                    if (entites.Count > entityIndex && Object.ReferenceEquals(entites[entityIndex].Entity, tor.Entity))
                    {
                        entityIndex++;
                    }
                    else
                    {
                        Assert.IsTrue(Object.ReferenceEquals(tor.Entity, entites[entityIndex - 1].Entity), "For MLE, it must match with the previous request");
                    }

                    Assert.IsNull(changeset.Error);
                }
                else if (changeset.Descriptor is LinkDescriptor)
                {
                    LinkDescriptor tor = (LinkDescriptor)changeset.Descriptor;
                    state           = tor.State;
                    wasDeletedState = deletedLinks.Contains(tor);

                    Assert.AreSame(tor.Source, links[linkIndex].Source);
                    Assert.AreEqual(tor.SourceProperty, links[linkIndex].SourceProperty);
                    Assert.AreSame(tor.Target, links[linkIndex].Target);
                    Assert.IsNull(changeset.Error);
                    linkIndex++;
                }
                else
                {
                    Assert.IsTrue(changeset.Descriptor is StreamDescriptor, "Must be stream descriptor");
                    if (streams.Count > streamIndex && streams.Contains(changeset.Descriptor))
                    {
                        streamIndex++;
                    }

                    state           = changeset.Descriptor.State;
                    wasDeletedState = false;
                }

                if (changeset.Error != null)
                {
                    Assert.AreNotEqual(EntityStates.Unchanged, state);
                }
                else
                {
                    if (wasDeletedState)
                    {
                        Assert.AreEqual(EntityStates.Detached, state);
                    }
                    else
                    {
                        Assert.AreEqual(EntityStates.Unchanged, state);
                    }
                }
            }

            Assert.AreEqual(entites.Count, entityIndex, "entities SaveChangesOptions.{0}", options);
            Assert.AreEqual(links.Count, linkIndex, "links SaveChangesOptions.{0}", options);
            Assert.AreEqual(streams.Count, streamIndex, "streams SaveChangesOptions.{0}", options);

            entites = context.Entities;
            links   = context.Links;
            return(response);
        }
예제 #54
0
        /// <summary>
        /// Get the source property Uri for the link URL
        /// </summary>
        /// <param name="binding">Link descriptor object of the binding</param>
        /// <param name="sourceEntityDescriptor">entity descriptor for source</param>
        /// <returns>source property Uri string</returns>
        private string GetSourcePropertyUri(LinkDescriptor binding, EntityDescriptor sourceEntityDescriptor)
        {
            Debug.Assert(binding != null, "binding != null");
            Debug.Assert(sourceEntityDescriptor != null, "sourceEntityDescriptor != null");

            if (string.IsNullOrEmpty(binding.SourceProperty))
            {
                return null;
            }

            string sourcePropertyUri = binding.SourceProperty;

            // Add type segment in the link URL for the derived entity type on which a navigation property is defined.
            // e.g. cxt.Attachto("<entitySetname>",<EntityToBeSource>)
            //      cxt.AddLink(<EntityToBeSource>, "<NavigationPropertyName>" <EntityToBeTarget>)
            // Get entity type name from model (here service model instead of client model should be used)
            string entityTypeFullName = this.RequestInfo.TypeResolver.ResolveServiceEntityTypeFullName(binding.Source.GetType());
            if (string.IsNullOrEmpty(entityTypeFullName))
            {
                return sourcePropertyUri;
            }

            // Get the type of entityset from service model.
            string sourceEntitySetTypeName = null;
            if (!string.IsNullOrEmpty(sourceEntityDescriptor.EntitySetName) && this.RequestInfo.TypeResolver.TryResolveEntitySetBaseTypeName(sourceEntityDescriptor.EntitySetName, out sourceEntitySetTypeName))
            {
                // Check whether the entity type and the entity set type are matched. if not matched, set the dervied entity type name as a key segment in the URL.
                if (!string.IsNullOrEmpty(sourceEntitySetTypeName) && !string.Equals(entityTypeFullName, sourceEntitySetTypeName, StringComparison.OrdinalIgnoreCase))
                {
                    sourcePropertyUri = entityTypeFullName + UriHelper.FORWARDSLASH + sourcePropertyUri;
                }
            }

            return sourcePropertyUri;
        }
예제 #55
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);
     }
 }
예제 #56
0
 /// <summary>Get the value of HttpMethod enum from link resource state</summary>
 /// <param name="link">Instance of LinkDescriptor containing the link state and type of link.</param>
 /// <returns>HttpMethod enum value for the link descriptor state.</returns>
 protected static string GetLinkHttpMethod(LinkDescriptor link)
 {
     if (!link.IsSourcePropertyCollection)
     {
         Debug.Assert(EntityStates.Modified == link.State, "not Modified state");
         if (null == link.Target)
         {   // REMOVE/DELETE a reference
             return XmlConstants.HttpMethodDelete;
         }
         else
         {   // UPDATE/PUT a reference
             return XmlConstants.HttpMethodPut;
         }
     }
     else if (EntityStates.Deleted == link.State)
     {   // you call DELETE on $ref
         return XmlConstants.HttpMethodDelete;
     }
     else
     {   // you INSERT/POST into a collection
         Debug.Assert(EntityStates.Added == link.State, "not Added state");
         return XmlConstants.HttpMethodPost;
     }
 }
예제 #57
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;
            }
        }
예제 #58
0
        /// <summary>
        /// Generate the link payload.
        /// </summary>
        /// <param name="binding">binding</param>
        /// <returns>An instance of ODataRequestMessage for the link request.</returns>
        protected ODataRequestMessageWrapper CreateRequest(LinkDescriptor binding)
        {
            Debug.Assert(null != binding, "null binding");
            if (binding.ContentGeneratedForSave)
            {
                return null;
            }

            EntityDescriptor sourceEntityDescriptor = this.RequestInfo.EntityTracker.GetEntityDescriptor(binding.Source);
            EntityDescriptor targetEntityDescriptor = (null != binding.Target) ? this.RequestInfo.EntityTracker.GetEntityDescriptor(binding.Target) : null;

            // We allow the source and target to be in Added state, i.e. without identities, for batch with single changeset.
            if (!Util.IsBatchWithSingleChangeset(this.Options))
            {
                ValidateLinkDescriptorSourceAndTargetHaveIdentities(binding, sourceEntityDescriptor, targetEntityDescriptor);
            }

            Debug.Assert(this.IsBatchRequest || null != sourceEntityDescriptor.GetLatestIdentity(), "missing sourceResource.Identity in non-batch");

            Uri requestUri = null;
            LinkInfo linkInfo = null;

            if (sourceEntityDescriptor.TryGetLinkInfo(binding.SourceProperty, out linkInfo)
                && linkInfo.AssociationLink != null)
            {
                Debug.Assert(null != sourceEntityDescriptor.GetLatestIdentity(), "Source must have an identity in order to have link info");

                // If there is already an Association link from the payload, use that
                requestUri = linkInfo.AssociationLink;
            }
            else
            {
                Uri sourceEntityUri;
                if (null == sourceEntityDescriptor.GetLatestIdentity())
                {
                    Debug.Assert(this.IsBatchRequest && Util.IsBatchWithSingleChangeset(this.Options), "Source must have an identity outside of batch with single changeset");

                    // if the source hasn't yet been inserted (because its in batch), then create a uri based on its content-ID
                    sourceEntityUri = UriUtil.CreateUri("$" + sourceEntityDescriptor.ChangeOrder.ToString(CultureInfo.InvariantCulture), UriKind.Relative);
                }
                else
                {
                    // otherwise use the edit link of the source
                    sourceEntityUri = sourceEntityDescriptor.GetResourceUri(this.RequestInfo.BaseUriResolver, false /*queryLink*/);
                }

                // get the source property Uri
                string sourcePropertyUri = GetSourcePropertyUri(binding, sourceEntityDescriptor);

                // get the convention-based relative uri for the association
                Uri conventionalRelativeUri = UriUtil.CreateUri(sourcePropertyUri, UriKind.Relative);

                // add $ref at the end
                conventionalRelativeUri = UriUtil.CreateUri(UriUtil.UriToString(conventionalRelativeUri) + UriHelper.FORWARDSLASH + XmlConstants.UriLinkSegment, UriKind.Relative);

                // combine the association uri with the source entity uri
                requestUri = UriUtil.CreateUri(sourceEntityUri, conventionalRelativeUri);
            }

            // in the case of deleting a link from a collection, the key of the target must be appended
            requestUri = AppendTargetEntityKeyIfNeeded(requestUri, binding, targetEntityDescriptor);

            string method = GetLinkHttpMethod(binding);

            HeaderCollection headers = new HeaderCollection();

            headers.SetRequestVersion(Util.ODataVersion4, this.RequestInfo.MaxProtocolVersionAsVersion);
            this.RequestInfo.Format.SetRequestAcceptHeader(headers);

            // if (EntityStates.Deleted || (EntityState.Modifed && null == TargetResource))
            // then the server will fail the batch section if content type exists
            if ((EntityStates.Added == binding.State) || (EntityStates.Modified == binding.State && (null != binding.Target)))
            {
                this.RequestInfo.Format.SetRequestContentTypeForLinks(headers);
            }

            return this.CreateRequestMessage(method, requestUri, headers, this.RequestInfo.HttpStack, binding, this.IsBatchRequest ? binding.ChangeOrder.ToString(CultureInfo.InvariantCulture) : null);
        }