コード例 #1
0
        /// <summary>
        /// Translate an ExpandedReferenceSelectItem
        /// </summary>
        /// <param name="item">the item to Translate</param>
        /// <returns>Defined by the implementer</returns>
        public override string Translate(ExpandedReferenceSelectItem item)
        {
            NodeToStringBuilder nodeToStringBuilder = new NodeToStringBuilder();
            string currentExpandClause = String.Join("/", item.PathToNavigationProperty.WalkWith(PathSegmentToStringTranslator.Instance).ToArray());
            string res = string.Empty;

            if (item.FilterOption != null)
            {
                res += "$filter=" + nodeToStringBuilder.TranslateFilterClause(item.FilterOption);
            }

            if (item.OrderByOption != null)
            {
                res += string.IsNullOrEmpty(res) ? null : ";";
                res += "$orderby=" + nodeToStringBuilder.TranslateOrderByClause(item.OrderByOption);
            }

            if (item.TopOption != null)
            {
                res += string.IsNullOrEmpty(res) ? null : ";";
                res += "$top=" + item.TopOption.ToString();
            }

            if (item.SkipOption != null)
            {
                res += string.IsNullOrEmpty(res) ? null : ";";
                res += "$skip=" + item.SkipOption.ToString();
            }

            if (item.CountOption != null)
            {
                res += string.IsNullOrEmpty(res) ? null : ";";
                res += "$count";
                res += ExpressionConstants.SymbolEqual;
                if (item.CountOption == true)
                {
                    res += ExpressionConstants.KeywordTrue;
                }
                else
                {
                    res += ExpressionConstants.KeywordFalse;
                }
            }

            if (item.SearchOption != null)
            {
                res += string.IsNullOrEmpty(res) ? null : ";";
                res += "$search";
                res += ExpressionConstants.SymbolEqual;
                res += nodeToStringBuilder.TranslateSearchClause(item.SearchOption);
            }

            return(string.Concat(currentExpandClause, string.IsNullOrEmpty(res) ? null : string.Concat(ExpressionConstants.SymbolOpenParen, res, ExpressionConstants.SymbolClosedParen)));
        }
コード例 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ODataSerializerContext"/> class for nested resources.
        /// </summary>
        /// <param name="resource">The resource whose navigation property is being expanded.</param>
        /// <param name="edmProperty">The complex property being nested or the navigation property being expanded.
        /// If the resource property is the dynamic complex, the resource property is null.
        /// </param>
        /// <param name="queryContext">The <see cref="ODataQueryContext"/> for the navigation property being expanded.</param>
        /// <param name="expandedItem">The <see cref="ExpandedReferenceSelectItem"/> for the navigation property being expanded.></param>
        internal ODataSerializerContext(ResourceContext resource, IEdmProperty edmProperty, ODataQueryContext queryContext, ExpandedReferenceSelectItem expandedItem)
        {
            if (resource == null)
            {
                throw Error.ArgumentNull("resource");
            }

            // Clone the resource's context. Use a helper function so it can
            // handle platform-specific differences in ODataSerializerContext.
            ODataSerializerContext context = resource.SerializerContext;

            this.CopyPlatformSpecificProperties(context);

            Model           = context.Model;
            Path            = context.Path;
            RootElementName = context.RootElementName;
            SkipExpensiveAvailabilityChecks = context.SkipExpensiveAvailabilityChecks;
            MetadataLevel   = context.MetadataLevel;
            Items           = context.Items;
            ExpandReference = context.ExpandReference;

            QueryContext              = queryContext;
            ExpandedResource          = resource; // parent resource
            CurrentExpandedSelectItem = expandedItem;

            var expandedNavigationSelectItem = expandedItem as ExpandedNavigationSelectItem;

            if (expandedNavigationSelectItem != null)
            {
                SelectExpandClause = expandedNavigationSelectItem.SelectAndExpand;
            }
            EdmProperty = edmProperty; // should be nested property

            Queue <IEdmProperty> parentPropertiesInPath =
                context.PropertiesInPath != null ? context.PropertiesInPath : new Queue <IEdmProperty>();

            parentPropertiesInPath.Enqueue(edmProperty);
            PropertiesInPath = parentPropertiesInPath;

            if (context.NavigationSource != null)
            {
                IEdmNavigationProperty navigationProperty = edmProperty as IEdmNavigationProperty;
                if (navigationProperty != null)
                {
                    NavigationSource = context.NavigationSource.FindNavigationTarget(navigationProperty);
                }
                else
                {
                    NavigationSource = context.NavigationSource;
                }
            }
        }
コード例 #3
0
        private void ValidateExpandReferenceItem(ExpandedReferenceSelectItem expandItem, ODataUrlValidationContext validationContext)
        {
            ValidateItem(expandItem, validationContext);
            foreach (ODataPathSegment segment in expandItem.PathToNavigationProperty)
            {
                ValidatePathSegment(segment, validationContext);
            }

            ValidateFilterClause(expandItem.FilterOption, validationContext);
            ValidateOrderByClause(expandItem.OrderByOption, validationContext);
            ValidateSearchClause(expandItem.SearchOption, validationContext);
            // todo: apply and compute are also defined on ExpandReferenceItem, but should only be valid on ExpandItem
            // add rule to fail if these are found on ExpandReferenceItem that is not ExpandItem?
        }
