Exemplo n.º 1
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])
            {
                CreateSubQuery = true
            });

            var prevSequence = sequence;

            // Wrap by subquery to handle aggregate limitations, especially for SQL Server
            //
            sequence = new SubQueryContext(sequence);

            if (prevSequence.SelectQuery.OrderBy.Items.Count > 0)
            {
                if (prevSequence.SelectQuery.Select.TakeValue == null && prevSequence.SelectQuery.Select.SkipValue == null)
                {
                    prevSequence.SelectQuery.OrderBy.Items.Clear();
                }
            }

            var context = new AggregationContext(buildInfo.Parent, sequence, methodCall);

            var methodName = methodCall.Method.Name.Replace("Async", "");

            var sql = sequence.ConvertToSql(null, 0, ConvertFlags.Field).Select(_ => _.Sql).ToArray();

            if (sql.Length == 1)
            {
                if (sql[0] is SelectQuery query)
                {
                    if (query.Select.Columns.Count == 1)
                    {
                        var join = query.OuterApply();
                        context.SelectQuery.From.Tables[0].Joins.Add(join.JoinedTable);
                        sql[0] = query.Select.Columns[0];
                    }
                }
            }

            ISqlExpression sqlExpression = new SqlFunction(methodCall.Type, methodName, true, sql);

            if (sqlExpression == null)
            {
                throw new LinqToDBException("Invalid Aggregate function implementation");
            }

            context.Sql        = context.SelectQuery;
            context.FieldIndex = context.SelectQuery.Select.Add(sqlExpression, methodName);

            return(context);
        }
Exemplo n.º 2
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
            var query    = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery()));
            var except   = query.SelectQuery;

            sequence = new SubQueryContext(sequence);

            var sql = sequence.SelectQuery;

            except.ParentSelect = sql;

            if (methodCall.Method.Name == "Except")
            {
                sql.Where.Not.Exists(except);
            }
            else
            {
                sql.Where.Exists(except);
            }

            var keys1 = sequence.ConvertToSql(null, 0, ConvertFlags.Key);
            var keys2 = query.ConvertToSql(null, 0, ConvertFlags.Key);

            if (keys1.Length != keys2.Length)
            {
                throw new InvalidOperationException();
            }

            for (var i = 0; i < keys1.Length; i++)
            {
                except.Where
                .Expr(keys1[i].Sql)
                .Equal
                .Expr(keys2[i].Sql);
            }

            return(sequence);
        }
Exemplo n.º 3
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence1 = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
            var sequence2 = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery()));

            SetOperation setOperation;

            switch (methodCall.Method.Name)
            {
            case "Concat":
            case "UnionAll": setOperation = SetOperation.UnionAll;     break;

            case "Union": setOperation = SetOperation.Union;        break;

            case "Except": setOperation = SetOperation.Except;       break;

            case "ExceptAll": setOperation = SetOperation.ExceptAll;    break;

            case "Intersect": setOperation = SetOperation.Intersect;    break;

            case "IntersectAll": setOperation = SetOperation.IntersectAll; break;

            default:
                throw new ArgumentException($"Invalid method name {methodCall.Method.Name}.");
            }

            var needsEmulation = !builder.DataContext.SqlProviderFlags.IsAllSetOperationsSupported &&
                                 setOperation.In(SetOperation.ExceptAll, SetOperation.IntersectAll)
                                 ||
                                 !builder.DataContext.SqlProviderFlags.IsDistinctSetOperationsSupported &&
                                 setOperation.In(SetOperation.Except, SetOperation.Intersect);

            if (needsEmulation)
            {
                // emulation

                var sequence = new SubQueryContext(sequence1);
                var query    = sequence2;
                var except   = query.SelectQuery;

                var sql = sequence.SelectQuery;

                if (setOperation.In(SetOperation.Except, SetOperation.Intersect))
                {
                    sql.Select.IsDistinct = true;
                }

                except.ParentSelect = sql;

                if (setOperation.In(SetOperation.Except, SetOperation.ExceptAll))
                {
                    sql.Where.Not.Exists(except);
                }
                else
                {
                    sql.Where.Exists(except);
                }

                var keys1 = sequence.ConvertToSql(null, 0, ConvertFlags.All);
                var keys2 = query.ConvertToSql(null, 0, ConvertFlags.All);

                if (keys1.Length != keys2.Length)
                {
                    throw new InvalidOperationException();
                }

                for (var i = 0; i < keys1.Length; i++)
                {
                    except.Where
                    .Expr(keys1[i].Sql)
                    .Equal
                    .Expr(keys2[i].Sql);
                }

                return(sequence);
            }

            var set1 = new SubQueryContext(sequence1);
            var set2 = new SubQueryContext(sequence2);

            var setOperator = new SqlSetOperator(set2.SelectQuery, setOperation);

            set1.SelectQuery.SetOperators.Add(setOperator);

            return(new SetOperationContext(set1, set2, methodCall));
        }