예제 #1
0
        private MemberBinding ToMemberBinding(Expression it, SelectClause selectClause)
        {
            Expression navigationProperty = Expression.MakeMemberAccess(it, _navigationProperty);

            if (_isCollection)
            {
                // NavigationProperty = it.NavigationProperty.Select( arg => new Item { ... } ).ToArray()
                // NavigationProperty = it.NavigationProperty.Select( arg => new Item { ... } ).ToList()

                // apply all constraints
                if (Select != null)
                {
                    navigationProperty = Select.ApplyTo(navigationProperty);
                }
                if (Orderby != null)
                {
                    navigationProperty = Orderby.ApplyTo(navigationProperty);
                }
                if (Filter != null)
                {
                    navigationProperty = Filter.ApplyTo(navigationProperty);
                }
                if (Skip != null)
                {
                    navigationProperty = Skip.ApplyTo(navigationProperty, ItemType);
                }
                if (Top != null)
                {
                    navigationProperty = Top.ApplyTo(navigationProperty, ItemType);
                }

                // build proper select of properties
                var expression = BuildSelectLambdaExpression(ItemType, selectClause, NestedExpands);

                navigationProperty = Expression.Call(null,
                                                     SelectInfo.MakeGenericMethod(ItemType, ItemType),
                                                     navigationProperty,
                                                     expression
                                                     );

                // add ToList/ToArray
                var loadFunction = _navigationProperty.PropertyType.IsArray
                    ? ToArrayInfo.MakeGenericMethod(ItemType)
                    : ToListInfo.MakeGenericMethod(ItemType);

                navigationProperty = Expression.Call(null,
                                                     loadFunction,
                                                     navigationProperty
                                                     );
            }
            else
            {
                // NavigationProperty = new Item { ... }
                navigationProperty = BuildMemberInit(ItemType, navigationProperty, selectClause, NestedExpands);
            }

            return(Expression.Bind(_navigationProperty, navigationProperty));
        }
        /// <summary>
        /// Apply the individual query to the given IQueryable in the right order.
        /// </summary>
        /// <param name="query">The original <see cref="IQueryable"/>.</param>
        /// <param name="querySettings">The settings to use in query composition.</param>
        /// <returns>The new <see cref="IQueryable"/> after the query has been applied to.</returns>
        public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings)
        {
            if (query == null)
            {
                throw Error.ArgumentNull(nameof(query));
            }

            if (querySettings == null)
            {
                throw Error.ArgumentNull(nameof(querySettings));
            }

            IQueryable    result       = query;
            IODataFeature odataFeature = Request.ODataFeature();

            // Update the query setting
            querySettings = Context.UpdateQuerySettings(querySettings, query);

            // First apply $apply
            // Section 3.15 of the spec http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/cs01/odata-data-aggregation-ext-v4.0-cs01.html#_Toc378326311
            if (IsAvailableODataQueryOption(Apply, AllowedQueryOptions.Apply))
            {
                result = Apply.ApplyTo(result, querySettings);
                odataFeature.ApplyClause    = Apply.ApplyClause;
                this.Context.ElementClrType = Apply.ResultClrType;
            }

            // TODO: need pass the result from $compute to the remaining query options
            // Construct the actual query and apply them in the following order: filter, orderby, skip, top
            if (IsAvailableODataQueryOption(Filter, AllowedQueryOptions.Filter))
            {
                if (IsAvailableODataQueryOption(Compute, AllowedQueryOptions.Compute))
                {
                    Filter.Compute = Compute;
                }

                result = Filter.ApplyTo(result, querySettings);
            }

            // If both $search and $filter are specified in the same request, only those items satisfying both criteria are returned
            // apply $search
            if (IsAvailableODataQueryOption(Search, AllowedQueryOptions.Search))
            {
                result = Search.ApplyTo(result, querySettings);
            }

            if (IsAvailableODataQueryOption(Count, AllowedQueryOptions.Count))
            {
                if (odataFeature.TotalCountFunc == null)
                {
                    Func <long> countFunc = Count.GetEntityCountFunc(result);
                    if (countFunc != null)
                    {
                        odataFeature.TotalCountFunc = countFunc;
                    }
                }

                if (Request.IsCountRequest())
                {
                    return(result);
                }
            }

            OrderByQueryOption orderBy = OrderBy;

            // $skip or $top require a stable sort for predictable results.
            // Result limits require a stable sort to be able to generate a next page link.
            // If either is present in the query and we have permission,
            // generate an $orderby that will produce a stable sort.
            if (querySettings.EnsureStableOrdering &&
                (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip) ||
                 IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top) ||
                 querySettings.PageSize.HasValue))
            {
                // If there is no OrderBy present, we manufacture a default.
                // If an OrderBy is already present, we add any missing
                // properties necessary to make a stable sort.
                // Instead of failing early here if we cannot generate the OrderBy,
                // let the IQueryable backend fail (if it has to).

                orderBy = GenerateStableOrder();
            }

            if (IsAvailableODataQueryOption(orderBy, AllowedQueryOptions.OrderBy))
            {
                if (IsAvailableODataQueryOption(Compute, AllowedQueryOptions.Compute))
                {
                    orderBy.Compute = Compute;
                }

                result = orderBy.ApplyTo(result, querySettings);
            }

            if (IsAvailableODataQueryOption(SkipToken, AllowedQueryOptions.SkipToken))
            {
                result = SkipToken.ApplyTo(result, querySettings, this);
            }

            AddAutoSelectExpandProperties();

            if (SelectExpand != null)
            {
                var tempResult = ApplySelectExpand(result, querySettings);
                if (tempResult != default(IQueryable))
                {
                    result = tempResult;
                }
            }

            if (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip))
            {
                result = Skip.ApplyTo(result, querySettings);
            }

            if (IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top))
            {
                result = Top.ApplyTo(result, querySettings);
            }

            result = ApplyPaging(result, querySettings);

            return(result);
        }
