public override void Visit(DbGroupByExpression e) { Check.NotNull <DbGroupByExpression>(e, nameof(e)); this.VisitExprKind(e.ExpressionKind); this._key.Append('('); this.VisitGroupBinding(e.Input); foreach (DbExpression key in (IEnumerable <DbExpression>)e.Keys) { this._key.Append("K("); key.Accept((DbExpressionVisitor)this); this._key.Append(')'); } foreach (DbAggregate aggregate in (IEnumerable <DbAggregate>)e.Aggregates) { DbGroupAggregate dbGroupAggregate = aggregate as DbGroupAggregate; if (dbGroupAggregate != null) { this._key.Append("GA("); dbGroupAggregate.Arguments[0].Accept((DbExpressionVisitor)this); this._key.Append(')'); } else { this._key.Append("A:"); DbFunctionAggregate functionAggregate = (DbFunctionAggregate)aggregate; if (functionAggregate.Distinct) { this._key.Append("D:"); } this.VisitFunction(functionAggregate.Function, functionAggregate.Arguments); } } this._key.Append(')'); }
private SqlFragment HandleFunction(DbFunctionAggregate fa, SqlFragment arg) { Debug.Assert(fa.Arguments.Count == 1); if (fa.Function.NamespaceName != "Edm") { throw new NotSupportedException(); } FunctionFragment fragment = new FunctionFragment(); fragment.Name = fa.Function.Name; if (fa.Function.Name == "BigCount") { fragment.Name = "COUNT"; } else { fragment.Name = fa.Function.Name.ToUpperInvariant(); } fragment.Distinct = fa.Distinct; fragment.Argmument = arg; return(fragment); //return new CastExpression(aggregate, GetDbType(functionAggregate.ResultType.EdmType)); }
public override void Visit(DbGroupByExpression e) { Check.NotNull <DbGroupByExpression>(e, nameof(e)); this.Begin((DbExpression)e); this.Dump(e.Input, "Input"); this.Dump((IEnumerable <DbExpression>)e.Keys, "Keys", "Key"); this.Begin("Aggregates"); foreach (DbAggregate aggregate in (IEnumerable <DbAggregate>)e.Aggregates) { DbFunctionAggregate functionAggregate = aggregate as DbFunctionAggregate; if (functionAggregate != null) { this.Begin("DbFunctionAggregate"); this.Dump(functionAggregate.Function); this.Dump((IEnumerable <DbExpression>)functionAggregate.Arguments, "Arguments", "Argument"); this.End("DbFunctionAggregate"); } else { DbGroupAggregate dbGroupAggregate = aggregate as DbGroupAggregate; this.Begin("DbGroupAggregate"); this.Dump((IEnumerable <DbExpression>)dbGroupAggregate.Arguments, "Arguments", "Argument"); this.End("DbGroupAggregate"); } } this.End("Aggregates"); this.End((DbExpression)e); }
public override void Visit(DbGroupByExpression e) { Begin(e); Dump(e.Input, "Input"); Dump(e.Keys, "Keys", "Key"); Begin("Aggregates"); foreach (DbAggregate agg in e.Aggregates) { DbFunctionAggregate funcAgg = agg as DbFunctionAggregate; if (funcAgg != null) { Begin("DbFunctionAggregate"); Dump(funcAgg.Function); Dump(funcAgg.Arguments, "Arguments", "Argument"); End("DbFunctionAggregate"); } else { DbGroupAggregate groupAgg = agg as DbGroupAggregate; Debug.Assert(groupAgg != null, "Invalid DbAggregate"); Begin("DbGroupAggregate"); Dump(groupAgg.Arguments, "Arguments", "Argument"); End("DbGroupAggregate"); } } End("Aggregates"); End(e); }
public override TreeNode Visit(DbGroupByExpression e) { List <TreeNode> keys = new List <TreeNode>(); List <TreeNode> aggs = new List <TreeNode>(); RowType outputType = TypeHelpers.GetEdmType <RowType>(TypeHelpers.GetEdmType <CollectionType>(e.ResultType).TypeUsage); int keyIdx = 0; for (int idx = 0; idx < e.Keys.Count; idx++) { keys.Add(this.VisitWithLabel("Key", outputType.Properties[idx].Name, e.Keys[keyIdx])); keyIdx++; } int aggIdx = 0; for (int idx = e.Keys.Count; idx < outputType.Properties.Count; idx++) { TreeNode aggInfo = new TreeNode("Aggregate : '"); aggInfo.Text.Append(outputType.Properties[idx].Name); aggInfo.Text.Append("'"); DbFunctionAggregate funcAgg = e.Aggregates[aggIdx] as DbFunctionAggregate; if (funcAgg != null) { TreeNode funcInfo = this.VisitFunction(funcAgg.Function, funcAgg.Arguments); if (funcAgg.Distinct) { funcInfo = new TreeNode("Distinct", funcInfo); } aggInfo.Children.Add(funcInfo); } else { DbGroupAggregate groupAgg = e.Aggregates[aggIdx] as DbGroupAggregate; Debug.Assert(groupAgg != null, "Invalid DbAggregate"); aggInfo.Children.Add(this.Visit("GroupAggregate", groupAgg.Arguments[0])); } aggs.Add(aggInfo); aggIdx++; } TreeNode retInfo = NodeFromExpression(e); retInfo.Children.Add(this.VisitGroupBinding(e.Input)); if (keys.Count > 0) { retInfo.Children.Add(new TreeNode("Keys", keys)); } if (aggs.Count > 0) { retInfo.Children.Add(new TreeNode("Aggregates", aggs)); } return(retInfo); }
public override TreeNode Visit(DbGroupByExpression e) { Check.NotNull <DbGroupByExpression>(e, nameof(e)); List <TreeNode> children1 = new List <TreeNode>(); List <TreeNode> children2 = new List <TreeNode>(); RowType edmType = TypeHelpers.GetEdmType <RowType>(TypeHelpers.GetEdmType <CollectionType>(e.ResultType).TypeUsage); int index1 = 0; for (int index2 = 0; index2 < e.Keys.Count; ++index2) { children1.Add(this.VisitWithLabel("Key", edmType.Properties[index2].Name, e.Keys[index1])); ++index1; } int index3 = 0; for (int count = e.Keys.Count; count < edmType.Properties.Count; ++count) { TreeNode treeNode1 = new TreeNode("Aggregate : '", new TreeNode[0]); treeNode1.Text.Append(edmType.Properties[count].Name); treeNode1.Text.Append("'"); DbFunctionAggregate aggregate1 = e.Aggregates[index3] as DbFunctionAggregate; if (aggregate1 != null) { TreeNode treeNode2 = this.VisitFunction(aggregate1.Function, aggregate1.Arguments); if (aggregate1.Distinct) { treeNode2 = new TreeNode("Distinct", new TreeNode[1] { treeNode2 }); } treeNode1.Children.Add(treeNode2); } else { DbGroupAggregate aggregate2 = e.Aggregates[index3] as DbGroupAggregate; treeNode1.Children.Add(this.Visit("GroupAggregate", aggregate2.Arguments[0])); } children2.Add(treeNode1); ++index3; } TreeNode treeNode = ExpressionPrinter.PrinterVisitor.NodeFromExpression((DbExpression)e); treeNode.Children.Add(this.VisitGroupBinding(e.Input)); if (children1.Count > 0) { treeNode.Children.Add(new TreeNode("Keys", children1)); } if (children2.Count > 0) { treeNode.Children.Add(new TreeNode("Aggregates", children2)); } return(treeNode); }
public override SqlFragment Visit(DbGroupByExpression expression) { // first process the input DbGroupExpressionBinding e = expression.Input; SelectStatement innerSelect = VisitInputExpressionEnsureSelect(e.Expression, e.VariableName, e.VariableType); scope.Add(e.GroupVariableName, innerSelect); SelectStatement select = WrapIfNotCompatible(innerSelect, expression.ExpressionKind); CollectionType ct = (CollectionType)expression.ResultType.EdmType; RowType rt = (RowType)ct.TypeUsage.EdmType; int propIndex = 0; foreach (DbExpression key in expression.Keys) { var fragment = key.Accept(this); select.AddGroupBy(fragment); propIndex++; var colFragment = fragment as ColumnFragment; if (colFragment != null) { colFragment = colFragment.Clone(); colFragment.ColumnAlias = String.Format("K{0}", propIndex); select.Columns.Add(colFragment); } } for (int agg = 0; agg < expression.Aggregates.Count; agg++) { DbAggregate a = expression.Aggregates[agg]; DbFunctionAggregate fa = a as DbFunctionAggregate; if (fa == null) { throw new NotSupportedException(); } string alias = rt.Properties[propIndex++].Name; ColumnFragment functionCol = new ColumnFragment(null, null); functionCol.Literal = HandleFunction(fa, a.Arguments[0].Accept(this)); functionCol.ColumnAlias = alias; select.Columns.Add(functionCol); } return(select); }
/// <summary> /// Aggregates are not visited by the normal visitor walk. /// </summary> /// <param name="aggregate">The aggreate go be translated</param> /// <param name="aggregateArgument">The translated aggregate argument</param> /// <returns></returns> private SqlBuilder VisitAggregate(DbAggregate aggregate, ISqlFragment aggregateArgument) { SqlBuilder aggregateResult = new SqlBuilder(); DbFunctionAggregate functionAggregate = aggregate as DbFunctionAggregate; if (functionAggregate == null) { throw new NotSupportedException(); } //The only aggregate function with different name is Big_Count //Note: If another such function is to be added, a dictionary should be created if (MetadataHelpers.IsCanonicalFunction(functionAggregate.Function) && String.Equals(functionAggregate.Function.Name, "BigCount", StringComparison.Ordinal)) { aggregateResult.Append("COUNT_BIG"); } else { WriteFunctionName(aggregateResult, functionAggregate.Function); } aggregateResult.Append("("); DbFunctionAggregate fnAggr = functionAggregate; if ((null != fnAggr) && (fnAggr.Distinct)) { aggregateResult.Append("DISTINCT "); } aggregateResult.Append(aggregateArgument); aggregateResult.Append(")"); return(aggregateResult); }
public override Expression Visit(DbGroupByExpression expression) { Expression source = this.Visit(expression.Input.Expression); Type elementType = TypeHelper.GetElementType(source.Type); Type resultType = edmTypeConverter.GetElementType(expression.ResultType); Expression result = source; if (expression.Keys.Count == 0) { // This is a special case // The DbGroupByExpression does not contain any Key element // There is no GroupByClause List <Expression> constructorArguments = new List <Expression>(); for (int i = 0; i < expression.Aggregates.Count; i++) { DbFunctionAggregate aggregation = expression.Aggregates[i] as DbFunctionAggregate; if (aggregation == null) { throw new InvalidOperationException(expression.Aggregates[i].GetType().ToString() + "is not supported"); } Expression arg = this.CreateAggregateFunction( aggregation, //Aggregation is executed on the source expression.Input.GroupVariableName, elementType, source, resultType.GetProperties()[0].PropertyType); constructorArguments.Add(arg); } Expression aggregationResults = Expression.New( resultType.GetConstructors().Single(), constructorArguments.ToArray(), resultType.GetProperties()); // Wrap by a SingleResult collection object result = Expression.New( typeof(SingleResult <>).MakeGenericType(resultType).GetConstructors().Single(), aggregationResults); // Make it queryable result = queryMethodExpressionBuilder.AsQueryable(result); } else { // The properties of the selector form a subset of the properties of the result type // These properties defined first in the edm type PropertyInfo[] props = resultType.GetProperties(); Dictionary <string, Type> selectorProperties = new Dictionary <string, Type>(); // Collect the properties for (int i = 0; i < expression.Keys.Count; i++) { selectorProperties.Add(props[i].Name, props[i].PropertyType); } Type selectorType = DataRowFactory.Create(selectorProperties); LambdaExpression selector = null; ParameterExpression groupParam = Expression.Parameter(elementType, expression.Input.VariableName); using (this.CreateVariable(groupParam, expression.Input.VariableName)) { Expression[] keys = this.VisitExpressions(expression.Keys); selector = Expression.Lambda( this.CreateSelector(keys, selectorType), groupParam); } // Build the GroupBy call expression result = queryMethodExpressionBuilder.GroupBy(result, selector); // Get IGrouping<> type Type groupingType = TypeHelper.GetElementType(result.Type); // Collect argument initiators in an array Expression[] groupInit = new Expression[expression.Keys.Count + expression.Aggregates.Count]; ParameterExpression selectParam = Expression.Parameter(groupingType, "group"); Expression keyParam = Expression.Property(selectParam, "Key"); // Collect the Key arguments for (int i = 0; i < expression.Keys.Count; i++) { groupInit[i] = Expression.Property(keyParam, props[i].Name); } // Collect the aggregate arguments for (int i = 0; i < expression.Aggregates.Count; i++) { DbFunctionAggregate aggregate = expression.Aggregates[i] as DbFunctionAggregate; if (aggregate == null) { throw new InvalidOperationException(expression.Aggregates[i].GetType().ToString() + "is not supported"); } groupInit[expression.Keys.Count + i] = this.CreateAggregateFunction( aggregate, // Aggregation is executed on the group expression.Input.GroupVariableName, elementType, selectParam, props[expression.Keys.Count + i].PropertyType); } selector = Expression.Lambda( Expression.New( resultType.GetConstructors().Single(), groupInit, resultType.GetProperties()), selectParam); result = queryMethodExpressionBuilder.Select(result, selector); } return(result); }
private SqlFragment HandleFunction(DbFunctionAggregate fa, SqlFragment arg) { Debug.Assert(fa.Arguments.Count == 1); if (fa.Function.NamespaceName != "Edm") throw new NotSupportedException(); FunctionFragment fragment = new FunctionFragment(); fragment.Name = fa.Function.Name; if (fa.Function.Name == "BigCount") fragment.Name = "COUNT"; else fragment.Name = fa.Function.Name.ToUpperInvariant(); fragment.Distinct = fa.Distinct; fragment.Argument = arg; return fragment; //return new CastExpression(aggregate, GetDbType(functionAggregate.ResultType.EdmType)); }
private Expression CreateAggregateFunction(DbFunctionAggregate functionAggregate, string sourceVariableName, Type sourceType, Expression sourceGroup, Type resultType) { Expression result = null; //More the one aggregate argument is not supported if (functionAggregate.Arguments.Count > 1) { throw new InvalidOperationException("DbFunctionAggreate contains more than one argument"); } LambdaExpression aggregateSelector = null; // Count does not have selector if (functionAggregate.Arguments.Count == 1) { // Build the selector of the current aggregate ParameterExpression aggregateContext = Expression.Parameter(sourceType, sourceVariableName); using (this.CreateVariable(aggregateContext, sourceVariableName)) { aggregateSelector = Expression.Lambda( this.Visit(functionAggregate.Arguments[0]), aggregateContext); } } //Create Expression Call switch (functionAggregate.Function.Name) { case "Count": result = queryMethodExpressionBuilder.Count(sourceGroup); break; case "Max": result = queryMethodExpressionBuilder.Max(sourceGroup, aggregateSelector); break; case "Min": result = queryMethodExpressionBuilder.Min(sourceGroup, aggregateSelector); break; case "Avg": result = queryMethodExpressionBuilder.Average(sourceGroup, aggregateSelector); break; case "Sum": result = queryMethodExpressionBuilder.Sum(sourceGroup, aggregateSelector); break; default: throw new NotSupportedException(functionAggregate.Function.Name + " is not a not supported DbFunctionAggregate"); } //Type unify if (resultType != null && result.Type != resultType) { result = Expression.Convert(result, resultType); } return(result); }