internal IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings) { if (query == null) { throw Error.ArgumentNull("query"); } if (querySettings == null) { throw Error.ArgumentNull("querySettings"); } if (Context.ElementClrType == null) { throw Error.NotSupported(SRResources.ApplyToOnUntypedQueryOption, "ApplyTo"); } ComputeClause computeClause = ComputeClause; Contract.Assert(computeClause != null); ODataQuerySettings updatedSettings = Context.UpdateQuerySettings(querySettings, query); var binder = new ComputeBinder(updatedSettings, _assembliesResolver, Context.ElementClrType, Context.Model, computeClause.ComputedItems); query = binder.Bind(query); return(query); }
public IQueryable Bind(IQueryable query, ApplyClause applyClause) { // groupby and aggregate transform input by collapsing everything not used in groupby/aggregate // as a result we have two distinct cases for expand implementation // 1. Expands followed by groupby/aggregate with entity set aggregations => filters in expand need to be applied (pushed down) to corresponding entityset aggregations // 2. Mix of expands and filters w/o any groupby/aggregation => falling back to $expand behavior and could just use SelectExpandBinder bool inputShapeChanged = false; foreach (var transformation in applyClause.Transformations) { if (transformation.Kind == TransformationNodeKind.Aggregate || transformation.Kind == TransformationNodeKind.GroupBy) { var binder = new AggregationBinder(_settings, _assembliesResolver, ResultClrType, _context.Model, transformation, _context, SelectExpandClause); query = binder.Bind(query); this.ResultClrType = binder.ResultClrType; inputShapeChanged = true; } else if (transformation.Kind == TransformationNodeKind.Compute) { var binder = new ComputeBinder(_settings, _assembliesResolver, ResultClrType, _context.Model, (ComputeTransformationNode)transformation); query = binder.Bind(query); this.ResultClrType = binder.ResultClrType; inputShapeChanged = true; } else if (transformation.Kind == TransformationNodeKind.Filter) { var filterTransformation = (FilterTransformationNode)transformation; Expression filter = FilterBinder.Bind(query, filterTransformation.FilterClause, ResultClrType, _context, _settings); query = ExpressionHelpers.Where(query, filter, ResultClrType); } else if (transformation.Kind == TransformationNodeKind.Expand) { var newClause = ((ExpandTransformationNode)transformation).ExpandClause; if (SelectExpandClause == null) { SelectExpandClause = newClause; } else { SelectExpandClause = new SelectExpandClause(SelectExpandClause.SelectedItems.Concat(newClause.SelectedItems), false); } } } if (SelectExpandClause != null && !inputShapeChanged) { var expandString = GetExpandsOnlyString(SelectExpandClause); var selectExpandQueryOption = new SelectExpandQueryOption(null, expandString, _context, SelectExpandClause); query = SelectExpandBinder.Bind(query, _settings, selectExpandQueryOption); } return(query); }
/// <summary> /// Apply the apply query to the given IQueryable. /// </summary> /// <remarks> /// The <see cref="ODataQuerySettings.HandleNullPropagation"/> property specifies /// how this method should handle null propagation. /// </remarks> /// <param name="query">The original <see cref="IQueryable"/>.</param> /// <param name="querySettings">The <see cref="ODataQuerySettings"/> that contains all the query application related settings.</param> /// <returns>The new <see cref="IQueryable"/> after the filter query has been applied to.</returns> public IQueryable ApplyTo(IQueryable query, ODataQuerySettings querySettings) { if (query == null) { throw Error.ArgumentNull("query"); } if (querySettings == null) { throw Error.ArgumentNull("querySettings"); } if (Context.ElementClrType == null) { throw Error.NotSupported(SRResources.ApplyToOnUntypedQueryOption, "ApplyTo"); } // Linq to SQL not supported for $apply if (query.Provider.GetType().Namespace == HandleNullPropagationOptionHelper.Linq2SqlQueryProviderNamespace) { throw Error.NotSupported(SRResources.ApplyQueryOptionNotSupportedForLinq2SQL); } ApplyClause applyClause = ApplyClause; Contract.Assert(applyClause != null); ODataQuerySettings updatedSettings = Context.UpdateQuerySettings(querySettings, query); // The IWebApiAssembliesResolver service is internal and can only be injected by WebApi. // This code path may be used in cases when the service container is not available // and the service container is available but may not contain an instance of IWebApiAssembliesResolver. IAssemblyResolver assembliesResolver = AssemblyResolverHelper.Default; if (Context.RequestContainer != null) { IAssemblyResolver injectedResolver = Context.RequestContainer.GetService <IAssemblyResolver>(); if (injectedResolver != null) { assembliesResolver = injectedResolver; } } foreach (var transformation in applyClause.Transformations) { if (transformation.Kind == TransformationNodeKind.Aggregate || transformation.Kind == TransformationNodeKind.GroupBy) { var binder = new AggregationBinder(updatedSettings, assembliesResolver, ResultClrType, Context.Model, transformation); query = binder.Bind(query); this.ResultClrType = binder.ResultClrType; } else if (transformation.Kind == TransformationNodeKind.Compute) { var binder = new ComputeBinder(updatedSettings, assembliesResolver, ResultClrType, Context.Model, (ComputeTransformationNode)transformation); query = binder.Bind(query); this.ResultClrType = binder.ResultClrType; } else if (transformation.Kind == TransformationNodeKind.Filter) { var filterTransformation = transformation as FilterTransformationNode; Expression filter = FilterBinder.Bind(query, filterTransformation.FilterClause, ResultClrType, Context, querySettings); query = ExpressionHelpers.Where(query, filter, ResultClrType); } } return(query); }