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

            if (methodCall.Arguments.Count == 2)
            {
                if (sequence.SelectQuery.Select.TakeValue != null ||
                    sequence.SelectQuery.Select.SkipValue != null)
                {
                    sequence = new SubQueryContext(sequence);
                }

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

                if (methodCall.Method.Name == "All")
                {
                    condition = Expression.Lambda(Expression.Not(condition.Body), condition.Name, condition.Parameters);
                }

                sequence = builder.BuildWhere(buildInfo.Parent, sequence, condition, true);
                sequence.SetAlias(condition.Parameters[0].Name);
            }

            return(new AllAnyContext(buildInfo.Parent, methodCall, sequence));
        }
コード例 #2
0
        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 (methodCall.Arguments[conditionIndex] != null)
            {
                var condition = (LambdaExpression)methodCall.Arguments[conditionIndex].Unwrap();

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

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

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

            return(sequence);
        }
コード例 #3
0
ファイル: WhereBuilder.cs プロジェクト: zuiwanting/linq2db
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence  = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
            var condition = (LambdaExpression)methodCall.Arguments[1].Unwrap();
            var result    = builder.BuildWhere(buildInfo.Parent, sequence, condition, true);

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

            return(result);
        }
コード例 #4
0
ファイル: DeleteBuilder.cs プロジェクト: exileDev/linq2db
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var deleteType = methodCall.Method.Name switch
            {
                nameof(LinqExtensions.DeleteWithOutput) => DeleteContext.DeleteType.DeleteOutput,
                nameof(LinqExtensions.DeleteWithOutputInto) => DeleteContext.DeleteType.DeleteOutputInto,
                _ => DeleteContext.DeleteType.Delete,
            };

            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

            if (methodCall.Arguments.Count == 2 && deleteType == DeleteContext.DeleteType.Delete)
            {
                sequence = builder.BuildWhere(buildInfo.Parent, sequence, (LambdaExpression)methodCall.Arguments[1].Unwrap(), false);
            }

            var deleteStatement = new SqlDeleteStatement(sequence.SelectQuery);

            sequence.Statement = deleteStatement;

            // Check association.
            //

            if (sequence is SelectContext ctx && ctx.IsScalar)
            {
                var res = ctx.IsExpression(null, 0, RequestFor.Association);

                if (res.Result)
                {
                    var isTableResult = res.Context !.IsExpression(null, 0, RequestFor.Table);
                    if (!isTableResult.Result)
                    {
                        throw new LinqException("Can not retrieve Table context from association.");
                    }

                    var atc = (TableBuilder.TableContext)isTableResult.Context !;
                    deleteStatement.Table = atc.SqlTable;
                }
                else
                {
                    res = ctx.IsExpression(null, 0, RequestFor.Table);

                    if (res.Result && res.Context is TableBuilder.TableContext context)
                    {
                        var tc = context;

                        if (deleteStatement.SelectQuery.From.Tables.Count == 0 || deleteStatement.SelectQuery.From.Tables[0].Source != tc.SelectQuery)
                        {
                            deleteStatement.Table = tc.SqlTable;
                        }
                    }
                }
            }
コード例 #5
0
        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;

                joinType = (SqlJoinType)methodCall.Arguments[1].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[1].EvaluateExpression()!}")
                };
                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);
        }
    }