예제 #3
0
        /// <summary>
        /// Apply the individual query to the given IQueryable in the right order.
        /// </summary>
        /// <param name="query">The original <see cref="IQueryable"/>.</param>
        /// <param name="querySettings">The settings to use in query composition.</param>
        /// <returns>The new <see cref="IQueryable"/> after the query has been applied to.</returns>
        public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings)
        {
            if (query == null)
            {
                throw Error.ArgumentNull("query");
            }

            if (querySettings == null)
            {
                throw Error.ArgumentNull("querySettings");
            }

            IQueryable result = query;

            // Construct the actual query and apply them in the following order: filter, orderby, skip, top
            if (Filter != null)
            {
                result = Filter.ApplyTo(result, querySettings, _assembliesResolver);
            }

            if (InlineCount != null)
            {
                long?count = InlineCount.GetEntityCount(result);
                if (count.HasValue)
                {
                    Request.SetInlineCount(count.Value);
                }
            }

            OrderByQueryOption orderBy = OrderBy;

            // $skip or $top require a stable sort for predictable results.
            // Result limits require a stable sort to be able to generate a next page link.
            // If either is present in the query and we have permission,
            // generate an $orderby that will produce a stable sort.
            if (querySettings.EnsureStableOrdering &&
                (Skip != null || Top != null || querySettings.PageSize.HasValue))
            {
                // If there is no OrderBy present, we manufacture a default.
                // If an OrderBy is already present, we add any missing
                // properties necessary to make a stable sort.
                // Instead of failing early here if we cannot generate the OrderBy,
                // let the IQueryable backend fail (if it has to).
                orderBy = orderBy == null
                            ? GenerateDefaultOrderBy(Context)
                            : EnsureStableSortOrderBy(orderBy, Context);
            }

            if (orderBy != null)
            {
                result = orderBy.ApplyTo(result);
            }

            if (Skip != null)
            {
                result = Skip.ApplyTo(result, querySettings);
            }

            if (Top != null)
            {
                result = Top.ApplyTo(result, querySettings);
            }

            if (querySettings.PageSize.HasValue)
            {
                bool resultsLimited;
                result = LimitResults(result, querySettings.PageSize.Value, Context, out resultsLimited);
                if (resultsLimited && Request.RequestUri != null && Request.RequestUri.IsAbsoluteUri)
                {
                    Uri nextPageLink = GetNextPageLink(Request, querySettings.PageSize.Value);
                    Request.SetNextPageLink(nextPageLink);
                }
            }

            return(result);
        }
