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