Exemple #1
0
        public void GetTemplatesWorksForODataPathWithDollarRefOnSingleNavigation()
        {
            // Arrange
            EdmEntityType customer = new EdmEntityType("NS", "Customer");

            customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32));
            EdmEntityContainer container = new EdmEntityContainer("NS", "Default");
            var entitySet  = container.AddEntitySet("Customers", customer);
            var navigation = customer.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo
            {
                TargetMultiplicity = EdmMultiplicity.One,
                Name   = "SubCustomer",
                Target = customer
            });

            ODataPathTemplate template = new ODataPathTemplate(
                new EntitySetSegmentTemplate(entitySet),
                KeySegmentTemplate.CreateKeySegment(customer, entitySet),
                new NavigationLinkSegmentTemplate(navigation, entitySet));

            // Act
            IEnumerable <(string, string)> actual = template.GetTemplates();

            // Assert
            Assert.Equal(2, actual.Count());
            Assert.Equal(new[]
            {
                "Customers({key})/SubCustomer/$ref",
                "Customers/{key}/SubCustomer/$ref"
            }, actual.Select(a => a.Item1));
        }
Exemple #2
0
        internal static bool ProcessNonNavigationProperty(string httpMethod, ODataControllerActionContext context,
                                                          ActionModel action,
                                                          IEdmNavigationSource navigationSource,
                                                          IEdmEntityType entityType, IEdmStructuredType castType)
        {
            // Action parameter should have a (string navigationProperty) parameter
            if (!action.HasParameter <string>("navigationProperty"))
            {
                return(false);
            }

            // Let's only handle single-key convention, for composite key, use attribute routing or non-generic navigation.
            bool hasRelatedKey = action.Parameters.Any(p => p.Name == "relatedKey"); // case sensitive?
            bool hasRelatedId  = action.Parameters.Any(p => p.Name == "relatedId");

            IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>();

            if (context.EntitySet != null)
            {
                segments.Add(new EntitySetSegmentTemplate(context.EntitySet));
                segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, context.EntitySet));
            }
            else
            {
                segments.Add(new SingletonSegmentTemplate(context.Singleton));
            }

            if (entityType != castType)
            {
                segments.Add(new CastSegmentTemplate(castType, entityType, navigationSource));
            }

            if (hasRelatedKey)
            {
                segments.Add(new NavigationLinkTemplateSegmentTemplate(entityType, navigationSource)
                {
                    RelatedKey = "relatedKey"
                });
            }
            else if (hasRelatedId)
            {
                segments.Add(new NavigationLinkTemplateSegmentTemplate(entityType, navigationSource)
                {
                    RelatedKey = "relatedId"
                });
            }
            else
            {
                segments.Add(new NavigationLinkTemplateSegmentTemplate(entityType, navigationSource));
            }

            ODataPathTemplate template = new ODataPathTemplate(segments);

            action.AddSelector(httpMethod, context.Prefix, context.Model, template, context.Options?.RouteOptions);

            return(true);
        }
Exemple #3
0
        public void TryTranslateNavigationLinkSegmentTemplate_ReturnsODataNavigationSegment()
        {
            // Arrange
            EdmModel model = new EdmModel();

            model.AddElement(_employee);

            NavigationLinkSegmentTemplate linkSegment          = new NavigationLinkSegmentTemplate(_navigation, null);
            RouteValueDictionary          routeValueDictionary = new RouteValueDictionary(new { id = "42" });
            ODataTemplateTranslateContext context = new ODataTemplateTranslateContext
            {
                RouteValues = routeValueDictionary,
                Model       = model
            };

            // Without key segment
            // Act & Assert
            bool ok = linkSegment.TryTranslate(context);

            Assert.True(ok);
            ODataPathSegment actual = Assert.Single(context.Segments);
            NavigationPropertyLinkSegment navLinkSegment = Assert.IsType <NavigationPropertyLinkSegment>(actual);

            Assert.Same(_navigation, navLinkSegment.NavigationProperty);
            Assert.Null(navLinkSegment.NavigationSource);

            // With Key segment
            // Act & Assert
            context = new ODataTemplateTranslateContext
            {
                RouteValues = routeValueDictionary,
                Model       = model
            };

            linkSegment.Key = KeySegmentTemplate.CreateKeySegment(_employee, null, "id");
            ok = linkSegment.TryTranslate(context);

            Assert.True(ok);
            Assert.Collection(context.Segments,
                              e =>
            {
                NavigationPropertyLinkSegment navLinkSegment = Assert.IsType <NavigationPropertyLinkSegment>(e);
                Assert.Same(_navigation, navLinkSegment.NavigationProperty);
                Assert.Null(navLinkSegment.NavigationSource);
            },
                              e =>
            {
                KeySegment keySegment             = Assert.IsType <KeySegment>(e);
                KeyValuePair <string, object> key = Assert.Single(keySegment.Keys);
                Assert.Equal("Id", key.Key);
                Assert.Equal(42, key.Value);
            });
        }