예제 #4
0
        public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings)
        {
            if (query == null)
            {
                throw Error.ArgumentNull("query");
            }

            if (querySettings == null)
            {
                throw Error.ArgumentNull("querySettings");
            }

            IQueryable result = query;

            // First apply $apply
            // Section 3.15 of the spec http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/cs01/odata-data-aggregation-ext-v4.0-cs01.html#_Toc378326311
            if (IsAvailableODataQueryOption(Apply, AllowedQueryOptions.Apply))
            {
                result = Apply.ApplyTo(result, querySettings, _assembliesResolver);
                Request.ODataProperties().ApplyClause = Apply.ApplyClause;
                this.Context.ElementClrType = Apply.ResultClrType;
            }

            // Construct the actual query and apply them in the following order: filter, orderby, skip, top
            if (IsAvailableODataQueryOption(Filter, AllowedQueryOptions.Filter))
            {
                result = Filter.ApplyTo(result, querySettings, _assembliesResolver);
            }

            if (IsAvailableODataQueryOption(Count, AllowedQueryOptions.Count))
            {
                if (Request.ODataProperties().TotalCountFunc == null)
                {
                    Func <long> countFunc = Count.GetEntityCountFunc(result);
                    if (countFunc != null)
                    {
                        Request.ODataProperties().TotalCountFunc = countFunc;
                    }
                }

                if (ODataCountMediaTypeMapping.IsCountRequest(Request))
                {
                    return(result);
                }
            }

            OrderByQueryOption orderBy = OrderBy;

            // $skip or $top require a stable sort for predictable results.
            // Result limits require a stable sort to be able to generate a next page link.
            // If either is present in the query and we have permission,
            // generate an $orderby that will produce a stable sort.
            if (querySettings.EnsureStableOrdering &&
                (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip) ||
                 IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top) ||
                 querySettings.PageSize.HasValue))
            {
                // If there is no OrderBy present, we manufacture a default.
                // If an OrderBy is already present, we add any missing
                // properties necessary to make a stable sort.
                // Instead of failing early here if we cannot generate the OrderBy,
                // let the IQueryable backend fail (if it has to).
                orderBy = orderBy == null
                            ? GenerateDefaultOrderBy(Context)
                            : EnsureStableSortOrderBy(orderBy, Context);
            }

            if (IsAvailableODataQueryOption(orderBy, AllowedQueryOptions.OrderBy))
            {
                result = orderBy.ApplyTo(result, querySettings);
            }

            if (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip))
            {
                result = Skip.ApplyTo(result, querySettings);
            }

            if (IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top))
            {
                result = Top.ApplyTo(result, querySettings);
            }

            AddAutoExpandProperties(querySettings);

            if (SelectExpand != null)
            {
                var tempResult = ApplySelectExpand(result, querySettings);
                if (tempResult != default(IQueryable))
                {
                    result = tempResult;
                }
            }

            if (querySettings.PageSize.HasValue)
            {
                bool resultsLimited;
                result = LimitResults(result, querySettings.PageSize.Value, out resultsLimited);
                if (resultsLimited && Request.RequestUri != null && Request.RequestUri.IsAbsoluteUri && Request.ODataProperties().NextLink == null)
                {
                    Uri nextPageLink = Request.GetNextPageLink(querySettings.PageSize.Value);
                    Request.ODataProperties().NextLink = nextPageLink;
                }
            }

            return(result);
        }
예제 #5
0
        public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings)
        {
            if (query == null)
            {
                throw Error.ArgumentNull("query");
            }

            if (querySettings == null)
            {
                throw Error.ArgumentNull("querySettings");
            }

            IQueryable result = query;

            // First apply $apply
            // Section 3.15 of the spec http://docs.oasis-open.org/odata/odata-data-aggregation-ext/v4.0/cs01/odata-data-aggregation-ext-v4.0-cs01.html#_Toc378326311
            if (IsAvailableODataQueryOption(Apply, AllowedQueryOptions.Apply))
            {
                result = Apply.ApplyTo(result, querySettings);
                InternalRequest.Context.ApplyClause = Apply.ApplyClause;
                if (Apply.SelectExpandClause != null)
                {
                    // In case of just expand in $apply falling back to $expand serialization
                    InternalRequest.Context.ProcessedSelectExpandClause = Apply.SelectExpandClause;
                }
                this.Context.ElementClrType = Apply.ResultClrType;
            }

            // Apply compute
            // It should be executed before $filter, because it defines computed properties that can be used in a $select or within a $filter or $orderby expression.
            if (IsAvailableODataQueryOption(Compute, AllowedQueryOptions.Compute))
            {
                result = Compute.ApplyTo(result, querySettings);
            }

            // Construct the actual query and apply them in the following order: filter, orderby, skip, top
            if (IsAvailableODataQueryOption(Filter, AllowedQueryOptions.Filter))
            {
                result = Filter.ApplyTo(result, querySettings);
            }

            if (IsAvailableODataQueryOption(Count, AllowedQueryOptions.Count))
            {
                if (InternalRequest.Context.TotalCountFunc == null)
                {
                    Func <long> countFunc = Count.GetEntityCountFunc(result);
                    if (countFunc != null)
                    {
                        InternalRequest.Context.TotalCountFunc = countFunc;
                    }
                }

                if (InternalRequest.IsCountRequest())
                {
                    return(result);
                }
            }

            OrderByQueryOption orderBy = OrderBy;

            // $skip or $top require a stable sort for predictable results.
            // Result limits require a stable sort to be able to generate a next page link.
            // If either is present in the query and we have permission,
            // generate an $orderby that will produce a stable sort.
            if (querySettings.EnsureStableOrdering &&
                (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip) ||
                 IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top) ||
                 querySettings.PageSize.HasValue))
            {
                // If there is no OrderBy present, we manufacture a default.
                // If an OrderBy is already present, we add any missing
                // properties necessary to make a stable sort.
                // Instead of failing early here if we cannot generate the OrderBy,
                // let the IQueryable backend fail (if it has to).

                orderBy = GenerateStableOrder();
            }

            if (IsAvailableODataQueryOption(orderBy, AllowedQueryOptions.OrderBy))
            {
                result = orderBy.ApplyTo(result, querySettings);
            }

            if (IsAvailableODataQueryOption(SkipToken, AllowedQueryOptions.SkipToken))
            {
                result = SkipToken.ApplyTo(result, querySettings, this);
            }


            if (!IsAggregated(Apply?.ApplyClause))
            {
                AddAutoSelectExpandProperties();
            }

            if (SelectExpand != null)
            {
                var tempResult = ApplySelectExpand(result, querySettings);
                if (tempResult != default(IQueryable))
                {
                    result = tempResult;
                }
            }

            if (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip))
            {
                result = Skip.ApplyTo(result, querySettings);
            }

            if (IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top))
            {
                result = Top.ApplyTo(result, querySettings);
            }

            result = ApplyPaging(result, querySettings);

            return(result);
        }
