Example #1
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall,
                                                         BuildInfo buildInfo)
        {
            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

            if (sequence.Select.Select.TakeValue != null ||
                sequence.Select.Select.SkipValue != null ||
                sequence.Select.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.Select.OrderBy.Items.Clear();
            }

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

            return(sequence);
        }
Example #2
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.Select.Select.IsDistinct ||
                sequence.Select.GroupBy.Items.Count > 0 ||
                groupSql.Any(_ => !(_.Sql is ISqlField || _.Sql is IColumn)))
            {
                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.Select.GroupBy.Expr(sql.Sql);
            }

            foreach (
                var join in
                QueryVisitor.FindOnce <IJoinedTable>(sequence.Select.From).Where(f => f.JoinType == EJoinType.Inner))
            {
                join.IsWeak = false;
            }

            var element = new SelectContext(buildInfo.Parent, elementSelector, sequence /*, key*/);
            var groupBy = new GroupByContext(buildInfo.Parent, sequenceExpr, groupingType, sequence, key, element);

            return(groupBy);
        }
Example #3
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall,
                                                         BuildInfo buildInfo)
        {
            var sequence1 = new SubQueryContext(builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])));
            var sequence2 =
                new SubQueryContext(
                    builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery())));
            var union = new Union(sequence2.Select, methodCall.Method.Name == "Concat");

            sequence1.Select.Unions.AddLast(union);

            return(new UnionContext(sequence1, sequence2, methodCall));
        }
Example #4
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall,
                                                         BuildInfo buildInfo)
        {
            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
            var sql      = sequence.Select;

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

            sequence.Select.Select.IsDistinct = true;
            sequence.ConvertToIndex(null, 0, ConvertFlags.All);

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

            if (sequence.Select.Select.IsDistinct ||
                sequence.Select.Select.TakeValue != null ||
                sequence.Select.Select.SkipValue != null ||
                !sequence.Select.GroupBy.IsEmpty)
            {
                sequence = new SubQueryContext(sequence);
            }

            if (sequence.Select.OrderBy.Items.Count > 0)
            {
                if (sequence.Select.Select.TakeValue == null && sequence.Select.Select.SkipValue == null)
                {
                    sequence.Select.OrderBy.Items.Clear();
                }
                else
                {
                    sequence = new SubQueryContext(sequence);
                }
            }

            var context = new AggregationContext(buildInfo.Parent, sequence, methodCall);
            var sql     = sequence.ConvertToSql(null, 0, ConvertFlags.Field).Select(_ => _.Sql).ToArray();

            if (sql.Length == 1 && sql[0] is ISelectQuery)
            {
                var query = (ISelectQuery)sql[0];

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

            context.Sql        = context.Select;
            context.FieldIndex = context.Select.Select.Add(
                new SqlFunction(methodCall.Type, methodCall.Method.Name, sql));

            return(context);
        }
Example #6
0
            public UnionContext(SubQueryContext sequence1, SubQueryContext sequence2, MethodCallExpression methodCall)
                : base(sequence1)
            {
                _sequence1  = sequence1;
                _sequence2  = sequence2;
                _methodCall = methodCall;

                _sequence2.Parent = this;

                _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");
                }

                Init();
            }
Example #7
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.Select;

            sequence = new SubQueryContext(sequence);

            var sql = sequence.Select;

            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);
        }