Exemple #4
0
        private static void AddSelector(string httpMethod, ODataControllerActionContext context, ActionModel action,
                                        IEdmNavigationSource navigationSource,
                                        IEdmStructuralProperty edmProperty,
                                        IEdmType cast, IEdmEntityType declaringType, bool dollarValue, bool dollarCount)
        {
            IEdmEntitySet  entitySet  = navigationSource as IEdmEntitySet;
            IEdmEntityType entityType = navigationSource.EntityType();

            IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>();

            if (entitySet != null)
            {
                segments.Add(new EntitySetSegmentTemplate(entitySet));
                segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, navigationSource));
            }
            else
            {
                segments.Add(new SingletonSegmentTemplate(navigationSource as IEdmSingleton));
            }

            if (declaringType != null && declaringType != entityType)
            {
                segments.Add(new CastSegmentTemplate(declaringType, entityType, navigationSource));
            }

            segments.Add(new PropertySegmentTemplate(edmProperty));

            if (cast != null)
            {
                if (edmProperty.Type.IsCollection())
                {
                    cast = new EdmCollectionType(cast.ToEdmTypeReference(edmProperty.Type.IsNullable));
                }

                // TODO: maybe create the collection type for the collection????
                segments.Add(new CastSegmentTemplate(cast, edmProperty.Type.Definition, navigationSource));
            }

            if (dollarValue)
            {
                segments.Add(new ValueSegmentTemplate(edmProperty.Type.Definition));
            }

            if (dollarCount)
            {
                segments.Add(CountSegmentTemplate.Instance);
            }

            ODataPathTemplate template = new ODataPathTemplate(segments);

            action.AddSelector(httpMethod.NormalizeHttpMethod(), context.Prefix, context.Model, template, context.Options?.RouteOptions);
        }
Exemple #5
0
        public void CreateKeySegmentKeySegmentTemplate_ReturnsKeySegmentTemplate()
        {
            // Arrange
            KeySegmentTemplate template = KeySegmentTemplate.CreateKeySegment(_customerType, _customers, "id");

            // Assert
            Assert.NotNull(template);
            Assert.Equal(1, template.Count);
            KeyValuePair <string, string> keyMapping = Assert.Single(template.KeyMappings);

            Assert.Equal("customerId", keyMapping.Key);
            Assert.Equal("id", keyMapping.Value);
        }
Exemple #6
0
        private void AddSelector(string httpMethod, ODataControllerActionContext context, ActionModel action,
                                 IEdmNavigationSource navigationSource, string declared, IEdmEntityType declaringEntityType,
                                 IEdmNavigationProperty navigationProperty, bool hasKey, bool dollarCount)
        {
            IEdmEntitySet  entitySet  = navigationSource as IEdmEntitySet;
            IEdmEntityType entityType = navigationSource.EntityType();

            // Starts the routing template
            IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>();

            if (entitySet != null)
            {
                segments.Add(new EntitySetSegmentTemplate(entitySet));
            }
            else
            {
                segments.Add(new SingletonSegmentTemplate(navigationSource as IEdmSingleton));
            }

            if (hasKey)
            {
                segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, navigationSource));
            }

            if (declared != null)
            {
                // It should be always single type
                if (entityType != declaringEntityType)
                {
                    segments.Add(new CastSegmentTemplate(declaringEntityType, entityType, navigationSource));
                }
            }

            IEdmNavigationSource targetNavigationSource = navigationSource.FindNavigationTarget(navigationProperty, segments, out _);

            segments.Add(new NavigationSegmentTemplate(navigationProperty, targetNavigationSource));

            if (dollarCount)
            {
                segments.Add(CountSegmentTemplate.Instance);
            }

            ODataPathTemplate template = new ODataPathTemplate(segments);

            action.AddSelector(httpMethod.NormalizeHttpMethod(), context.Prefix, context.Model, template, context.RouteOptions);

            Log.AddedODataSelector(_logger, action, template);
        }
