public void OrderByOptionSetCorrectly() { SingleValuePropertyAccessNode propertyAccessNode = new SingleValuePropertyAccessNode(new ConstantNode(1), HardCodedTestModel.GetPersonNameProp()); OrderByClause orderBy = new OrderByClause(null, propertyAccessNode, OrderByDirection.Descending, new EntityRangeVariable(ExpressionConstants.It, HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet())); ExpandedNavigationSelectItem expansion = new ExpandedNavigationSelectItem(new ODataExpandPath(new NavigationPropertySegment(ModelBuildingHelpers.BuildValidNavigationProperty(), null)), HardCodedTestModel.GetPeopleSet(), null, null, orderBy, null, null, null, null, null); expansion.OrderByOption.Expression.ShouldBeSingleValuePropertyAccessQueryNode(HardCodedTestModel.GetPersonNameProp()); }
private void ValidateExpandedItem(ExpandedNavigationSelectItem item) { // If the navigation source doesn't exist, means that we are in query composition mode, so we just examine // the $expand path (The list of navigation properties) and check the annotations on their IEdmTypes. if (item.NavigationSource != null && CanAccess(item.NavigationSource.EntityType())) { foreach (var element in GetExpandedProperties(item.SelectAndExpand)) { ValidateExpandedItem(element); } } else if (item.NavigationSource == null) { IEnumerable<NavigationPropertySegment> path = item.PathToNavigationProperty.OfType<NavigationPropertySegment>(); ValidateExpandedPath(path); } else { var segment = item.PathToNavigationProperty.OfType<NavigationPropertySegment>().First(); string message = string.Format("Not authorized to expand the navigation property '{0}'", segment.NavigationProperty.Name); throw new ODataException(message); } }
public void FilterOptionSetCorrectly() { BinaryOperatorNode filterExpression = new BinaryOperatorNode(BinaryOperatorKind.Equal, new ConstantNode(1), new ConstantNode(1)); FilterClause filterClause = new FilterClause(filterExpression, new EntityRangeVariable(ExpressionConstants.It, HardCodedTestModel.GetPersonTypeReference(), HardCodedTestModel.GetPeopleSet())); ExpandedNavigationSelectItem expansion = new ExpandedNavigationSelectItem(new ODataExpandPath(new NavigationPropertySegment(ModelBuildingHelpers.BuildValidNavigationProperty(), null)), HardCodedTestModel.GetPeopleSet(), null, filterClause, null, null, null, null, null, null); expansion.FilterOption.Expression.ShouldBeBinaryOperatorNode(BinaryOperatorKind.Equal); expansion.FilterOption.Expression.As<BinaryOperatorNode>().Left.ShouldBeConstantQueryNode(1); expansion.FilterOption.Expression.As<BinaryOperatorNode>().Right.ShouldBeConstantQueryNode(1); }
public void TryEnableNoDollarSignSystemQueryOption(string relativeUri) { // Create parser specifying optional-$-sign setting. var parser = new ODataUriParser(GetModel(), new Uri(relativeUri, UriKind.Relative)) { EnableNoDollarQueryOptions = true }; // Verify path is parsed correctly. Microsoft.OData.UriParser.ODataPath path = parser.ParsePath(); Assert.NotNull(path); Assert.Equal(path.Count, 2); // Verify expand & select clause is parsed correctly. SelectExpandClause result = parser.ParseSelectAndExpand(); Assert.NotNull(result); Assert.Equal(result.SelectedItems.Count(), 1); ExpandedNavigationSelectItem selectItems = (result.SelectedItems.First() as ExpandedNavigationSelectItem); Assert.NotNull(selectItems); Assert.Equal(selectItems.NavigationSource.Name, "PermanentAccount"); Assert.Equal(selectItems.SelectAndExpand.SelectedItems.Count(), 2); }
public void ProjectAsWrapper_NullExpandedProperty_HasNullValueInProjectedWrapper() { // Arrange IPropertyMapper mapper = new IdentityPropertyMapper(); Order order = new Order(); ExpandedNavigationSelectItem expandItem = new ExpandedNavigationSelectItem( new ODataExpandPath(new NavigationPropertySegment(_model.Order.NavigationProperties().Single(), navigationSource: _model.Customers)), _model.Customers, selectExpandOption: null); SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[] { expandItem }, allSelected: true); Expression source = Expression.Constant(order); _model.Model.SetAnnotationValue(_model.Order, new DynamicPropertyDictionaryAnnotation(typeof(Order).GetProperty("OrderProperties"))); // Act Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order, _model.Orders); // Assert SelectExpandWrapper <Order> projectedOrder = Expression.Lambda(projection).Compile().DynamicInvoke() as SelectExpandWrapper <Order>; Assert.NotNull(projectedOrder); Assert.Contains("Customer", projectedOrder.Container.ToDictionary(mapper).Keys); Assert.Null(projectedOrder.Container.ToDictionary(mapper)["Customer"]); }
private ExpandedNavigationSelectItem Build(ExpandedNavigationSelectItem navigationSelectItem) { if (navigationSelectItem.SelectAndExpand == null) return navigationSelectItem; var segment = (NavigationPropertySegment)navigationSelectItem.PathToNavigationProperty.LastSegment; IEdmNavigationProperty navigationProperty = segment.NavigationProperty; SelectExpandClause selectExpandClause = GetSelectItems(navigationSelectItem.SelectAndExpand, _modelBoundProvider.GetSettings(navigationProperty)); if (selectExpandClause == navigationSelectItem.SelectAndExpand) return navigationSelectItem; return new ExpandedNavigationSelectItem( navigationSelectItem.PathToNavigationProperty, navigationSelectItem.NavigationSource, selectExpandClause, navigationSelectItem.FilterOption, navigationSelectItem.OrderByOption, navigationSelectItem.TopOption, navigationSelectItem.SkipOption, navigationSelectItem.CountOption, navigationSelectItem.SearchOption, navigationSelectItem.LevelsOption); }
string BuildSqlQueryCmd(ExpandedNavigationSelectItem expanded, string condition) { string table = string.Format("[{0}]", expanded.NavigationSource.Name); string cmdSql = "select {0} {1} from {2} {3} {4} {5} {6}"; string top = string.Empty; string skip = string.Empty; string fetch = string.Empty; if (!expanded.CountOption.HasValue && expanded.TopOption.HasValue) { if (expanded.SkipOption.HasValue) { skip = string.Format("OFFSET {0} ROWS", expanded.SkipOption.Value); ; fetch = string.Format("FETCH NEXT {0} ROWS ONLY", expanded.TopOption.Value); top = string.Empty; } else top = "top " + expanded.TopOption.Value; } var cmdtxt = string.Format(cmdSql , top , expanded.ParseSelect() , table , expanded.ParseWhere(condition, this.Model) , expanded.ParseOrderBy() , skip , fetch); return cmdtxt; }
public static int GetPageSize(this ExpandedNavigationSelectItem navigationSelectItem) { return(navigationSelectItem.SelectAndExpand.GetPageSize()); }
public void EntitySetSetCorrectly() { ExpandedNavigationSelectItem expansion = new ExpandedNavigationSelectItem(new ODataExpandPath(new NavigationPropertySegment(HardCodedTestModel.GetPersonMyDogNavProp(), null)), HardCodedTestModel.GetDogsSet(), null); expansion.NavigationSource.Should().Be(HardCodedTestModel.GetDogsSet()); }
// Process $levels in ExpandedNavigationSelectItem. private ExpandedNavigationSelectItem ProcessLevels( ExpandedNavigationSelectItem expandItem, int levelsMaxLiteralExpansionDepth, out bool levelsEncounteredInExpand, out bool isMaxLevelInExpand) { int level; isMaxLevelInExpand = false; // $level=x if (expandItem.LevelsOption != null && !expandItem.LevelsOption.IsMaxLevel) { levelsEncounteredInExpand = true; level = (int)expandItem.LevelsOption.Level; if (LevelsMaxLiteralExpansionDepth < 0) { levelsMaxLiteralExpansionDepth = level; } } else { if (levelsMaxLiteralExpansionDepth < 0) { levelsMaxLiteralExpansionDepth = ODataValidationSettings.DefaultMaxExpansionDepth; } if (expandItem.LevelsOption == null) { // no $level levelsEncounteredInExpand = false; level = 1; } else { // $level=max levelsEncounteredInExpand = true; isMaxLevelInExpand = true; level = levelsMaxLiteralExpansionDepth; } } // Do not expand when: // 1. $levels is equal to or less than 0. // 2. $levels value is greater than current MaxExpansionDepth if (level <= 0 || level > levelsMaxLiteralExpansionDepth) { return(null); } ExpandedNavigationSelectItem item = null; SelectExpandClause currentSelectExpandClause = null; SelectExpandClause selectExpandClause = null; bool levelsEncounteredInInnerExpand = false; bool isMaxLevelInInnerExpand = false; // Try diffent expansion depth until expandItem.SelectAndExpand is successfully expanded while (selectExpandClause == null && level > 0) { selectExpandClause = ProcessLevels( expandItem.SelectAndExpand, levelsMaxLiteralExpansionDepth - level, out levelsEncounteredInInnerExpand, out isMaxLevelInInnerExpand); level--; } if (selectExpandClause == null) { return(null); } // Correct level value level++; var entityType = expandItem.NavigationSource.EntityType(); string alreadyExpandedNavigationSourceName = (expandItem.PathToNavigationProperty.LastSegment as NavigationPropertySegment).NavigationProperty.Name; IEnumerable <SelectItem> autoExpandNavigationSelectItems = GetAutoExpandedNavigationSelectItems( entityType, Context.Model, alreadyExpandedNavigationSourceName, expandItem.NavigationSource, selectExpandClause.AllSelected); bool hasAutoExpandInExpand = (autoExpandNavigationSelectItems.Count() != 0); while (level > 0) { if (item == null) { if (hasAutoExpandInExpand) { currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { }.Concat(selectExpandClause.SelectedItems) .Concat(autoExpandNavigationSelectItems), selectExpandClause.AllSelected); } else { currentSelectExpandClause = selectExpandClause; } } else if (selectExpandClause.AllSelected) { // Concat the processed items currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { item }.Concat(selectExpandClause.SelectedItems) .Concat(autoExpandNavigationSelectItems), selectExpandClause.AllSelected); } else { // PathSelectItem is needed for the expanded item if AllSelected is false. PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(expandItem.PathToNavigationProperty)); // Keep default SelectItems before expanded item to keep consistent with normal SelectExpandClause SelectItem[] items = new SelectItem[] { item, pathSelectItem }; currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { }.Concat(selectExpandClause.SelectedItems) .Concat(items) .Concat(autoExpandNavigationSelectItems), selectExpandClause.AllSelected); } // Construct a new ExpandedNavigationSelectItem with current SelectExpandClause. item = new ExpandedNavigationSelectItem( expandItem.PathToNavigationProperty, expandItem.NavigationSource, currentSelectExpandClause); level--; // Need expand and construct selectExpandClause every time if it is max level in inner expand if (isMaxLevelInInnerExpand) { selectExpandClause = ProcessLevels( expandItem.SelectAndExpand, levelsMaxLiteralExpansionDepth - level, out levelsEncounteredInInnerExpand, out isMaxLevelInInnerExpand); } } levelsEncounteredInExpand = levelsEncounteredInExpand || levelsEncounteredInInnerExpand || hasAutoExpandInExpand; isMaxLevelInExpand = isMaxLevelInExpand || isMaxLevelInInnerExpand; return(item); }
public void LevelsOptionSetCorrectly() { LevelsClause levels = new LevelsClause(false, 16384); ExpandedNavigationSelectItem expansion = new ExpandedNavigationSelectItem(new ODataExpandPath(new NavigationPropertySegment(ModelBuildingHelpers.BuildValidNavigationProperty(), null)), HardCodedTestModel.GetPeopleSet(), null, null, null, null, null, null, null, levels); expansion.LevelsOption.IsMaxLevel.Should().BeFalse(); expansion.LevelsOption.Level.Should().Be(16384); }
private static ODataUri GetCountODataUri(IEdmModel edmModel, OeEntryFactory entryFactory, ExpandedNavigationSelectItem item, Object value) { FilterClause?filterClause = GetFilter(edmModel, entryFactory, item, value); if (filterClause == null) { throw new InvalidOperationException("Cannot create count expression"); } var entitytSet = (IEdmEntitySet)((ResourceRangeVariable)filterClause.RangeVariable).NavigationSource; var pathSegments = new ODataPathSegment[] { new EntitySetSegment(entitytSet) { Identifier = entitytSet.Name }, CountSegment.Instance }; return(new ODataUri() { Filter = filterClause, Path = new ODataPath(pathSegments), }); }
/// <summary> /// Handle an ExpandedNavigationSelectItem /// </summary> /// <param name="item">the item to Handle</param> public virtual void Handle(ExpandedNavigationSelectItem item) { throw new NotImplementedException(); }
// Process $levels in ExpandedNavigationSelectItem. private ExpandedNavigationSelectItem ProcessLevels( ExpandedNavigationSelectItem expandItem, int levelsMaxLiteralExpansionDepth, out bool levelsEncounteredInExpand, out bool isMaxLevelInExpand) { int level; isMaxLevelInExpand = false; // $level=x if (expandItem.LevelsOption != null && !expandItem.LevelsOption.IsMaxLevel) { levelsEncounteredInExpand = true; level = (int)expandItem.LevelsOption.Level; if (LevelsMaxLiteralExpansionDepth < 0) { levelsMaxLiteralExpansionDepth = level; } } else { if (levelsMaxLiteralExpansionDepth < 0) { levelsMaxLiteralExpansionDepth = ODataValidationSettings.DefaultMaxExpansionDepth; } if (expandItem.LevelsOption == null) { // no $level levelsEncounteredInExpand = false; level = 1; } else { // $level=max levelsEncounteredInExpand = true; isMaxLevelInExpand = true; level = levelsMaxLiteralExpansionDepth; } } // Do not expand when: // 1. $levels is equal to or less than 0. // 2. $levels value is greater than current MaxExpansionDepth if (level <= 0 || level > levelsMaxLiteralExpansionDepth) { return null; } ExpandedNavigationSelectItem item = null; SelectExpandClause currentSelectExpandClause = null; SelectExpandClause selectExpandClause = null; bool levelsEncounteredInInnerExpand = false; bool isMaxLevelInInnerExpand = false; // Try diffent expansion depth until expandItem.SelectAndExpand is successfully expanded while (selectExpandClause == null && level > 0) { selectExpandClause = ProcessLevels( expandItem.SelectAndExpand, levelsMaxLiteralExpansionDepth - level, out levelsEncounteredInInnerExpand, out isMaxLevelInInnerExpand); level--; } if (selectExpandClause == null) { return null; } // Correct level value level++; var entityType = expandItem.NavigationSource.EntityType(); string alreadyExpandedNavigationSourceName = (expandItem.PathToNavigationProperty.LastSegment as NavigationPropertySegment).NavigationProperty.Name; IEnumerable<SelectItem> autoExpandNavigationSelectItems = GetAutoExpandedNavigationSelectItems( entityType, Context.Model, alreadyExpandedNavigationSourceName, expandItem.NavigationSource, selectExpandClause.AllSelected); bool hasAutoExpandInExpand = (autoExpandNavigationSelectItems.Count() != 0); while (level > 0) { if (item == null) { if (hasAutoExpandInExpand) { currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { }.Concat(selectExpandClause.SelectedItems) .Concat(autoExpandNavigationSelectItems), selectExpandClause.AllSelected); } else { currentSelectExpandClause = selectExpandClause; } } else if (selectExpandClause.AllSelected) { // Concat the processed items currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { item }.Concat(selectExpandClause.SelectedItems) .Concat(autoExpandNavigationSelectItems), selectExpandClause.AllSelected); } else { // PathSelectItem is needed for the expanded item if AllSelected is false. PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(expandItem.PathToNavigationProperty)); // Keep default SelectItems before expanded item to keep consistent with normal SelectExpandClause SelectItem[] items = new SelectItem[] { item, pathSelectItem }; currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { }.Concat(selectExpandClause.SelectedItems) .Concat(items) .Concat(autoExpandNavigationSelectItems), selectExpandClause.AllSelected); } // Construct a new ExpandedNavigationSelectItem with current SelectExpandClause. item = new ExpandedNavigationSelectItem( expandItem.PathToNavigationProperty, expandItem.NavigationSource, currentSelectExpandClause); level--; // Need expand and construct selectExpandClause every time if it is max level in inner expand if (isMaxLevelInInnerExpand) { selectExpandClause = ProcessLevels( expandItem.SelectAndExpand, levelsMaxLiteralExpansionDepth - level, out levelsEncounteredInInnerExpand, out isMaxLevelInInnerExpand); } } levelsEncounteredInExpand = levelsEncounteredInExpand || levelsEncounteredInInnerExpand || hasAutoExpandInExpand; isMaxLevelInExpand = isMaxLevelInExpand || isMaxLevelInInnerExpand; return item; }
public void ExpandWithNestedQueryOptionsShouldWork() { var ervFilter = new EntityRangeVariable(ExpressionConstants.It, HardCodedTestModel.GetDogTypeReference(), HardCodedTestModel.GetDogsSet()); var ervOrderby = new EntityRangeVariable(ExpressionConstants.It, HardCodedTestModel.GetDogTypeReference(), HardCodedTestModel.GetDogsSet()); var expand = new ExpandedNavigationSelectItem( new ODataExpandPath(new NavigationPropertySegment(HardCodedTestModel.GetPersonMyDogNavProp(), null)), HardCodedTestModel.GetPeopleSet(), null, new FilterClause( new BinaryOperatorNode( BinaryOperatorKind.Equal, new SingleValuePropertyAccessNode(new EntityRangeVariableReferenceNode("$it", ervFilter), HardCodedTestModel.GetDogColorProp()), new ConstantNode("Brown", "'Brown'")), ervFilter), new OrderByClause( null, new SingleValuePropertyAccessNode(new EntityRangeVariableReferenceNode("$it", ervOrderby), HardCodedTestModel.GetDogColorProp()), OrderByDirection.Ascending, ervOrderby), 1, /* skipOption */ null, true, new SearchClause(new SearchTermNode("termX")), /* levelsOption*/ null); ODataUri uri = new ODataUri() { ServiceRoot = new Uri("http://gobbledygook/"), Path = new ODataPath(new EntitySetSegment(HardCodedTestModel.GetPeopleSet())), SelectAndExpand = new SelectExpandClause(new[] { expand }, true) }; Uri actualUri = new ODataUriBuilder(ODataUrlConventions.Default, uri).BuildUri(); Assert.Equal("http://gobbledygook/People?$expand=" + Uri.EscapeDataString("MyDog($filter=Color eq 'Brown';$orderby=Color;$top=1;$count=true;$search=termX)"), actualUri.OriginalString); }
/// <summary> /// Creates an instance of <see cref="ExpandSegment"/> based on the metadata in the given <see cref="ExpandedNavigationSelectItem"/>. /// </summary> /// <param name="expandItem">The metadata-bound expand segment to create the <see cref="ExpandSegment"/> from.</param> /// <param name="currentResourceType">The current resource type.</param> /// <returns>The created <see cref="ExpandSegment"/>.</returns> private ExpandSegment CreateExpandSegment(ExpandedNavigationSelectItem expandItem, ResourceType currentResourceType) { Debug.Assert(expandItem != null, "expandItem != null"); Debug.Assert(currentResourceType != null, "currentResourceType != null"); // pull the Resource* instances from annotations on the IEdm* instances. IEdmNavigationProperty navigationProperty = ((NavigationPropertySegment)expandItem.PathToNavigationProperty.LastSegment).NavigationProperty; ResourceProperty property = ((IResourcePropertyBasedEdmProperty)navigationProperty).ResourceProperty; Debug.Assert(property != null, "property != null"); ResourceSetWrapper targetResourceSet = ((IResourceSetBasedEdmEntitySet)expandItem.NavigationSource).ResourceSet; Debug.Assert(targetResourceSet != null, "targetResourceSet != null"); // Further scope the type based on type segments in the path. currentResourceType = this.GetTargetResourceTypeFromTypeSegments(expandItem.PathToNavigationProperty, currentResourceType); Debug.Assert(currentResourceType != null, "currentResourceType != null"); // The expanded resource type may require higher response version. Update version of the response accordingly // // Note the response DSV is payload specific and since for GET we won't know what DSV the instances to be // serialized will require until serialization time which happens after the headers are written, // the best we can do is to determine this at the set level. this.description.UpdateVersion(targetResourceSet, this.service); bool singleResult = property.Kind == ResourcePropertyKind.ResourceReference; DataServiceConfiguration.CheckResourceRightsForRead(targetResourceSet, singleResult); Expression filter = DataServiceConfiguration.ComposeQueryInterceptors(this.service.Instance, targetResourceSet); if (targetResourceSet.PageSize != 0 && !singleResult && !this.IsCustomPaged) { OrderingInfo internalOrderingInfo = new OrderingInfo(true); ParameterExpression p = Expression.Parameter(targetResourceSet.ResourceType.InstanceType, "p"); foreach (var keyProp in targetResourceSet.GetKeyPropertiesForOrderBy()) { Expression e; if (keyProp.CanReflectOnInstanceTypeProperty) { e = Expression.Property(p, targetResourceSet.ResourceType.GetPropertyInfo(keyProp)); } else { // object LateBoundMethods.GetValue(object, ResourceProperty) e = Expression.Call( null, /*instance*/ DataServiceProviderMethods.GetValueMethodInfo, p, Expression.Constant(keyProp)); e = Expression.Convert(e, keyProp.Type); } internalOrderingInfo.Add(new OrderingExpression(Expression.Lambda(e, p), true)); } return new ExpandSegment(property.Name, filter, targetResourceSet.PageSize, targetResourceSet, currentResourceType, property, internalOrderingInfo); } if (!singleResult && this.IsCustomPaged) { // Expansion of collection could result in custom paging provider giving next link, so we need to set the null continuation token. this.CheckAndApplyCustomPaging(null); } return new ExpandSegment(property.Name, filter, this.service.Configuration.MaxResultsPerCollection, targetResourceSet, currentResourceType, property, null); }
public void SearchOptionSetCorrectly() { SearchClause search = new SearchClause(new SearchTermNode("SearchMe")); ExpandedNavigationSelectItem expansion = new ExpandedNavigationSelectItem(new ODataExpandPath(new NavigationPropertySegment(ModelBuildingHelpers.BuildValidNavigationProperty(), null)), HardCodedTestModel.GetPeopleSet(), null, null, null, null, null, null, search, null); expansion.SearchOption.Expression.ShouldBeSearchTermNode("SearchMe"); }
public void CountQueryOptionSetCorrectly() { ExpandedNavigationSelectItem expansion = new ExpandedNavigationSelectItem(new ODataExpandPath(new NavigationPropertySegment(ModelBuildingHelpers.BuildValidNavigationProperty(), null)), HardCodedTestModel.GetPeopleSet(), null, null, null, null, null, true, null, null); expansion.CountOption.Should().BeTrue(); }
public void SelectExpandOptionSetCorrectly() { SelectExpandClause selectAndExpand = new SelectExpandClause(null, true); ExpandedNavigationSelectItem expansion = new ExpandedNavigationSelectItem(new ODataExpandPath(new NavigationPropertySegment(ModelBuildingHelpers.BuildValidNavigationProperty(), null)), HardCodedTestModel.GetPeopleSet(), selectAndExpand, null, null, null, null, null, null, null); expansion.SelectAndExpand.AllSelected.Should().BeTrue(); expansion.SelectAndExpand.SelectedItems.Should().BeEmpty(); }
public void EntitySetCanBeNullInOptionConstructor() { ExpandedNavigationSelectItem expansion = new ExpandedNavigationSelectItem(new ODataExpandPath(new NavigationPropertySegment(ModelBuildingHelpers.BuildValidNavigationProperty(), null)), null, null, null, null, null, null, null, null, null); expansion.NavigationSource.Should().BeNull(); }
internal Expression ProjectAsWrapper(Expression source, SelectExpandClause selectExpandClause, IEdmEntityType entityType, IEdmNavigationSource navigationSource, ExpandedNavigationSelectItem expandedItem = null) { Type elementType; if (source.Type.IsCollection(out elementType)) { // new CollectionWrapper<ElementType> { Instance = source.Select(s => new Wrapper { ... }) }; return(ProjectCollection(source, elementType, selectExpandClause, entityType, navigationSource, expandedItem)); } else { // new Wrapper { v1 = source.property ... } return(ProjectElement(source, selectExpandClause, entityType, navigationSource)); } }
private void BuildOrderBySkipTake(OeNavigationSelectItem navigationItem, OrderByClause orderByClause, bool hasSelectItems) { while (orderByClause != null) { var propertyNode = (SingleValuePropertyAccessNode)orderByClause.Expression; if (propertyNode.Source is SingleNavigationNode navigationNode) { OeNavigationSelectItem? match; ExpandedNavigationSelectItem?navigationSelectItem = null; for (; ;) { if ((match = navigationItem.FindHierarchyNavigationItem(navigationNode.NavigationProperty)) != null) { match.AddStructuralItem((IEdmStructuralProperty)propertyNode.Property, true); break; } SelectExpandClause selectExpandClause; if (navigationSelectItem == null) { var pathSelectItem = new PathSelectItem(new ODataSelectPath(new PropertySegment((IEdmStructuralProperty)propertyNode.Property))); selectExpandClause = new SelectExpandClause(new[] { pathSelectItem }, false); } else { selectExpandClause = new SelectExpandClause(new[] { navigationSelectItem }, false); } var segment = new NavigationPropertySegment(navigationNode.NavigationProperty, navigationNode.NavigationSource); navigationSelectItem = new ExpandedNavigationSelectItem(new ODataExpandPath(segment), navigationNode.NavigationSource, selectExpandClause); if (navigationNode.Source is SingleNavigationNode singleNavigationNode) { navigationNode = singleNavigationNode; } else { break; } } if (navigationSelectItem != null) { if (match == null) { match = navigationItem; } var selectItemTranslator = new OeSelectItemTranslator(_edmModel, true); selectItemTranslator.Translate(match, navigationSelectItem); } } else { if (hasSelectItems) { navigationItem.AddStructuralItem((IEdmStructuralProperty)propertyNode.Property, true); } } orderByClause = orderByClause.ThenBy; } }
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 static Uri BuildNavigationNextPageLink(ODataResource entry, ExpandedNavigationSelectItem expandedNavigationSelectItem) { var segment = (NavigationPropertySegment)expandedNavigationSelectItem.PathToNavigationProperty.LastSegment; ResourceRangeVariableReferenceNode refNode = OeGetParser.CreateRangeVariableReferenceNode((IEdmEntitySet)segment.NavigationSource); IEdmNavigationProperty navigationProperty = segment.NavigationProperty; var keys = new List <KeyValuePair <IEdmStructuralProperty, Object> >(); if (navigationProperty.IsPrincipal()) { IEnumerator <IEdmStructuralProperty> dependentProperties = navigationProperty.Partner.DependentProperties().GetEnumerator(); foreach (IEdmStructuralProperty key in navigationProperty.Partner.PrincipalProperties()) { foreach (ODataProperty property in entry.Properties) { if (property.Name == key.Name) { dependentProperties.MoveNext(); keys.Add(new KeyValuePair <IEdmStructuralProperty, Object>(dependentProperties.Current, property.Value)); break; } } } } else { IEnumerator <IEdmStructuralProperty> principalProperties = navigationProperty.PrincipalProperties().GetEnumerator(); foreach (IEdmStructuralProperty key in navigationProperty.DependentProperties()) { foreach (ODataProperty property in entry.Properties) { if (property.Name == key.Name) { principalProperties.MoveNext(); keys.Add(new KeyValuePair <IEdmStructuralProperty, Object>(principalProperties.Current, property.Value)); break; } } } } BinaryOperatorNode filterExpression = OeGetParser.CreateFilterExpression(refNode, keys); if (expandedNavigationSelectItem.FilterOption != null) { filterExpression = new BinaryOperatorNode(BinaryOperatorKind.And, filterExpression, expandedNavigationSelectItem.FilterOption.Expression); } var segments = new ODataPathSegment[] { new EntitySetSegment((IEdmEntitySet)refNode.NavigationSource) }; var odataUri = new ODataUri() { Path = new ODataPath(segments), Filter = new FilterClause(filterExpression, refNode.RangeVariable), OrderBy = expandedNavigationSelectItem.OrderByOption, SelectAndExpand = expandedNavigationSelectItem.SelectAndExpand, Top = expandedNavigationSelectItem.TopOption, Skip = expandedNavigationSelectItem.SkipOption, QueryCount = expandedNavigationSelectItem.CountOption }; return(odataUri.BuildUri(ODataUrlKeyDelimiter.Parentheses)); }
// Process $levels in ExpandedNavigationSelectItem. private ExpandedNavigationSelectItem ProcessLevels( ExpandedNavigationSelectItem expandItem, int levelsMaxLiteralExpansionDepth, ModelBoundQuerySettings querySettings, out bool levelsEncounteredInExpand, out bool isMaxLevelInExpand) { int level; isMaxLevelInExpand = false; if (expandItem.LevelsOption == null) { levelsEncounteredInExpand = false; level = 1; } else { levelsEncounteredInExpand = true; if (expandItem.LevelsOption.IsMaxLevel) { isMaxLevelInExpand = true; level = levelsMaxLiteralExpansionDepth; } else { level = (int)expandItem.LevelsOption.Level; } } // Do not expand when: // 1. $levels is equal to or less than 0. // 2. $levels value is greater than current MaxExpansionDepth if (level <= 0 || level > levelsMaxLiteralExpansionDepth) { return(null); } ExpandedNavigationSelectItem item = null; SelectExpandClause currentSelectExpandClause = null; SelectExpandClause selectExpandClause = null; bool levelsEncounteredInInnerExpand = false; bool isMaxLevelInInnerExpand = false; var entityType = expandItem.NavigationSource.EntityType(); IEdmNavigationProperty navigationProperty = (expandItem.PathToNavigationProperty.LastSegment as NavigationPropertySegment).NavigationProperty; ModelBoundQuerySettings nestQuerySettings = EdmLibHelpers.GetModelBoundQuerySettings(navigationProperty, navigationProperty.ToEntityType(), Context.Model); // Try different expansion depth until expandItem.SelectAndExpand is successfully expanded while (selectExpandClause == null && level > 0) { selectExpandClause = ProcessLevels( expandItem.SelectAndExpand, levelsMaxLiteralExpansionDepth - level, nestQuerySettings, out levelsEncounteredInInnerExpand, out isMaxLevelInInnerExpand); level--; } if (selectExpandClause == null) { return(null); } // Correct level value level++; List <SelectItem> originAutoSelectItems; List <SelectItem> originAutoExpandItems; int maxDepth = GetMaxExpandDepth(querySettings, navigationProperty.Name); if (maxDepth == 0 || levelsMaxLiteralExpansionDepth > maxDepth) { maxDepth = levelsMaxLiteralExpansionDepth; } GetAutoSelectExpandItems( entityType, Context.Model, expandItem.NavigationSource, selectExpandClause.AllSelected, nestQuerySettings, maxDepth - 1, out originAutoSelectItems, out originAutoExpandItems); if (expandItem.SelectAndExpand.SelectedItems.Any(it => it is PathSelectItem)) { originAutoSelectItems.Clear(); } if (level > 1) { RemoveSameExpandItem(navigationProperty, originAutoExpandItems); } List <SelectItem> autoExpandItems = new List <SelectItem>(originAutoExpandItems); bool hasAutoSelectExpandInExpand = (originAutoSelectItems.Count() + originAutoExpandItems.Count() != 0); bool allSelected = originAutoSelectItems.Count == 0 && selectExpandClause.AllSelected; var typeLevelSettings = EdmLibHelpers.GetModelBoundQuerySettings(entityType, this.Context.Model, this.Context.DefaultQuerySettings); bool allAutoSelected = (typeLevelSettings != null && typeLevelSettings.DefaultSelectType == SelectExpandType.Automatic); while (level > 0) { autoExpandItems = RemoveExpandItemExceedMaxDepth(maxDepth - level, originAutoExpandItems); if (item == null) { if (hasAutoSelectExpandInExpand) { currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { }.Concat(selectExpandClause.SelectedItems) .Concat(originAutoSelectItems).Concat(autoExpandItems), allSelected, allAutoSelected); } else { currentSelectExpandClause = selectExpandClause; } } else if (selectExpandClause.AllSelected) { // Concat the processed items currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { item }.Concat(selectExpandClause.SelectedItems) .Concat(originAutoSelectItems).Concat(autoExpandItems), allSelected, allAutoSelected); } else { // PathSelectItem is needed for the expanded item if AllSelected is false. PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(expandItem.PathToNavigationProperty)); // Keep default SelectItems before expanded item to keep consistent with normal SelectExpandClause SelectItem[] items = new SelectItem[] { item, pathSelectItem }; currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { }.Concat(selectExpandClause.SelectedItems) .Concat(items) .Concat(originAutoSelectItems).Concat(autoExpandItems), allSelected, allAutoSelected); } // Construct a new ExpandedNavigationSelectItem with current SelectExpandClause. item = new ExpandedNavigationSelectItem( expandItem.PathToNavigationProperty, expandItem.NavigationSource, currentSelectExpandClause, expandItem.FilterOption, expandItem.OrderByOption, expandItem.TopOption, expandItem.SkipOption, expandItem.CountOption, expandItem.SearchOption, null, expandItem.ComputeOption, expandItem.ApplyOption); level--; // Need expand and construct selectExpandClause every time if it is max level in inner expand if (isMaxLevelInInnerExpand) { selectExpandClause = ProcessLevels( expandItem.SelectAndExpand, levelsMaxLiteralExpansionDepth - level, nestQuerySettings, out levelsEncounteredInInnerExpand, out isMaxLevelInInnerExpand); } } levelsEncounteredInExpand = levelsEncounteredInExpand || levelsEncounteredInInnerExpand || hasAutoSelectExpandInExpand; isMaxLevelInExpand = isMaxLevelInExpand || isMaxLevelInInnerExpand; return(item); }
/// <summary> /// Handle an ExpandedNavigationSelectItem /// </summary> /// <param name="item">the item to Handle</param> public override void Handle(ExpandedNavigationSelectItem item) { var navigationProperty = (item.PathToNavigationProperty.LastSegment as NavigationPropertySegment).NavigationProperty; this.ExpandedChildElement = this.ParentElement.GetType().GetProperty(navigationProperty.Name).GetValue(this.ParentElement, null); if (this.ExpandedChildElement is IEnumerable) { var entityInstanceType = EdmClrTypeUtils.GetInstanceType(item.NavigationSource.EntityType().FullName()); Expression resultExpression = (this.ExpandedChildElement as IEnumerable).AsQueryable().Expression; if (item.FilterOption != null) { resultExpression = resultExpression.ApplyFilter(entityInstanceType, null, item.FilterOption); } if (item.SearchOption != null) { resultExpression = resultExpression.ApplySearch(entityInstanceType, null, item.SearchOption); } if (item.OrderByOption != null) { resultExpression = resultExpression.ApplyOrderBy(entityInstanceType, null, item.OrderByOption); } if (item.SkipOption.HasValue) { resultExpression = resultExpression.ApplySkip(entityInstanceType, item.SkipOption.Value); } if (item.TopOption.HasValue) { resultExpression = resultExpression.ApplyTop(entityInstanceType, item.TopOption.Value); } Expression<Func<object>> lambda = Expression.Lambda<Func<object>>(resultExpression); Func<object> compiled = lambda.Compile(); this.ExpandedChildElement = compiled() as IEnumerable; } }
public void NavPropSetCorrectly() { ExpandedNavigationSelectItem expansion = new ExpandedNavigationSelectItem(new ODataExpandPath(new NavigationPropertySegment(HardCodedTestModel.GetPersonMyDogNavProp(), null)), HardCodedTestModel.GetPeopleSet(), null); expansion.PathToNavigationProperty.FirstSegment.ShouldBeNavigationPropertySegment(HardCodedTestModel.GetPersonMyDogNavProp()); }
private void ValidateRestrictions( int?remainDepth, int currentDepth, SelectExpandClause selectExpandClause, IEdmNavigationProperty navigationProperty, ODataValidationSettings validationSettings) { IEdmModel edmModel = _selectExpandQueryOption.Context.Model; int? depth = remainDepth; if (remainDepth < 0) { throw new ODataException( Error.Format(SRResources.MaxExpandDepthExceeded, currentDepth - 1, "MaxExpansionDepth")); } IEdmProperty pathProperty; IEdmStructuredType pathStructuredType; if (navigationProperty == null) { pathProperty = _selectExpandQueryOption.Context.TargetProperty; pathStructuredType = _selectExpandQueryOption.Context.TargetStructuredType; } else { pathProperty = navigationProperty; pathStructuredType = navigationProperty.ToEntityType(); } foreach (SelectItem selectItem in selectExpandClause.SelectedItems) { ExpandedNavigationSelectItem expandItem = selectItem as ExpandedNavigationSelectItem; if (expandItem != null) { NavigationPropertySegment navigationSegment = (NavigationPropertySegment)expandItem.PathToNavigationProperty.LastSegment; IEdmNavigationProperty property = navigationSegment.NavigationProperty; if (EdmHelpers.IsNotExpandable(property, edmModel)) { throw new ODataException(Error.Format(SRResources.NotExpandablePropertyUsedInExpand, property.Name)); } if (edmModel != null) { ValidateOtherQueryOptionInExpand(property, edmModel, expandItem, validationSettings); bool isExpandable; ExpandConfiguration expandConfiguration; isExpandable = EdmHelpers.IsExpandable(property.Name, pathProperty, pathStructuredType, edmModel, out expandConfiguration); if (isExpandable) { int maxDepth = expandConfiguration.MaxDepth; if (maxDepth > 0 && (remainDepth == null || maxDepth < remainDepth)) { remainDepth = maxDepth; } } else if (!isExpandable) { if (!_defaultQuerySettings.EnableExpand || (expandConfiguration != null && expandConfiguration.ExpandType == SelectExpandType.Disabled)) { throw new ODataException(Error.Format(SRResources.NotExpandablePropertyUsedInExpand, property.Name)); } } } if (remainDepth.HasValue) { remainDepth--; if (expandItem.LevelsOption != null) { ValidateLevelsOption(expandItem.LevelsOption, remainDepth.Value, currentDepth + 1, edmModel, property); } } ValidateRestrictions(remainDepth, currentDepth + 1, expandItem.SelectAndExpand, property, validationSettings); remainDepth = depth; } ValidateSelectItem(selectItem, pathProperty, pathStructuredType, edmModel); } }
public void SkipOptionSetCorrectly() { ExpandedNavigationSelectItem expansion = new ExpandedNavigationSelectItem(new ODataExpandPath(new NavigationPropertySegment(ModelBuildingHelpers.BuildValidNavigationProperty(), null)), HardCodedTestModel.GetPeopleSet(), null, null, null, 42, null, null, null, null); expansion.SkipOption.Should().Be(42); }
string BuildSqlQueryCmd(ExpandedNavigationSelectItem expanded, string condition) { string table = string.Format("[{0}]", expanded.NavigationSource.Name); string cmdTxt = string.Empty; if (!expanded.CountOption.HasValue && expanded.TopOption.HasValue) { if (expanded.SkipOption.HasValue) { cmdTxt = string.Format( @"select t.* from( select ROW_NUMBER() over ({0}) as rowIndex,{1} from {2} {3} ) as t where t.rowIndex between {4} and {5}" , expanded.ParseOrderBy() , expanded.ParseSelect() , table , expanded.ParseWhere(condition, this.Model) , expanded.SkipOption.Value + 1 , expanded.SkipOption.Value + expanded.TopOption.Value); } else cmdTxt = string.Format("select top {0} {1} from {2} {3} {4}" , expanded.TopOption.Value , expanded.ParseSelect() , table , expanded.ParseWhere(condition, this.Model) , expanded.ParseOrderBy()); } else { cmdTxt = string.Format("select {0} from {1} {2} {3} " , expanded.ParseSelect() , table , expanded.ParseWhere(condition, this.Model) , expanded.ParseOrderBy()); } return cmdTxt; }
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); } } } }
public void ProjectAsWrapper_ProjectionContainsExpandedProperties() { // Arrange Order order = new Order(); ExpandedNavigationSelectItem expandItem = new ExpandedNavigationSelectItem( new ODataExpandPath(new NavigationPropertySegment(_model.Order.NavigationProperties().Single(), navigationSource: _model.Customers)), _model.Customers, selectExpandOption: null); SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[] { expandItem }, allSelected: true); Expression source = Expression.Constant(order); _model.Model.SetAnnotationValue(_model.Order, new DynamicPropertyDictionaryAnnotation(typeof(Order).GetProperty("OrderProperties"))); // Act Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order); // Assert SelectExpandWrapper<Order> projectedOrder = Expression.Lambda(projection).Compile().DynamicInvoke() as SelectExpandWrapper<Order>; Assert.NotNull(projectedOrder); Assert.Contains("Customer", projectedOrder.Container.ToDictionary(new IdentityPropertyMapper()).Keys); }
// Process $levels in ExpandedNavigationSelectItem. private static ExpandedNavigationSelectItem ProcessLevels( ExpandedNavigationSelectItem expandItem, int levelsMaxLiteralExpansionDepth, out bool levelsEncounteredInExpand) { // Call ProcessLevels on SelectExpandClause recursively. SelectExpandClause selectExpandClause = ProcessLevels( expandItem.SelectAndExpand, levelsMaxLiteralExpansionDepth - 1, out levelsEncounteredInExpand); if (expandItem.LevelsOption == null) { if (levelsEncounteredInExpand) { return new ExpandedNavigationSelectItem( expandItem.PathToNavigationProperty, expandItem.NavigationSource, selectExpandClause); } else { // Return the original ExpandedNavigationSelectItem if no $levels is found. return expandItem; } } // There is $levels in current ExpandedNavigationSelectItem. levelsEncounteredInExpand = true; int level = expandItem.LevelsOption.IsMaxLevel ? levelsMaxLiteralExpansionDepth : (int)expandItem.LevelsOption.Level; if (level <= 0) { // Do not expand if $levels is equal to 0. return null; } // Initialize current SelectExpandClause with processed SelectExpandClause. SelectExpandClause currentSelectExpandClause = selectExpandClause; ExpandedNavigationSelectItem item = null; // Construct new ExpandedNavigationSelectItem with recursive expansion. while (level > 0) { // Construct a new ExpandedNavigationSelectItem with current SelectExpandClause. item = new ExpandedNavigationSelectItem( expandItem.PathToNavigationProperty, expandItem.NavigationSource, currentSelectExpandClause); // Update current SelectExpandClause with the new ExpandedNavigationSelectItem. if (selectExpandClause.AllSelected) { currentSelectExpandClause = new SelectExpandClause( new[] { item }.Concat(selectExpandClause.SelectedItems), selectExpandClause.AllSelected); } else { // PathSelectItem is needed for the expanded item if AllSelected is false. PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(expandItem.PathToNavigationProperty)); currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { item, pathSelectItem }.Concat(selectExpandClause.SelectedItems), selectExpandClause.AllSelected); } level--; } return item; }
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; }
// Process $levels in ExpandedNavigationSelectItem. private static ExpandedNavigationSelectItem ProcessLevels( ExpandedNavigationSelectItem expandItem, int levelsMaxLiteralExpansionDepth, out bool levelsEncounteredInExpand, out bool isMaxLevelInExpand) { int level; isMaxLevelInExpand = false; if (expandItem.LevelsOption == null) { levelsEncounteredInExpand = false; level = 1; } else { levelsEncounteredInExpand = true; if (expandItem.LevelsOption.IsMaxLevel) { isMaxLevelInExpand = true; level = levelsMaxLiteralExpansionDepth; } else { level = (int)expandItem.LevelsOption.Level; } } // Do not expand when: // 1. $levels is equal to or less than 0. // 2. $levels value is greater than current MaxExpansionDepth if (level <= 0 || level > levelsMaxLiteralExpansionDepth) { return(null); } ExpandedNavigationSelectItem item = null; SelectExpandClause currentSelectExpandClause = null; SelectExpandClause selectExpandClause = null; bool levelsEncounteredInInnerExpand = false; bool isMaxLevelInInnerExpand = false; // Try diffent expansion depth until expandItem.SelectAndExpand is successfully expanded while (selectExpandClause == null && level > 0) { selectExpandClause = ProcessLevels( expandItem.SelectAndExpand, levelsMaxLiteralExpansionDepth - level, out levelsEncounteredInInnerExpand, out isMaxLevelInInnerExpand); level--; } if (selectExpandClause == null) { return(null); } // Correct level value level++; while (level > 0) { if (item == null) { currentSelectExpandClause = selectExpandClause; } else if (selectExpandClause.AllSelected) { // Concat the processed items currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { item }.Concat(selectExpandClause.SelectedItems), selectExpandClause.AllSelected); } else { // PathSelectItem is needed for the expanded item if AllSelected is false. PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(expandItem.PathToNavigationProperty)); // Keep default SelectItems before expanded item to keep consistent with normal SelectExpandClause SelectItem[] items = new SelectItem[] { item, pathSelectItem }; currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { }.Concat(selectExpandClause.SelectedItems).Concat(items), selectExpandClause.AllSelected); } // Construct a new ExpandedNavigationSelectItem with current SelectExpandClause. item = new ExpandedNavigationSelectItem( expandItem.PathToNavigationProperty, expandItem.NavigationSource, currentSelectExpandClause); level--; // Need expand and construct selectExpandClause every time if it is max level in inner expand if (isMaxLevelInInnerExpand) { selectExpandClause = ProcessLevels( expandItem.SelectAndExpand, levelsMaxLiteralExpansionDepth - level, out levelsEncounteredInInnerExpand, out isMaxLevelInInnerExpand); } } levelsEncounteredInExpand = levelsEncounteredInExpand || levelsEncounteredInInnerExpand; isMaxLevelInExpand = isMaxLevelInExpand || isMaxLevelInInnerExpand; return(item); }
private void BuildExpansions(IEnumerable <SelectItem> selectedItems, HashSet <IEdmNavigationProperty> allNavigationProperties) { foreach (SelectItem selectItem in selectedItems) { ExpandedReferenceSelectItem expandReferenceItem = selectItem as ExpandedReferenceSelectItem; if (expandReferenceItem != null) { ValidatePathIsSupportedForExpand(expandReferenceItem.PathToNavigationProperty); NavigationPropertySegment navigationSegment = (NavigationPropertySegment)expandReferenceItem.PathToNavigationProperty.LastSegment; IEdmNavigationProperty navigationProperty = navigationSegment.NavigationProperty; int propertyCountInPath = expandReferenceItem.PathToNavigationProperty.OfType <PropertySegment>().Count(); bool numberOfPropertiesInPathMatch = (propertyCountInPath > 0 && PropertiesInPath != null && PropertiesInPath.Count == propertyCountInPath) || propertyCountInPath < 1; if (numberOfPropertiesInPathMatch && allNavigationProperties.Contains(navigationProperty)) { ExpandedNavigationSelectItem expandItem = selectItem as ExpandedNavigationSelectItem; if (expandItem != null) { if (!ExpandedProperties.ContainsKey(navigationProperty)) { ExpandedProperties.Add(navigationProperty, expandItem); } else { ExpandedProperties[navigationProperty] = expandItem; } } else { ReferencedNavigationProperties.Add(navigationProperty); } } else { //This is the case where the navigation property is not on the current type. We need to propagate the expand item to deeper SelectExpandNode. IEdmStructuralProperty complexProperty = FindNextPropertySegment(expandReferenceItem.PathToNavigationProperty); if (complexProperty != null) { SelectExpandClause newClause; if (ExpandedPropertiesOnSubChildren.ContainsKey(complexProperty)) { SelectExpandClause oldClause = ExpandedPropertiesOnSubChildren[complexProperty].SelectAndExpand; newClause = new SelectExpandClause( oldClause.SelectedItems.Concat(new SelectItem[] { expandReferenceItem }), false); ExpandedNavigationSelectItem newItem = new ExpandedNavigationSelectItem(expandReferenceItem.PathToNavigationProperty, navigationSegment.NavigationSource, newClause); ExpandedPropertiesOnSubChildren[complexProperty] = newItem; } else { newClause = new SelectExpandClause(new SelectItem[] { expandReferenceItem }, false); ExpandedNavigationSelectItem newItem = new ExpandedNavigationSelectItem(expandReferenceItem.PathToNavigationProperty, navigationSegment.NavigationSource, newClause); ExpandedPropertiesOnSubChildren.Add(complexProperty, newItem); } } } } } }
// Process $levels in ExpandedNavigationSelectItem. private static ExpandedNavigationSelectItem ProcessLevels( ExpandedNavigationSelectItem expandItem, int levelsMaxLiteralExpansionDepth, out bool levelsEncounteredInExpand, out bool isMaxLevelInExpand) { int level; isMaxLevelInExpand = false; if (expandItem.LevelsOption == null) { levelsEncounteredInExpand = false; level = 1; } else { levelsEncounteredInExpand = true; if (expandItem.LevelsOption.IsMaxLevel) { isMaxLevelInExpand = true; level = levelsMaxLiteralExpansionDepth; } else { level = (int)expandItem.LevelsOption.Level; } } // Do not expand when: // 1. $levels is equal to or less than 0. // 2. $levels value is greater than current MaxExpansionDepth if (level <= 0 || level > levelsMaxLiteralExpansionDepth) { return null; } ExpandedNavigationSelectItem item = null; SelectExpandClause currentSelectExpandClause = null; SelectExpandClause selectExpandClause = null; bool levelsEncounteredInInnerExpand = false; bool isMaxLevelInInnerExpand = false; // Try diffent expansion depth until expandItem.SelectAndExpand is successfully expanded while (selectExpandClause == null && level > 0) { selectExpandClause = ProcessLevels( expandItem.SelectAndExpand, levelsMaxLiteralExpansionDepth - level, out levelsEncounteredInInnerExpand, out isMaxLevelInInnerExpand); level--; } if (selectExpandClause == null) { return null; } // Correct level value level++; while (level > 0) { if (item == null) { currentSelectExpandClause = selectExpandClause; } else if (selectExpandClause.AllSelected) { // Concat the processed items currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { item }.Concat(selectExpandClause.SelectedItems), selectExpandClause.AllSelected); } else { // PathSelectItem is needed for the expanded item if AllSelected is false. PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(expandItem.PathToNavigationProperty)); // Keep default SelectItems before expanded item to keep consistent with normal SelectExpandClause SelectItem[] items = new SelectItem[] { item, pathSelectItem }; currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { }.Concat(selectExpandClause.SelectedItems).Concat(items), selectExpandClause.AllSelected); } // Construct a new ExpandedNavigationSelectItem with current SelectExpandClause. item = new ExpandedNavigationSelectItem( expandItem.PathToNavigationProperty, expandItem.NavigationSource, currentSelectExpandClause); level--; // Need expand and construct selectExpandClause every time if it is max level in inner expand if (isMaxLevelInInnerExpand) { selectExpandClause = ProcessLevels( expandItem.SelectAndExpand, levelsMaxLiteralExpansionDepth - level, out levelsEncounteredInInnerExpand, out isMaxLevelInInnerExpand); } } levelsEncounteredInExpand = levelsEncounteredInExpand || levelsEncounteredInInnerExpand; isMaxLevelInExpand = isMaxLevelInExpand || isMaxLevelInInnerExpand; return item; }
public OeNavigationSelectItem(IEdmEntitySetBase entitySet, OeNavigationSelectItem parent, ExpandedNavigationSelectItem item, OeNavigationSelectItemKind kind) : this(entitySet, CreatePath(parent.Path, item.PathToNavigationProperty)) { _edmProperty = ((NavigationPropertySegment)item.PathToNavigationProperty.LastSegment).NavigationProperty; _navigationSelectItem = item; EntitySet = entitySet; Kind = kind; Parent = parent; }
private async Task WriteNavigationNextLink(OeEntryFactory parentEntryFactory, ExpandedNavigationSelectItem item, Object value) { Uri?nextPageLink = new OeNextPageLinkBuilder(_queryContext).GetNavigationUri(parentEntryFactory, item, value); if (nextPageLink == null) { return; } var segment = (NavigationPropertySegment)item.PathToNavigationProperty.LastSegment; bool isCollection = segment.NavigationProperty.Type.IsCollection(); var resourceInfo = new ODataNestedResourceInfo() { IsCollection = isCollection, Name = segment.NavigationProperty.Name }; await _writer.WriteStartAsync(resourceInfo).ConfigureAwait(false); if (isCollection) { var resourceSet = new ODataResourceSet() { NextPageLink = nextPageLink }; await _writer.WriteStartAsync(resourceSet).ConfigureAwait(false); await _writer.WriteEndAsync().ConfigureAwait(false); } else { resourceInfo.Url = nextPageLink; } await _writer.WriteEndAsync().ConfigureAwait(false); }
private static void HandleExpandedNavigationSelectItem(SelectStatement statement, ExpandedNavigationSelectItem item) { var property = item.PathToNavigationProperty.FirstSegment as NavigationPropertySegment; if (property != null) { var firstPart = property.NavigationProperty.Name; var newSelect = new SelectStatement(new List <string>()); HandleItems(item.SelectAndExpand, newSelect); statement.Columns(newSelect.ColumnsList.Select(x => firstPart + "/" + x).ToArray()); } else { throw new NotSupportedException(string.Format("ExpandedNavigationSelectItem type '{0}' is not supported.", item.PathToNavigationProperty.FirstSegment.GetType().FullName)); } }
// new CollectionWrapper<ElementType> { Instance = source.Select((ElementType element) => new Wrapper { }) } private Expression ProjectCollection(Expression source, Type elementType, SelectExpandClause selectExpandClause, IEdmEntityType entityType, IEdmNavigationSource navigationSource, ExpandedNavigationSelectItem expandedItem) { ParameterExpression element = Expression.Parameter(elementType); // expression // new Wrapper { } Expression projection = ProjectElement(element, selectExpandClause, entityType, navigationSource); // expression // (ElementType element) => new Wrapper { } LambdaExpression selector = Expression.Lambda(projection, element); if (expandedItem != null) { source = AddOrderByQueryForSource(source, expandedItem.OrderByOption, elementType); } if (_settings.PageSize.HasValue || (expandedItem != null && (expandedItem.TopOption.HasValue || expandedItem.SkipOption.HasValue))) { // nested paging. Need to apply order by first, and take one more than page size as we need to know // whether the collection was truncated or not while generating next page links. IEnumerable <IEdmStructuralProperty> properties = entityType.Key().Any() ? entityType.Key() : entityType .StructuralProperties() .Where(property => property.Type.IsPrimitive()).OrderBy(property => property.Name); if (expandedItem == null || expandedItem.OrderByOption == null) { bool alreadyOrdered = false; foreach (var prop in properties) { source = ExpressionHelpers.OrderByPropertyExpression(source, prop.Name, elementType, alreadyOrdered); if (!alreadyOrdered) { alreadyOrdered = true; } } } if (expandedItem != null && expandedItem.SkipOption.HasValue) { Contract.Assert(expandedItem.SkipOption.Value <= Int32.MaxValue); source = ExpressionHelpers.Skip(source, (int)expandedItem.SkipOption.Value, elementType, _settings.EnableConstantParameterization); } if (expandedItem != null && expandedItem.TopOption.HasValue) { Contract.Assert(expandedItem.TopOption.Value <= Int32.MaxValue); source = ExpressionHelpers.Take(source, (int)expandedItem.TopOption.Value, elementType, _settings.EnableConstantParameterization); } if (_settings.PageSize.HasValue) { source = ExpressionHelpers.Take(source, _settings.PageSize.Value + 1, elementType, _settings.EnableConstantParameterization); } } // expression // source.Select((ElementType element) => new Wrapper { }) Expression selectedExpresion = Expression.Call(GetSelectMethod(elementType, projection.Type), source, selector); if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // source == null ? null : projectedCollection return(Expression.Condition( test: Expression.Equal(source, Expression.Constant(null)), ifTrue: Expression.Constant(null, selectedExpresion.Type), ifFalse: selectedExpresion)); } else { return(selectedExpresion); } }
/// <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; } } } }
private void Translate(ExpandTransformationNode transformation) { ExpandedNavigationSelectItem expandedNavigation = transformation.ExpandClause.SelectedItems.Single() as ExpandedNavigationSelectItem; AppendExpandExpression(expandedNavigation); }
private Expression BuildPropertyContainer(IEdmEntityType elementType, Expression source, Dictionary <IEdmNavigationProperty, ExpandedNavigationSelectItem> propertiesToExpand, ISet <IEdmStructuralProperty> propertiesToInclude, ISet <IEdmStructuralProperty> autoSelectedProperties, bool isSelectingOpenTypeSegments) { IList <NamedPropertyExpression> includedProperties = new List <NamedPropertyExpression>(); foreach (KeyValuePair <IEdmNavigationProperty, ExpandedNavigationSelectItem> kvp in propertiesToExpand) { IEdmNavigationProperty propertyToExpand = kvp.Key; ExpandedNavigationSelectItem expandItem = kvp.Value; SelectExpandClause projection = expandItem.SelectAndExpand; Expression propertyName = CreatePropertyNameExpression(elementType, propertyToExpand, source); Expression propertyValue = CreatePropertyValueExpressionWithFilter(elementType, propertyToExpand, source, expandItem.FilterOption); Expression nullCheck = Expression.Equal(propertyValue, Expression.Constant(null)); Expression countExpression = CreateTotalCountExpression(propertyValue, expandItem); // projection can be null if the expanded navigation property is not further projected or expanded. if (projection != null) { propertyValue = ProjectAsWrapper(propertyValue, projection, propertyToExpand.ToEntityType(), expandItem.NavigationSource as IEdmEntitySet); } NamedPropertyExpression propertyExpression = new NamedPropertyExpression(propertyName, propertyValue); if (projection != null) { if (!propertyToExpand.Type.IsCollection()) { propertyExpression.NullCheck = nullCheck; } else if (_settings.PageSize != null) { propertyExpression.PageSize = _settings.PageSize.Value; } propertyExpression.TotalCount = countExpression; propertyExpression.CountOption = expandItem.CountOption; } includedProperties.Add(propertyExpression); } foreach (IEdmStructuralProperty propertyToInclude in propertiesToInclude) { Expression propertyName = CreatePropertyNameExpression(elementType, propertyToInclude, source); Expression propertyValue = CreatePropertyValueExpression(elementType, propertyToInclude, source); includedProperties.Add(new NamedPropertyExpression(propertyName, propertyValue)); } foreach (IEdmStructuralProperty propertyToInclude in autoSelectedProperties) { Expression propertyName = CreatePropertyNameExpression(elementType, propertyToInclude, source); Expression propertyValue = CreatePropertyValueExpression(elementType, propertyToInclude, source); includedProperties.Add(new NamedPropertyExpression(propertyName, propertyValue) { AutoSelected = true }); } if (isSelectingOpenTypeSegments) { var dynamicPropertyDictionary = EdmLibHelpers.GetDynamicPropertyDictionary(elementType, _model); Expression propertyName = Expression.Constant(dynamicPropertyDictionary.Name); Expression propertyValue = Expression.Property(source, dynamicPropertyDictionary.Name); Expression nullablePropertyValue = ExpressionHelpers.ToNullable(propertyValue); if (_settings.HandleNullPropagation == HandleNullPropagationOption.True) { // source == null ? null : propertyValue propertyValue = Expression.Condition( test: Expression.Equal(source, Expression.Constant(value: null)), ifTrue: Expression.Constant(value: null, type: propertyValue.Type.ToNullable()), ifFalse: nullablePropertyValue); } else { propertyValue = nullablePropertyValue; } includedProperties.Add(new NamedPropertyExpression(propertyName, propertyValue)); } // create a property container that holds all these property names and values. return(PropertyContainer.CreatePropertyContainer(includedProperties)); }
public void ProjectAsWrapper_NonCollection_ProjectedValueNullAndHandleNullPropagationTrue() { // Arrange _settings.HandleNullPropagation = HandleNullPropagationOption.True; ExpandedNavigationSelectItem expandItem = new ExpandedNavigationSelectItem( new ODataExpandPath(new NavigationPropertySegment(_model.Order.NavigationProperties().Single(), entitySet: _model.Customers)), _model.Customers, selectExpandOption: null); SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[] { expandItem }, allSelected: true); Expression source = Expression.Constant(null, typeof(Order)); // Act Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order); // Assert SelectExpandWrapper<Order> projectedOrder = Expression.Lambda(projection).Compile().DynamicInvoke() as SelectExpandWrapper<Order>; Assert.NotNull(projectedOrder); Assert.Null(projectedOrder.Instance); Assert.Null(projectedOrder.Container.ToDictionary()["Customer"]); }
private OeNavigationSelectItem AddOrGetNavigationItem(OeNavigationSelectItem parentNavigationItem, ExpandedNavigationSelectItem item, bool isExpand) { IEdmEntitySetBase entitySet = OeEdmClrHelper.GetEntitySet(_edmModel, item); OeNavigationSelectItemKind kind; if (_notSelected) { kind = OeNavigationSelectItemKind.NotSelected; } else if (item.SelectAndExpand.IsNextLink()) { kind = OeNavigationSelectItemKind.NextLink; } else { kind = OeNavigationSelectItemKind.Normal; } var childNavigationSelectItem = new OeNavigationSelectItem(entitySet, parentNavigationItem, item, kind); return(parentNavigationItem.AddOrGetNavigationItem(childNavigationSelectItem, isExpand)); }
public void ProjectAsWrapper_NonCollection_ProjectedValueNullAndHandleNullPropagationFalse_Throws() { // Arrange _settings.HandleNullPropagation = HandleNullPropagationOption.False; ExpandedNavigationSelectItem expandItem = new ExpandedNavigationSelectItem( new ODataExpandPath(new NavigationPropertySegment(_model.Order.NavigationProperties().Single(), entitySet: _model.Customers)), _model.Customers, selectExpandOption: null); SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[] { expandItem }, allSelected: true); Expression source = Expression.Constant(null, typeof(Order)); // Act Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order); // Assert var e = Assert.Throws<TargetInvocationException>( () => Expression.Lambda(projection).Compile().DynamicInvoke()); Assert.IsType<NullReferenceException>(e.InnerException); }
private static FilterClause?GetFilter(IEdmModel edmModel, OeEntryFactory entryFactory, ExpandedNavigationSelectItem item, Object value) { SingleValueNode filterExpression; ResourceRangeVariableReferenceNode refNode; var segment = (NavigationPropertySegment)item.PathToNavigationProperty.LastSegment; IEdmNavigationProperty navigationProperty = segment.NavigationProperty; if (navigationProperty.ContainsTarget) { ModelBuilder.ManyToManyJoinDescription joinDescription = edmModel.GetManyToManyJoinDescription(navigationProperty); navigationProperty = joinDescription.JoinNavigationProperty.Partner; IEdmEntitySet joinNavigationSource = OeEdmClrHelper.GetEntitySet(edmModel, joinDescription.JoinNavigationProperty); ResourceRangeVariableReferenceNode joinRefNode = OeEdmClrHelper.CreateRangeVariableReferenceNode(joinNavigationSource, "d"); IEdmEntitySet targetNavigationSource = OeEdmClrHelper.GetEntitySet(edmModel, joinDescription.TargetNavigationProperty); ResourceRangeVariableReferenceNode targetRefNode = OeEdmClrHelper.CreateRangeVariableReferenceNode(targetNavigationSource); var anyNode = new AnyNode(new Collection <RangeVariable>() { joinRefNode.RangeVariable, targetRefNode.RangeVariable }, joinRefNode.RangeVariable) { Source = new CollectionNavigationNode(targetRefNode, joinDescription.TargetNavigationProperty.Partner, null), Body = OeExpressionHelper.CreateFilterExpression(joinRefNode, GetKeys(navigationProperty.PrincipalProperties(), navigationProperty.DependentProperties())) }; refNode = targetRefNode; filterExpression = anyNode; } else { IEnumerable <IEdmStructuralProperty> parentKeys; IEnumerable <IEdmStructuralProperty> childKeys; if (navigationProperty.IsPrincipal()) { parentKeys = navigationProperty.Partner.PrincipalProperties(); childKeys = navigationProperty.Partner.DependentProperties(); } else { if (navigationProperty.Type.IsCollection()) { parentKeys = navigationProperty.PrincipalProperties(); childKeys = navigationProperty.DependentProperties(); } else { parentKeys = navigationProperty.DependentProperties(); childKeys = navigationProperty.PrincipalProperties(); } } refNode = OeEdmClrHelper.CreateRangeVariableReferenceNode((IEdmEntitySetBase)segment.NavigationSource); List <KeyValuePair <IEdmStructuralProperty, Object> > keys = GetKeys(parentKeys, childKeys); if (IsNullKeys(keys)) { return(null); } filterExpression = OeExpressionHelper.CreateFilterExpression(refNode, keys); } if (item.FilterOption != null) { filterExpression = new BinaryOperatorNode(BinaryOperatorKind.And, filterExpression, item.FilterOption.Expression); } return(new FilterClause(filterExpression, refNode.RangeVariable)); List <KeyValuePair <IEdmStructuralProperty, Object> > GetKeys(IEnumerable <IEdmStructuralProperty> parentKeys, IEnumerable <IEdmStructuralProperty> childKeys) { var keys = new List <KeyValuePair <IEdmStructuralProperty, Object> >(); IEnumerator <IEdmStructuralProperty> childKeyEnumerator = childKeys.GetEnumerator(); foreach (IEdmStructuralProperty parentKey in parentKeys) { childKeyEnumerator.MoveNext(); Object keyValue = entryFactory.GetAccessorByName(parentKey.Name).GetValue(value); keys.Add(new KeyValuePair <IEdmStructuralProperty, Object>(childKeyEnumerator.Current, keyValue)); } return(keys); }
public void ProjectAsWrapper_NullExpandedProperty_HasNullValueInProjectedWrapper() { // Arrange Order order = new Order(); ExpandedNavigationSelectItem expandItem = new ExpandedNavigationSelectItem( new ODataExpandPath(new NavigationPropertySegment(_model.Order.NavigationProperties().Single(), entitySet: _model.Customers)), _model.Customers, selectExpandOption: null); SelectExpandClause selectExpand = new SelectExpandClause(new SelectItem[] { expandItem }, allSelected: true); Expression source = Expression.Constant(order); // Act Expression projection = _binder.ProjectAsWrapper(source, selectExpand, _model.Order); // Assert SelectExpandWrapper<Order> projectedOrder = Expression.Lambda(projection).Compile().DynamicInvoke() as SelectExpandWrapper<Order>; Assert.NotNull(projectedOrder); Assert.Contains("Customer", projectedOrder.Container.ToDictionary().Keys); Assert.Null(projectedOrder.Container.ToDictionary()["Customer"]); }
// Process $levels in ExpandedNavigationSelectItem. private static ExpandedNavigationSelectItem ProcessLevels( ExpandedNavigationSelectItem expandItem, int levelsMaxLiteralExpansionDepth, out bool levelsEncounteredInExpand) { // Call ProcessLevels on SelectExpandClause recursively. SelectExpandClause selectExpandClause = ProcessLevels( expandItem.SelectAndExpand, levelsMaxLiteralExpansionDepth - 1, out levelsEncounteredInExpand); if (expandItem.LevelsOption == null) { if (levelsEncounteredInExpand) { return(new ExpandedNavigationSelectItem( expandItem.PathToNavigationProperty, expandItem.NavigationSource, selectExpandClause)); } else { // Return the original ExpandedNavigationSelectItem if no $levels is found. return(expandItem); } } // There is $levels in current ExpandedNavigationSelectItem. levelsEncounteredInExpand = true; int level = expandItem.LevelsOption.IsMaxLevel ? levelsMaxLiteralExpansionDepth : (int)expandItem.LevelsOption.Level; if (level <= 0) { // Do not expand if $levels is equal to 0. return(null); } // Initialize current SelectExpandClause with processed SelectExpandClause. SelectExpandClause currentSelectExpandClause = selectExpandClause; ExpandedNavigationSelectItem item = null; // Construct new ExpandedNavigationSelectItem with recursive expansion. while (level > 0) { // Construct a new ExpandedNavigationSelectItem with current SelectExpandClause. item = new ExpandedNavigationSelectItem( expandItem.PathToNavigationProperty, expandItem.NavigationSource, currentSelectExpandClause); // Update current SelectExpandClause with the new ExpandedNavigationSelectItem. if (selectExpandClause.AllSelected) { currentSelectExpandClause = new SelectExpandClause( new[] { item }.Concat(selectExpandClause.SelectedItems), selectExpandClause.AllSelected); } else { // PathSelectItem is needed for the expanded item if AllSelected is false. PathSelectItem pathSelectItem = new PathSelectItem( new ODataSelectPath(expandItem.PathToNavigationProperty)); currentSelectExpandClause = new SelectExpandClause( new SelectItem[] { item, pathSelectItem }.Concat(selectExpandClause.SelectedItems), selectExpandClause.AllSelected); } level--; } return(item); }
/// <summary> /// Writes ExpandItem node to string /// </summary> /// <param name="node">Node to write to string</param> /// <returns>String representation of node.</returns> private static string ToString(ExpandedNavigationSelectItem node) { if (node != null) { var expandItemString = "Expanded Navigation Property" + tabHelper.Indent(() => { string text = tabHelper.Prefix + ToString(node.PathToNavigationProperty); // Include when we add V4 support ////if (node.TopOption != null) expandItemString += tabHelper.Prefix + string.Format("TopOption({0})", node.TopOption); ////if (node.SkipOption != null) expandItemString += tabHelper.Prefix + string.Format("SkipOption({0})", node.SkipOption); ////if (node.InlineCountOption != null) expandItemString += tabHelper.Prefix + string.Format("InlineCountOption({0})", node.InlineCountOption); if (node.FilterOption != null) text += ToString(node.FilterOption); if (node.OrderByOption != null) text += ToString(node.OrderByOption); if (node.SearchOption != null) text += ToString(node.SearchOption); if (node.SelectAndExpand != null) text += ToString(node.SelectAndExpand); return text; }); return expandItemString; } return String.Empty; }