コード例 #4
0
 public OeNavigationEntryFactory(
     IEdmEntitySetBase entitySet,
     OePropertyAccessor[] accessors,
     OePropertyAccessor[]?skipTokenAccessors,
     IReadOnlyList <OeNavigationEntryFactory> navigationLinks,
     LambdaExpression?linkAccessor,
     IEdmNavigationProperty edmNavigationProperty,
     ExpandedReferenceSelectItem navigationSelectItem,
     bool nextLink)
     : base(entitySet, accessors, skipTokenAccessors, navigationLinks, linkAccessor)
 {
     EdmNavigationProperty = edmNavigationProperty;
     NavigationSelectItem  = navigationSelectItem;
     NextLink = nextLink;
 }
コード例 #5
0
 /// <summary>
 /// Handle an ExpandedReferenceSelectItem
 /// </summary>
 /// <param name="item">the item to Handle</param>
 public virtual void Handle(ExpandedReferenceSelectItem item)
 {
     throw new NotImplementedException();
 }
コード例 #6
0
ファイル: SelectExpandNode.cs プロジェクト: xsmerek/WebApi
        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);
                            }
                        }
                    }
                }
            }
        }
コード例 #7
0
        private static FilterClause?GetFilter(IEdmModel edmModel, OeEntryFactory entryFactory, ExpandedReferenceSelectItem 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);
            }
コード例 #8
0
        private static ODataUri GetCountODataUri(IEdmModel edmModel, OeEntryFactory entryFactory, ExpandedReferenceSelectItem 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),
            });
        }
コード例 #9
0
        /// <summary>
        /// Handle an ExpandedReferenceSelectItem
        /// </summary>
        /// <param name="item">the item to Handle</param>
        public override void Handle(ExpandedReferenceSelectItem 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;
            }
        }
コード例 #10
0
 /// <summary>
 /// Handle an ExpandedReferenceSelectItem
 /// </summary>
 /// <param name="item">the item to Handle</param>
 public virtual void Handle(ExpandedReferenceSelectItem item)
 {
     throw new NotImplementedException();
 }