Exemple #7
0
        public void CreateKeySegmentKeySegmentTemplate_ReturnsKeySegmentTemplate_CompositeKey()
        {
            // Arrange
            EdmEntityType         customerType  = new EdmEntityType("NS", "Customer");
            EdmStructuralProperty firstProperty = customerType.AddStructuralProperty("firstName", EdmPrimitiveTypeKind.String);
            EdmStructuralProperty lastProperty  = customerType.AddStructuralProperty("lastName", EdmPrimitiveTypeKind.String);

            customerType.AddKeys(firstProperty, lastProperty);

            // Act
            KeySegmentTemplate template = KeySegmentTemplate.CreateKeySegment(customerType, null);

            // Assert
            Assert.NotNull(template);
            Assert.Equal(2, template.Count);
        }
Exemple #8
0
        public void GetTemplatesWorksForPathWithTypeCastAndFunction()
        {
            // Arrange
            EdmEntityType customer = new EdmEntityType("NS", "Customer");

            customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32));

            // VipCustomer
            EdmEntityType vipCustomer = new EdmEntityType("NS", "VipCustomer", customer);

            EdmEntityContainer container = new EdmEntityContainer("NS", "Default");
            var entitySet = container.AddEntitySet("Customers", customer);

            // function with optional parameters
            EdmFunction getSalaray = new EdmFunction("NS", "GetWholeSalary", IntType, isBound: true, entitySetPathExpression: null, isComposable: false);

            getSalaray.AddParameter("entityset", new EdmEntityTypeReference(vipCustomer, false));
            getSalaray.AddParameter("salary", IntType);
            getSalaray.AddOptionalParameter("minSalary", IntType);
            getSalaray.AddOptionalParameter("maxSalary", IntType, "129");

            ODataPathTemplate template = new ODataPathTemplate(
                new EntitySetSegmentTemplate(entitySet),
                KeySegmentTemplate.CreateKeySegment(customer, entitySet),
                new CastSegmentTemplate(vipCustomer, customer, entitySet),
                new FunctionSegmentTemplate(getSalaray, null));

            // Act
            IEnumerable <(string, string)> actual = template.GetTemplates();

            Assert.Equal(4, actual.Count());
            Assert.Equal(new[]
            {
                "Customers({key})/NS.VipCustomer/NS.GetWholeSalary({salary;minSalary;maxSalary})",
                "Customers({key})/NS.VipCustomer/GetWholeSalary({salary;minSalary;maxSalary})",
                "Customers/{key}/NS.VipCustomer/NS.GetWholeSalary({salary;minSalary;maxSalary})",
                "Customers/{key}/NS.VipCustomer/GetWholeSalary({salary;minSalary;maxSalary})",
            }, actual.Select(a => a.Item1));

            Assert.Equal(new[]
            {
                "Customers({key})/NS.VipCustomer/NS.GetWholeSalary(salary={salary},minSalary={minSalary},maxSalary={maxSalary})",
                "Customers({key})/NS.VipCustomer/GetWholeSalary(salary={salary},minSalary={minSalary},maxSalary={maxSalary})",
                "Customers/{key}/NS.VipCustomer/NS.GetWholeSalary(salary={salary},minSalary={minSalary},maxSalary={maxSalary})",
                "Customers/{key}/NS.VipCustomer/GetWholeSalary(salary={salary},minSalary={minSalary},maxSalary={maxSalary})",
            }, actual.Select(a => a.Item2));
        }