Example #8
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall,
                                                         BuildInfo buildInfo)
        {
            var returnType = methodCall.Method.ReturnType;
            var sequence   =
                builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])
            {
                CreateSubQuery = true
            });

            if (sequence.Select != buildInfo.SelectQuery)
            {
                if (sequence is GroupByBuilder.GroupByContext)
                {
                    return(new CountContext(buildInfo.Parent, sequence, returnType)
                    {
                        Sql = SqlFunction.CreateCount(returnType, sequence.Select),
                        FieldIndex = -1
                    });
                }
            }

            if (sequence.Select.Select.IsDistinct ||
                sequence.Select.Select.TakeValue != null ||
                sequence.Select.Select.SkipValue != null)
            {
                sequence.ConvertToIndex(null, 0, ConvertFlags.Key);
                sequence = new SubQueryContext(sequence);
            }
            else if (!sequence.Select.GroupBy.IsEmpty)
            {
                if (!builder.DataContextInfo.SqlProviderFlags.IsSybaseBuggyGroupBy)
                {
                    sequence.Select.Select.Add(new SqlValue(0));
                }
                else
                {
                    foreach (var item in sequence.Select.GroupBy.Items)
                    {
                        sequence.Select.Select.Add(item);
                    }
                }

                sequence = new SubQueryContext(sequence);
            }

            if (sequence.Select.OrderBy.Items.Count > 0)
            {
                if (sequence.Select.Select.TakeValue == null && sequence.Select.Select.SkipValue == null)
                {
                    sequence.Select.OrderBy.Items.Clear();
                }
                else
                {
                    sequence = new SubQueryContext(sequence);
                }
            }

            var context = new CountContext(buildInfo.Parent, sequence, returnType);

            context.Sql        = context.Select;
            context.FieldIndex = context.Select.Select.Add(SqlFunction.CreateCount(returnType, context.Select), "cnt");

            return(context);
        }
Example #9
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall,
                                                         BuildInfo buildInfo)
        {
            var sequence           = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
            var collectionSelector = (LambdaExpression)methodCall.Arguments[1].Unwrap();
            var resultSelector     = (LambdaExpression)methodCall.Arguments[2].Unwrap();

            if (!sequence.Select.GroupBy.IsEmpty)
            {
                sequence = new SubQueryContext(sequence);
            }

            var context = new SelectManyContext(buildInfo.Parent, collectionSelector, sequence);
            var expr    = collectionSelector.Body.Unwrap();

            var collectionInfo = new BuildInfo(context, expr, new SelectQuery());
            var collection     = builder.BuildSequence(collectionInfo);
            var leftJoin       = collection is DefaultIfEmptyBuilder.DefaultIfEmptyContext;
            var sql            = collection.Select;

            var sequenceTables = new HashSet <ISqlTableSource>(sequence.Select.From.Tables.First.Value.GetTables());
            var newQuery       = sql != collectionInfo.SelectQuery &&
                                 QueryVisitor.FindFirstOrDefault <ISelectQuery>(sql, e => e == collectionInfo.SelectQuery) ==
                                 null;
            var crossApply = null !=
                             QueryVisitor.FindFirstOrDefault <IQueryExpression>(
                sql,
                e =>
                e.ElementType == EQueryElementType.TableSource &&
                sequenceTables.Contains((ISqlTableSource)e) ||
                e.ElementType == EQueryElementType.SqlField &&
                sequenceTables.Contains(((ISqlField)e).Table) ||
                e.ElementType == EQueryElementType.Column &&
                sequenceTables.Contains(((IColumn)e).Parent));

            var groupJoinSubQueryContext = collection as JoinBuilder.GroupJoinSubQueryContext;

            if (groupJoinSubQueryContext != null)
            {
                var groupJoin = groupJoinSubQueryContext.GroupJoin;

                var joinedTables = groupJoin.Select.From.Tables.First.Value.Joins.First.Value;
                joinedTables.JoinType = EJoinType.Inner;
                joinedTables.IsWeak   = false;
            }

            if (newQuery)
            {
                context.Collection = new SubQueryContext(collection, sequence.Select, false);
                return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
            }

            if (!crossApply)
            {
                if (!leftJoin)
                {
                    context.Collection = new SubQueryContext(collection, sequence.Select, true);
                    return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
                }

                var join = SelectQuery.OuterApply(sql);
                sequence.Select.From.Tables.First.Value.Joins.AddLast(join.JoinedTable);
                context.Collection = new SubQueryContext(collection, sequence.Select, false);

                return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
            }

            var tableContext = collection as TableBuilder.TableContext;

            if (tableContext != null)
            {
                var join = tableContext.SqlTable.TableArguments != null &&
                           tableContext.SqlTable.TableArguments.Count > 0
                    ? (leftJoin
                        ? SelectQuery.OuterApply(sql)
                        : SelectQuery.CrossApply(sql))
                    : (leftJoin
                        ? SelectQuery.LeftJoin(sql)
                        : SelectQuery.InnerJoin(sql));

                join.JoinedTable.Condition.Conditions.AddRange(sql.Where.Search.Conditions);
                join.JoinedTable.CanConvertApply = false;

                sql.Where.Search.Conditions.Clear();

                var collectionParent = collection.Parent as TableBuilder.TableContext;

                // Association.
                //
                if (collectionParent != null && collectionInfo.IsAssociationBuilt)
                {
                    QueryVisitor.FindFirstOrDefault <ITableSource>(sequence.Select.From,
                                                                   t => t.Source == collectionParent.SqlTable);
                }
                else
                {
                    sequence.Select.From.Tables.First.Value.Joins.AddLast(join.JoinedTable);
                }

                context.Collection = new SubQueryContext(collection, sequence.Select, false);
                return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
            }
            else
            {
                var join = leftJoin
                    ? SelectQuery.OuterApply(sql)
                    : SelectQuery.CrossApply(sql);
                sequence.Select.From.Tables.First.Value.Joins.AddLast(join.JoinedTable);

                context.Collection = new SubQueryContext(collection, sequence.Select, false);
                return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
            }
        }
