private void BuildQueryOptions(IDictionary <string, string> queryParameters)
        {
            foreach (KeyValuePair <string, string> kvp in queryParameters)
            {
                switch (kvp.Key.ToLowerInvariant())
                {
                case "$filter":
                    ThrowIfEmpty(kvp.Value, "$filter");
                    RawValues.Filter = kvp.Value;
                    Filter           = new FilterQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$orderby":
                    ThrowIfEmpty(kvp.Value, "$orderby");
                    RawValues.OrderBy = kvp.Value;
                    OrderBy           = new OrderByQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$top":
                    ThrowIfEmpty(kvp.Value, "$top");
                    RawValues.Top = kvp.Value;
                    Top           = new TopQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$skip":
                    ThrowIfEmpty(kvp.Value, "$skip");
                    RawValues.Skip = kvp.Value;
                    Skip           = new SkipQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$select":
                    RawValues.Select = kvp.Value;
                    break;

                case "$count":
                    ThrowIfEmpty(kvp.Value, "$count");
                    RawValues.Count = kvp.Value;
                    Count           = new CountQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$expand":
                    RawValues.Expand = kvp.Value;
                    break;

                case "$format":
                    RawValues.Format = kvp.Value;
                    break;

                case "$skiptoken":
                    RawValues.SkipToken = kvp.Value;
                    SkipToken           = new SkipTokenQueryOption(kvp.Value, Context);
                    break;

                case "$deltatoken":
                    RawValues.DeltaToken = kvp.Value;
                    break;

                case "$apply":
                    ThrowIfEmpty(kvp.Value, "$apply");
                    RawValues.Apply = kvp.Value;
                    Apply           = new ApplyQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$compute":
                    ThrowIfEmpty(kvp.Value, "$compute");
                    RawValues.Compute = kvp.Value;
                    Compute           = new ComputeQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$search":
                    ThrowIfEmpty(kvp.Value, "$search");
                    RawValues.Search = kvp.Value;
                    Search           = new SearchQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                default:
                    // we don't throw if we can't recognize the query
                    break;
                }
            }

            if (RawValues.Select != null || RawValues.Expand != null)
            {
                SelectExpand = new SelectExpandQueryOption(RawValues.Select, RawValues.Expand,
                                                           Context, _queryOptionParser);
            }

            if (Request.IsCountRequest())
            {
                Count = new CountQueryOption(
                    "true",
                    Context,
                    new ODataQueryOptionParser(
                        Context.Model,
                        Context.ElementType,
                        Context.NavigationSource,
                        new Dictionary <string, string> {
                    { "$count", "true" }
                },
                        Context.RequestContainer));
            }
        }
        /// <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="pageSize">The page size for this query</param>
        /// <param name="queryOptions"></param>
        /// <returns>The new <see cref="IQueryable"/> after the query has been applied to.</returns>
        public virtual IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings, int?pageSize,
                                          ODataQueryOptions queryOptions)
        {
            if (query == null)
            {
                throw Error.ArgumentNull("query");
            }

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

            var 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 && queryOptions.IgnoreSkip == false) ||
                 (Top != null && queryOptions.IgnoreTop == false) ||
                 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
                            ? OrderByHelper.GenerateDefaultOrderBy(Context, _serviceProvider)
                            : OrderByHelper.EnsureStableSortOrderBy(orderBy, Context, _serviceProvider);
            }

            // 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 (Apply != null)
            {
                query = Apply.ApplyTo(query, querySettings, _assemblyProvider);
                Request.ODataFeature().ApplyClause = Apply.ApplyClause;
                Context.ElementClrType = Apply.ResultClrType;
            }

            if (orderBy != null && Apply == null)
            {
                query = orderBy.ApplyTo(query, querySettings);
            }

            if (Skip.HasValue && queryOptions.IgnoreSkip == false)
            {
                query = ExpressionHelpers.Skip(query, Skip.Value, Context.ElementClrType, false);
            }

            int?take = null;

            if (querySettings.PageSize.HasValue)
            {
                take = Math.Min(querySettings.PageSize.Value, int.MaxValue);
            }
            if (Top.HasValue && queryOptions.IgnoreTop == false)
            {
                take = Math.Min(Top.Value, take ?? int.MaxValue);
            }
            if (take.HasValue)
            {
                query = ExpressionHelpers.Take(query, take.Value, Context.ElementClrType, false);
            }

            if (SelectExpand != null)
            {
                query = SelectExpand.ApplyTo(query, querySettings, _assemblyProvider);
            }

            if (CountQueryOption != null)
            {
                if (Request.ODataFeature().TotalCountFunc == null)
                {
                    Func <long> countFunc = CountQueryOption.GetEntityCountFunc(query);
                    if (countFunc != null)
                    {
                        Request.ODataFeature().TotalCountFunc = countFunc;
                    }
                }

                if (ODataCountMediaTypeMapping.IsCountRequest(Request.HttpContext))
                {
                    return(query);
                }
            }
            if (pageSize.HasValue && Apply == null)
            {
                bool resultsLimited;
                query = LimitResults(query, pageSize.Value, out resultsLimited);
                if (resultsLimited && Request.GetDisplayUrl() != null && new Uri(Request.GetDisplayUrl()).IsAbsoluteUri&& Request.ODataFeature().NextLink == null)
                {
                    Uri nextPageLink = Request.GetNextPageLink(pageSize.Value);
                    Request.ODataFeature().NextLink = nextPageLink;
                }
            }
            return(query);
        }
        private void BuildQueryOptions(IDictionary <string, string> queryParameters)
        {
            foreach (var kvp in queryParameters)
            {
                switch (kvp.Key.ToLowerInvariant())
                {
                case "$filter":
                    ThrowIfEmpty(kvp.Value, "$filter");
                    RawValues.Filter = kvp.Value;
                    Filter           = new FilterQueryOption(kvp.Value, Context, _queryOptionParser, _serviceProvider);
                    break;

                case "$orderby":
                    ThrowIfEmpty(kvp.Value, "$orderby");
                    RawValues.OrderBy = kvp.Value;
                    OrderBy           = new OrderByQueryOption(kvp.Value, Context, _queryOptionParser, _serviceProvider);
                    break;

                case "$top":
                    ThrowIfEmpty(kvp.Value, "$top");
                    RawValues.Top = kvp.Value;
                    Top           = TryParseNonNegativeInteger("$top", kvp.Value);
                    break;

                case "$skip":
                    ThrowIfEmpty(kvp.Value, "$skip");
                    RawValues.Skip  = kvp.Value;
                    Skip            = TryParseNonNegativeInteger("$skip", kvp.Value);
                    SkipQueryOption = new SkipQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$select":
                    RawValues.Select = kvp.Value;
                    break;

                case "$apply":
                    ThrowIfEmpty(kvp.Value, "$apply");
                    RawValues.Apply = kvp.Value;
                    Apply           = new ApplyQueryOption(kvp.Value, Context, _queryOptionParser, _serviceProvider);
                    break;

                case "$count":
                    // According to the OData 4 protocol, the value of this query option is optional:
                    // http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part1-protocol/odata-v4.0-errata02-os-part1-protocol-complete.html#_Toc406398308
                    // "A $count query option with a value of false (or not specified) hints that the service SHOULD NOT return a count."
                    RawValues.Count = kvp.Value;
                    if (string.IsNullOrWhiteSpace(kvp.Value) == false)
                    {
                        bool count;
                        if (bool.TryParse(kvp.Value, out count))
                        {
                            Count = count;
                        }
                        else
                        {
                            throw new ODataException($"If a value for the query '$count' is specified, it must have a value of '{bool.TrueString}' or '{bool.FalseString}'");
                        }
                    }
                    break;

                case "$expand":
                    RawValues.Expand = kvp.Value;
                    // TODO Parse the select statement if any
                    Request.ODataFeature().SelectExpandClause = _queryOptionParser.ParseSelectAndExpand();
                    SelectExpand = new SelectExpandQueryOption(string.Empty, kvp.Value, Context, _queryOptionParser, Request, _serviceProvider);
                    break;

                case "$format":
                    RawValues.Format = kvp.Value;
                    break;

                case "$skiptoken":
                    RawValues.SkipToken = kvp.Value;
                    break;
                }
            }
            if (ODataCountMediaTypeMapping.IsCountRequest(Request.HttpContext))
            {
                CountQueryOption = new CountQueryOption(
                    "true",
                    Context,
                    new ODataQueryOptionParser(
                        Context.Model,
                        Context.ElementType,
                        Context.NavigationSource,
                        new Dictionary <string, string> {
                    { "$count", "true" }
                }));
            }
        }
