Ejemplo n.º 1
0
        /// <summary>
        /// Generate a new type for the group-by results and return an instance of the results with the aggregated values.
        /// </summary>
        /// <param name="groupByTrasformation">The group-by transformation clause.</param>
        /// <param name="keys">The collection of the group-by keys.</param>
        /// <param name="aggragatedValues">The results of the group-by aggregation.</param>
        /// <param name="keyType">The group-by key type.</param>
        /// <param name="context">The OData query context.</param>
        /// <returns>The group-by results as <see cref="IQueryable"/>.</returns>
        private IQueryable ProjectGroupedResult(ApplyGroupbyClause groupByTrasformation, IQueryable keys, object[] aggragatedValues, Type keyType, ODataQueryContext context)
        {
            List <object> result         = new List <object>();
            var           keyProperties  = keyType.GetProperties();
            var           projectionType = this.GetAggregationResultProjectionType(groupByTrasformation, keyType);

            int i = 0;

            foreach (var key in keys)
            {
                var objToProject = Activator.CreateInstance(projectionType);
                var pi           = projectionType.GetProperty(groupByTrasformation.Aggregate.Alias);
                pi.SetValue(objToProject, aggragatedValues[i]);

                foreach (var key_pi in keyProperties)
                {
                    if (key_pi.Name == "ComparerInstance")
                    {
                        continue;
                    }
                    pi = projectionType.GetProperty(key_pi.Name);
                    pi.SetValue(objToProject, key_pi.GetValue(key));
                }
                result.Add(objToProject);
                i++;
            }

            return(ExpressionHelpers.Cast(projectionType, result.AsQueryable()));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Combine temporary results by simply writing them to a flat list of distinct items.
        /// </summary>
        /// <param name="temporaryResults">Results to combine.</param>
        /// <returns>A flatten list of all distinct temporary results.</returns>
        private IQueryable CombineTemporaryResults(List <Tuple <object, int> > temporaryResults)
        {
            if (!temporaryResults.Any())
            {
                return(null);
            }

            Type elementType;

            if (temporaryResults.First().Item1 is IEnumerable <object> )
            {
                elementType = (temporaryResults.First().Item1 as IEnumerable <object>).First().GetType();
            }
            else
            {
                elementType = temporaryResults.First().Item1.GetType();
            }

            var finalRes = new List <object>();

            foreach (var item in temporaryResults.Select(pair => pair.Item1))
            {
                if (item is IEnumerable <object> )
                {
                    finalRes.AddRange(item as IEnumerable <object>);
                }
                else
                {
                    finalRes.Add(item);
                }
            }
            return(ExpressionHelpers.Cast(elementType, finalRes.AsQueryable()));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Get the elements to memory.
        /// </summary>
        /// <typeparam name="T">The type of elements in the collection.</typeparam>
        /// <param name="index">The index in the original collection after enumeration.</param>
        /// <param name="limitReached">Was the max number of elements allowed to query in a single transaction reached.</param>
        /// <param name="dataToload">Data to bring to memory.</param>
        /// <returns>The IQueryable in memory.</returns>
        private IQueryable GetElements <T>(ref int index, out bool limitReached, object dataToload)
        {
            var realCollection   = new List <T>();
            var objectCollection = new List <object>();

            if (dataToload is IEnumerable <T> )
            {
                int counter = 0;
                limitReached = false;
                var enumerator = (dataToload as IEnumerable <T>).GetEnumerator();
                while (enumerator.MoveNext())
                {
                    counter++;
                    if (counter <= this.MaxCollectionSize)
                    {
                        realCollection.Add(enumerator.Current);
                        index++;
                    }
                    else
                    {
                        limitReached = true;
                        return(realCollection.AsQueryable());
                    }
                }

                return(realCollection.AsQueryable());
            }
            else
            {
                if (dataToload is IQueryable)
                {
                    int counter = 0;
                    limitReached = false;
                    var enumerator = (dataToload as IQueryable).GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        counter++;
                        if (counter <= this.MaxCollectionSize)
                        {
                            objectCollection.Add(enumerator.Current);
                            index++;
                        }
                        else
                        {
                            limitReached = true;
                            return(ExpressionHelpers.Cast((dataToload as IQueryable).ElementType, objectCollection.AsQueryable()));
                        }
                    }
                    return(ExpressionHelpers.Cast((dataToload as IQueryable).ElementType, objectCollection.AsQueryable()));
                }

                throw new InvalidOperationException("cannot enumerate data");
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Generate a new type for the aggregated results and return an instance of the results with the aggregated value.
        /// </summary>
        /// <param name="dataToProject">The results to project.</param>
        /// <param name="alias">The name of the alias to use in the new type.</param>
        /// <param name="aliasType">The type of the alias to use in the new type.</param>
        /// <returns>An instance of the results with the aggregated value as <see cref="IQueryable"/>.</returns>
        private IQueryable ProjectResult(object dataToProject, string alias, Type aliasType)
        {
            var properties = new List <Tuple <Type, string> >()
            {
                new Tuple <Type, string>(aliasType, alias)
            };
            var resType = AggregationTypesGenerator.CreateType(properties.Distinct(new TypeStringTupleComapere()).ToList(), Context, true);

            var objToProject = Activator.CreateInstance(resType);
            var pi           = resType.GetProperty(alias);

            pi.SetValue(objToProject, dataToProject);

            var dataToProjectList = (new List <object>()
            {
                objToProject
            }).AsQueryable();

            return(ExpressionHelpers.Cast(resType, dataToProjectList));
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Implement the Count-Distinct aggregation method
        /// </summary>
        /// <param name="elementType">The type of entities</param>
        /// <param name="query">The collection</param>
        /// <param name="transformation">The transformation clause created by the parser</param>
        /// <param name="propertyToAggregateExpression">Projection Expression that defines access to the property to aggregate</param>
        /// <param name="parameters">A list of string parameters sent to the aggregation method</param>
        /// <returns>The Sum result</returns>
        public override object DoAggregatinon(Type elementType, IQueryable collection, ApplyAggregateClause transformation, LambdaExpression propertyToAggregateExpression, params string[] parameters)
        {
            var propertyType   = GetAggregatedPropertyType(elementType, transformation.AggregatableProperty);
            var selectedValues = GetSelectedValues(elementType, collection, transformation, propertyToAggregateExpression);

            //call: (selected.AsQueryable() as IQueryable<double>).Ditinct();
            var distinct = ExpressionHelpers.Distinct(propertyType, selectedValues);

            try
            {
                //call: (distinct.AsQueryable() as IQueryable<double>).Count();
                return(ExpressionHelpers.Count(propertyType, distinct));
            }
            catch (TargetInvocationException)
            {
                //salve a problem in mongo that throw the error "No further operators may follow Distinct in a LINQ query." when trying to construct the expression tree.
                distinct = ExpressionHelpers.Cast(propertyType, distinct.AllElements().AsQueryable());
                return(ExpressionHelpers.Count(propertyType, distinct));
            }
        }
Ejemplo n.º 6
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;
        }