Example #10
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall,
                                                         BuildInfo buildInfo)
        {
            var isGroup      = methodCall.Method.Name == "GroupJoin";
            var outerContext =
                builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0], buildInfo.SelectQuery));
            var innerContext =
                builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery()));

            var context = new SubQueryContext(outerContext);

            innerContext = isGroup ? new GroupJoinSubQueryContext(innerContext) : new SubQueryContext(innerContext);

            var join = isGroup ? innerContext.Select.WeakLeftJoin() : innerContext.Select.InnerJoin();
            var sql  = context.Select;

            sql.From.Tables.First.Value.Joins.AddLast(join.JoinedTable);

            var selector = (LambdaExpression)methodCall.Arguments[4].Unwrap();

            context.SetAlias(selector.Parameters[0].Name);
            innerContext.SetAlias(selector.Parameters[1].Name);

            var outerKeyLambda = (LambdaExpression)methodCall.Arguments[2].Unwrap();
            var innerKeyLambda = (LambdaExpression)methodCall.Arguments[3].Unwrap();

            var outerKeySelector = outerKeyLambda.Body.Unwrap();
            var innerKeySelector = innerKeyLambda.Body.Unwrap();

            var outerParent = context.Parent;
            var innerParent = innerContext.Parent;

            var outerKeyContext = new ExpressionContext(buildInfo.Parent, context, outerKeyLambda);
            var innerKeyContext = new InnerKeyContext(buildInfo.Parent, innerContext, innerKeyLambda);

            // Make join and where for the counter.
            //
            if (outerKeySelector.NodeType == ExpressionType.New)
            {
                var new1 = (NewExpression)outerKeySelector;
                var new2 = (NewExpression)innerKeySelector;

                for (var i = 0; i < new1.Arguments.Count; i++)
                {
                    var arg1 = new1.Arguments[i];
                    var arg2 = new2.Arguments[i];

                    BuildJoin(builder, join, outerKeyContext, arg1, innerKeyContext, arg2);
                }
            }
            else if (outerKeySelector.NodeType == ExpressionType.MemberInit)
            {
                var mi1 = (MemberInitExpression)outerKeySelector;
                var mi2 = (MemberInitExpression)innerKeySelector;

                for (var i = 0; i < mi1.Bindings.Count; i++)
                {
                    if (mi1.Bindings[i].Member != mi2.Bindings[i].Member)
                    {
                        throw new LinqException(
                                  "List of member inits does not match for entity type '{0}'.".Args(outerKeySelector.Type));
                    }

                    var arg1 = ((MemberAssignment)mi1.Bindings[i]).Expression;
                    var arg2 = ((MemberAssignment)mi2.Bindings[i]).Expression;

                    BuildJoin(builder, join, outerKeyContext, arg1, innerKeyContext, arg2);
                }
            }
            else
            {
                BuildJoin(builder, join, outerKeyContext, outerKeySelector, innerKeyContext, innerKeySelector);
            }

            builder.ReplaceParent(outerKeyContext, outerParent);
            builder.ReplaceParent(innerKeyContext, innerParent);

            if (isGroup)
            {
                var inner = (GroupJoinSubQueryContext)innerContext;

                inner.Join = join.JoinedTable;
                inner.GetSubQueryContext = () =>
                                           GetSubQueryContext(builder, methodCall, buildInfo, sql,
                                                              innerKeyLambda, outerKeySelector, innerKeySelector, outerKeyContext);

                return(new GroupJoinContext(
                           buildInfo.Parent, selector, context, inner, methodCall.Arguments[1], outerKeyLambda, innerKeyLambda));
            }

            return(new JoinContext(buildInfo.Parent, selector, context, innerContext)
#if DEBUG
            {
                MethodCall = methodCall
            }
#endif
                   );
        }