示例#4
0
        private void BuildQueryOptions(IDictionary <string, string> queryParameters)
        {
            foreach (var kvp in queryParameters)
            {
                switch (kvp.Key.ToLowerInvariant())
                {
                case "$filter":
                    ThrowIfEmpty(kvp.Value, "$filter");
                    RawValues.Filter = kvp.Value;
                    Filter           = new FilterQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$orderby":
                    ThrowIfEmpty(kvp.Value, "$orderby");
                    RawValues.OrderBy = kvp.Value;
                    OrderBy           = new OrderByQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$top":
                    ThrowIfEmpty(kvp.Value, "$top");
                    RawValues.Top = kvp.Value;
                    Top           = new TopQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$skip":
                    ThrowIfEmpty(kvp.Value, "$skip");
                    RawValues.Skip = kvp.Value;
                    Skip           = new SkipQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$select":
                    RawValues.Select = kvp.Value;
                    break;

                case "$count":
                    ThrowIfEmpty(kvp.Value, "$count");
                    RawValues.Count = kvp.Value;
                    Count           = new CountQueryOption(kvp.Value, Context, _queryOptionParser);
                    break;

                case "$expand":
                    RawValues.Expand = kvp.Value;
                    break;

                case "$format":
                    RawValues.Format = kvp.Value;
                    break;

                case "$skiptoken":
                    RawValues.SkipToken = kvp.Value;
                    break;
                }

                if (RawValues.Select != null || RawValues.Expand != null)
                {
                    SelectExpand = new SelectExpandQueryOption(RawValues.Select, RawValues.Expand, Context);
                }
            }

            if (ODataCountMediaTypeMapping.IsCountRequest(Request))
            {
                Count = new CountQueryOption(
                    "true",
                    Context,
                    new ODataQueryOptionParser(
                        Context.Model,
                        Context.ElementType,
                        Context.NavigationSource,
                        new Dictionary <string, string> {
                    { "$count", "true" }
                }));
            }
        }