/// <summary>
        /// Returns whether or not the given link descriptor data will be sent as a separate request during SaveChanges
        /// </summary>
        /// <param name="linkDescriptorData">The link descriptor data</param>
        /// <returns>True if it will be sent as a separate request, otherwise false</returns>
        public static bool WillTriggerSeparateRequest(this LinkDescriptorData linkDescriptorData)
        {
            ExceptionUtilities.CheckArgumentNotNull(linkDescriptorData, "linkDescriptorData");

            // no request will be made for these
            if (linkDescriptorData.State == EntityStates.Unchanged || linkDescriptorData.State == EntityStates.Detached)
            {
                return(false);
            }

            // delete link requests are always seperate
            if (linkDescriptorData.State == EntityStates.Deleted)
            {
                return(true);
            }

            // link will be folded into the insert
            if (linkDescriptorData.SourceDescriptor.State == EntityStates.Added &&
                !linkDescriptorData.SourceDescriptor.IsMediaLinkEntry &&
                linkDescriptorData.TargetDescriptor != null &&
                linkDescriptorData.TargetDescriptor.State != EntityStates.Added)
            {
                return(false);
            }

            // insert uri will be based on the link
            if (linkDescriptorData.TargetDescriptor != null && linkDescriptorData.TargetDescriptor.ParentPropertyForInsert == linkDescriptorData.SourcePropertyName)
            {
                return(false);
            }

            return(true);
        }
Example #2
0
 /// <summary>
 /// Clones the current link descriptor data
 /// </summary>
 /// <param name="clonedSource">The already-cloned source for the link</param>
 /// <param name="clonedTarget">The already-cloded target for the link</param>
 /// <returns>A clone of this link descriptor data</returns>
 public LinkDescriptorData Clone(EntityDescriptorData clonedSource, EntityDescriptorData clonedTarget)
 {
     var clone = new LinkDescriptorData(clonedSource, this.SourcePropertyName, clonedTarget);
     clone.ChangeOrder = this.ChangeOrder;
     clone.State = this.State;
     return clone;
 }
