コード例 #1
0
        /// <summary>
        /// Get the list of parameter expression to be binded to the method call,
        /// If the number of arguments provided by the query does not match the method signature this method will ignore non required arguments or create arguments with default values.
        /// </summary>
        /// <param name="samplingMethod">The sampling method string that contain the arguments</param>
        /// <param name="method">The <see cref="MethodInfo"/> of the sampling method to call</param>
        /// <returns>Array of expressions</returns>
        private static Expression[] GetAggregationArgumentsExpressions(string samplingMethod, MethodInfo method)
        {
            Expression[] aggregationParamsExpressions = null;
            string[]     aggregationParamsAsStrings   = AggregationImplementationBase.GetAggregationParams(samplingMethod);
            var          expcetedParameters           = method.GetParameters();

            if (aggregationParamsAsStrings != null && aggregationParamsAsStrings.Any())
            {
                aggregationParamsExpressions = ParseAggregationParams(aggregationParamsAsStrings, expcetedParameters);
                if (expcetedParameters.Length != aggregationParamsAsStrings.Length + 1)
                {
                    if (aggregationParamsAsStrings.Length > expcetedParameters.Length - 1)
                    {
                        var tmp = new Expression[expcetedParameters.Length - 1];
                        Array.Copy(aggregationParamsExpressions, tmp, expcetedParameters.Length - 1);
                        aggregationParamsExpressions = tmp;
                    }
                    else
                    {
                        var tmp = new List <Expression>();
                        tmp.AddRange(aggregationParamsExpressions);
                        GetDefaultArgumentsExpressions(aggregationParamsExpressions.Length, expcetedParameters.Length - 1, expcetedParameters, tmp);
                        aggregationParamsExpressions = tmp.ToArray();
                    }
                }
            }
            else
            {
                var tmp = new List <Expression>();
                GetDefaultArgumentsExpressions(0, expcetedParameters.Length - 1, expcetedParameters, tmp);
                aggregationParamsExpressions = tmp.ToArray();
            }
            return(aggregationParamsExpressions);
        }
コード例 #2
0
        /// <summary>
        /// Execute group-by with aggregation on the results.
        /// </summary>
        /// <param name="query">The collection to group.</param>
        /// <param name="maxResults">The max number of elements in a result set.</param>
        /// <param name="transformation">The group-by transformation as <see cref="ApplyGroupbyClause"/>.</param>
        /// <param name="keyType">The key type to group by.</param>
        /// <param name="propertiesToGroupByExpressions">Lambda expression that represents access to the properties to group by.</param>
        /// <param name="propertyToAggregateExpression">Lambda expression that represents access to the property to aggregate.</param>
        /// <param name="keys">Output the collection keys of the grouped results.</param>
        /// <param name="aggragatedValues">Output the aggregated results.</param>
        public void DoAggregatedGroupBy(
            IQueryable query, int maxResults, ApplyGroupbyClause transformation,
            Type keyType, IEnumerable <LambdaExpression> propertiesToGroupByExpressions, LambdaExpression propertyToAggregateExpression, out IQueryable keys, out object[] aggragatedValues)
        {
            var propToGroupBy = (propertiesToGroupByExpressions != null)
               ? propertiesToGroupByExpressions.ToArray()
               : null;
            var    keySelector               = this.GetGroupByProjectionLambda(transformation.SelectedStatements.ToArray(), keyType, propToGroupBy);
            object comparer                  = keyType.GetProperty("ComparerInstance").GetValue(null);
            var    groupingResults           = ExpressionHelpers.GroupBy(query, keySelector, this.Context.ElementClrType, keyType, comparer);
            var    aggregationImplementation =
                AggregationMethodsImplementations.GetAggregationImplementation(transformation.Aggregate.AggregationMethod);

            // if group by is not supported in this IQueriable provider convert the grouping into memory implementation
            object convertedResult = null;
            int    numberOfTempResults;

            if (QueriableProviderAdapter.ConvertionIsRequiredAsExpressionIfNotSupported(groupingResults, maxResults, out convertedResult, out numberOfTempResults))
            {
                groupingResults = convertedResult as IQueryable;
            }

            var resType = typeof(List <>).MakeGenericType(this.Context.ElementClrType);

            keys = this.GetGroupingKeys(groupingResults, keyType, this.Context.ElementClrType);
            var groupedValues = this.GetGroupingValues(groupingResults, keyType, resType, this.Context.ElementClrType);

            // In case of paging due to memory execution of unsupported functions keys may not be distinct.
            // Here we make sure that keys are distinct and all values that belong to a key are written to the right list.
            List <object> distictKeys;
            List <object> groupedValuesPerKey;

            if (numberOfTempResults > 1)
            {
                this.CombineValuesListsPerKey(keys.AllElements(), groupedValues.AllElements(), out distictKeys, out groupedValuesPerKey);
                keys = distictKeys.AsQueryable();
            }
            groupedValuesPerKey = groupedValues.AllElements();
            int numberOfResults = groupedValuesPerKey.Count;

            var tmpAggragatedValues = new object[numberOfResults];
            var projectionLambda    = AggregationImplementationBase.GetProjectionLambda(this.Context.ElementClrType, transformation.Aggregate, propertyToAggregateExpression);

            string[] aggregationParams = AggregationImplementationBase.GetAggregationParams(transformation.Aggregate.AggregationMethod);

            Parallel.For(0, numberOfResults, (i =>
            {
                IQueryable valuesAsQueryable;
                if (groupedValuesPerKey[i] is IEnumerable <object> )
                {
                    valuesAsQueryable = ExpressionHelpers.Cast(this.Context.ElementClrType,
                                                               (groupedValuesPerKey[i] as IEnumerable <Object>).AsQueryable());
                }
                else
                {
                    valuesAsQueryable = ExpressionHelpers.Cast(this.Context.ElementClrType,
                                                               (new List <Object>()
                    {
                        groupedValuesPerKey[i]
                    }).AsQueryable());
                }

                IQueryable queryToUse = valuesAsQueryable;
                if (transformation.Aggregate.AggregatableProperty.Contains('/'))
                {
                    queryToUse = AggregationImplementationBase.FilterNullValues(query, this.Context.ElementClrType,
                                                                                transformation.Aggregate);
                }

                var aggragationResult = aggregationImplementation.DoAggregatinon(this.Context.ElementClrType, queryToUse,
                                                                                 transformation.Aggregate, projectionLambda, aggregationParams);
                tmpAggragatedValues[i] = aggragationResult;
            }));

            aggragatedValues = tmpAggragatedValues;
        }