public DbAggregateSubqueryExpression(DbTableAlias groupByAlias, Expression aggregateInGroupSelect, DbScalarExpression aggregateAsSubquery) : base(DbExpressionType.AggregateSubquery, aggregateAsSubquery.Type) { _aggregateInGroupSelect = aggregateInGroupSelect; _groupByAlias = groupByAlias; _aggregateAsSubquery = aggregateAsSubquery; }
public DbAggregateSubqueryExpression(DbTableAlias groupByAlias, Expression aggregateInGroupSelect, DbScalarExpression aggregateAsSubquery) : base(DbExpressionType.AggregateSubquery, aggregateAsSubquery.Type) { _aggregateInGroupSelect = aggregateInGroupSelect; _groupByAlias = groupByAlias; _aggregateAsSubquery = aggregateAsSubquery; }
protected DbScalarExpression UpdateScalar(DbScalarExpression scalar, DbSelectExpression select) { if (select != scalar.Select) { return(new DbScalarExpression(scalar.Type, select)); } return(scalar); }
protected DbAggregateSubqueryExpression UpdateAggregateSubquery( DbAggregateSubqueryExpression aggregate, DbScalarExpression subquery) { if (subquery != aggregate.AggregateAsSubquery) { return(new DbAggregateSubqueryExpression(aggregate.GroupByAlias, aggregate.AggregateInGroupSelect, subquery)); } return(aggregate); }
protected DbAggregateSubqueryExpression UpdateAggregateSubquery( DbAggregateSubqueryExpression aggregate, DbScalarExpression subquery) { if (subquery != aggregate.AggregateAsSubquery) return new DbAggregateSubqueryExpression(aggregate.GroupByAlias, aggregate.AggregateInGroupSelect, subquery); return aggregate; }
protected DbScalarExpression UpdateScalar(DbScalarExpression scalar, DbSelectExpression select) { if (select != scalar.Select) return new DbScalarExpression(scalar.Type, select); return scalar; }
protected virtual Expression VisitScalar(DbScalarExpression scalar) { DbSelectExpression select = (DbSelectExpression)Visit(scalar.Select); return UpdateScalar(scalar, select); }
protected virtual bool CompareScalar(DbScalarExpression a, DbScalarExpression b) { return(Compare(a.Select, b.Select)); }
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 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; }
protected override Expression VisitScalar(DbScalarExpression subquery) { this.Write("("); this.WriteLine(Indentation.Inner); this.Visit(subquery.Select); this.WriteLine(Indentation.Same); this.Write(")"); this.Indent(Indentation.Outer); return subquery; }
protected virtual bool CompareScalar(DbScalarExpression a, DbScalarExpression b) { return Compare(a.Select, b.Select); }
protected virtual Expression VisitAggregateSubquery(DbAggregateSubqueryExpression aggregate) { DbScalarExpression subquery = (DbScalarExpression)Visit(aggregate.AggregateAsSubquery); return(UpdateAggregateSubquery(aggregate, subquery)); }
protected virtual Expression VisitScalar(DbScalarExpression scalar) { DbSelectExpression select = (DbSelectExpression)Visit(scalar.Select); return(UpdateScalar(scalar, select)); }