예제 #6
0
        /// <summary>
        /// Apply the individual query to the given IQueryable in the right order.
        /// </summary>
        /// <param name="query">The original <see cref="IQueryable"/>.</param>
        /// <param name="querySettings">The settings to use in query composition.</param>
        /// <param name="ignoreQueryOptions">The query parameters that are already applied in queries.</param>
        /// <returns>The new <see cref="IQueryable"/> after the query has been applied to.</returns>
        public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings, AllowedQueryOptions ignoreQueryOptions)
        {
            _ignoreQueryOptions = ignoreQueryOptions;
            if (query == null)
            {
                throw Error.ArgumentNull("query");
            }

            // Construct the actual query and apply them in the following order: filter
            if (IsAvailableODataQueryOption(Filter, AllowedQueryOptions.Filter))
            {
                query = Filter.ApplyTo(query, querySettings, _assembliesResolver);
            }

            if (IsAvailableODataQueryOption(Count, AllowedQueryOptions.Count))
            {
                if (Request.ODataProperties().TotalCountFunc == null)
                {
                    Func <long> countFunc = Count.GetEntityCountFunc(query);
                    if (countFunc != null)
                    {
                        Request.ODataProperties().TotalCountFunc = countFunc;
                    }
                }

                if (ODataCountMediaTypeMapping.IsCountRequest(Request))
                {
                    return(query);
                }
            }

            OrderByQueryOption orderBy = OrderBy;

            // $skip or $top require a stable sort for predictable results.
            // Result limits require a stable sort to be able to generate a next page link.
            // If either is present in the query and we have permission,
            // generate an $orderby that will produce a stable sort.
            if (querySettings.EnsureStableOrdering &&
                (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip) ||
                 IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top) ||
                 querySettings.PageSize.HasValue))
            {
                // If there is no OrderBy present, we manufacture a default.
                // If an OrderBy is already present, we add any missing
                // properties necessary to make a stable sort.
                // Instead of failing early here if we cannot generate the OrderBy,
                // let the IQueryable backend fail (if it has to).
                orderBy = orderBy == null
                                                        ? GenerateDefaultOrderBy(Context)
                                                        : EnsureStableSortOrderBy(orderBy, Context);
            }

            if (IsAvailableODataQueryOption(orderBy, AllowedQueryOptions.OrderBy))
            {
                query = orderBy.ApplyTo(query, querySettings);
            }
            if (IsAvailableODataQueryOption(Skip, AllowedQueryOptions.Skip))
            {
                query = Skip.ApplyTo(query, querySettings);
            }
            if (IsAvailableODataQueryOption(Top, AllowedQueryOptions.Top))
            {
                query = Top.ApplyTo(query, querySettings);
            }

            AddAutoExpandProperties(querySettings);

            if (SelectExpand != null)
            {
                var tempResult = ApplySelectExpand(query, querySettings);
                if (tempResult != default(IQueryable))
                {
                    query = tempResult;
                }
            }

            if (querySettings.PageSize.HasValue)
            {
                bool resultsLimited = true;
                query = LimitResults(query, querySettings.PageSize.Value, out resultsLimited);
                var uriString = Request.GetDisplayUrl();
                if (!string.IsNullOrWhiteSpace(uriString))
                {
                    var uri = new Uri(uriString);
                    if (resultsLimited && uri != null && uri.IsAbsoluteUri && Request.ODataProperties().NextLink == null)
                    {
                        Uri nextPageLink = Request.GetNextPageLink(querySettings.PageSize.Value);
                        Request.ODataProperties().NextLink = nextPageLink;
                    }
                }
            }

            return(query);
        }
예제 #7
0
 public IQueryable <T> ApplyTake(IQueryable <T> query)
 {
     return(Top.ApplyTo(query, new ODataQuerySettings()));
 }