public DbAggregateExpression(Type type, DbAggregateType aggType, Expression argument, bool isDistinct) : base(DbExpressionType.Aggregate, type) { _type = aggType; _argument = argument; _isDistinct = isDistinct; }
protected DbAggregateExpression UpdateAggregate(DbAggregateExpression aggregate, Type type, DbAggregateType aggType, Expression arg, bool isDistinct) { if (type != aggregate.Type || aggType != aggregate.AggregateType || arg != aggregate.Argument || isDistinct != aggregate.IsDistinct) { return(new DbAggregateExpression(type, aggType, arg, isDistinct)); } return(aggregate); }
protected virtual string GetAggregateName(DbAggregateType aggregateType) { switch (aggregateType) { case DbAggregateType.Count: return("COUNT"); case DbAggregateType.Min: return("MIN"); case DbAggregateType.Max: return("MAX"); case DbAggregateType.Sum: return("SUM"); case DbAggregateType.Average: return("AVG"); default: throw new Exception(string.Format("Unknown aggregate type: {0}", aggregateType)); } }
protected DbAggregateExpression UpdateAggregate(DbAggregateExpression aggregate, Type type, DbAggregateType aggType, Expression arg, bool isDistinct) { if (type != aggregate.Type || aggType != aggregate.AggregateType || arg != aggregate.Argument || isDistinct != aggregate.IsDistinct) return new DbAggregateExpression(type, aggType, arg, isDistinct); return aggregate; }
private Expression BindAggregate(Expression source, MethodInfo method, LambdaExpression argument, bool isRoot) { Type returnType = method.ReturnType; DbAggregateType aggType = this.GetAggregateType(method.Name); bool hasPredicateArg = this.HasPredicateArg(aggType); bool isDistinct = false; bool argumentWasPredicate = false; bool useAlternateArg = false; // check for distinct MethodCallExpression mcs = source as MethodCallExpression; if (mcs != null && !hasPredicateArg && argument == null) { if (mcs.Method.Name == "Distinct" && mcs.Arguments.Count == 1 && (mcs.Method.DeclaringType == typeof(Queryable) || mcs.Method.DeclaringType == typeof(Enumerable)) && this.mapping.Language.AllowDistinctInAggregates) { source = mcs.Arguments[0]; isDistinct = true; } } if (argument != null && hasPredicateArg) { // convert query.Count(predicate) into query.Where(predicate).Count() source = Expression.Call(typeof(Queryable), "Where", method.GetGenericArguments(), source, argument); argument = null; argumentWasPredicate = true; } DbProjectionExpression projection = this.VisitSequence(source); Expression argExpr = null; if (argument != null) { this.map[argument.Parameters[0]] = projection.Projector; argExpr = this.Visit(argument.Body); } else if (!hasPredicateArg || useAlternateArg) { argExpr = projection.Projector; } var alias = this.GetNextAlias(); var pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias); Expression aggExpr = new DbAggregateExpression(returnType, aggType, argExpr, isDistinct); DbSelectExpression select = new DbSelectExpression(alias, new DbColumnDeclaration[] { new DbColumnDeclaration("", aggExpr) }, projection.Select, null); if (isRoot) { ParameterExpression p = Expression.Parameter(typeof(IEnumerable <>).MakeGenericType(aggExpr.Type), "p"); LambdaExpression gator = Expression.Lambda(Expression.Call(typeof(Enumerable), "Single", new Type[] { returnType }, p), p); return(new DbProjectionExpression(select, new DbColumnExpression(returnType, null, alias, ""), gator)); } DbScalarExpression subquery = new DbScalarExpression(returnType, select); // if we can find the corresponding group-info we can build a special AggregateSubquery node that will enable us to // optimize the aggregate expression later using AggregateRewriter GroupByInfo info; if (!argumentWasPredicate && this.groupByMap.TryGetValue(projection, out info)) { // use the element expression from the group-by info to rebind the argument so the resulting expression is one that // would be legal to add to the columns in the select expression that has the corresponding group-by clause. if (argument != null) { this.map[argument.Parameters[0]] = info.Element; argExpr = this.Visit(argument.Body); } else if (!hasPredicateArg || useAlternateArg) { argExpr = info.Element; } aggExpr = new DbAggregateExpression(returnType, aggType, argExpr, isDistinct); // check for easy to optimize case. If the projection that our aggregate is based on is really the 'group' argument from // the query.GroupBy(xxx, (key, group) => yyy) method then whatever expression we return here will automatically // become part of the select expression that has the group-by clause, so just return the simple aggregate expression. if (projection == this.currentGroupElement) { return(aggExpr); } return(new DbAggregateSubqueryExpression(info.Alias, aggExpr, subquery)); } return(subquery); }
private bool HasPredicateArg(DbAggregateType aggregateType) { return(aggregateType == DbAggregateType.Count); }
private bool HasPredicateArg(DbAggregateType aggregateType) { return aggregateType == DbAggregateType.Count; }
protected virtual bool RequiresAsteriskWhenNoArgument(DbAggregateType aggregateType) { return(aggregateType == DbAggregateType.Count); }
protected virtual bool RequiresAsteriskWhenNoArgument(DbAggregateType aggregateType) { return aggregateType == DbAggregateType.Count; }
protected virtual string GetAggregateName(DbAggregateType aggregateType) { switch (aggregateType) { case DbAggregateType.Count: return "COUNT"; case DbAggregateType.Min: return "MIN"; case DbAggregateType.Max: return "MAX"; case DbAggregateType.Sum: return "SUM"; case DbAggregateType.Average: return "AVG"; default: throw new Exception(string.Format("Unknown aggregate type: {0}", aggregateType)); } }