Example #11
0
        private IBuildContext GetSubQueryContext(ExpressionBuilder builder, MethodCallExpression methodCall,
                                                 BuildInfo buildInfo,
                                                 ISelectQuery sql,
                                                 LambdaExpression innerKeyLambda,
                                                 Expression outerKeySelector,
                                                 Expression innerKeySelector,
                                                 IBuildContext outerKeyContext)
        {
            var subQueryContext =
                builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery()));

            subQueryContext = new SubQueryContext(subQueryContext);

            var subQueryParent     = subQueryContext.Parent;
            var subQueryKeyContext = new ExpressionContext(buildInfo.Parent, subQueryContext, innerKeyLambda);

            // Process SubQuery.
            //
            var subQuerySql = ((SubQueryContext)subQueryContext).Select;

            // Make join and where for the counter.
            //
            if (outerKeySelector.NodeType == ExpressionType.New)
            {
                var new1 = (NewExpression)outerKeySelector;
                var new2 = (NewExpression)innerKeySelector;

                for (var i = 0; i < new1.Arguments.Count; i++)
                {
                    var arg1 = new1.Arguments[i];
                    var arg2 = new2.Arguments[i];

                    BuildSubQueryJoin(builder, outerKeyContext, arg1, arg2, subQueryKeyContext, subQuerySql);
                }
            }
            else if (outerKeySelector.NodeType == ExpressionType.MemberInit)
            {
                var mi1 = (MemberInitExpression)outerKeySelector;
                var mi2 = (MemberInitExpression)innerKeySelector;

                for (var i = 0; i < mi1.Bindings.Count; i++)
                {
                    if (mi1.Bindings[i].Member != mi2.Bindings[i].Member)
                    {
                        throw new LinqException(
                                  "List of member inits does not match for entity type '{0}'.".Args(outerKeySelector.Type));
                    }

                    var arg1 = ((MemberAssignment)mi1.Bindings[i]).Expression;
                    var arg2 = ((MemberAssignment)mi2.Bindings[i]).Expression;

                    BuildSubQueryJoin(builder, outerKeyContext, arg1, arg2, subQueryKeyContext, subQuerySql);
                }
            }
            else
            {
                BuildSubQueryJoin(builder, outerKeyContext, outerKeySelector, innerKeySelector, subQueryKeyContext,
                                  subQuerySql);
            }

            builder.ReplaceParent(subQueryKeyContext, subQueryParent);

            subQuerySql.ParentSelect = sql;
            subQuerySql.Select.Columns.Clear();

            return(subQueryContext);
        }