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

            JoinType joinType;
            var      conditionIndex = 1;

            switch (methodCall.Method.Name)
            {
            case "InnerJoin": joinType = JoinType.Inner; break;

            case "LeftJoin": joinType = JoinType.Left;  break;

            case "RightJoin": joinType = JoinType.Right; break;

            case "FullJoin": joinType = JoinType.Full;  break;

            default:
                conditionIndex = 2;

                var joinValue = (SqlJoinType)methodCall.Arguments[1].EvaluateExpression() !;

                switch (joinValue)
                {
                case SqlJoinType.Inner: joinType = JoinType.Inner; break;

                case SqlJoinType.Left: joinType = JoinType.Left;  break;

                case SqlJoinType.Right: joinType = JoinType.Right; break;

                case SqlJoinType.Full: joinType = JoinType.Full;  break;

                default: throw new ArgumentOutOfRangeException();
                }

                break;
            }

            buildInfo.JoinType = joinType;

            if (joinType == JoinType.Left || joinType == JoinType.Full)
            {
                sequence = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, sequence, null);
            }
            sequence = new SubQueryContext(sequence);

            if (methodCall.Arguments[conditionIndex] != null)
            {
                var condition = (LambdaExpression)methodCall.Arguments[conditionIndex].Unwrap();

                var result = builder.BuildWhere(buildInfo.Parent, sequence, condition, false, false);

                result.SetAlias(condition.Parameters[0].Name);
                return(result);
            }

            return(sequence);
        }
Exemple #2
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();

            var expr = collectionSelector.Body.Unwrap();

            DefaultIfEmptyBuilder.DefaultIfEmptyContext?defaultIfEmpty = null;
            if (expr is MethodCallExpression mc && AllJoinsBuilder.IsMatchingMethod(mc, true))
            {
                defaultIfEmpty = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, sequence, null);
                sequence       = new SubQueryContext(defaultIfEmpty);

                defaultIfEmpty.Disabled = true;
            }
Exemple #3
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var outerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
            var innerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery()));

            JoinType joinType;
            var      conditionIndex = 2;

            switch (methodCall.Method.Name)
            {
            case "InnerJoin": joinType = JoinType.Inner; break;

            case "CrossJoin": joinType = JoinType.Inner; conditionIndex = -1; break;

            case "LeftJoin": joinType = JoinType.Left;  break;

            case "RightJoin": joinType = JoinType.Right; break;

            case "FullJoin": joinType = JoinType.Full;  break;

            default:
                conditionIndex = 3;

                var joinValue = (SqlJoinType)methodCall.Arguments[2].EvaluateExpression();

                switch (joinValue)
                {
                case SqlJoinType.Inner: joinType = JoinType.Inner; break;

                case SqlJoinType.Left: joinType = JoinType.Left;  break;

                case SqlJoinType.Right: joinType = JoinType.Right; break;

                case SqlJoinType.Full: joinType = JoinType.Full;  break;

                default: throw new ArgumentOutOfRangeException();
                }

                break;
            }

            if (joinType == JoinType.Right || joinType == JoinType.Full)
            {
                outerContext = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, outerContext, null);
            }
            outerContext = new SubQueryContext(outerContext);


            if (joinType == JoinType.Left || joinType == JoinType.Full)
            {
                innerContext = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, innerContext, null);
            }
            innerContext = new SubQueryContext(innerContext);

            var selector = (LambdaExpression)methodCall.Arguments[methodCall.Arguments.Count - 1].Unwrap();

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

            var joinContext = new JoinContext(buildInfo.Parent, selector, outerContext, innerContext)
#if DEBUG
            {
                MethodCall = methodCall
            }
#endif
            ;

            if (conditionIndex != -1)
            {
                var condition     = (LambdaExpression)methodCall.Arguments[conditionIndex].Unwrap();
                var conditionExpr = condition.GetBody(selector.Parameters[0], selector.Parameters[1]);

                conditionExpr = builder.ConvertExpression(conditionExpr);

                var join = new SqlFromClause.Join(joinType, innerContext.SelectQuery, null, false,
                                                  Array <SqlFromClause.Join> .Empty);

                outerContext.SelectQuery.From.Tables[0].Joins.Add(join.JoinedTable);

                builder.BuildSearchCondition(
                    joinContext,
                    conditionExpr,
                    join.JoinedTable.Condition.Conditions,
                    false);
            }
            else
            {
                outerContext.SelectQuery.From.Table(innerContext.SelectQuery);
            }

            return(joinContext);
        }