Exemple #9
0
        public void GetTemplatesNavigationLinkSegmentTemplate_ReturnsTemplates()
        {
            // Arrange
            NavigationLinkSegmentTemplate linkSegment = new NavigationLinkSegmentTemplate(_navigation, null);

            // Act & Assert
            IEnumerable <string> templates = linkSegment.GetTemplates();
            string template = Assert.Single(templates);

            Assert.Equal("/DirectReports/$ref", template);

            // Act & Assert
            linkSegment.Key = KeySegmentTemplate.CreateKeySegment(_employee, null);
            templates       = linkSegment.GetTemplates();
            Assert.Collection(templates,
                              e => Assert.Equal("/DirectReports({key})/$ref", e),
                              e => Assert.Equal("/DirectReports/{key}/$ref", e));
        }
Exemple #10
0
        public void GetTemplatesWorksForBasicPath()
        {
            // Arrange
            EdmEntityType customer = new EdmEntityType("NS", "Customer");

            customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32));
            EdmEntityContainer container = new EdmEntityContainer("NS", "Default");
            var entitySet = container.AddEntitySet("Customers", customer);

            ODataPathTemplate template = new ODataPathTemplate(
                new EntitySetSegmentTemplate(entitySet),
                KeySegmentTemplate.CreateKeySegment(customer, entitySet));

            // Act
            IEnumerable <(string, string)> actual = template.GetTemplates();

            // Assert
            Assert.Equal(2, actual.Count());
            Assert.Equal(new[] { "Customers({key})", "Customers/{key}" }, actual.Select(a => a.Item1));
        }
        public void GetTemplatesWorksForODataPathWithDollarRefOnCollectionNavigation()
        {
            // Arrange
            EdmEntityType customer = new EdmEntityType("NS", "Customer");

            customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32));
            EdmEntityContainer container = new EdmEntityContainer("NS", "Default");
            var entitySet  = container.AddEntitySet("Customers", customer);
            var navigation = customer.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo
            {
                TargetMultiplicity = EdmMultiplicity.Many,
                Name   = "SubCustomers",
                Target = customer
            });

            KeyValuePair <string, object>[] keys = new KeyValuePair <string, object>[]
            {
                new KeyValuePair <string, object>("Id", "{nextKey}")
            };
            KeySegment        keySegment = new KeySegment(keys, customer, entitySet);
            ODataPathTemplate template   = new ODataPathTemplate(
                new EntitySetSegmentTemplate(entitySet),
                KeySegmentTemplate.CreateKeySegment(customer, entitySet),
                new NavigationLinkSegmentTemplate(navigation, entitySet)
            {
                Key = new KeySegmentTemplate(keySegment)
            });

            // Act
            IEnumerable <string> actual = template.GetTemplates();

            // Assert
            Assert.Equal(4, actual.Count());
            Assert.Equal(new[]
            {
                "Customers({key})/SubCustomers({nextKey})/$ref",
                "Customers({key})/SubCustomers/{nextKey}/$ref",
                "Customers/{key}/SubCustomers({nextKey})/$ref",
                "Customers/{key}/SubCustomers/{nextKey}/$ref"
            }, actual);
        }