Example #3
0
        /// <summary>
        /// Clones the current link descriptor data
        /// </summary>
        /// <param name="clonedSource">The already-cloned source for the link</param>
        /// <param name="clonedTarget">The already-cloded target for the link</param>
        /// <returns>A clone of this link descriptor data</returns>
        public LinkDescriptorData Clone(EntityDescriptorData clonedSource, EntityDescriptorData clonedTarget)
        {
            var clone = new LinkDescriptorData(clonedSource, this.SourcePropertyName, clonedTarget);

            clone.ChangeOrder = this.ChangeOrder;
            clone.State       = this.State;
            return(clone);
        }
        private bool RemoveLinkData(LinkDescriptorData linkData)
        {
            if (!this.linkDatas.Remove(linkData))
            {
                return false;
            }

            SetDetachedState(linkData);
            return true;
        }
        /// <summary>
        /// Creates the link descriptor data and puts in into the list of link descriptors data.
        /// <see cref="ChangeStateAndChangeOrder"/> for the restrictions on the state and change order.        
        /// </summary>
        /// <param name="state">The state.</param>
        /// <param name="changeOrder">The change order.</param>
        /// <param name="sourceData">The source.</param>
        /// <param name="sourcePropertyName">Name of the source property.</param>
        /// <param name="targetData">The target.</param>
        /// <returns>The created link descriptor data.</returns>
        /// <exception cref="TaupoArgumentNullException">
        /// When source or sourcePropertyName is null.
        /// </exception>
        /// <exception cref="TaupoArgumentException">
        /// When sourcePropertyName is empty.
        /// </exception>
        /// <exception cref="TaupoInvalidOperationException">
        /// When entity descriptor data is not found for the source or target (if target is not null).
        /// </exception>
        public LinkDescriptorData CreateLinkDescriptorData(EntityStates state, long changeOrder, EntityDescriptorData sourceData, string sourcePropertyName, EntityDescriptorData targetData)
        {
            ExceptionUtilities.CheckArgumentNotNull(sourceData, "sourceData");
            ExceptionUtilities.CheckArgumentNotNull(sourcePropertyName, "sourcePropertyName");

            var linkData = new LinkDescriptorData(sourceData, sourcePropertyName, targetData);
            this.ChangeStateAndChangeOrder(linkData, state, changeOrder);

            this.linkDatas.Add(linkData);

            return linkData;
        }
        private ExpectedClientRequest CreateLinkRequest(LinkDescriptorData linkDescriptorData, SaveChangesOptions options)
        {
            var info = linkDescriptorData.SourceDescriptor.LinkInfos.SingleOrDefault(l => l.Name == linkDescriptorData.SourcePropertyName);
            ExpectedClientRequest request = new ExpectedClientRequest() { Uri = BuildLinkUri(linkDescriptorData, info) };

            if (linkDescriptorData.State == EntityStates.Added)
            {
                request.Verb = HttpVerb.Post;

                // note: the edit-link is used rather than identity because the server needs to be able to query for the target entity
                // and the identity may not be an actual uri
                request.Body = new DeferredLink() { UriString = linkDescriptorData.TargetDescriptor.EditLink.OriginalString };
            }
            else if (linkDescriptorData.State == EntityStates.Modified)
            {
                if (linkDescriptorData.TargetDescriptor == null)
                {
                    request.Verb = HttpVerb.Delete;
                }
                else
                {
                    request.Verb = HttpVerb.Put;

                    // note: the edit-link is used rather than identity because the server needs to be able to query for the target entity
                    // and the identity may not be an actual uri
                    request.Body = new DeferredLink() { UriString = linkDescriptorData.TargetDescriptor.EditLink.OriginalString };
                }
            }
            else
            {
                ExceptionUtilities.Assert(linkDescriptorData.State == EntityStates.Deleted, "Link descriptor was in unexpected state '{0}'", linkDescriptorData.State);

                string keyString = this.EntityDescriptorValueCalculator.CalculateEntityKey(linkDescriptorData.TargetDescriptor.Entity);
                request.Uri = new Uri(request.Uri.OriginalString + keyString);
                request.Verb = HttpVerb.Delete;
            }

            request.Headers[HttpHeaders.IfMatch] = null;
            request.Headers[HttpHeaders.Prefer] = null;
            request.Headers[HttpHeaders.DataServiceVersion] = ToClientHeaderFormat(DataServiceProtocolVersion.V4);

            this.SetDefaultAcceptHeader(request, options);

            if (request.Verb != HttpVerb.Delete)
            {
                request.Headers[HttpHeaders.ContentType] = string.IsNullOrWhiteSpace(this.ClientRequestAcceptHeader) ? MimeTypes.ApplicationXml : this.ClientRequestAcceptHeader;
            }
            else
            {
                request.Headers[HttpHeaders.ContentType] = null;
            }

            string hintString = @"Link\r\n{{\r\n  Descriptor = {0}\r\n  Options = {1}\r\n}}";
            request.DebugHintString = string.Format(CultureInfo.InvariantCulture, hintString, linkDescriptorData, options);
            
            return request;
        }
        internal static Uri BuildLinkUri(LinkDescriptorData linkDescriptorData, LinkInfoData info)
        {
            Uri linkUri;
            if (info != null && info.RelationshipLink != null)
            {
                linkUri = info.RelationshipLink;
            }
            else
            {
                ExceptionUtilities.CheckObjectNotNull(linkDescriptorData.SourceDescriptor.EditLink, "Edit link of source descriptor cannot be null");
                linkUri = new Uri(UriHelpers.ConcatenateUriSegments(linkDescriptorData.SourceDescriptor.EditLink.OriginalString, Endpoints.Ref, linkDescriptorData.SourcePropertyName), UriKind.RelativeOrAbsolute);
            }

            return linkUri;
        }
            /// <summary>
            /// Creates LinkChangeData which captures the state of the specified link descriptor data.
            /// </summary>
            /// <param name="linkData">The link descriptor data.</param>
            /// <returns>Link change data.</returns>
            public static LinkChangeData Create(LinkDescriptorData linkData)
            {
                ExceptionUtilities.CheckArgumentNotNull(linkData, "linkData");

                LinkChangeData changeData = new LinkChangeData(linkData);

                var isEnumerable = linkData.SourceDescriptor.EntityClrType.GetProperty(linkData.SourcePropertyName).PropertyType.GetInterfaces().Any(t => t.Name == "IEnumerable");
                changeData.IsReference = !isEnumerable;

                if (linkData.TargetDescriptor != null)
                {
                    changeData.ClrTypeForRequery = linkData.TargetDescriptor.EntityClrType;
                }
                else
                {
                    ExceptionUtilities.Assert(changeData.IsReference, "TargetDescriptor can not be null for the link descriptor representing collection.");
                    changeData.ClrTypeForRequery = linkData.SourceDescriptor.EntityClrType.GetProperty(linkData.SourcePropertyName).PropertyType;
                }

                return changeData;
            }
 /// <summary>
 /// Initializes a new instance of the <see cref="LinkChangeData"/> class.
 /// </summary>
 /// <param name="linkDescriptorData">The link descriptor data.</param>
 protected LinkChangeData(LinkDescriptorData linkDescriptorData)
     : base(linkDescriptorData)
 {
 }
        /// <summary>
        /// Tries to get link descriptor data for the specified link.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="sourcePropertyName">Name of the source property.</param>
        /// <param name="target">The target.</param>
        /// <param name="linkData">The link descriptor data to be retrieved.</param>
        /// <returns>True if link descriptor data is found, false otherwise.</returns>
        public bool TryGetLinkDescriptorData(object source, string sourcePropertyName, object target, out LinkDescriptorData linkData)
        {
            CheckLinkArguments(source, sourcePropertyName);

            // Consider using dictionary for faster look-up and to avoid duplicates.
            var found = this.LinkDescriptorsData.Where(e => IsMatch(e.SourceDescriptor, source) && 
                ((target == null && e.TargetDescriptor == null) || (e.TargetDescriptor != null && IsMatch(e.TargetDescriptor, target)))
                && e.SourcePropertyName == sourcePropertyName).ToList();

            if (found.Count > 1)
            {
                throw new TaupoInvalidOperationException(
                    string.Format(CultureInfo.InvariantCulture, "Multiple link descriptors data found for the specified link: source = {{{0}}}, source property name='{1}', target = {{{2}}}.", source, sourcePropertyName, target));
            }

            linkData = found.FirstOrDefault();

            return linkData != null;
        }