public Expression GetGrouping(GroupByContext context) { if (Configuration.Linq.GuardGrouping && !context._isGroupingGuardDisabled) { if (context.Element.Lambda.Parameters.Count == 1 && context.Element.Body == context.Element.Lambda.Parameters[0]) { var ex = new LinqToDBException( "You should explicitly specify selected fields for server-side GroupBy() call or add AsEnumerable() call before GroupBy() to perform client-side grouping.\n" + "Set Configuration.Linq.GuardGrouping = false to disable this check.\n" + "Additionally this guard exception can be disabled by extension GroupBy(...).DisableGuard().\n" + "NOTE! By disabling this guard you accept additional Database Connection(s) to the server for processing such requests." ) { HelpLink = "https://github.com/linq2db/linq2db/issues/365" }; throw ex; } } var parameters = context.Builder.ParametersContext.CurrentSqlParameters .Select((p, i) => (p, i)) .ToDictionary(_ => _.p.Expression, _ => _.i); var paramArray = Expression.Parameter(typeof(object[]), "ps"); var groupExpression = context._sequenceExpr.Transform( (parameters, paramArray),
protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var sequenceExpr = methodCall.Arguments[0]; var sequence = builder.BuildSequence(new BuildInfo(buildInfo, sequenceExpr)); var groupingType = methodCall.Type.GetGenericArguments()[0]; var keySelector = (LambdaExpression)methodCall.Arguments[1].Unwrap(); var elementSelector = (LambdaExpression)methodCall.Arguments[2].Unwrap(); if (methodCall.Arguments[0].NodeType == ExpressionType.Call) { var call = (MethodCallExpression)methodCall.Arguments[0]; if (call.Method.Name == "Select") { var type = ((LambdaExpression)call.Arguments[1].Unwrap()).Body.Type; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ExpressionBuilder.GroupSubQuery <,>)) { sequence = new SubQueryContext(sequence); } } } var key = new KeyContext(buildInfo.Parent, keySelector, sequence); var groupSql = builder.ConvertExpressions(key, keySelector.Body.Unwrap(), ConvertFlags.Key); if (sequence.SqlQuery.Select.IsDistinct || sequence.SqlQuery.GroupBy.Items.Count > 0 || groupSql.Any(_ => !(_.Sql is SqlField || _.Sql is SqlQuery.Column))) { sequence = new SubQueryContext(sequence); key = new KeyContext(buildInfo.Parent, keySelector, sequence); groupSql = builder.ConvertExpressions(key, keySelector.Body.Unwrap(), ConvertFlags.Key); } //sequence.SqlQuery.GroupBy.Items.Clear(); foreach (var sql in groupSql) { sequence.SqlQuery.GroupBy.Expr(sql.Sql); } new QueryVisitor().Visit(sequence.SqlQuery.From, e => { if (e.ElementType == QueryElementType.JoinedTable) { var jt = (SqlQuery.JoinedTable)e; if (jt.JoinType == SqlQuery.JoinType.Inner) { jt.IsWeak = false; } } }); var element = new SelectContext(buildInfo.Parent, elementSelector, sequence /*, key*/); var groupBy = new GroupByContext(buildInfo.Parent, sequenceExpr, groupingType, sequence, key, element); return(groupBy); }
public ExtraEntry(int?skip, int?take, IEnumerable <PropertyOrder> orders, SelectContext selectContext, GroupByContext groupByContext) { Skip = skip; Take = take; Orders = orders; SelectContext = selectContext; GroupByContext = groupByContext; }
public SelectCommandContext(SchemaMetaData schemaMetaData, string sql, ParameterContext parameterContext, SelectCommand sqlCommand) : base(sqlCommand) { _tablesContext = new TablesContext(sqlCommand.GetSimpleTableSegments()); _groupByContext = new GroupByContextEngine().CreateGroupByContext(sqlCommand); _orderByContext = new OrderByContextEngine().CreateOrderBy(sqlCommand, _groupByContext); _projectionsContext = new ProjectionsContextEngine(schemaMetaData).CreateProjectionsContext(sql, sqlCommand, _groupByContext, _orderByContext); _paginationContext = new PaginationContextEngine().CreatePaginationContext(sqlCommand, _projectionsContext, parameterContext); _containsSubQuery = ContainsSubQuery(); }
// TODO to be remove, for test case only public SelectCommandContext(SelectCommand sqlCommand, GroupByContext groupByContext, OrderByContext orderByContext, ProjectionsContext projectionsContext, PaginationContext paginationContext) : base(sqlCommand) { _tablesContext = new TablesContext(sqlCommand.GetSimpleTableSegments()); this._groupByContext = groupByContext; this._orderByContext = orderByContext; this._projectionsContext = projectionsContext; this._paginationContext = paginationContext; _containsSubQuery = ContainsSubQuery(); }
public ReWriteResult(IQueryable <T> originalQueryable, IQueryable <T> reWriteQueryable, int?skip, int?take, IEnumerable <PropertyOrder> orders, SelectContext selectContext, GroupByContext groupByContext) { OriginalQueryable = originalQueryable; ReWriteQueryable = reWriteQueryable; Skip = skip; Take = take; Orders = orders; SelectContext = selectContext; GroupByContext = groupByContext; }
public Expression GetGrouping(GroupByContext context) { var keyParam = Expression.Parameter(typeof(TKey), "key"); // ReSharper disable AssignNullToNotNullAttribute var expr = Expression.Call( null, ReflectionHelper.Expressor <object> .MethodExpressor(_ => Queryable.Where(null, (Expression <Func <TSource, bool> >)null)), context._sequenceExpr, Expression.Lambda <Func <TSource, bool> >( Expression.Equal(context._key.Lambda.Body, keyParam), new[] { context._key.Lambda.Parameters[0] })); expr = Expression.Call( null, ReflectionHelper.Expressor <object> .MethodExpressor(_ => Queryable.Select(null, (Expression <Func <TSource, TElement> >)null)), expr, context._element.Lambda); // ReSharper restore AssignNullToNotNullAttribute var lambda = Expression.Lambda <Func <IDataContext, TKey, IQueryable <TElement> > >( Expression.Convert(expr, typeof(IQueryable <TElement>)), Expression.Parameter(typeof(IDataContext), "ctx"), keyParam); var itemReader = CompiledQuery.Compile(lambda); var keyExpr = context._key.BuildExpression(null, 0); var keyReader = Expression.Lambda <Func <QueryContext, IDataContext, IDataReader, Expression, object[], TKey> >( keyExpr, new [] { ExpressionBuilder.ContextParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam, }); return(Expression.Call( null, ReflectionHelper.Expressor <object> .MethodExpressor(_ => GetGrouping(null, null, null, null, null, null, null)), new Expression[] { ExpressionBuilder.ContextParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam, Expression.Constant(keyReader.Compile()), Expression.Constant(itemReader), })); }
internal override List <GremlinVariable> FetchAllTableVars() { List <GremlinVariable> variableList = new List <GremlinVariable>() { this }; variableList.AddRange(GroupByContext.FetchAllTableVars()); variableList.AddRange(ProjectByContext.FetchAllTableVars()); return(variableList); }
protected override IParseContext ParseMethodCall(ExpressionParser parser, IParseContext parent, MethodCallExpression methodCall, SqlQuery sqlQuery) { var sequence = parser.ParseSequence(parent, methodCall.Arguments[0], sqlQuery); var sequenceExpr = methodCall.Arguments[0]; var groupingType = methodCall.Type.GetGenericArguments()[0]; var keySelector = (LambdaExpression)methodCall.Arguments[1].Unwrap(); var elementSelector = (LambdaExpression)methodCall.Arguments[2].Unwrap(); if (methodCall.Arguments[0].NodeType == ExpressionType.Call) { var call = (MethodCallExpression)methodCall.Arguments[0]; if (call.Method.Name == "Select") { var type = ((LambdaExpression)call.Arguments[1].Unwrap()).Body.Type; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ExpressionParser.GroupSubQuery<,>)) { sequence = new SubQueryContext(sequence); } } } var key = new KeyContext(keySelector, sequence); var groupSql = parser.ParseExpressions(key, keySelector.Body.Unwrap(), ConvertFlags.Key); if (groupSql.Any(_ => !(_.Sql is SqlField || _.Sql is SqlQuery.Column))) { sequence = new SubQueryContext(sequence); key = new KeyContext(keySelector, sequence); groupSql = parser.ParseExpressions(key, keySelector.Body.Unwrap(), ConvertFlags.Key); } sequence.SqlQuery.GroupBy.Items.Clear(); foreach (var sql in groupSql) sequence.SqlQuery.GroupBy.Expr(sql.Sql); new QueryVisitor().Visit(sequence.SqlQuery.From, e => { if (e.ElementType == QueryElementType.JoinedTable) { var jt = (SqlQuery.JoinedTable)e; if (jt.JoinType == SqlQuery.JoinType.Inner) jt.IsWeak = false; } }); var element = new SelectContext (elementSelector, sequence); var groupBy = new GroupByContext(sequenceExpr, groupingType, sequence, key, element); return groupBy; }
public override WTableReference ToTableReference() { List <WScalarExpression> parameters = new List <WScalarExpression>(); parameters.Add(SqlUtil.GetValueExpr(SideEffectKey)); parameters.Add(SqlUtil.GetScalarSubquery(GroupByContext.ToSelectQueryBlock())); parameters.Add(SqlUtil.GetScalarSubquery(ProjectByContext.ToSelectQueryBlock())); var tableRef = SqlUtil.GetFunctionTableReference(GremlinKeyword.func.Group, parameters, GetVariableName()); ((WGroupTableReference)tableRef).IsProjectingACollection = IsProjectingACollection; return(SqlUtil.GetCrossApplyTableReference(tableRef)); }
internal override List <GremlinVariable> FetchVarsFromCurrAndChildContext() { List <GremlinVariable> variableList = new List <GremlinVariable>(); if (GroupByContext != null) { variableList.AddRange(GroupByContext.FetchVarsFromCurrAndChildContext()); } if (ProjectByContext != null) { variableList.AddRange(ProjectByContext.FetchVarsFromCurrAndChildContext()); } return(variableList); }
public StreamMergeContext(IQueryable <T> source, IEnumerable <RouteResult> routeResults, IShardingParallelDbContextFactory shardingParallelDbContextFactory, IShardingScopeFactory shardingScopeFactory) { _shardingParallelDbContextFactory = shardingParallelDbContextFactory; _shardingScopeFactory = shardingScopeFactory; _source = source; RouteResults = routeResults; var reWriteResult = new ReWriteEngine <T>(source).ReWrite(); Skip = reWriteResult.Skip; Take = reWriteResult.Take; Orders = reWriteResult.Orders ?? Enumerable.Empty <PropertyOrder>(); SelectContext = reWriteResult.SelectContext; GroupByContext = reWriteResult.GroupByContext; _reWriteSource = reWriteResult.ReWriteQueryable; }
public OrderByContext CreateOrderBy(SelectCommand selectCommand, GroupByContext groupByContext) { if (null == selectCommand.OrderBy || !selectCommand.OrderBy.GetOrderByItems().Any()) { OrderByContext orderByContext = CreateOrderByContextForDistinctRowWithoutGroupBy(selectCommand, groupByContext); return(null != orderByContext ? orderByContext : new OrderByContext(groupByContext.GetItems(), groupByContext.GetItems().Any())); } ICollection <OrderByItem> orderByItems = new LinkedList <OrderByItem>(); foreach (var orderByItemSegment in selectCommand.OrderBy.GetOrderByItems()) { OrderByItem orderByItem = new OrderByItem(orderByItemSegment); if (orderByItemSegment is IndexOrderByItemSegment indexOrderByItemSegment) { orderByItem.SetIndex(indexOrderByItemSegment.GetColumnIndex()); } orderByItems.Add(orderByItem); } return(new OrderByContext(orderByItems, false)); }
public Expression GetGrouping(GroupByContext context) { var parameters = context.Builder.CurrentSqlParameters .Select((p, i) => new { p, i }) .ToDictionary(_ => _.p.Expression, _ => _.i); var paramArray = Expression.Parameter(typeof(object[]), "ps"); var groupExpression = context._sequenceExpr.Transform(e => { int idx; if (parameters.TryGetValue(e, out idx)) { return (Expression.Convert( Expression.ArrayIndex(paramArray, Expression.Constant(idx)), e.Type)); } return(e); }); var keyParam = Expression.Parameter(typeof(TKey), "key"); // ReSharper disable AssignNullToNotNullAttribute var expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Where(null, (Expression <Func <TSource, bool> >)null)), groupExpression, Expression.Lambda <Func <TSource, bool> >( Expression.Equal(context._key.Lambda.Body, keyParam), context._key.Lambda.Parameters[0])); expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Select(null, (Expression <Func <TSource, TElement> >)null)), expr, context._element.Lambda); // ReSharper restore AssignNullToNotNullAttribute var lambda = Expression.Lambda <Func <IDataContext, TKey, object[], IQueryable <TElement> > >( Expression.Convert(expr, typeof(IQueryable <TElement>)), Expression.Parameter(typeof(IDataContext), "ctx"), keyParam, paramArray); var itemReader = CompiledQuery.Compile(lambda); var keyExpr = context._key.BuildExpression(null, 0); var dataReaderLocal = context.Builder.DataReaderLocal; if (!Common.Configuration.AvoidSpecificDataProviderAPI && keyExpr.Find(e => e == dataReaderLocal) != null) { keyExpr = Expression.Block( new[] { context.Builder.DataReaderLocal }, Expression.Assign(dataReaderLocal, Expression.Convert(ExpressionBuilder.DataReaderParam, context.Builder.DataContextInfo.DataContext.DataReaderType)), keyExpr); } var keyReader = Expression .Lambda <Func <QueryContext, IDataContext, IDataReader, Expression, object[], TKey> >( keyExpr, ExpressionBuilder.ContextParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam); return(Expression.Call( null, MemberHelper.MethodOf(() => GetGrouping(null, null, null, null, null, null, null, null)), ExpressionBuilder.ContextParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, Expression.Constant(context.Builder.CurrentSqlParameters), ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam, Expression.Constant(keyReader.Compile()), Expression.Constant(itemReader))); }
public Expression GetGrouping(GroupByContext context) { if (Configuration.Linq.GuardGrouping) { if (context._element.Lambda.Parameters.Count == 1 && context._element.Body == context._element.Lambda.Parameters[0]) { var ex = new LinqToDBException( "You should explicitly specify selected fields for server-side GroupBy() call or add AsEnumerable() call before GroupBy() to perform client-side grouping.\n" + "Set Configuration.Linq.GuardGrouping = false to disable this check." ) { HelpLink = "https://github.com/linq2db/linq2db/issues/365" }; throw ex; } } var parameters = context.Builder.CurrentSqlParameters .Select((p, i) => new { p, i }) .ToDictionary(_ => _.p.Expression, _ => _.i); var paramArray = Expression.Parameter(typeof(object[]), "ps"); var groupExpression = context._sequenceExpr.Transform(e => { int idx; if (parameters.TryGetValue(e, out idx)) { return (Expression.Convert( Expression.ArrayIndex(paramArray, Expression.Constant(idx)), e.Type)); } return(e); }); var keyParam = Expression.Parameter(typeof(TKey), "key"); // ReSharper disable AssignNullToNotNullAttribute var expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Where(null, (Expression <Func <TSource, bool> >)null)), groupExpression, Expression.Lambda <Func <TSource, bool> >( ExpressionBuilder.Equal(context.Builder.MappingSchema, context._key.Lambda.Body, keyParam), new[] { context._key.Lambda.Parameters[0] })); expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Select(null, (Expression <Func <TSource, TElement> >)null)), expr, context._element.Lambda); // ReSharper restore AssignNullToNotNullAttribute var lambda = Expression.Lambda <Func <IDataContext, TKey, object[], IQueryable <TElement> > >( Expression.Convert(expr, typeof(IQueryable <TElement>)), Expression.Parameter(typeof(IDataContext), "ctx"), keyParam, paramArray); var itemReader = CompiledQuery.Compile(lambda); var keyExpr = context._key.BuildExpression(null, 0, false); var dataReaderLocal = context.Builder.DataReaderLocal; if (!Configuration.AvoidSpecificDataProviderAPI && keyExpr.Find(e => e == dataReaderLocal) != null) { keyExpr = Expression.Block( new[] { context.Builder.DataReaderLocal }, new[] { Expression.Assign(dataReaderLocal, Expression.Convert(ExpressionBuilder.DataReaderParam, context.Builder.DataContext.DataReaderType)), keyExpr }); } var keyReader = Expression.Lambda <Func <IQueryRunner, IDataContext, IDataReader, Expression, object[], TKey> >( keyExpr, new [] { ExpressionBuilder.QueryRunnerParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam }); return(Expression.Call( null, MemberHelper.MethodOf(() => GetGrouping(null, null, null, null, null, null, null, null)), new Expression[] { ExpressionBuilder.QueryRunnerParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, Expression.Constant(context.Builder.CurrentSqlParameters), ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam, Expression.Constant(keyReader.Compile()), Expression.Constant(itemReader) })); }
/// <summary> /// Returns a Slinq that enumerates the key, value groupings contained in the lookup, with the values returned in Linked form. /// As the groupings are enumerated, ownership of the values in each grouping is transferred to the owner of the grouping, who is /// responsible for their disposal. /// When the enumeration is complete, the lookup and any unenumerated values it contains are added to the disposal queue. /// </summary> public Slinq <Grouping <K, T>, GroupByContext <K, T> > SlinqLinkedAndDispose() { return(GroupByContext <K, T> .SlinqLinked(this, true)); }
/// <summary> /// Returns a Slinq that enumerates the key, value groupings contained in the lookup, with the values returned in Linked form. /// Ownership of the lookup and any values it contains is retained by the caller. /// </summary> public Slinq <Grouping <K, T>, GroupByContext <K, T> > SlinqLinkedAndKeep() { return(GroupByContext <K, T> .SlinqLinked(this, false)); }
private OrderByContext CreateOrderByContextForDistinctRowWithoutGroupBy(SelectCommand selectCommand, GroupByContext groupByContext) { if (!groupByContext.GetItems().Any() && selectCommand.Projections.IsDistinctRow()) { int index = 0; ICollection <OrderByItem> orderByItems = new LinkedList <OrderByItem>(); foreach (var projectionSegment in selectCommand.Projections.GetProjections()) { if (projectionSegment is ColumnProjectionSegment columnProjectionSegment) { var columnOrderByItemSegment = new ColumnOrderByItemSegment(columnProjectionSegment.GetColumn(), OrderDirectionEnum.ASC); OrderByItem item = new OrderByItem(columnOrderByItemSegment); item.SetIndex(index); orderByItems.Add(item); index++; } } if (orderByItems.Any()) { return(new OrderByContext(orderByItems, true)); } } return(null); }
protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var sequenceExpr = methodCall.Arguments[0]; var wrapSequence = false; LambdaExpression?groupingKey = null; var groupingKind = GroupingType.Default; if (sequenceExpr.NodeType == ExpressionType.Call) { var call = (MethodCallExpression)methodCall.Arguments[0]; if (call.IsQueryable("Select")) { var selectParam = (LambdaExpression)call.Arguments[1].Unwrap(); var type = selectParam.Body.Type; if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ExpressionBuilder.GroupSubQuery <,>)) { wrapSequence = true; var selectParamBody = selectParam.Body.Unwrap(); MethodCallExpression?groupingMethod = null; if (selectParamBody is MemberInitExpression mi) { var assignment = mi.Bindings.OfType <MemberAssignment>().FirstOrDefault(m => m.Member.Name == "Key"); if (assignment?.Expression.NodeType == ExpressionType.Call) { var mc = (MethodCallExpression)assignment.Expression; if (mc.IsSameGenericMethod(Methods.LinqToDB.GroupBy.Rollup, Methods.LinqToDB.GroupBy.Cube, Methods.LinqToDB.GroupBy.GroupingSets)) { groupingMethod = mc; groupingKey = (LambdaExpression)mc.Arguments[0].Unwrap(); if (mc.IsSameGenericMethod(Methods.LinqToDB.GroupBy.Rollup)) { groupingKind = GroupingType.Rollup; } else if (mc.IsSameGenericMethod(Methods.LinqToDB.GroupBy.Cube)) { groupingKind = GroupingType.Cube; } else if (mc.IsSameGenericMethod(Methods.LinqToDB.GroupBy.GroupingSets)) { groupingKind = GroupingType.GroupBySets; } else { throw new InvalidOperationException(); } } } } if (groupingMethod != null && groupingKey != null) { sequenceExpr = sequenceExpr.Replace(groupingMethod, groupingKey.Body.Unwrap()); } } } } var sequence = builder.BuildSequence(new BuildInfo(buildInfo, sequenceExpr)); var keySequence = sequence; var groupingType = methodCall.Type.GetGenericArguments()[0]; var keySelector = (LambdaExpression)methodCall.Arguments[1].Unwrap() !; var elementSelector = (LambdaExpression)methodCall.Arguments[2].Unwrap() !; if (wrapSequence) { sequence = new SubQueryContext(sequence); } sequence = new SubQueryContext(sequence); var key = new KeyContext(buildInfo.Parent, keySelector, sequence); if (groupingKind != GroupingType.GroupBySets) { var groupSql = builder.ConvertExpressions(key, keySelector.Body.Unwrap(), ConvertFlags.Key, null); var allowed = groupSql.Where(s => !QueryHelper.IsConstant(s.Sql)); foreach (var sql in allowed) { sequence.SelectQuery.GroupBy.Expr(sql.Sql); } } else { var goupingSetBody = groupingKey !.Body; var groupingSets = EnumGroupingSets(goupingSetBody).ToArray(); if (groupingSets.Length == 0) { throw new LinqException($"Invalid groping sets expression '{goupingSetBody}'."); } foreach (var groupingSet in groupingSets) { var groupSql = builder.ConvertExpressions(keySequence, groupingSet, ConvertFlags.Key, null); sequence.SelectQuery.GroupBy.Items.Add( new SqlGroupingSet(groupSql.Select(s => keySequence.SelectQuery.Select.AddColumn(s.Sql)))); } } sequence.SelectQuery.GroupBy.GroupingType = groupingKind; var element = new SelectContext(buildInfo.Parent, elementSelector, sequence /*, key*/); var groupBy = new GroupByContext(buildInfo.Parent, sequenceExpr, groupingType, sequence, key, element, builder.IsGroupingGuardDisabled); Debug.WriteLine("BuildMethodCall GroupBy:\n" + groupBy.SelectQuery); return(groupBy); }
public Expression GetGrouping(GroupByContext context) { if (Configuration.Linq.GuardGrouping && !context._isGroupingGuardDisabled) { if (context.Element.Lambda.Parameters.Count == 1 && context.Element.Body == context.Element.Lambda.Parameters[0]) { var ex = new LinqToDBException( "You should explicitly specify selected fields for server-side GroupBy() call or add AsEnumerable() call before GroupBy() to perform client-side grouping.\n" + "Set Configuration.Linq.GuardGrouping = false to disable this check.\n" + "Additionally this guard exception can be disabled by extension GroupBy(...).DisableGuard().\n" + "NOTE! By disabling this guard you accept additional Database Connection(s) to the server for processing such requests." ) { HelpLink = "https://github.com/linq2db/linq2db/issues/365" }; throw ex; } } var parameters = context.Builder.CurrentSqlParameters .Select((p, i) => new { p, i }) .ToDictionary(_ => _.p.Expression, _ => _.i); var paramArray = Expression.Parameter(typeof(object[]), "ps"); var groupExpression = context._sequenceExpr.Transform(e => { if (parameters.TryGetValue(e, out var idx)) { return (Expression.Convert( Expression.ArrayIndex(paramArray, Expression.Constant(idx)), e.Type)); } return(e); }); var keyParam = Expression.Parameter(typeof(TKey), "key"); // ReSharper disable AssignNullToNotNullAttribute var expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Where(null, (Expression <Func <TSource, bool> >)null !)), groupExpression, Expression.Lambda <Func <TSource, bool> >( ExpressionBuilder.Equal(context.Builder.MappingSchema, context._key.Lambda.Body, keyParam), new[] { context._key.Lambda.Parameters[0] })); expr = Expression.Call( null, MemberHelper.MethodOf(() => Queryable.Select(null, (Expression <Func <TSource, TElement> >)null !)), expr, context.Element.Lambda); // ReSharper restore AssignNullToNotNullAttribute var lambda = Expression.Lambda <Func <IDataContext, TKey, object?[]?, IQueryable <TElement> > >( Expression.Convert(expr, typeof(IQueryable <TElement>)), Expression.Parameter(typeof(IDataContext), "ctx"), keyParam, paramArray); var itemReader = CompiledQuery.Compile(lambda); var keyExpr = context._key.BuildExpression(null, 0, false); var keyReader = Expression.Lambda <Func <IQueryRunner, IDataContext, IDataReader, Expression, object?[]?, TKey> >( keyExpr, new [] { ExpressionBuilder.QueryRunnerParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam }); return(Expression.Call( null, MemberHelper.MethodOf(() => GetGrouping(null !, null !, null !, null !, null !, null !, null !, null !)), new Expression[] { ExpressionBuilder.QueryRunnerParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, Expression.Constant(context.Builder.CurrentSqlParameters), ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam, keyReader, Expression.Constant(itemReader) })); }
private ICollection <IProjection> GetDerivedGroupByColumns(ICollection <IProjection> projections, GroupByContext groupByContext, SelectCommand selectCommand) { return(GetDerivedOrderColumns(projections, groupByContext.GetItems(), DerivedColumn.Get(DerivedColumnEnum.GROUP_BY_ALIAS), selectCommand)); }
public Expression GetGrouping(GroupByContext context) { var parameters = context.Builder.CurrentSqlParameters .Select((p, i) => new { p, i }) .ToDictionary(_ => _.p.Expression, _ => _.i); var paramArray = Expression.Parameter(typeof(object[]), "ps"); var groupExpression = context._sequenceExpr.Convert(e => { int idx; if (parameters.TryGetValue(e, out idx)) { return (Expression.Convert( Expression.ArrayIndex(paramArray, Expression.Constant(idx)), e.Type)); } return(e); }); var keyParam = Expression.Parameter(typeof(TKey), "key"); // ReSharper disable AssignNullToNotNullAttribute var expr = Expression.Call( null, ReflectionHelper.Expressor <object> .MethodExpressor(_ => Queryable.Where(null, (Expression <Func <TSource, bool> >)null)), groupExpression, Expression.Lambda <Func <TSource, bool> >( Expression.Equal(context._key.Lambda.Body, keyParam), new[] { context._key.Lambda.Parameters[0] })); expr = Expression.Call( null, ReflectionHelper.Expressor <object> .MethodExpressor(_ => Queryable.Select(null, (Expression <Func <TSource, TElement> >)null)), expr, context._element.Lambda); // ReSharper restore AssignNullToNotNullAttribute var lambda = Expression.Lambda <Func <IDataContext, TKey, object[], IQueryable <TElement> > >( Expression.Convert(expr, typeof(IQueryable <TElement>)), Expression.Parameter(typeof(IDataContext), "ctx"), keyParam, paramArray); var itemReader = CompiledQuery.Compile(lambda); var keyExpr = context._key.BuildExpression(null, 0); var keyReader = Expression.Lambda <Func <QueryContext, IDataContext, IDataReader, Expression, object[], TKey> >( keyExpr, new [] { ExpressionBuilder.ContextParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam, }); return(Expression.Call( null, ReflectionHelper.Expressor <object> .MethodExpressor(_ => GetGrouping(null, null, null, null, null, null, null, null)), new Expression[] { ExpressionBuilder.ContextParam, ExpressionBuilder.DataContextParam, ExpressionBuilder.DataReaderParam, Expression.Constant(context.Builder.CurrentSqlParameters), ExpressionBuilder.ExpressionParam, ExpressionBuilder.ParametersParam, Expression.Constant(keyReader.Compile()), Expression.Constant(itemReader), })); }
/// <summary> /// Create projections context. /// </summary> /// <param name="sql"></param> /// <param name="selectCommand"></param> /// <param name="groupByContext"></param> /// <param name="orderByContext"></param> /// <returns></returns> public ProjectionsContext CreateProjectionsContext(string sql, SelectCommand selectCommand, GroupByContext groupByContext, OrderByContext orderByContext) { ProjectionsSegment projectionsSegment = selectCommand.Projections; ICollection <IProjection> projections = GetProjections(sql, selectCommand.GetSimpleTableSegments(), projectionsSegment); ProjectionsContext result = new ProjectionsContext(projectionsSegment.GetStartIndex(), projectionsSegment.GetStopIndex(), projectionsSegment.IsDistinctRow(), projections); result.GetProjections().AddAll(GetDerivedGroupByColumns(projections, groupByContext, selectCommand)); result.GetProjections().AddAll(GetDerivedOrderByColumns(projections, orderByContext, selectCommand)); return(result); }
protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var sequenceExpr = methodCall.Arguments[0]; var sequence = builder.BuildSequence(new BuildInfo(buildInfo, sequenceExpr)); var groupingType = methodCall.Type.GetGenericArgumentsEx()[0]; var keySelector = (LambdaExpression)methodCall.Arguments[1].Unwrap(); var elementSelector = (LambdaExpression)methodCall.Arguments[2].Unwrap(); if (methodCall.Arguments[0].NodeType == ExpressionType.Call) { var call = (MethodCallExpression)methodCall.Arguments[0]; if (call.Method.Name == "Select") { var type = ((LambdaExpression)call.Arguments[1].Unwrap()).Body.Type; if (type.IsGenericTypeEx() && type.GetGenericTypeDefinition() == typeof(ExpressionBuilder.GroupSubQuery <,>)) { sequence = new SubQueryContext(sequence); } } } var key = new KeyContext(buildInfo.Parent, keySelector, sequence); var groupSql = builder.ConvertExpressions(key, keySelector.Body.Unwrap(), ConvertFlags.Key); if (sequence.SelectQuery.Select.IsDistinct || sequence.SelectQuery.GroupBy.Items.Count > 0 || groupSql.Any(_ => !(_.Sql is SqlField || _.Sql is SelectQuery.Column))) { sequence = new SubQueryContext(sequence); key = new KeyContext(buildInfo.Parent, keySelector, sequence); groupSql = builder.ConvertExpressions(key, keySelector.Body.Unwrap(), ConvertFlags.Key); } else if (groupSql.Length == 1 && groupSql.Any(_ => _.Sql is SelectQuery.Column)) { //var columns = (SelectQuery.Column) groupSql[0]. Sql; //var value = columns.Expression as SqlValue; //if (value != null && value.SystemType.Name.Equals("String")) //{ // // var allColumns = value.Value.ToString().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); // sequence.SelectQuery.GroupBy.Items.Add(new SqlField {Name = value.Value.ToString(),PhysicalName ="columnString" }); // } } foreach (var sql in groupSql) { sequence.SelectQuery.GroupBy.Expr(sql.Sql); } new QueryVisitor().Visit(sequence.SelectQuery.From, (e, table_cloumn) => { if (e.ElementType == QueryElementType.JoinedTable) { var jt = (SelectQuery.JoinedTable)e; if (jt.JoinType == SelectQuery.JoinType.Inner) { jt.IsWeak = false; } } }); var element = new SelectContext(buildInfo.Parent, elementSelector, sequence /*, key*/); var groupBy = new GroupByContext(buildInfo.Parent, sequenceExpr, groupingType, sequence, key, element); return(groupBy); }