Exemple #12
0
        public void TranslateODataPathTemplate_ToODataPath()
        {
            // Assert
            EdmEntityType customer = new EdmEntityType("NS", "Customer");

            customer.AddKeys(customer.AddStructuralProperty("CustomerId", EdmPrimitiveTypeKind.Int32));
            EdmEntityContainer container = new EdmEntityContainer("NS", "Default");
            var      entitySet           = container.AddEntitySet("Customers", customer);
            EdmModel model = new EdmModel();

            model.AddElement(customer);
            model.AddElement(container);

            ODataPathTemplate template = new ODataPathTemplate(
                new EntitySetSegmentTemplate(entitySet),
                KeySegmentTemplate.CreateKeySegment(customer, entitySet));

            DefaultODataTemplateTranslator translator = new DefaultODataTemplateTranslator();
            ODataTemplateTranslateContext  context    = new ODataTemplateTranslateContext
            {
                RouteValues = new RouteValueDictionary(new { key = "42" }),
                Model       = model
            };

            // Act
            ODataPath path = translator.Translate(template, context);

            // Assert
            Assert.NotNull(path);
            Assert.Equal(2, path.Count);
            EntitySetSegment entitySetSegment = Assert.IsType <EntitySetSegment>(path.FirstSegment);

            Assert.Equal("Customers", entitySetSegment.EntitySet.Name);

            KeySegment keySegment             = Assert.IsType <KeySegment>(path.LastSegment);
            KeyValuePair <string, object> key = Assert.Single(keySegment.Keys);

            Assert.Equal("CustomerId", key.Key);
            Assert.Equal(42, key.Value);
        }
        private static void AddSelector(IEdmEntitySet entitySet, IEdmEntityType entityType,
                                        IEdmStructuredType castType, string prefix, IEdmModel model, ActionModel action, string httpMethod)
        {
            IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>
            {
                new EntitySetSegmentTemplate(entitySet),
                KeySegmentTemplate.CreateKeySegment(entityType, entitySet)
            };

            // If we have the type cast
            if (castType != null)
            {
                if (castType == entityType)
                {
                    // If cast type is the entity type of the entity set.
                    // we support two templates
                    // ~/Customers({key})
                    action.AddSelector(httpMethod, prefix, model, new ODataPathTemplate(segments));

                    // ~/Customers({key})/Ns.Customer
                    segments.Add(new CastSegmentTemplate(castType, entityType, entitySet));
                    action.AddSelector(httpMethod, prefix, model, new ODataPathTemplate(segments));
                }
                else
                {
                    // ~/Customers({key})/Ns.VipCustomer
                    segments.Add(new CastSegmentTemplate(castType, entityType, entitySet));
                    action.AddSelector(httpMethod, prefix, model, new ODataPathTemplate(segments));
                }
            }
            else
            {
                // ~/Customers({key})
                action.AddSelector(httpMethod, prefix, model, new ODataPathTemplate(segments));
            }
        }
Exemple #14
0
 public void CreateKeySegmentKeySegmentTemplate_ThrowsArgumentNull_EntityType()
 {
     // Arrange & Act & Assert
     ExceptionAssert.ThrowsArgumentNull(() => KeySegmentTemplate.CreateKeySegment(null, null), "entityType");
 }
Exemple #15
0
        /// <summary>
        /// Add the template to the action
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="edmOperation">The Edm operation.</param>
        /// <param name="hasKeyParameter">Has key parameter or not.</param>
        /// <param name="entityType">The entity type.</param>
        /// <param name="navigationSource">The navigation source.</param>
        /// <param name="castType">The type cast.</param>
        protected static void AddSelector(ODataControllerActionContext context,
                                          IEdmOperation edmOperation,
                                          bool hasKeyParameter,
                                          IEdmEntityType entityType,
                                          IEdmNavigationSource navigationSource,
                                          IEdmEntityType castType)
        {
            Contract.Assert(context != null);
            Contract.Assert(entityType != null);
            Contract.Assert(navigationSource != null);
            Contract.Assert(edmOperation != null);

            // Now, let's add the selector model.
            IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>();

            if (context.EntitySet != null)
            {
                segments.Add(new EntitySetSegmentTemplate(context.EntitySet));
                if (hasKeyParameter)
                {
                    segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, navigationSource));
                }
            }
            else
            {
                segments.Add(new SingletonSegmentTemplate(context.Singleton));
            }

            if (castType != null)
            {
                if (context.Singleton != null || !hasKeyParameter)
                {
                    segments.Add(new CastSegmentTemplate(castType, entityType, navigationSource));
                }
                else
                {
                    segments.Add(new CastSegmentTemplate(new EdmCollectionType(castType.ToEdmTypeReference(false)),
                                                         new EdmCollectionType(entityType.ToEdmTypeReference(false)), navigationSource));
                }
            }

            IEdmNavigationSource targetset = null;

            if (edmOperation.ReturnType != null)
            {
                targetset = edmOperation.GetTargetEntitySet(navigationSource, context.Model);
            }

            string httpMethod;

            if (edmOperation.IsAction())
            {
                segments.Add(new ActionSegmentTemplate((IEdmAction)edmOperation, targetset));
                httpMethod = "post";
            }
            else
            {
                IDictionary <string, string> required = GetRequiredFunctionParamters(edmOperation, context.Action);
                segments.Add(new FunctionSegmentTemplate(required, (IEdmFunction)edmOperation, targetset));
                httpMethod = "get";
            }

            ODataPathTemplate template = new ODataPathTemplate(segments);

            context.Action.AddSelector(httpMethod, context.Prefix, context.Model, template, context.Options?.RouteOptions);
        }
