コード例 #1
0
        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 SqlColumn)))
            {
                sequence = new SubQueryContext(sequence);
                key      = new KeyContext(buildInfo.Parent, keySelector, sequence);
                groupSql = builder.ConvertExpressions(key, keySelector.Body.Unwrap(), ConvertFlags.Key);
            }

            foreach (var sql in groupSql)
            {
                sequence.SelectQuery.GroupBy.Expr(sql.Sql);
            }

//			new QueryVisitor().Visit(sequence.SelectQuery.From, e =>
//			{
//				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);

            Debug.WriteLine("BuildMethodCall GroupBy:\n" + groupBy.SelectQuery);

            return(groupBy);
        }
コード例 #2
0
ファイル: OrderByBuilder.cs プロジェクト: tcomlab/linq2db
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

            if (sequence.SelectQuery.Select.TakeValue != null ||
                sequence.SelectQuery.Select.SkipValue != null ||
                sequence.SelectQuery.Select.IsDistinct && !builder.DataContextInfo.SqlProviderFlags.IsDistinctOrderBySupported)
            {
                sequence = new SubQueryContext(sequence);
            }

            var lambda  = (LambdaExpression)methodCall.Arguments[1].Unwrap();
            var sparent = sequence.Parent;
            var order   = new ExpressionContext(buildInfo.Parent, sequence, lambda);
            var body    = lambda.Body.Unwrap();
            var sql     = builder.ConvertExpressions(order, body, ConvertFlags.Key);

            builder.ReplaceParent(order, sparent);

            if (!methodCall.Method.Name.StartsWith("Then"))
            {
                sequence.SelectQuery.OrderBy.Items.Clear();
            }

            foreach (var expr in sql)
            {
                var e = builder.ConvertSearchCondition(sequence, expr.Sql);
                sequence.SelectQuery.OrderBy.Expr(e, methodCall.Method.Name.EndsWith("Descending"));
            }

            return(sequence);
        }
コード例 #3
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

            var keySelector = (LambdaExpression)methodCall.Arguments[1].Unwrap();
            var keyContext  = new SelectContext(buildInfo.Parent, keySelector, sequence);
            var keySql      = builder.ConvertExpressions(keyContext, keySelector.Body.Unwrap(), ConvertFlags.All, null);

            var uniqueKeys = keySql
                             .Select(info => sequence.SelectQuery.Select.Columns[sequence.SelectQuery.Select.Add(info.Sql)])
                             .ToArray();

            sequence.SelectQuery.UniqueKeys.Add(uniqueKeys);

            return(new SubQueryContext(sequence));
        }
コード例 #4
0
        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);
        }
コード例 #5
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

            var wrapped = false;

            if (sequence.SelectQuery.Select.TakeValue != null ||
                sequence.SelectQuery.Select.SkipValue != null)
            {
                sequence = new SubQueryContext(sequence);
                wrapped  = true;
            }

            var lambda = (LambdaExpression)methodCall.Arguments[1].Unwrap();

            SqlInfo[] sql;

            while (true)
            {
                var sparent = sequence.Parent;
                var order   = new ExpressionContext(buildInfo.Parent, sequence, lambda);
                var body    = lambda.Body.Unwrap();
                sql = builder.ConvertExpressions(order, body, ConvertFlags.Key, null);

                builder.ReplaceParent(order, sparent);

                if (wrapped)
                {
                    break;
                }

                // handle situation when order by uses complex field

                var isComplex = false;

                foreach (var sqlInfo in sql)
                {
                    // immutable expressions will be removed later
                    //
                    var isImmutable = QueryHelper.IsConstant(sqlInfo.Sql);
                    if (isImmutable)
                    {
                        continue;
                    }

                    // possible we have to extend this list
                    //
                    isComplex = null != new QueryVisitor().Find(sqlInfo.Sql,
                                                                e => e.ElementType == QueryElementType.SqlQuery);
                    if (isComplex)
                    {
                        break;
                    }
                }

                if (!isComplex)
                {
                    break;
                }

                sequence = new SubQueryContext(sequence);
                wrapped  = true;
            }


            if (!methodCall.Method.Name.StartsWith("Then") && !Configuration.Linq.DoNotClearOrderBys)
            {
                sequence.SelectQuery.OrderBy.Items.Clear();
            }

            foreach (var expr in sql)
            {
                // we do not need sorting by immutable values, like "Some", Func("Some"), "Some1" + "Some2". It does nothing for ordering
                //
                if (QueryHelper.IsConstant(expr.Sql))
                {
                    continue;
                }

                var e = builder.ConvertSearchCondition(expr.Sql);
                sequence.SelectQuery.OrderBy.Expr(e, methodCall.Method.Name.EndsWith("Descending"));
            }

            return(sequence);
        }