Dynamic LINQ aggregates on IQueryable as a single query

后端 未结 3 755
一个人的身影
一个人的身影 2021-01-06 20:06

I\'m building a datagrid library that works on generic IQueryable data sources. At the bottom selected columns will have aggregates: sum, average, count etc.

I can c

3条回答
  •  夕颜
    夕颜 (楼主)
    2021-01-06 20:42

    here is my solution for sum, average and min, max .. this is what i have used in one of the projects.

    public static object AggregateFunc(this IQueryable source, string function, string member)
    {
            if (source == null) throw new ArgumentNullException("source");
            if (member == null) throw new ArgumentNullException("member");
    
            // Properties
            PropertyInfo property = source.ElementType.GetProperty(member);
            ParameterExpression parameter = Expression.Parameter(source.ElementType, "s");
    
            // We've tried to find an expression of the type Expression>,
            // which is expressed as ( (TSource s) => s.Price );
    
            Type propertyType = property.PropertyType;
            Type convertPropType = property.PropertyType;
            if (function == "Sum")//convert int to bigint
            {
                if (propertyType == typeof(Int32))
                    convertPropType = typeof(Int64);
                else if (propertyType == typeof(Int32?))
                    convertPropType = typeof(Int64?);
            }
            Expression selector = Expression.Lambda(Expression.Convert(Expression.MakeMemberAccess(parameter, property), convertPropType), parameter);
            //var methods = typeof(Queryable).GetMethods().Where(x => x.Name == function);
            // Method
            MethodInfo aggregateMethod = typeof(Queryable).GetMethods().SingleOrDefault(
                m => m.Name == function
                    && m.IsGenericMethod
                    && m.GetParameters().Length == 2 && m.GetParameters()[1].ParameterType.GenericTypeArguments[0].GenericTypeArguments[1] == convertPropType);// very hacky but works :)
    
            MethodCallExpression callExpr;
            // Sum, Average
            if (aggregateMethod != null)
            {
                callExpr = Expression.Call(
                        null,
                        aggregateMethod.MakeGenericMethod(new[] { source.ElementType }),
                        new[] { source.Expression, Expression.Quote(selector) });
                return source.Provider.Execute(callExpr);
            }
            // Min, Max
            else
            {
                aggregateMethod = typeof(Queryable).GetMethods().SingleOrDefault(
                    m => m.Name == function
                        && m.GetGenericArguments().Length == 2
                        && m.IsGenericMethod);
                if (aggregateMethod != null)
                {
                    callExpr = Expression.Call(
                        null,
                        aggregateMethod.MakeGenericMethod(new[] { source.ElementType, propertyType }),
                        new[] { source.Expression, Expression.Quote(selector) });
    
                    return source.Provider.Execute(callExpr);
                }                
            }
            return null;
        }
    

提交回复
热议问题