コード例 #1
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));
        }
コード例 #2
0
            public SetOperationContext(SubQueryContext sequence1, SubQueryContext sequence2, MethodCallExpression methodCall, SqlSetOperator setOperator)
                : base(sequence1)
            {
                _isObject =
                    sequence1.IsExpression(null, 0, RequestFor.Object).Result ||
                    sequence2.IsExpression(null, 0, RequestFor.Object).Result;

                if (_isObject)
                {
                    _type           = methodCall.Method.GetGenericArguments()[0];
                    _unionParameter = Expression.Parameter(_type, "t");
                }

                // initial sequences
                AddSequence(sequence1, null);
                AddSequence(sequence2, setOperator);
            }