/// <summary> /// Adds an OData annotation to a property. /// </summary> /// <param name="propertyName">The name of the property to add annotation to. string.empty means the annotation is for the current scope.</param> /// <param name="annotationName">The name of the annotation to add.</param> /// <param name="annotationValue">The valud of the annotation to add.</param> internal void AddODataPropertyAnnotation(string propertyName, string annotationName, object annotationValue) { Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)"); Debug.Assert(!string.IsNullOrEmpty(annotationName), "!string.IsNullOrEmpty(annotationName)"); Debug.Assert(JsonLight.ODataJsonLightReaderUtils.IsODataAnnotationName(annotationName), "annotationName must be an OData annotation."); DuplicationRecord duplicationRecord = this.GetDuplicationRecordToAddPropertyAnnotation(propertyName, annotationName); Dictionary <string, object> odataAnnotations = duplicationRecord.PropertyODataAnnotations; if (odataAnnotations == null) { odataAnnotations = new Dictionary <string, object>(StringComparer.Ordinal); duplicationRecord.PropertyODataAnnotations = odataAnnotations; } else if (odataAnnotations.ContainsKey(annotationName)) { if (ODataJsonLightReaderUtils.IsAnnotationProperty(propertyName)) { throw new ODataException(Strings.DuplicatePropertyNamesChecker_DuplicateAnnotationForInstanceAnnotationNotAllowed(annotationName, propertyName)); } throw new ODataException(Strings.DuplicatePropertyNamesChecker_DuplicateAnnotationForPropertyNotAllowed(annotationName, propertyName)); } odataAnnotations.Add(annotationName, annotationValue); }
/// <summary> /// Sets the properties on a duplication record for a navigation link. /// </summary> /// <param name="duplicationRecord">The duplication record to modify.</param> /// <param name="isExpanded">true if the navigation link is expanded, false otherwise.</param> /// <param name="isCollection">true if the navigation link is marked as collection, false if it's marked as singletong or null if we don't know.</param> private static void ApplyNavigationLinkToDuplicationRecord(DuplicationRecord duplicationRecord, bool isExpanded, bool?isCollection) { duplicationRecord.NavigationLinkFound = true; // We only take the cardinality of the link for granted if it was expanded or if it is a collection. // We can't rely on singleton deferred links to know the cardinality since they can be used for binding even if the actual link is a collection. duplicationRecord.NavigationPropertyIsCollection = GetIsCollectionEffectiveValue(isExpanded, isCollection); }
private bool TryGetDuplicationRecord(string propertyName, out DuplicationRecord duplicationRecord) { if (this.propertyNameCache == null) { this.propertyNameCache = new Dictionary <string, DuplicationRecord>(EqualityComparer <string> .Default); duplicationRecord = null; return(false); } return(this.propertyNameCache.TryGetValue(propertyName, out duplicationRecord)); }
/// <summary> /// Tries to get an existing duplication record for the specified <paramref name="propertyName"/>. /// </summary> /// <param name="propertyName">The property name to look for.</param> /// <param name="duplicationRecord">The existing duplication if one was already found.</param> /// <returns>true if a duplication record already exists, false otherwise.</returns> /// <remarks>This method also initializes the cache if it was not initialized yet.</remarks> private bool TryGetDuplicationRecord(string propertyName, out DuplicationRecord duplicationRecord) { if (this.propertyNameCache == null) { this.propertyNameCache = new Dictionary <string, DuplicationRecord>(StringComparer.Ordinal); duplicationRecord = null; return(false); } return(this.propertyNameCache.TryGetValue(propertyName, out duplicationRecord)); }
/// <summary> /// Throw if property is processed already. /// </summary> /// <param name="propertyName">Name of the property.</param> /// <param name="duplicationRecord">DuplicationRecord of the property.</param> private static void ThrowIfPropertyIsProcessed(string propertyName, DuplicationRecord duplicationRecord) { if (object.ReferenceEquals(duplicationRecord.PropertyODataAnnotations, propertyAnnotationsProcessedToken)) { if (ODataJsonLightReaderUtils.IsAnnotationProperty(propertyName) && !ODataJsonLightUtils.IsMetadataReferenceProperty(propertyName)) { throw new ODataException(Strings.DuplicatePropertyNamesChecker_DuplicateAnnotationNotAllowed(propertyName)); } throw new ODataException(Strings.DuplicatePropertyNamesChecker_DuplicatePropertyNamesNotAllowed(propertyName)); } }
/// <summary> /// Marks the <paramref name="propertyName"/> property to note that all its annotations were already processed. /// </summary> /// <param name="propertyName">The property name to mark.</param> /// <remarks> /// Properties marked like this will fail if there are more annotations found for them in the payload. /// </remarks> internal void MarkPropertyAsProcessed(string propertyName) { DebugUtils.CheckNoExternalCallers(); Debug.Assert(propertyName != null, "propertyName != null"); DuplicationRecord duplicationRecord; if (!this.TryGetDuplicationRecord(propertyName, out duplicationRecord)) { duplicationRecord = new DuplicationRecord(DuplicationKind.PropertyAnnotationSeen); this.propertyNameCache.Add(propertyName, duplicationRecord); } ThrowIfPropertyIsProcessed(propertyName, duplicationRecord); duplicationRecord.PropertyODataAnnotations = propertyAnnotationsProcessedToken; }
/// <summary> /// Marks the <paramref name="propertyName"/> property to note that all its annotations were already processed. /// </summary> /// <param name="propertyName">The property name to mark.</param> /// <remarks> /// Properties marked like this will fail if there are more annotations found for them in the payload. /// </remarks> internal void MarkPropertyAsProcessed(string propertyName) { if (this.disabled) { return; } Debug.Assert(propertyName != null, "propertyName != null"); DuplicationRecord duplicationRecord; if (!this.TryGetDuplicationRecord(propertyName, out duplicationRecord)) { duplicationRecord = new DuplicationRecord(DuplicationKind.PropertyAnnotationSeen); this.propertyNameCache.Add(propertyName, duplicationRecord); } ThrowIfPropertyIsProcessed(propertyName, duplicationRecord); duplicationRecord.PropertyODataAnnotations = propertyAnnotationsProcessedToken; }
internal void CheckForDuplicatePropertyNames(ODataAssociationLink associationLink) { DuplicationRecord record; string name = associationLink.Name; if (!this.TryGetDuplicationRecord(name, out record)) { DuplicationRecord record2 = new DuplicationRecord(DuplicationKind.NavigationProperty) { AssociationLinkFound = true }; this.propertyNameCache.Add(name, record2); } else { if ((record.DuplicationKind != DuplicationKind.NavigationProperty) || record.AssociationLinkFound) { throw new ODataException(Strings.DuplicatePropertyNamesChecker_DuplicatePropertyNamesNotAllowed(name)); } record.AssociationLinkFound = true; } }
/// <summary> /// Gets a duplication record to use for adding property annotation. /// </summary> /// <param name="propertyName">The name of the property to get the duplication record for.</param> /// <param name="annotationName">The name of the annotation being added (only for error reporting).</param> /// <returns>The duplication record to use. This will never be null.</returns> private DuplicationRecord GetDuplicationRecordToAddPropertyAnnotation(string propertyName, string annotationName) { Debug.Assert(propertyName != null, "propertyName != null"); Debug.Assert(!string.IsNullOrEmpty(annotationName), "!string.IsNullOrEmpty(annotationName)"); DuplicationRecord duplicationRecord; if (!this.TryGetDuplicationRecord(propertyName, out duplicationRecord)) { duplicationRecord = new DuplicationRecord(DuplicationKind.PropertyAnnotationSeen); this.propertyNameCache.Add(propertyName, duplicationRecord); } if (object.ReferenceEquals(duplicationRecord.PropertyODataAnnotations, propertyAnnotationsProcessedToken)) { throw new ODataException(Strings.DuplicatePropertyNamesChecker_PropertyAnnotationAfterTheProperty(annotationName, propertyName)); } Debug.Assert(duplicationRecord != null, "duplicationRecord != null"); return(duplicationRecord); }
/// <summary> /// Adds a custom annotation to a property. /// </summary> /// <param name="propertyName">The name of the property to add annotation to. string.empty means the annotation is for the current scope.</param> /// <param name="annotationName">The name of the annotation to add.</param> internal void AddCustomPropertyAnnotation(string propertyName, string annotationName) { Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)"); Debug.Assert(!string.IsNullOrEmpty(annotationName), "!string.IsNullOrEmpty(annotationName)"); Debug.Assert(!JsonLight.ODataJsonLightReaderUtils.IsODataAnnotationName(annotationName), "annotationName must not be an OData annotation."); DuplicationRecord duplicationRecord = this.GetDuplicationRecordToAddPropertyAnnotation(propertyName, annotationName); HashSet <string> customAnnotations = duplicationRecord.PropertyCustomAnnotations; if (customAnnotations == null) { customAnnotations = new HashSet <string>(StringComparer.Ordinal); duplicationRecord.PropertyCustomAnnotations = customAnnotations; } else if (customAnnotations.Contains(annotationName)) { throw new ODataException(Strings.DuplicatePropertyNamesChecker_DuplicateAnnotationForPropertyNotAllowed(annotationName, propertyName)); } customAnnotations.Add(annotationName); }
internal void CheckForDuplicatePropertyNames(ODataNavigationLink navigationLink, bool isExpanded, bool?isCollection) { DuplicationRecord record; string name = navigationLink.Name; if (!this.TryGetDuplicationRecord(name, out record)) { DuplicationRecord duplicationRecord = new DuplicationRecord(DuplicationKind.NavigationProperty); ApplyNavigationLinkToDuplicationRecord(duplicationRecord, isExpanded, isCollection); this.propertyNameCache.Add(name, duplicationRecord); } else { this.CheckNavigationLinkDuplicateNameForExistingDuplicationRecord(name, record); if (((record.DuplicationKind == DuplicationKind.NavigationProperty) && record.AssociationLinkFound) && !record.NavigationLinkFound) { ApplyNavigationLinkToDuplicationRecord(record, isExpanded, isCollection); } else if (this.allowDuplicateProperties) { record.DuplicationKind = DuplicationKind.NavigationProperty; ApplyNavigationLinkToDuplicationRecord(record, isExpanded, isCollection); } else { bool?isCollectionEffectiveValue = GetIsCollectionEffectiveValue(isExpanded, isCollection); if ((isCollectionEffectiveValue == false) || (record.NavigationPropertyIsCollection == false)) { throw new ODataException(Strings.DuplicatePropertyNamesChecker_MultipleLinksForSingleton(name)); } if (isCollectionEffectiveValue.HasValue) { record.NavigationPropertyIsCollection = isCollectionEffectiveValue; } } } }
internal void CheckForDuplicatePropertyNames(ODataNavigationLink navigationLink, bool isExpanded, bool? isCollection) { DuplicationRecord record; string name = navigationLink.Name; if (!this.TryGetDuplicationRecord(name, out record)) { DuplicationRecord duplicationRecord = new DuplicationRecord(DuplicationKind.NavigationProperty); ApplyNavigationLinkToDuplicationRecord(duplicationRecord, isExpanded, isCollection); this.propertyNameCache.Add(name, duplicationRecord); } else { this.CheckNavigationLinkDuplicateNameForExistingDuplicationRecord(name, record); if (((record.DuplicationKind == DuplicationKind.NavigationProperty) && record.AssociationLinkFound) && !record.NavigationLinkFound) { ApplyNavigationLinkToDuplicationRecord(record, isExpanded, isCollection); } else if (this.allowDuplicateProperties) { record.DuplicationKind = DuplicationKind.NavigationProperty; ApplyNavigationLinkToDuplicationRecord(record, isExpanded, isCollection); } else { bool? isCollectionEffectiveValue = GetIsCollectionEffectiveValue(isExpanded, isCollection); if ((isCollectionEffectiveValue == false) || (record.NavigationPropertyIsCollection == false)) { throw new ODataException(Strings.DuplicatePropertyNamesChecker_MultipleLinksForSingleton(name)); } if (isCollectionEffectiveValue.HasValue) { record.NavigationPropertyIsCollection = isCollectionEffectiveValue; } } } }
private static void ApplyNavigationLinkToDuplicationRecord(DuplicationRecord duplicationRecord, bool isExpanded, bool? isCollection) { duplicationRecord.NavigationLinkFound = true; duplicationRecord.NavigationPropertyIsCollection = GetIsCollectionEffectiveValue(isExpanded, isCollection); }
/// <summary> /// Tries to get an existing duplication record for the specified <paramref name="propertyName"/>. /// </summary> /// <param name="propertyName">The property name to look for.</param> /// <param name="duplicationRecord">The existing duplication if one was already found.</param> /// <returns>true if a duplication record already exists, false otherwise.</returns> /// <remarks>This method also initializes the cache if it was not initialized yet.</remarks> private bool TryGetDuplicationRecord(string propertyName, out DuplicationRecord duplicationRecord) { if (this.propertyNameCache == null) { this.propertyNameCache = new Dictionary<string, DuplicationRecord>(EqualityComparer<string>.Default); duplicationRecord = null; return false; } return this.propertyNameCache.TryGetValue(propertyName, out duplicationRecord); }
/// <summary> /// Check the <paramref name="navigationLink"/> for duplicate property names in an entry or complex value. /// If not explicitly allowed throw when duplicate properties are detected. /// If duplicate properties are allowed see the comment on ODataWriterBehavior.AllowDuplicatePropertyNames /// or ODataReaderBehavior.AllowDuplicatePropertyNames for further details. /// </summary> /// <param name="navigationLink">The navigation link to be checked.</param> /// <param name="isExpanded">true if the link is expanded, false otherwise.</param> /// <param name="isCollection">true if the navigation link is a collection, false if it's a singleton or null if we don't know.</param> /// <returns>The association link uri with the same name if there already was one.</returns> internal Uri CheckForDuplicatePropertyNames(ODataNavigationLink navigationLink, bool isExpanded, bool? isCollection) { if (this.disabled) { return null; } #if DEBUG this.startNavigationLinkName = null; #endif string propertyName = navigationLink.Name; DuplicationRecord existingDuplicationRecord; if (!this.TryGetDuplicationRecord(propertyName, out existingDuplicationRecord)) { DuplicationRecord duplicationRecord = new DuplicationRecord(DuplicationKind.NavigationProperty); ApplyNavigationLinkToDuplicationRecord(duplicationRecord, navigationLink, isExpanded, isCollection); this.propertyNameCache.Add(propertyName, duplicationRecord); return null; } else { // First check for duplication without expansion knowledge. this.CheckNavigationLinkDuplicateNameForExistingDuplicationRecord(propertyName, existingDuplicationRecord); if (existingDuplicationRecord.DuplicationKind == DuplicationKind.PropertyAnnotationSeen || (existingDuplicationRecord.DuplicationKind == DuplicationKind.NavigationProperty && existingDuplicationRecord.AssociationLinkName != null && existingDuplicationRecord.NavigationLink == null)) { // If the existing one is just an association link, update it to include the navigation link portion as well ApplyNavigationLinkToDuplicationRecord(existingDuplicationRecord, navigationLink, isExpanded, isCollection); } else if (this.allowDuplicateProperties) { Debug.Assert( (existingDuplicationRecord.DuplicationKind == DuplicationKind.PotentiallyAllowed || existingDuplicationRecord.DuplicationKind == DuplicationKind.NavigationProperty), "We should have already taken care of prohibit duplication."); // If the configuration explicitly allows duplication, then just turn the existing property into a nav link with all the information we have existingDuplicationRecord.DuplicationKind = DuplicationKind.NavigationProperty; ApplyNavigationLinkToDuplicationRecord(existingDuplicationRecord, navigationLink, isExpanded, isCollection); } else { // We've found two navigation links in a request Debug.Assert( existingDuplicationRecord.DuplicationKind == DuplicationKind.NavigationProperty && existingDuplicationRecord.NavigationLink != null && !this.isResponse, "We can only get here if we've found two navigation links in a request."); bool? isCollectionEffectiveValue = GetIsCollectionEffectiveValue(isExpanded, isCollection); // If one of them is a definitive singleton, then we fail. if (isCollectionEffectiveValue == false || existingDuplicationRecord.NavigationPropertyIsCollection == false) { // This is the case where an expanded singleton is followed by a deferred link for example. // Once we know for sure that the nav. prop. is a singleton we can't allow more than one link for it. throw new ODataException(Strings.DuplicatePropertyNamesChecker_MultipleLinksForSingleton(propertyName)); } // Otherwise allow it, but update the link with the new information if (isCollectionEffectiveValue.HasValue) { existingDuplicationRecord.NavigationPropertyIsCollection = isCollectionEffectiveValue; } } return existingDuplicationRecord.AssociationLinkUrl; } }
/// <summary> /// Check the <paramref name="navigationLink"/> for duplicate property names in an entry or complex value. /// If not explicitly allowed throw when duplicate properties are detected. /// If duplicate properties are allowed see the comment on ODataWriterBehavior.AllowDuplicatePropertyNames /// or ODataReaderBehavior.AllowDuplicatePropertyNames for further details. /// </summary> /// <param name="navigationLink">The navigation link to be checked.</param> /// <param name="isExpanded">true if the link is expanded, false otherwise.</param> /// <param name="isCollection">true if the navigation link is a collection, false if it's a singleton or null if we don't know.</param> /// <returns>The association link uri with the same name if there already was one.</returns> internal Uri CheckForDuplicatePropertyNames(ODataNavigationLink navigationLink, bool isExpanded, bool?isCollection) { if (this.disabled) { return(null); } #if DEBUG this.startNavigationLinkName = null; #endif string propertyName = navigationLink.Name; DuplicationRecord existingDuplicationRecord; if (!this.TryGetDuplicationRecord(propertyName, out existingDuplicationRecord)) { DuplicationRecord duplicationRecord = new DuplicationRecord(DuplicationKind.NavigationProperty); ApplyNavigationLinkToDuplicationRecord(duplicationRecord, navigationLink, isExpanded, isCollection); this.propertyNameCache.Add(propertyName, duplicationRecord); return(null); } else { // First check for duplication without expansion knowledge. this.CheckNavigationLinkDuplicateNameForExistingDuplicationRecord(propertyName, existingDuplicationRecord); if (existingDuplicationRecord.DuplicationKind == DuplicationKind.PropertyAnnotationSeen || (existingDuplicationRecord.DuplicationKind == DuplicationKind.NavigationProperty && existingDuplicationRecord.AssociationLinkName != null && existingDuplicationRecord.NavigationLink == null)) { // If the existing one is just an association link, update it to include the navigation link portion as well ApplyNavigationLinkToDuplicationRecord(existingDuplicationRecord, navigationLink, isExpanded, isCollection); } else if (this.allowDuplicateProperties) { Debug.Assert( (existingDuplicationRecord.DuplicationKind == DuplicationKind.PotentiallyAllowed || existingDuplicationRecord.DuplicationKind == DuplicationKind.NavigationProperty), "We should have already taken care of prohibit duplication."); // If the configuration explicitly allows duplication, then just turn the existing property into a nav link with all the information we have existingDuplicationRecord.DuplicationKind = DuplicationKind.NavigationProperty; ApplyNavigationLinkToDuplicationRecord(existingDuplicationRecord, navigationLink, isExpanded, isCollection); } else { // We've found two navigation links in a request Debug.Assert( existingDuplicationRecord.DuplicationKind == DuplicationKind.NavigationProperty && existingDuplicationRecord.NavigationLink != null && !this.isResponse, "We can only get here if we've found two navigation links in a request."); bool?isCollectionEffectiveValue = GetIsCollectionEffectiveValue(isExpanded, isCollection); // If one of them is a definitive singleton, then we fail. if (isCollectionEffectiveValue == false || existingDuplicationRecord.NavigationPropertyIsCollection == false) { // This is the case where an expanded singleton is followed by a deferred link for example. // Once we know for sure that the nav. prop. is a singleton we can't allow more than one link for it. throw new ODataException(Strings.DuplicatePropertyNamesChecker_MultipleLinksForSingleton(propertyName)); } // Otherwise allow it, but update the link with the new information if (isCollectionEffectiveValue.HasValue) { existingDuplicationRecord.NavigationPropertyIsCollection = isCollectionEffectiveValue; } } return(existingDuplicationRecord.AssociationLinkUrl); } }
/// <summary> /// Tries to get an existing duplication record for the specified <paramref name="propertyName"/>. /// </summary> /// <param name="propertyName">The property name to look for.</param> /// <param name="duplicationRecord">The existing duplication if one was already found.</param> /// <returns>true if a duplication record already exists, false otherwise.</returns> /// <remarks>This method also initializes the cache if it was not initialized yet.</remarks> private bool TryGetDuplicationRecord(string propertyName, out DuplicationRecord duplicationRecord) { if (this.propertyNameCache == null) { this.propertyNameCache = new Dictionary<string, DuplicationRecord>(StringComparer.Ordinal); duplicationRecord = null; return false; } return this.propertyNameCache.TryGetValue(propertyName, out duplicationRecord); }
private static void ApplyNavigationLinkToDuplicationRecord(DuplicationRecord duplicationRecord, bool isExpanded, bool?isCollection) { duplicationRecord.NavigationLinkFound = true; duplicationRecord.NavigationPropertyIsCollection = GetIsCollectionEffectiveValue(isExpanded, isCollection); }
private void CheckNavigationLinkDuplicateNameForExistingDuplicationRecord(string propertyName, DuplicationRecord existingDuplicationRecord) { if ((((existingDuplicationRecord.DuplicationKind != DuplicationKind.NavigationProperty) || !existingDuplicationRecord.AssociationLinkFound) || existingDuplicationRecord.NavigationLinkFound) && (((existingDuplicationRecord.DuplicationKind == DuplicationKind.Prohibited) || ((existingDuplicationRecord.DuplicationKind == DuplicationKind.PotentiallyAllowed) && !this.allowDuplicateProperties)) || (((existingDuplicationRecord.DuplicationKind == DuplicationKind.NavigationProperty) && this.isResponse) && !this.allowDuplicateProperties))) { throw new ODataException(Strings.DuplicatePropertyNamesChecker_DuplicatePropertyNamesNotAllowed(propertyName)); } }
/// <summary> /// Checks for duplication of a navigation link against an existing duplication record. /// </summary> /// <param name="propertyName">The name of the navigation link.</param> /// <param name="existingDuplicationRecord">The existing duplication record.</param> /// <remarks>This only performs checks possible without the knowledge of whether the link was expanded or not.</remarks> private void CheckNavigationLinkDuplicateNameForExistingDuplicationRecord(string propertyName, DuplicationRecord existingDuplicationRecord) { if (existingDuplicationRecord.DuplicationKind == DuplicationKind.NavigationProperty && existingDuplicationRecord.AssociationLinkUrl != null && existingDuplicationRecord.NavigationLink == null) { // Existing one is just an association link, so the new one is a navigation link portion which is OK always. } else if (existingDuplicationRecord.DuplicationKind == DuplicationKind.Prohibited || (existingDuplicationRecord.DuplicationKind == DuplicationKind.PotentiallyAllowed && !this.allowDuplicateProperties) || (existingDuplicationRecord.DuplicationKind == DuplicationKind.NavigationProperty && this.isResponse && !this.allowDuplicateProperties)) { // If the existing one doesn't allow duplication at all, // or it's simple property which does allow duplication, but the configuration does not allow it, // or it's a duplicate navigation property in a response, // fail. throw new ODataException(Strings.DuplicatePropertyNamesChecker_DuplicatePropertyNamesNotAllowed(propertyName)); } }
/// <summary> /// Gets a duplication record to use for adding property annotation. /// </summary> /// <param name="propertyName">The name of the property to get the duplication record for.</param> /// <param name="annotationName">The name of the annotation being added (only for error reporting).</param> /// <returns>The duplication record to use. This will never be null.</returns> private DuplicationRecord GetDuplicationRecordToAddPropertyAnnotation(string propertyName, string annotationName) { Debug.Assert(propertyName != null, "propertyName != null"); Debug.Assert(!string.IsNullOrEmpty(annotationName), "!string.IsNullOrEmpty(annotationName)"); DuplicationRecord duplicationRecord; if (!this.TryGetDuplicationRecord(propertyName, out duplicationRecord)) { duplicationRecord = new DuplicationRecord(DuplicationKind.PropertyAnnotationSeen); this.propertyNameCache.Add(propertyName, duplicationRecord); } if (object.ReferenceEquals(duplicationRecord.PropertyODataAnnotations, propertyAnnotationsProcessedToken)) { throw new ODataException(Strings.DuplicatePropertyNamesChecker_PropertyAnnotationAfterTheProperty(annotationName, propertyName)); } Debug.Assert(duplicationRecord != null, "duplicationRecord != null"); return duplicationRecord; }
/// <summary> /// Sets the properties on a duplication record for a navigation link. /// </summary> /// <param name="duplicationRecord">The duplication record to modify.</param> /// <param name="navigationLink">The navigation link found for this property.</param> /// <param name="isExpanded">true if the navigation link is expanded, false otherwise.</param> /// <param name="isCollection">true if the navigation link is marked as collection, false if it's marked as singletong or null if we don't know.</param> private static void ApplyNavigationLinkToDuplicationRecord(DuplicationRecord duplicationRecord, ODataNavigationLink navigationLink, bool isExpanded, bool? isCollection) { duplicationRecord.DuplicationKind = DuplicationKind.NavigationProperty; duplicationRecord.NavigationLink = navigationLink; // We only take the cardinality of the link for granted if it was expanded or if it is a collection. // We can't rely on singleton deferred links to know the cardinality since they can be used for binding even if the actual link is a collection. duplicationRecord.NavigationPropertyIsCollection = GetIsCollectionEffectiveValue(isExpanded, isCollection); }