Exemple #16
0
        /// <inheritdoc />
        public bool AppliesToAction(ODataControllerActionContext context)
        {
            if (context == null)
            {
                throw Error.ArgumentNull(nameof(context));
            }

            Debug.Assert(context.Action != null);

            ActionModel action           = context.Action;
            string      actionMethodName = action.ActionName;

            // Need to refactor the following
            // for example:  CreateRef( with the navigation property parameter) should for all navigation properties
            // CreateRefToOrdersFromCustomer, CreateRefToOrders, CreateRef.
            string method = SplitRefActionName(actionMethodName, out string httpMethod, out string property, out string declaring);

            if (method == null)
            {
                return(false);
            }

            IEdmNavigationSource navigationSource = context.NavigationSource;
            IEdmEntityType       entityType       = context.EntityType;

            // For entity set, we should have the key parameter
            // For Singleton, we should not have the key parameter
            bool hasODataKeyParameter = action.HasODataKeyParameter(entityType);

            if ((context.EntitySet != null && !hasODataKeyParameter) ||
                (context.Singleton != null && hasODataKeyParameter))
            {
                return(false);
            }

            // Find the navigation property declaring type
            IEdmStructuredType declaringType = entityType;

            if (declaring != null)
            {
                declaringType = entityType.FindTypeInInheritance(context.Model, declaring);
                if (declaringType == null)
                {
                    return(false);
                }
            }

            // Process the generic scenario
            if (property == null)
            {
                return(ProcessNonNavigationProperty(httpMethod, context, action, navigationSource, entityType, declaringType));
            }

            // Find the navigation property if have
            IEdmNavigationProperty navigationProperty = null;

            if (property != null)
            {
                navigationProperty = declaringType.DeclaredNavigationProperties().FirstOrDefault(p => p.Name == property);
            }

            if (navigationProperty == null)
            {
                return(false);
            }

            IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>();

            if (context.EntitySet != null)
            {
                segments.Add(new EntitySetSegmentTemplate(context.EntitySet));
                segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, context.EntitySet));
            }
            else
            {
                segments.Add(new SingletonSegmentTemplate(context.Singleton));
            }

            if (entityType != declaringType)
            {
                segments.Add(new CastSegmentTemplate(declaringType, entityType, navigationSource));
            }

            IEdmNavigationSource          targetNavigationSource = navigationSource.FindNavigationTarget(navigationProperty, segments, out _);
            NavigationLinkSegmentTemplate linkTemplate           = new NavigationLinkSegmentTemplate(navigationProperty, targetNavigationSource);

            IEdmEntityType navigationPropertyType            = navigationProperty.Type.GetElementTypeOrSelf().AsEntity().EntityDefinition();
            bool           hasNavigationPropertyKeyParameter = action.HasODataKeyParameter(navigationPropertyType, "relatedKey");

            if (hasNavigationPropertyKeyParameter)
            {
                linkTemplate.Key = KeySegmentTemplate.CreateKeySegment(navigationPropertyType, targetNavigationSource, "relatedKey");
            }
            else
            {
                hasNavigationPropertyKeyParameter = action.HasODataKeyParameter(navigationPropertyType, "relatedId");
                if (hasNavigationPropertyKeyParameter)
                {
                    linkTemplate.Key = KeySegmentTemplate.CreateKeySegment(navigationPropertyType, targetNavigationSource, "relatedId");
                }
            }

            segments.Add(linkTemplate);

            ODataPathTemplate template = new ODataPathTemplate(segments);

            action.AddSelector(httpMethod, context.Prefix, context.Model, template, context.Options?.RouteOptions);

            // processed
            return(true);
        }