Exemple #4
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.SelectQuery.HasUnion || !sequence.SelectQuery.IsSimple)
            {
                sequence = new SubQueryContext(sequence);
            }

            var expr = collectionSelector.Body.Unwrap();

            DefaultIfEmptyBuilder.DefaultIfEmptyContext defaultIfEmpty = null;
            if (expr is MethodCallExpression mc && AllJoinsBuilder.IsMatchingMethod(mc, true))
            {
                defaultIfEmpty          = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, sequence, null);
                defaultIfEmpty.Disabled = true;
                sequence = new SubQueryContext(defaultIfEmpty);
            }

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

            context.SetAlias(collectionSelector.Parameters[0].Name);

            var collectionInfo = new BuildInfo(context, expr, new SelectQuery());
            var collection     = builder.BuildSequence(collectionInfo);

            if (resultSelector.Parameters.Count > 1)
            {
                collection.SetAlias(resultSelector.Parameters[1].Name);
            }

            if (defaultIfEmpty != null && (collectionInfo.JoinType == JoinType.Right || collectionInfo.JoinType == JoinType.Full))
            {
                defaultIfEmpty.Disabled = false;
            }

            var leftJoin = collection is DefaultIfEmptyBuilder.DefaultIfEmptyContext || collectionInfo.JoinType == JoinType.Left;
            var sql      = collection.SelectQuery;

            var sequenceTables = new HashSet <ISqlTableSource>(sequence.SelectQuery.From.Tables[0].GetTables());
            var newQuery       = null != QueryVisitor.Find(sql, e => e == collectionInfo.SelectQuery);
            var crossApply     = null != QueryVisitor.Find(sql, e =>
                                                           e.ElementType == QueryElementType.TableSource && sequenceTables.Contains((ISqlTableSource)e) ||
                                                           e.ElementType == QueryElementType.SqlField && sequenceTables.Contains(((SqlField)e).Table) ||
                                                           e.ElementType == QueryElementType.Column && sequenceTables.Contains(((SqlColumn)e).Parent));

            if (collection is JoinBuilder.GroupJoinSubQueryContext queryContext)
            {
                var groupJoin = queryContext.GroupJoin;

                groupJoin.SelectQuery.From.Tables[0].Joins[0].JoinType = JoinType.Inner;
                groupJoin.SelectQuery.From.Tables[0].Joins[0].IsWeak   = false;
            }

            if (!newQuery)
            {
                if (collection.SelectQuery.Select.HasModifier)
                {
                    if (crossApply)
                    {
                        var foundJoin = context.SelectQuery.FindJoin(j => j.Table.Source == collection.SelectQuery);
                        if (foundJoin != null)
                        {
                            foundJoin.JoinType = leftJoin ? JoinType.OuterApply : JoinType.CrossApply;

                            collection.SelectQuery.Where.ConcatSearchCondition(foundJoin.Condition);

                            ((ISqlExpressionWalkable)collection.SelectQuery.Where).Walk(new WalkOptions(), e =>
                            {
                                if (e is SqlColumn column)
                                {
                                    if (column.Parent == collection.SelectQuery)
                                    {
                                        return(column.UnderlyingColumn);
                                    }
                                }
                                return(e);
                            });

                            foundJoin.Condition.Conditions.Clear();
                        }
                    }
                }

                context.Collection = new SubQueryContext(collection, sequence.SelectQuery, false);
                return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
            }

            if (!crossApply)
            {
                if (!leftJoin)
                {
                    context.Collection = new SubQueryContext(collection, sequence.SelectQuery, true);
                    return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context));
                }
                else
                {
                    var join = sql.OuterApply();
                    sequence.SelectQuery.From.Tables[0].Joins.Add(join.JoinedTable);
                    context.Collection = new SubQueryContext(collection, sequence.SelectQuery, false);

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

            void MoveSearchConditionsToJoin(SqlFromClause.Join join)
            {
                var tableSources = new HashSet <ISqlTableSource>();

                ((ISqlExpressionWalkable)sql.Where.SearchCondition).Walk(new WalkOptions(), e =>
                {
                    if (e is ISqlTableSource ts && !tableSources.Contains(ts))
                    {
                        tableSources.Add(ts);
                    }
                    return(e);
                });

                bool ContainsTable(ISqlTableSource tbl, IQueryElement qe)
                {
                    return(null != QueryVisitor.Find(qe, e =>
                                                     e == tbl ||
                                                     e.ElementType == QueryElementType.SqlField && tbl == ((SqlField)e).Table ||
                                                     e.ElementType == QueryElementType.Column && tbl == ((SqlColumn)e).Parent));
                }

                var conditions = sql.Where.SearchCondition.Conditions;

                if (conditions.Count > 0)
                {
                    for (var i = conditions.Count - 1; i >= 0; i--)
                    {
                        var condition = conditions[i];

                        if (!tableSources.Any(ts => ContainsTable(ts, condition)))
                        {
                            join.JoinedTable.Condition.Conditions.Insert(0, condition);
                            conditions.RemoveAt(i);
                        }
                    }
                }
            }
Exemple #5
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var outerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
            var innerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery()));

            List <SqlQueryExtension>?extensions = null;

            if (innerContext is QueryExtensionBuilder.JoinHintContext jhc)
            {
                innerContext = jhc.Context;
                extensions   = jhc.Extensions;
            }

            JoinType joinType;
            var      conditionIndex = 2;

            switch (methodCall.Method.Name)
            {
            case "InnerJoin": joinType = JoinType.Inner; break;

            case "CrossJoin": joinType = JoinType.Inner; conditionIndex = -1; break;

            case "LeftJoin": joinType = JoinType.Left;  break;

            case "RightJoin": joinType = JoinType.Right; break;

            case "FullJoin": joinType = JoinType.Full;  break;

            default:
                conditionIndex = 3;

                joinType = (SqlJoinType)methodCall.Arguments[2].EvaluateExpression() !switch
                {
                    SqlJoinType.Inner => JoinType.Inner,
                    SqlJoinType.Left => JoinType.Left,
                    SqlJoinType.Right => JoinType.Right,
                    SqlJoinType.Full => JoinType.Full,
                    _ => throw new InvalidOperationException($"Unexpected join type: {(SqlJoinType)methodCall.Arguments[2].EvaluateExpression()!}")
                };
                break;
            }

            if (joinType == JoinType.Right || joinType == JoinType.Full)
            {
                outerContext = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, outerContext, null);
            }
            outerContext = new SubQueryContext(outerContext);

            if (joinType == JoinType.Left || joinType == JoinType.Full)
            {
                innerContext = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, innerContext, null);
            }
            innerContext = new SubQueryContext(innerContext);

            var selector = (LambdaExpression)methodCall.Arguments[methodCall.Arguments.Count - 1].Unwrap();

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

            var joinContext = new JoinContext(buildInfo.Parent, selector, outerContext, innerContext)
#if DEBUG
            {
                Debug_MethodCall = methodCall
            }
#endif
            ;

            if (conditionIndex != -1)
            {
                var condition     = (LambdaExpression)methodCall.Arguments[conditionIndex].Unwrap();
                var conditionExpr = condition.GetBody(selector.Parameters[0], selector.Parameters[1]);

                conditionExpr = builder.ConvertExpression(conditionExpr);

                var join = new SqlFromClause.Join(joinType, innerContext.SelectQuery, null, false,
                                                  Array <SqlFromClause.Join> .Empty);

                outerContext.SelectQuery.From.Tables[0].Joins.Add(join.JoinedTable);

                if (extensions != null)
                {
                    join.JoinedTable.SqlQueryExtensions = extensions;
                }

                builder.BuildSearchCondition(
                    joinContext,
                    conditionExpr,
                    @join.JoinedTable.Condition.Conditions);
            }
            else
            {
                outerContext.SelectQuery.From.Table(innerContext.SelectQuery);
            }

            return(joinContext);
        }