コード例 #11
0
        internal Expression CreatePropertyValueExpressionWithFilter(IEdmStructuredType elementType, IEdmProperty property,
                                                                    Expression source, ExpandedReferenceSelectItem expandItem)
        {
            Contract.Assert(elementType != null);
            Contract.Assert(property != null);
            Contract.Assert(source != null);

            FilterClause filterClause = expandItem != null ? expandItem.FilterOption : null;

            IEdmStructuredType declaringType;
            IEdmStructuredType currentType = elementType;

            if (expandItem != null)
            {
                foreach (ODataPathSegment segment in expandItem.PathToNavigationProperty)
                {
                    string          currentProperty           = String.Empty;
                    PropertySegment propertyAccessPathSegment =
                        segment as PropertySegment;
                    if (propertyAccessPathSegment != null)
                    {
                        IEdmProperty propertyInPath = propertyAccessPathSegment.Property;
                        currentProperty = EdmLibHelpers.GetClrPropertyName(propertyInPath, _model);
                        declaringType   = propertyInPath.DeclaringType;
                        Contract.Assert(!String.IsNullOrEmpty(currentProperty), "Property name could not be found on the model.");
                        if (_settings.HandleNullPropagation == HandleNullPropagationOption.True)
                        {
                            // create expression similar to: 'source == null ? null : propertyValue'
                            if (declaringType != currentType)
                            {
                                Type castType = EdmLibHelpers.GetClrType(property.DeclaringType, _model);
                                if (castType == null)
                                {
                                    throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType,
                                                                          property.DeclaringType.FullTypeName()));
                                }

                                source = Expression.TypeAs(source, castType);
                            }
                            Expression propertyExpression = Expression.Property(source, currentProperty);
                            Type       nullablePropType   = TypeHelper.ToNullable(propertyExpression.Type);

                            source = Expression.Condition(
                                test: Expression.Equal(propertyExpression, Expression.Constant(value: null)),
                                ifTrue: Expression.Constant(value: null, type: nullablePropType),
                                ifFalse: propertyExpression);
                        }
                        else
                        {
                            source = Expression.Property(source, currentProperty);
                        }

                        currentType = propertyInPath.Type.ToStructuredType();
                    }
                    else
                    {
                        TypeSegment typeSegment = segment as TypeSegment;
                        if (typeSegment != null)
                        {
                            Type castType = EdmLibHelpers.GetClrType(typeSegment.EdmType, _model);
                            source      = Expression.TypeAs(source, castType);
                            currentType = typeSegment.EdmType as IEdmStructuredType;
                        }
                    }
                }
            }

            // derived property using cast
            if (currentType != property.DeclaringType)
            {
                Type castType = EdmLibHelpers.GetClrType(property.DeclaringType, _model);
                if (castType == null)
                {
                    throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType,
                                                          property.DeclaringType.FullTypeName()));
                }

                source = Expression.TypeAs(source, castType);
            }

            string       propertyName          = EdmLibHelpers.GetClrPropertyName(property, _model);
            PropertyInfo propertyInfo          = source.Type.GetProperty(propertyName);
            Expression   propertyValue         = Expression.Property(source, propertyInfo);
            Type         nullablePropertyType  = TypeHelper.ToNullable(propertyValue.Type);
            Expression   nullablePropertyValue = ExpressionHelpers.ToNullable(propertyValue);

            if (filterClause != null)
            {
                bool isCollection = property.Type.IsCollection();

                IEdmTypeReference edmElementType = (isCollection ? property.Type.AsCollection().ElementType() : property.Type);
                Type clrElementType = EdmLibHelpers.GetClrType(edmElementType, _model);
                if (clrElementType == null)
                {
                    throw new ODataException(Error.Format(SRResources.MappingDoesNotContainResourceType,
                                                          edmElementType.FullName()));
                }

                Expression filterResult = nullablePropertyValue;

                ODataQuerySettings querySettings = new ODataQuerySettings()
                {
                    HandleNullPropagation = HandleNullPropagationOption.True,
                };

                if (isCollection)
                {
                    Expression filterSource = nullablePropertyValue;

                    // TODO: Implement proper support for $select/$expand after $apply
                    Expression filterPredicate = FilterBinder.Bind(null, filterClause, clrElementType, _context, querySettings);
                    filterResult = Expression.Call(
                        ExpressionHelperMethods.EnumerableWhereGeneric.MakeGenericMethod(clrElementType),
                        filterSource,
                        filterPredicate);

                    nullablePropertyType = filterResult.Type;
                }
                else if (_settings.HandleReferenceNavigationPropertyExpandFilter)
                {
                    LambdaExpression filterLambdaExpression = FilterBinder.Bind(null, filterClause, clrElementType, _context, querySettings) as LambdaExpression;
                    if (filterLambdaExpression == null)
                    {
                        throw new ODataException(Error.Format(SRResources.ExpandFilterExpressionNotLambdaExpression,
                                                              property.Name, "LambdaExpression"));
                    }

                    ParameterExpression filterParameter     = filterLambdaExpression.Parameters.First();
                    Expression          predicateExpression = new ReferenceNavigationPropertyExpandFilterVisitor(filterParameter, nullablePropertyValue).Visit(filterLambdaExpression.Body);

                    // create expression similar to: 'predicateExpression == true ? nullablePropertyValue : null'
                    filterResult = Expression.Condition(
                        test: predicateExpression,
                        ifTrue: nullablePropertyValue,
                        ifFalse: Expression.Constant(value: null, type: nullablePropertyType));
                }

                if (_settings.HandleNullPropagation == HandleNullPropagationOption.True)
                {
                    // create expression similar to: 'nullablePropertyValue == null ? null : filterResult'
                    nullablePropertyValue = Expression.Condition(
                        test: Expression.Equal(nullablePropertyValue, Expression.Constant(value: null)),
                        ifTrue: Expression.Constant(value: null, type: nullablePropertyType),
                        ifFalse: filterResult);
                }
                else
                {
                    nullablePropertyValue = filterResult;
                }
            }

            if (_settings.HandleNullPropagation == HandleNullPropagationOption.True)
            {
                // create expression similar to: 'source == null ? null : propertyValue'
                propertyValue = Expression.Condition(
                    test: Expression.Equal(source, Expression.Constant(value: null)),
                    ifTrue: Expression.Constant(value: null, type: nullablePropertyType),
                    ifFalse: nullablePropertyValue);
            }
            else
            {
                // need to cast this to nullable as EF would fail while materializing if the property is not nullable and source is null.
                propertyValue = nullablePropertyValue;
            }

            return(propertyValue);
        }
コード例 #12
0
 /// <summary>
 /// Translate an ExpandedReferenceSelectItem
 /// </summary>
 /// <param name="item">the item to Translate</param>
 /// <returns>Defined by the implementer</returns>
 public virtual T Translate(ExpandedReferenceSelectItem item)
 {
     throw new NotImplementedException();
 }
コード例 #13
0
        private OeNavigationSelectItem AddOrGetNavigationItem(OeNavigationSelectItem parentNavigationItem, ExpandedReferenceSelectItem item, bool isExpand)
        {
            IEdmEntitySetBase entitySet = OeEdmClrHelper.GetEntitySet(_edmModel, item);

            OeNavigationSelectItemKind kind;

            if (_notSelected)
            {
                kind = OeNavigationSelectItemKind.NotSelected;
            }
            else if (item is ExpandedNavigationSelectItem expanded && expanded.SelectAndExpand.IsNextLink())
            {
                kind = OeNavigationSelectItemKind.NextLink;
            }
コード例 #14
0
        private async Task WriteNavigationNextLink(OeEntryFactory parentEntryFactory, ExpandedReferenceSelectItem 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);
        }