static bool IsAggregateResultWithCustomShaper(MethodInfo method) { if (method.IsGenericMethod) { method = method.GetGenericMethodDefinition(); } return(QueryableMethods.IsAverageWithoutSelector(method) || QueryableMethods.IsAverageWithSelector(method) || method == QueryableMethods.MaxWithoutSelector || method == QueryableMethods.MaxWithSelector || method == QueryableMethods.MinWithoutSelector || method == QueryableMethods.MinWithSelector || QueryableMethods.IsSumWithoutSelector(method) || QueryableMethods.IsSumWithSelector(method)); }
protected override Expression VisitMethodCall(MethodCallExpression m) { if (QueryableMethods.IsAverageWithoutSelector(m.Method) || QueryableMethods.IsSumWithoutSelector(m.Method)) { return(Visit(m.Arguments[0])); } MethodInfo?genericDefinition = m.Method.IsGenericMethod ? m.Method.GetGenericMethodDefinition() : null; if (genericDefinition != null && genericDefinition.IsSupportedByComposition()) { return(Visit(m.Arguments[0])); } // Queryable if (genericDefinition == QueryableMethods.Where) { return(VisitWhereMethod(m)); } if (genericDefinition == QueryableMethods.OrderBy || genericDefinition == QueryableMethods.ThenBy) { return(VisitOrderAscendingMethod(m)); } if (genericDefinition == QueryableMethods.OrderByDescending || genericDefinition == QueryableMethods.ThenByDescending) { return(VisitOrderDescendingMethod(m)); } if (genericDefinition == QueryableMethods.Skip) { return(VisitSkipMethod(m)); } if (genericDefinition == QueryableMethods.Take) { return(VisitTakeMethod(m)); } if (genericDefinition == QueryableMethods.Select) { return(VisitSelectMethod(m)); } // Enumerable if (m.Method == SupportedQueryMethods.Contains) { return(VisitContainsMethod(m)); } // IQueryable extensions if (genericDefinition == SupportedQueryMethods.AnyWithPredicate) { return(VisitAnyMethod(m)); } if (genericDefinition == SupportedQueryMethods.All) { return(VisitAllMethod(m)); } if (genericDefinition == SupportedQueryMethods.UseBookmark) { return(VisitUseBookmarkMethod(m)); } if (genericDefinition == SupportedQueryMethods.WithReadQuorum) { return(VisitWithQuorumMethod(m)); } if (genericDefinition == SupportedQueryMethods.WithoutIndexUpdate) { return(VisitWithoutIndexUpdateMethod(m)); } if (genericDefinition == SupportedQueryMethods.FromStable) { return(VisitFromStableMethod(m)); } if (genericDefinition == SupportedQueryMethods.UseIndex) { return(VisitUseIndexMethod(m)); } if (genericDefinition == SupportedQueryMethods.IncludeExecutionStats) { return(VisitIncludeExecutionStatsMethod(m)); } if (genericDefinition == SupportedQueryMethods.IncludeConflicts) { return(VisitIncludeConflictsMethod(m)); } if (genericDefinition == SupportedQueryMethods.Select) { return(VisitSelectFieldMethod(m)); } if (genericDefinition == SupportedQueryMethods.Convert) { return(VisitConvertMethod(m)); } // IEnumerable extensions if (genericDefinition == SupportedQueryMethods.EnumerableContains) { return(VisitEnumerableContains(m)); } // Object extensions if (genericDefinition == SupportedQueryMethods.FieldExists) { return(VisitFieldExistsMethod(m)); } if (genericDefinition == SupportedQueryMethods.IsCouchType) { return(VisitIsCouchTypeMethod(m)); } if (genericDefinition == SupportedQueryMethods.In) { return(VisitInMethod(m)); } // String extensions if (m.Method == SupportedQueryMethods.IsMatch) { return(VisitIsMatchMethod(m)); } // List if (m.Method.Name == nameof(List <object> .Contains) && m.Method.DeclaringType.IsGenericType && m.Method.DeclaringType.GetGenericTypeDefinition() == typeof(List <>)) { return(VisitContainsMethod(m)); } throw new NotSupportedException($"The method '{m.Method.Name}' is not supported"); }
public virtual SqlExpression?Translate( MethodInfo method, EnumerableExpression source, IReadOnlyList <SqlExpression> arguments, IDiagnosticsLogger <DbLoggerCategory.Query> logger) { if (method.DeclaringType == typeof(Queryable)) { var methodInfo = method.IsGenericMethod ? method.GetGenericMethodDefinition() : method; switch (methodInfo.Name) { case nameof(Queryable.Average) when(QueryableMethods.IsAverageWithoutSelector(methodInfo) || QueryableMethods.IsAverageWithSelector(methodInfo)) && source.Selector is SqlExpression averageSqlExpression: var averageInputType = averageSqlExpression.Type; if (averageInputType == typeof(int) || averageInputType == typeof(long)) { averageSqlExpression = _sqlExpressionFactory.ApplyDefaultTypeMapping( _sqlExpressionFactory.Convert(averageSqlExpression, typeof(double))); } return(averageInputType == typeof(float) ? _sqlExpressionFactory.Convert( _sqlExpressionFactory.AggregateFunction( "avg", new[] { averageSqlExpression }, nullable: true, argumentsPropagateNullability: FalseArrays[1], source, typeof(double)), averageSqlExpression.Type, averageSqlExpression.TypeMapping) : _sqlExpressionFactory.AggregateFunction( "avg", new[] { averageSqlExpression }, nullable: true, argumentsPropagateNullability: FalseArrays[1], source, averageSqlExpression.Type, averageSqlExpression.TypeMapping)); // PostgreSQL COUNT() always returns bigint, so we need to downcast to int case nameof(Queryable.Count) when methodInfo == QueryableMethods.CountWithoutPredicate || methodInfo == QueryableMethods.CountWithPredicate: var countSqlExpression = (source.Selector as SqlExpression) ?? _sqlExpressionFactory.Fragment("*"); return(_sqlExpressionFactory.Convert( _sqlExpressionFactory.AggregateFunction( "count", new[] { countSqlExpression }, nullable: false, argumentsPropagateNullability: FalseArrays[1], source, typeof(long)), typeof(int), _typeMappingSource.FindMapping(typeof(int)))); case nameof(Queryable.LongCount) when methodInfo == QueryableMethods.LongCountWithoutPredicate || methodInfo == QueryableMethods.LongCountWithPredicate: var longCountSqlExpression = (source.Selector as SqlExpression) ?? _sqlExpressionFactory.Fragment("*"); return(_sqlExpressionFactory.AggregateFunction( "count", new[] { longCountSqlExpression }, nullable: false, argumentsPropagateNullability: FalseArrays[1], source, typeof(long))); case nameof(Queryable.Max) when(methodInfo == QueryableMethods.MaxWithoutSelector || methodInfo == QueryableMethods.MaxWithSelector) && source.Selector is SqlExpression maxSqlExpression: return(_sqlExpressionFactory.AggregateFunction( "max", new[] { maxSqlExpression }, nullable: true, argumentsPropagateNullability: FalseArrays[1], source, maxSqlExpression.Type, maxSqlExpression.TypeMapping)); case nameof(Queryable.Min) when(methodInfo == QueryableMethods.MinWithoutSelector || methodInfo == QueryableMethods.MinWithSelector) && source.Selector is SqlExpression minSqlExpression: return(_sqlExpressionFactory.AggregateFunction( "min", new[] { minSqlExpression }, nullable: true, argumentsPropagateNullability: FalseArrays[1], source, minSqlExpression.Type, minSqlExpression.TypeMapping)); // In PostgreSQL SUM() doesn't return the same type as its argument for smallint, int and bigint. // Cast to get the same type. // http://www.postgresql.org/docs/current/static/functions-aggregate.html case nameof(Queryable.Sum) when(QueryableMethods.IsSumWithoutSelector(methodInfo) || QueryableMethods.IsSumWithSelector(methodInfo)) && source.Selector is SqlExpression sumSqlExpression: var sumInputType = sumSqlExpression.Type; // Note that there is no Sum over short in LINQ if (sumInputType == typeof(int)) { return(_sqlExpressionFactory.Convert( _sqlExpressionFactory.AggregateFunction( "sum", new[] { sumSqlExpression }, nullable: true, argumentsPropagateNullability: FalseArrays[1], source, typeof(long)), sumInputType, sumSqlExpression.TypeMapping)); } if (sumInputType == typeof(long)) { return(_sqlExpressionFactory.Convert( _sqlExpressionFactory.AggregateFunction( "sum", new[] { sumSqlExpression }, nullable: true, argumentsPropagateNullability: FalseArrays[1], source, typeof(decimal)), sumInputType, sumSqlExpression.TypeMapping)); } return(_sqlExpressionFactory.AggregateFunction( "sum", new[] { sumSqlExpression }, nullable: true, argumentsPropagateNullability: FalseArrays[1], source, sumInputType, sumSqlExpression.TypeMapping)); } } return(null); }