コード例 #6
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var isHaving  = methodCall.Method.Name == "Having";
            var sequence  = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
            var condition = (LambdaExpression)methodCall.Arguments[1].Unwrap();

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

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

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

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

            if (methodCall.Arguments.Count == 2)
            {
                sequence = builder.BuildWhere(buildInfo.Parent, sequence, (LambdaExpression)methodCall.Arguments[1].Unwrap(), false);
            }

            var deleteStatement = new SqlDeleteStatement(sequence.SelectQuery);

            sequence.Statement = deleteStatement;

            // Check association.
            //

            if (sequence is SelectContext ctx && ctx.IsScalar)
            {
                var res = ctx.IsExpression(null, 0, RequestFor.Association);

                if (res.Result && res.Context is TableBuilder.AssociatedTableContext)
                {
                    var atc = (TableBuilder.AssociatedTableContext)res.Context;
                    deleteStatement.Table = atc.SqlTable;
                }
                else
                {
                    res = ctx.IsExpression(null, 0, RequestFor.Table);

                    if (res.Result && res.Context is TableBuilder.TableContext)
                    {
                        var tc = (TableBuilder.TableContext)res.Context;

                        if (deleteStatement.SelectQuery.From.Tables.Count == 0 || deleteStatement.SelectQuery.From.Tables[0].Source != tc.SelectQuery)
                        {
                            deleteStatement.Table = tc.SqlTable;
                        }
                    }
                }
            }

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

            var updateStatement = sequence.Statement as SqlUpdateStatement ?? new SqlUpdateStatement(sequence.SelectQuery);

            sequence.Statement = updateStatement;

            switch (methodCall.Arguments.Count)
            {
            case 1:                     // int Update<T>(this IUpdateable<T> source)
            {
                CheckAssociation(sequence);
                break;
            }

            case 2:                      // int Update<T>(this IQueryable<T> source, Expression<Func<T,T>> setter)
            {
                CheckAssociation(sequence);

                if (sequence.SelectQuery.Select.SkipValue != null || !sequence.SelectQuery.Select.OrderBy.IsEmpty)
                {
                    sequence = new SubQueryContext(sequence);
                    updateStatement.SelectQuery = sequence.SelectQuery;
                    sequence.Statement          = updateStatement;
                }

                BuildSetter(
                    builder,
                    buildInfo,
                    (LambdaExpression)methodCall.Arguments[1].Unwrap(),
                    sequence,
                    updateStatement.Update.Items,
                    sequence);
                break;
            }

            case 3:
            {
                var expr = methodCall.Arguments[1].Unwrap();

                if (expr is LambdaExpression lex && lex.ReturnType == typeof(bool))
                {
                    CheckAssociation(sequence);

                    // int Update<T>(this IQueryable<T> source, Expression<Func<T,bool>> predicate, Expression<Func<T,T>> setter)
                    //
                    sequence = builder.BuildWhere(buildInfo.Parent, sequence, (LambdaExpression)methodCall.Arguments[1].Unwrap(), false);

                    if (sequence.SelectQuery.Select.SkipValue != null || !sequence.SelectQuery.Select.OrderBy.IsEmpty)
                    {
                        sequence = new SubQueryContext(sequence);
                    }

                    updateStatement.SelectQuery = sequence.SelectQuery;
                    sequence.Statement          = updateStatement;

                    BuildSetter(
                        builder,
                        buildInfo,
                        (LambdaExpression)methodCall.Arguments[2].Unwrap(),
                        sequence,
                        updateStatement.Update.Items,
                        sequence);
                }
コード例 #9
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var deleteType = methodCall.Method.Name switch
            {
                nameof(LinqExtensions.DeleteWithOutput) => DeleteContext.DeleteType.DeleteOutput,
                nameof(LinqExtensions.DeleteWithOutputInto) => DeleteContext.DeleteType.DeleteOutputInto,
                _ => DeleteContext.DeleteType.Delete,
            };

            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

            if (methodCall.Arguments.Count == 2 && deleteType == DeleteContext.DeleteType.Delete)
            {
                sequence = builder.BuildWhere(buildInfo.Parent, sequence, (LambdaExpression)methodCall.Arguments[1].Unwrap(), false);
            }

            var deleteStatement = new SqlDeleteStatement(sequence.SelectQuery);

            sequence.Statement = deleteStatement;

            // Check association.
            //

            if (sequence is SelectContext ctx && ctx.IsScalar)
            {
                var res = ctx.IsExpression(null, 0, RequestFor.Association);

                if (res.Result)
                {
                    var isTableResult = res.Context !.IsExpression(null, 0, RequestFor.Table);
                    if (!isTableResult.Result)
                    {
                        throw new LinqException("Can not retrieve Table context from association.");
                    }

                    var atc = (TableBuilder.TableContext)isTableResult.Context !;
                    deleteStatement.Table = atc.SqlTable;
                }
                else
                {
                    res = ctx.IsExpression(null, 0, RequestFor.Table);

                    if (res.Result && res.Context is TableBuilder.TableContext context)
                    {
                        var tc = context;

                        if (deleteStatement.SelectQuery.From.Tables.Count == 0 || deleteStatement.SelectQuery.From.Tables[0].Source != tc.SelectQuery)
                        {
                            deleteStatement.Table = tc.SqlTable;
                        }
                    }
                }
            }

            var indexedParameters
                = methodCall.Method.GetParameters().Select((p, i) => Tuple.Create(p, i)).ToDictionary(t => t.Item1.Name, t => t.Item2);

            Expression GetArgumentByName(string name)
            {
                return(methodCall.Arguments[indexedParameters[name]]);
            }

            LambdaExpression GetOutputExpression(Type outputType)
            {
                if (!indexedParameters.TryGetValue("outputExpression", out var index))
                {
                    var param = Expression.Parameter(outputType);
                    return(Expression.Lambda(param, param));
                }

                return((LambdaExpression)methodCall.Arguments[index].Unwrap());
            }

            IBuildContext?   outputContext    = null;
            LambdaExpression?outputExpression = null;

            if (deleteType != DeleteContext.DeleteType.Delete)
            {
                outputExpression = GetOutputExpression(methodCall.Method.GetGenericArguments().Last());

                deleteStatement.Output = new SqlOutputClause();

                var deletedTable = SqlTable.Deleted(methodCall.Method.GetGenericArguments()[0]);

                outputContext = new TableBuilder.TableContext(builder, new SelectQuery(), deletedTable);

                deleteStatement.Output.DeletedTable = deletedTable;

                if (deleteType == DeleteContext.DeleteType.DeleteOutputInto)
                {
                    var outputTable = GetArgumentByName("outputTable");
                    var destination = builder.BuildSequence(new BuildInfo(buildInfo, outputTable, new SelectQuery()));

                    UpdateBuilder.BuildSetter(
                        builder,
                        buildInfo,
                        outputExpression,
                        destination,
                        deleteStatement.Output.OutputItems,
                        outputContext);

                    deleteStatement.Output.OutputTable = ((TableBuilder.TableContext)destination).SqlTable;
                }
            }

            if (deleteType == DeleteContext.DeleteType.DeleteOutput)
            {
                return(new DeleteWithOutputContext(buildInfo.Parent, sequence, outputContext !, outputExpression !));
            }

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

            switch (methodCall.Arguments.Count)
            {
            case 1:                      // int Update<T>(this IUpdateable<T> source)
                CheckAssociation(sequence);
                break;

            case 2:                      // int Update<T>(this IQueryable<T> source, Expression<Func<T,T>> setter)
            {
                CheckAssociation(sequence);

                if (sequence.SelectQuery.Select.SkipValue != null || !sequence.SelectQuery.Select.OrderBy.IsEmpty)
                {
                    sequence = new SubQueryContext(sequence);
                }

                BuildSetter(
                    builder,
                    buildInfo,
                    (LambdaExpression)methodCall.Arguments[1].Unwrap(),
                    sequence,
                    sequence.SelectQuery.Update.Items,
                    sequence);
                break;
            }

            case 3:
            {
                var expr = methodCall.Arguments[1].Unwrap();

                if (expr is LambdaExpression && ((LambdaExpression)expr).ReturnType == typeof(bool))
                {
                    CheckAssociation(sequence);

                    // int Update<T>(this IQueryable<T> source, Expression<Func<T,bool>> predicate, Expression<Func<T,T>> setter)
                    //
                    sequence = builder.BuildWhere(buildInfo.Parent, sequence, (LambdaExpression)methodCall.Arguments[1].Unwrap(), false);

                    if (sequence.SelectQuery.Select.SkipValue != null || !sequence.SelectQuery.Select.OrderBy.IsEmpty)
                    {
                        sequence = new SubQueryContext(sequence);
                    }

                    BuildSetter(
                        builder,
                        buildInfo,
                        (LambdaExpression)methodCall.Arguments[2].Unwrap(),
                        sequence,
                        sequence.SelectQuery.Update.Items,
                        sequence);
                }
                else
                {
                    IBuildContext into;

                    if (expr is LambdaExpression)
                    {
                        // static int Update<TSource,TTarget>(this IQueryable<TSource> source, Expression<Func<TSource,TTarget>> target, Expression<Func<TSource,TTarget>> setter)
                        //
                        var body      = ((LambdaExpression)expr).Body;
                        int level     = body.GetLevel();
                        var tableInfo = sequence.IsExpression(body, level, RequestFor.Table);

                        if (tableInfo.Result == false)
                        {
                            throw new LinqException("Expression '{0}' must be a table.");
                        }

                        into = tableInfo.Context;
                    }
                    else
                    {
                        // static int Update<TSource,TTarget>(this IQueryable<TSource> source, Table<TTarget> target, Expression<Func<TSource,TTarget>> setter)
                        //
                        into = builder.BuildSequence(new BuildInfo(buildInfo, expr, new SelectQuery()));
                    }

                    sequence.ConvertToIndex(null, 0, ConvertFlags.All);
                    new SelectQueryOptimizer(builder.DataContext.SqlProviderFlags, sequence.SelectQuery)
                    .ResolveWeakJoins(new List <ISqlTableSource>());
                    sequence.SelectQuery.Select.Columns.Clear();

                    BuildSetter(
                        builder,
                        buildInfo,
                        (LambdaExpression)methodCall.Arguments[2].Unwrap(),
                        into,
                        sequence.SelectQuery.Update.Items,
                        sequence);

                    var sql = sequence.SelectQuery;

                    sql.Select.Columns.Clear();

                    foreach (var item in sql.Update.Items)
                    {
                        sql.Select.Columns.Add(new SelectQuery.Column(sql, item.Expression));
                    }

                    sql.Update.Table = ((TableBuilder.TableContext)into).SqlTable;
                }

                break;
            }
            }

            sequence.SelectQuery.ChangeQueryType(QueryType.Update);

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

            switch (methodCall.Arguments.Count)
            {
            case 1:                      // int Update<T>(this IUpdateable<T> source)
                CheckAssociation(sequence);
                break;

            case 2:                      // int Update<T>(this IQueryable<T> source, Expression<Func<T,T>> setter)
            {
                CheckAssociation(sequence);

                BuildSetter(
                    builder,
                    buildInfo,
                    (LambdaExpression)methodCall.Arguments[1].Unwrap(),
                    sequence,
                    sequence.SelectQuery.Update.Items,
                    sequence);
                break;
            }

            case 3:
            {
                var expr = methodCall.Arguments[1].Unwrap();

                if (expr is LambdaExpression)
                {
                    CheckAssociation(sequence);

                    // int Update<T>(this IQueryable<T> source, Expression<Func<T,bool>> predicate, Expression<Func<T,T>> setter)
                    //
                    sequence = builder.BuildWhere(buildInfo.Parent, sequence, (LambdaExpression)methodCall.Arguments[1].Unwrap(), false);

                    BuildSetter(
                        builder,
                        buildInfo,
                        (LambdaExpression)methodCall.Arguments[2].Unwrap(),
                        sequence,
                        sequence.SelectQuery.Update.Items,
                        sequence);
                }
                else
                {
                    // static int Update<TSource,TTarget>(this IQueryable<TSource> source, Table<TTarget> target, Expression<Func<TSource,TTarget>> setter)
                    //
                    var into = builder.BuildSequence(new BuildInfo(buildInfo, expr, new SelectQuery()));

                    sequence.ConvertToIndex(null, 0, ConvertFlags.All);
                    new SelectQueryOptimizer(builder.DataContextInfo.SqlProviderFlags, sequence.SelectQuery)
                    .ResolveWeakJoins(new List <ISqlTableSource>());
                    sequence.SelectQuery.Select.Columns.Clear();

                    BuildSetter(
                        builder,
                        buildInfo,
                        (LambdaExpression)methodCall.Arguments[2].Unwrap(),
                        into,
                        sequence.SelectQuery.Update.Items,
                        sequence);

                    var sql = sequence.SelectQuery;

                    sql.Select.Columns.Clear();

                    foreach (var item in sql.Update.Items)
                    {
                        sql.Select.Columns.Add(new SelectQuery.Column(sql, item.Expression));
                    }

                    sql.Update.Table = ((TableBuilder.TableContext)into).SqlTable;
                }

                break;
            }
            }

            sequence.SelectQuery.QueryType = QueryType.Update;

            return(new UpdateContext(buildInfo.Parent, sequence));
        }