private static ODataPath CreatePath(ODataPath parentPath, ODataExpandPath pathToNavigationProperty) { var segments = new List <ODataPathSegment>(parentPath); segments.AddRange(pathToNavigationProperty); return(new ODataPath(segments)); }
public void GetFirstNonTypeCastSegment_WorksForExpandPathWithPropertySegment() { // Arrange EdmEntityType entityType = new EdmEntityType("NS", "Customer"); IEdmStructuralProperty property = entityType.AddStructuralProperty("Id", EdmPrimitiveTypeKind.String); var navProperty = entityType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { Name = "Nav", Target = entityType, TargetMultiplicity = EdmMultiplicity.One }); EdmEntityContainer container = new EdmEntityContainer("NS", "Container"); EdmEntitySet set = new EdmEntitySet(container, "set", entityType); NavigationPropertySegment navSegment = new NavigationPropertySegment(navProperty, set); TypeSegment typeSegment = new TypeSegment(entityType, null); ODataPathSegment propertySegment = new PropertySegment(property); ODataExpandPath expandPath = new ODataExpandPath(typeSegment, propertySegment, navSegment); // Act IList <ODataPathSegment> remainingSegments; ODataPathSegment firstNonTypeSegment = expandPath.GetFirstNonTypeCastSegment(out remainingSegments); // Assert Assert.NotNull(firstNonTypeSegment); Assert.Same(propertySegment, firstNonTypeSegment); Assert.NotNull(remainingSegments); Assert.Same(navSegment, Assert.Single(remainingSegments)); }
private static IEnumerable <SelectItem> GetAutoExpandedNavigationSelectItems( IEdmEntityType baseEntityType, IEdmModel model, string alreadyExpandedNavigationSourceName, IEdmNavigationSource navigationSource, bool isAllSelected, bool searchDerivedTypeWhenAutoExpand) { var expandItems = new List <SelectItem>(); var autoExpandNavigationProperties = EdmLibHelpers.GetAutoExpandNavigationProperties(baseEntityType, model, searchDerivedTypeWhenAutoExpand); foreach (var navigationProperty in autoExpandNavigationProperties) { if (!alreadyExpandedNavigationSourceName.Equals(navigationProperty.Name)) { IEdmEntityType entityType = navigationProperty.DeclaringEntityType(); IEdmNavigationSource currentEdmNavigationSource = navigationSource.FindNavigationTarget(navigationProperty); if (currentEdmNavigationSource != null) { List <ODataPathSegment> pathSegments = new List <ODataPathSegment>() { new NavigationPropertySegment(navigationProperty, currentEdmNavigationSource) }; ODataExpandPath expandPath = new ODataExpandPath(pathSegments); SelectExpandClause selectExpandClause = new SelectExpandClause(new List <SelectItem>(), true); ExpandedNavigationSelectItem item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource, selectExpandClause); if (!currentEdmNavigationSource.EntityType().Equals(entityType)) { IEnumerable <SelectItem> nestedSelectItems = GetAutoExpandedNavigationSelectItems( currentEdmNavigationSource.EntityType(), model, alreadyExpandedNavigationSourceName, item.NavigationSource, true, searchDerivedTypeWhenAutoExpand); selectExpandClause = new SelectExpandClause(nestedSelectItems, true); item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource, selectExpandClause); } expandItems.Add(item); if (!isAllSelected) { PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(pathSegments)); expandItems.Add(pathSelectItem); } } } } return(expandItems); }
public void GetFirstNonTypeCastSegment_ExpandPath_ThrowsArgumentNull() { // Arrange & Act ODataExpandPath expandPath = null; IList <ODataPathSegment> remainingSegments; // Assert ExceptionAssert.ThrowsArgumentNull(() => expandPath.GetFirstNonTypeCastSegment(out remainingSegments), "expandPath"); }
private SelectExpandClause BuildSelectExpandClause(IEdmEntitySet entitySet, GraphQLSelectionSet selectionSet) { var selectItems = new List <SelectItem>(); foreach (ASTNode astNode in selectionSet.Selections) { if (astNode is GraphQLFieldSelection fieldSelection) { IEdmProperty edmProperty = FindEdmProperty(entitySet.EntityType(), fieldSelection.Name.Value); if (fieldSelection.SelectionSet == null) { var structuralProperty = (IEdmStructuralProperty)edmProperty; selectItems.Add(new PathSelectItem(new ODataSelectPath(new PropertySegment(structuralProperty)))); } else { var navigationProperty = (IEdmNavigationProperty)edmProperty; IEdmEntitySet parentEntitySet; if (navigationProperty.ContainsTarget) { ModelBuilder.ManyToManyJoinDescription joinDescription = _edmModel.GetManyToManyJoinDescription(navigationProperty); parentEntitySet = OeEdmClrHelper.GetEntitySet(_edmModel, joinDescription.TargetNavigationProperty); } else { parentEntitySet = OeEdmClrHelper.GetEntitySet(_edmModel, navigationProperty); } var expandPath = new ODataExpandPath(new NavigationPropertySegment(navigationProperty, parentEntitySet)); FilterClause filterOption = null; if (fieldSelection.Arguments.Any()) { filterOption = BuildFilterClause(parentEntitySet, fieldSelection); } SelectExpandClause childSelectExpand = BuildSelectExpandClause(parentEntitySet, fieldSelection.SelectionSet); var expandedSelectItem = new ExpandedNavigationSelectItem(expandPath, parentEntitySet, childSelectExpand, filterOption, null, null, null, null, null, null); selectItems.Add(expandedSelectItem); } } else { throw new NotSupportedException("selection " + astNode.GetType().Name + " not supported"); } } return(new SelectExpandClause(selectItems, false)); }
/// <summary> /// Verify the $expand path and gets the first non type cast segment in this expand path. /// For example: $expand=NS.SubType1/abc/NS.SubType2/nav /// => firstPropertySegment: "abc" /// => remainingSegments: NS.SubType2/nav /// => leadingTypeSegment: NS.SubType1 /// </summary> /// <param name="expandPath">The input $expand path.</param> /// <param name="remainingSegments">The remaining segments after the first non type segment.</param> /// <returns>First non-type cast segment.</returns> public static ODataPathSegment GetFirstNonTypeCastSegment(this ODataExpandPath expandPath, out IList <ODataPathSegment> remainingSegments) { if (expandPath == null) { throw new ArgumentNullException(nameof(expandPath)); } // In fact, ODataExpandPath constructor verifies the supporting segments, we add the verification here for double check. return(GetFirstNonTypeCastSegment(expandPath, //The middle segment should be "TypeSegment" or "PropertySegment". m => m is PropertySegment || m is TypeSegment, // The last segment could be "NavigationPropertySegment" s => s is NavigationPropertySegment, out remainingSegments)); }
private SelectExpandClause BuildSelectExpandClause(IEdmEntitySet entitySet, GraphQLSelectionSet selectionSet) { var selectItems = new List <SelectItem>(); foreach (ASTNode astNode in selectionSet.Selections) { if (astNode is GraphQLFieldSelection fieldSelection) { IEdmProperty edmProperty = FindEdmProperty(entitySet.EntityType(), fieldSelection.Name.Value); if (fieldSelection.SelectionSet == null) { var structuralProperty = (IEdmStructuralProperty)edmProperty; selectItems.Add(new PathSelectItem(new ODataSelectPath(new PropertySegment(structuralProperty)))); } else { IEdmType edmType = edmProperty.Type.Definition; if (edmType is IEdmCollectionType collectionType) { edmType = collectionType.ElementType.Definition; } IEdmEntitySet parentEntitySet = OeEdmClrHelper.GetEntitySet(_edmModel, edmType); SelectExpandClause childSelectExpand = BuildSelectExpandClause(parentEntitySet, fieldSelection.SelectionSet); var navigationProperty = (IEdmNavigationProperty)edmProperty; IEdmEntitySet navigationSource = OeEdmClrHelper.GetEntitySet(_edmModel, navigationProperty.Type.Definition); var expandPath = new ODataExpandPath(new NavigationPropertySegment(navigationProperty, navigationSource)); FilterClause filterOption = null; if (fieldSelection.Arguments.Any()) { filterOption = BuildFilterClause(parentEntitySet, fieldSelection); } var expandedSelectItem = new ExpandedNavigationSelectItem(expandPath, navigationSource, childSelectExpand, filterOption, null, null, null, null, null, null); selectItems.Add(expandedSelectItem); } } else { throw new NotSupportedException("selection " + astNode.GetType().Name + " not supported"); } } return(new SelectExpandClause(selectItems, false)); }
/// <summary> /// Add sub $expand item for this include property. /// </summary> /// <param name="remainingSegments">The remaining segments star from this include property.</param> /// <param name="oldRefItem">The old $expand item.</param> public void AddSubExpandItem(IList <ODataPathSegment> remainingSegments, ExpandedReferenceSelectItem oldRefItem) { // remainingSegments should never be null, because at least a navigation property segment in it. Contract.Assert(remainingSegments != null); if (_subSelectItems == null) { _subSelectItems = new List <SelectItem>(); } ODataExpandPath newPath = new ODataExpandPath(remainingSegments); ExpandedNavigationSelectItem expandedNav = oldRefItem as ExpandedNavigationSelectItem; if (expandedNav != null) { _subSelectItems.Add(new ExpandedNavigationSelectItem(newPath, expandedNav.NavigationSource, expandedNav.SelectAndExpand, expandedNav.FilterOption, expandedNav.OrderByOption, expandedNav.TopOption, expandedNav.SkipOption, expandedNav.CountOption, expandedNav.SearchOption, expandedNav.LevelsOption, expandedNav.ComputeOption, expandedNav.ApplyOption)); } else { _subSelectItems.Add(new ExpandedReferenceSelectItem(newPath, oldRefItem.NavigationSource, oldRefItem.FilterOption, oldRefItem.OrderByOption, oldRefItem.TopOption, oldRefItem.SkipOption, oldRefItem.CountOption, oldRefItem.SearchOption, oldRefItem.ComputeOption, oldRefItem.ApplyOption)); } }
public ExpandDepthAndCountValidatorTests() { this.emptyTree = new SelectExpandClause(new SelectItem[0], true); var pathToMyDog = new ODataExpandPath(new NavigationPropertySegment(HardCodedTestModel.GetPersonMyDogNavProp(), HardCodedTestModel.GetDogsSet())); this.treeWithDepth1 = new SelectExpandClause(new[] { new ExpandedNavigationSelectItem(pathToMyDog, HardCodedTestModel.GetDogsSet(), this.emptyTree) }, true); var pathToPerson = new ODataExpandPath(new NavigationPropertySegment(HardCodedTestModel.GetDogMyPeopleNavProp(), HardCodedTestModel.GetPeopleSet())); this.treeWithDepth2 = new SelectExpandClause(new[] { new ExpandedNavigationSelectItem(pathToPerson, HardCodedTestModel.GetPeopleSet(), this.treeWithDepth1) }, true); var pathToLions = new ODataExpandPath(new NavigationPropertySegment(HardCodedTestModel.GetPersonMyLionsNavProp(), HardCodedTestModel.GetLionSet())); this.treeWithWidth2 = new SelectExpandClause(new[] { new ExpandedNavigationSelectItem(pathToMyDog, HardCodedTestModel.GetDogsSet(), this.emptyTree), new ExpandedNavigationSelectItem(pathToLions, HardCodedTestModel.GetLionSet(), this.emptyTree) }, true); this.treeWithDepthAndWidth2WithRepeatedParent = new SelectExpandClause(new[] { new ExpandedNavigationSelectItem(pathToPerson, HardCodedTestModel.GetPeopleSet(), this.treeWithWidth2) }, true); var pathToPaintings = new ODataExpandPath(new NavigationPropertySegment(HardCodedTestModel.GetPersonMyPaintingsNavProp(), HardCodedTestModel.GetPaintingsSet())); this.bigComplexTree = new SelectExpandClause(new[] { new ExpandedNavigationSelectItem(pathToMyDog, HardCodedTestModel.GetDogsSet(), this.treeWithDepthAndWidth2WithRepeatedParent), new ExpandedNavigationSelectItem(pathToLions, HardCodedTestModel.GetLionSet(), this.emptyTree), new ExpandedNavigationSelectItem(pathToPaintings, HardCodedTestModel.GetPaintingsSet(), this.emptyTree) }, true); }
/// <summary> /// Generate an expand item (and a select item for the implicit nav prop if necessary) based on an ExpandTermToken /// </summary> /// <param name="tokenIn">the expandTerm token to visit</param> /// <returns>the expand item for this expand term token.</returns> private SelectItem GenerateExpandItem(ExpandTermToken tokenIn) { ExceptionUtils.CheckArgumentNotNull(tokenIn, "tokenIn"); // ensure that we're always dealing with proper V4 syntax if (tokenIn.PathToNavProp.NextToken != null && !tokenIn.PathToNavProp.IsNamespaceOrContainerQualified()) { if (tokenIn.PathToNavProp.NextToken.Identifier != UriQueryConstants.RefSegment || tokenIn.PathToNavProp.NextToken.NextToken != null) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_TraversingMultipleNavPropsInTheSamePath); } } PathSegmentToken currentToken = tokenIn.PathToNavProp; IEdmStructuredType currentLevelEntityType = this.EdmType; List <ODataPathSegment> pathSoFar = new List <ODataPathSegment>(); PathSegmentToken firstNonTypeToken = currentToken; if (currentToken.IsNamespaceOrContainerQualified()) { pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(currentToken, this.Model, this.Settings.SelectExpandLimit, this.configuration.Resolver, ref currentLevelEntityType, out firstNonTypeToken)); } IEdmProperty edmProperty = this.configuration.Resolver.ResolveProperty(currentLevelEntityType, firstNonTypeToken.Identifier); if (edmProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(currentLevelEntityType.FullTypeName(), currentToken.Identifier)); } IEdmNavigationProperty currentNavProp = edmProperty as IEdmNavigationProperty; if (currentNavProp == null) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_PropertyIsNotANavigationProperty(currentToken.Identifier, currentLevelEntityType.FullTypeName())); } bool isRef = false; if (firstNonTypeToken.NextToken != null) { // lastly... make sure that, since we're on a NavProp, that the next token isn't null. if (firstNonTypeToken.NextToken.Identifier == UriQueryConstants.RefSegment) { isRef = true; } else { throw new ODataException(ODataErrorStrings.ExpandItemBinder_TraversingMultipleNavPropsInTheSamePath); } } pathSoFar.Add(new NavigationPropertySegment(currentNavProp, /*entitySet*/ null)); ODataExpandPath pathToNavProp = new ODataExpandPath(pathSoFar); IEdmNavigationSource targetNavigationSource = null; if (this.NavigationSource != null) { targetNavigationSource = this.NavigationSource.FindNavigationTarget(currentNavProp); } // call MetadataBinder to build the filter clause FilterClause filterOption = null; if (tokenIn.FilterOption != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetNavigationSource); FilterBinder filterBinder = new FilterBinder(binder.Bind, binder.BindingState); filterOption = filterBinder.BindFilter(tokenIn.FilterOption); } // call MetadataBinder again to build the orderby clause OrderByClause orderbyOption = null; if (tokenIn.OrderByOptions != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetNavigationSource); OrderByBinder orderByBinder = new OrderByBinder(binder.Bind); orderbyOption = orderByBinder.BindOrderBy(binder.BindingState, tokenIn.OrderByOptions); } SearchClause searchOption = null; if (tokenIn.SearchOption != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetNavigationSource); SearchBinder searchBinder = new SearchBinder(binder.Bind); searchOption = searchBinder.BindSearch(tokenIn.SearchOption); } if (isRef) { return(new ExpandedReferenceSelectItem(pathToNavProp, targetNavigationSource, filterOption, orderbyOption, tokenIn.TopOption, tokenIn.SkipOption, tokenIn.CountQueryOption, searchOption)); } SelectExpandClause subSelectExpand; if (tokenIn.ExpandOption != null) { subSelectExpand = this.GenerateSubExpand(currentNavProp, tokenIn); } else { subSelectExpand = BuildDefaultSubExpand(); } subSelectExpand = this.DecorateExpandWithSelect(subSelectExpand, currentNavProp, tokenIn.SelectOption); LevelsClause levelsOption = this.ParseLevels(tokenIn.LevelsOption, currentLevelEntityType, currentNavProp); return(new ExpandedNavigationSelectItem(pathToNavProp, targetNavigationSource, subSelectExpand, filterOption, orderbyOption, tokenIn.TopOption, tokenIn.SkipOption, tokenIn.CountQueryOption, searchOption, levelsOption)); }
/// <summary> /// Generate an expand item based on an ExpandTermToken /// </summary> /// <param name="tokenIn">the expandTerm token to visit</param> /// <returns>the expand item for this expand term token.</returns> private ExpandedNavigationSelectItem GenerateExpandItem(ExpandTermToken tokenIn) { ExceptionUtils.CheckArgumentNotNull(tokenIn, "tokenIn"); // ensure that we're always dealing with a normalized tree if (tokenIn.PathToNavProp.NextToken != null && !tokenIn.PathToNavProp.IsNamespaceOrContainerQualified()) { throw new ODataException(ODataErrorStrings.ExpandItemBinder_TraversingANonNormalizedTree); } PathSegmentToken currentToken = tokenIn.PathToNavProp; IEdmEntityType currentLevelEntityType = this.entityType; List <ODataPathSegment> pathSoFar = new List <ODataPathSegment>(); PathSegmentToken firstNonTypeToken = currentToken; if (currentToken.IsNamespaceOrContainerQualified()) { pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(currentToken, this.Model, this.Settings.SelectExpandLimit, ref currentLevelEntityType, out firstNonTypeToken)); } IEdmProperty edmProperty = currentLevelEntityType.FindProperty(firstNonTypeToken.Identifier); if (edmProperty == null) { throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(currentLevelEntityType.FullName(), currentToken.Identifier)); } IEdmNavigationProperty currentNavProp = edmProperty as IEdmNavigationProperty; if (currentNavProp == null) { // the server allowed non-navigation, non-stream properties to be expanded, but then ignored them. if (this.Settings.UseWcfDataServicesServerBehavior && !edmProperty.Type.IsStream()) { return(null); } throw new ODataException(ODataErrorStrings.ExpandItemBinder_PropertyIsNotANavigationProperty(currentToken.Identifier, currentLevelEntityType.FullName())); } pathSoFar.Add(new NavigationPropertySegment(currentNavProp, /*entitySet*/ null)); ODataExpandPath pathToNavProp = new ODataExpandPath(pathSoFar); SelectExpandClause subSelectExpand; if (tokenIn.ExpandOption != null) { subSelectExpand = this.GenerateSubExpand(currentNavProp, tokenIn); } else { subSelectExpand = BuildDefaultSubExpand(); } subSelectExpand = this.DecorateExpandWithSelect(subSelectExpand, currentNavProp, tokenIn.SelectOption); IEdmEntitySet targetEntitySet = null; if (this.entitySet != null) { targetEntitySet = this.entitySet.FindNavigationTarget(currentNavProp); } // call MetadataBinder to build the filter clause FilterClause filterOption = null; if (tokenIn.FilterOption != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetEntitySet); FilterBinder filterBinder = new FilterBinder(binder.Bind, binder.BindingState); filterOption = filterBinder.BindFilter(tokenIn.FilterOption); } // call MetadataBinder again to build the orderby clause OrderByClause orderbyOption = null; if (tokenIn.OrderByOption != null) { MetadataBinder binder = this.BuildNewMetadataBinder(targetEntitySet); OrderByBinder orderByBinder = new OrderByBinder(binder.Bind); orderbyOption = orderByBinder.BindOrderBy(binder.BindingState, new OrderByToken[] { tokenIn.OrderByOption }); } return(new ExpandedNavigationSelectItem(pathToNavProp, targetEntitySet, filterOption, orderbyOption, tokenIn.TopOption, tokenIn.SkipOption, tokenIn.InlineCountOption, subSelectExpand)); }
private void GetAutoSelectExpandItems( IEdmEntityType baseEntityType, IEdmModel model, IEdmNavigationSource navigationSource, bool isAllSelected, ModelBoundQuerySettings modelBoundQuerySettings, int depth, out List <SelectItem> autoSelectItems, out List <SelectItem> autoExpandItems) { autoSelectItems = new List <SelectItem>(); var autoSelectProperties = EdmLibHelpers.GetAutoSelectProperties(null, baseEntityType, model, modelBoundQuerySettings); foreach (var autoSelectProperty in autoSelectProperties) { List <ODataPathSegment> pathSegments = new List <ODataPathSegment>() { new PropertySegment(autoSelectProperty) }; PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(pathSegments)); autoSelectItems.Add(pathSelectItem); } autoExpandItems = new List <SelectItem>(); depth--; if (depth < 0) { return; } var autoExpandNavigationProperties = EdmLibHelpers.GetAutoExpandNavigationProperties(null, baseEntityType, model, !isAllSelected, modelBoundQuerySettings); foreach (var navigationProperty in autoExpandNavigationProperties) { IEdmNavigationSource currentEdmNavigationSource = navigationSource.FindNavigationTarget(navigationProperty); if (currentEdmNavigationSource != null) { List <ODataPathSegment> pathSegments = new List <ODataPathSegment>() { new NavigationPropertySegment(navigationProperty, currentEdmNavigationSource) }; ODataExpandPath expandPath = new ODataExpandPath(pathSegments); SelectExpandClause selectExpandClause = new SelectExpandClause(new List <SelectItem>(), true); ExpandedNavigationSelectItem item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource, selectExpandClause); modelBoundQuerySettings = EdmLibHelpers.GetModelBoundQuerySettings(navigationProperty, navigationProperty.ToEntityType(), model); List <SelectItem> nestedSelectItems; List <SelectItem> nestedExpandItems; int maxExpandDepth = GetMaxExpandDepth(modelBoundQuerySettings, navigationProperty.Name); if (maxExpandDepth != 0 && maxExpandDepth < depth) { depth = maxExpandDepth; } GetAutoSelectExpandItems( currentEdmNavigationSource.EntityType(), model, item.NavigationSource, true, modelBoundQuerySettings, depth, out nestedSelectItems, out nestedExpandItems); selectExpandClause = new SelectExpandClause(nestedSelectItems.Concat(nestedExpandItems), nestedSelectItems.Count == 0); item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource, selectExpandClause); autoExpandItems.Add(item); if (!isAllSelected || autoSelectProperties.Count() != 0) { PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(pathSegments)); autoExpandItems.Add(pathSelectItem); } } } }
private void GetAutoSelectExpandItems(IEdmEntityType baseEntityType, IEdmModel model, IEdmNavigationSource navigationSource, bool isAllSelected, ModelBoundQuerySettings modelBoundQuerySettings, int depth, out List <SelectItem> autoSelectItems, out List <SelectItem> autoExpandItems) { autoSelectItems = new List <SelectItem>(); autoExpandItems = new List <SelectItem>(); if (baseEntityType == null) { return; } IList <SelectModelPath> autoSelectProperties = model.GetAutoSelectPaths(baseEntityType, null, modelBoundQuerySettings); foreach (var autoSelectProperty in autoSelectProperties) { ODataSelectPath odataSelectPath = BuildSelectPath(autoSelectProperty, navigationSource); PathSelectItem pathSelectItem = new PathSelectItem(odataSelectPath); autoSelectItems.Add(pathSelectItem); } depth--; if (depth < 0) { return; } IList <ExpandModelPath> autoExpandNavigationProperties = model.GetAutoExpandPaths(baseEntityType, null, !isAllSelected, modelBoundQuerySettings); foreach (ExpandModelPath itemPath in autoExpandNavigationProperties) { string navigationPath = itemPath.NavigationPropertyPath; IEdmNavigationProperty navigationProperty = itemPath.Navigation; IEdmNavigationSource currentEdmNavigationSource; if (navigationPath != null) { currentEdmNavigationSource = navigationSource.FindNavigationTarget(navigationProperty); } else { currentEdmNavigationSource = navigationSource.FindNavigationTarget(navigationProperty, new EdmPathExpression(navigationPath)); } if (currentEdmNavigationSource != null) { ODataExpandPath expandPath = BuildExpandPath(itemPath, navigationSource, currentEdmNavigationSource); SelectExpandClause selectExpandClause = new SelectExpandClause(new List <SelectItem>(), true); ExpandedNavigationSelectItem item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource, selectExpandClause); modelBoundQuerySettings = model.GetModelBoundQuerySettings(navigationProperty, navigationProperty.ToEntityType()); List <SelectItem> nestedSelectItems; List <SelectItem> nestedExpandItems; int maxExpandDepth = GetMaxExpandDepth(modelBoundQuerySettings, navigationProperty.Name); if (maxExpandDepth != 0 && maxExpandDepth < depth) { depth = maxExpandDepth; } GetAutoSelectExpandItems( currentEdmNavigationSource.EntityType(), model, item.NavigationSource, true, modelBoundQuerySettings, depth, out nestedSelectItems, out nestedExpandItems); selectExpandClause = new SelectExpandClause(nestedSelectItems.Concat(nestedExpandItems), nestedSelectItems.Count == 0); item = new ExpandedNavigationSelectItem(expandPath, currentEdmNavigationSource, selectExpandClause); autoExpandItems.Add(item); if (!isAllSelected || autoSelectProperties.Any()) { PathSelectItem pathSelectItem = new PathSelectItem(new ODataSelectPath(expandPath)); autoExpandItems.Add(pathSelectItem); } } } }
private void AppendExpression(ODataExpandPath path) { string text = path.ToContextUrlPathString(); query.Append(text); }
/// <summary> /// Build the $expand item, it maybe $expand=nav, $expand=complex/nav, $expand=nav/$ref, etc. /// </summary> /// <param name="expandReferenceItem">The expanded reference select item.</param> /// <param name="currentLevelPropertiesInclude">The current properties to include at current level.</param> /// <param name="structuralTypeInfo">The structural type properties.</param> private void BuildExpandItem(ExpandedReferenceSelectItem expandReferenceItem, IDictionary <IEdmStructuralProperty, SelectExpandIncludedProperty> currentLevelPropertiesInclude, EdmStructuralTypeInfo structuralTypeInfo) { Contract.Assert(expandReferenceItem != null && expandReferenceItem.PathToNavigationProperty != null); Contract.Assert(currentLevelPropertiesInclude != null); Contract.Assert(structuralTypeInfo != null); // Verify and process the $expand=abc/xyz/nav. ODataExpandPath expandPath = expandReferenceItem.PathToNavigationProperty; IList <ODataPathSegment> remainingSegments; ODataPathSegment segment = expandPath.GetFirstNonTypeCastSegment(out remainingSegments); PropertySegment firstPropertySegment = segment as PropertySegment; if (firstPropertySegment != null) { // for example: $expand=abc/xyz/nav, the remaining segment can't be null // because at least the last navigation property segment is there. Contract.Assert(remainingSegments != null); if (structuralTypeInfo.IsStructuralPropertyDefined(firstPropertySegment.Property)) { SelectExpandIncludedProperty newPropertySelectItem; if (!currentLevelPropertiesInclude.TryGetValue(firstPropertySegment.Property, out newPropertySelectItem)) { newPropertySelectItem = new SelectExpandIncludedProperty(firstPropertySegment); currentLevelPropertiesInclude[firstPropertySegment.Property] = newPropertySelectItem; } newPropertySelectItem.AddSubExpandItem(remainingSegments, expandReferenceItem); } } else { // for example: $expand=nav, or $expand=NS.SubType/nav, the navigation property segment should be the last segment. // So, the remaining segments should be null. Contract.Assert(remainingSegments == null); NavigationPropertySegment firstNavigationSegment = segment as NavigationPropertySegment; Contract.Assert(firstNavigationSegment != null); if (structuralTypeInfo.IsNavigationPropertyDefined(firstNavigationSegment.NavigationProperty)) { // It's not allowed to have mulitple navigation expanded or referenced. // for example: "$expand=nav($top=2),nav($skip=3)" is not allowed and will be merged (or throw exception) at ODL side. ExpandedNavigationSelectItem expanded = expandReferenceItem as ExpandedNavigationSelectItem; if (expanded != null) { if (ExpandedProperties == null) { ExpandedProperties = new Dictionary <IEdmNavigationProperty, ExpandedNavigationSelectItem>(); } ExpandedProperties[firstNavigationSegment.NavigationProperty] = expanded; } else { // $expand=..../nav/$ref if (ReferencedProperties == null) { ReferencedProperties = new Dictionary <IEdmNavigationProperty, ExpandedReferenceSelectItem>(); } ReferencedProperties[firstNavigationSegment.NavigationProperty] = expandReferenceItem; } } } }