Ejemplo n.º 1
0
        TableBuilder.TableContext GetTableContext(IBuildContext ctx, Expression path, out Expression?stopExpression)
        {
            stopExpression = null;

            var table = ctx as TableBuilder.TableContext;

            if (table != null)
            {
                return(table);
            }

            if (ctx is LoadWithContext lwCtx)
            {
                return(lwCtx.TableContext);
            }

            if (table == null)
            {
                var isTableResult = ctx.IsExpression(null, 0, RequestFor.Table);
                if (isTableResult.Result)
                {
                    table = isTableResult.Context as TableBuilder.TableContext;
                    if (table != null)
                    {
                        return(table);
                    }
                }
            }

            var maxLevel = path.GetLevel(ctx.Builder.MappingSchema);
            var level    = 1;

            while (level <= maxLevel)
            {
                var levelExpression = path.GetLevelExpression(ctx.Builder.MappingSchema, level);
                var isTableResult   = ctx.IsExpression(levelExpression, 1, RequestFor.Table);
                if (isTableResult.Result)
                {
                    table = isTableResult.Context switch
                    {
                        TableBuilder.TableContext t => t,
                        AssociationContext a => a.TableContext as TableBuilder.TableContext,
                                                  _ => null
                    };

                    if (table != null)
                    {
                        stopExpression = levelExpression;
                        return(table);
                    }
                }

                ++level;
            }

            var expr = path.GetLevelExpression(ctx.Builder.MappingSchema, 0);

            throw new LinqToDBException(
                      $"Unable to find table information for LoadWith. Consider moving LoadWith closer to GetTable<{expr.Type.Name}>() method.");
        }
Ejemplo n.º 2
0
        private static SelectQuery RemoveContextFromQuery(TableBuilder.TableContext tableContext, SelectQuery query)
        {
            var clonedTableSource = tableContext.SelectQuery.From.Tables[0];

            while (clonedTableSource.Joins.Count > 0)
            {
                var join = clonedTableSource.Joins[0];
                tableContext.SelectQuery.From.Tables.Add(join.Table);
                clonedTableSource.Joins.RemoveAt(0);
            }

            tableContext.SelectQuery.From.Tables.RemoveAt(0);
            query.Visit(query, static (query, e) =>
Ejemplo n.º 3
0
            protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
            {
                var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));
                var extract  = (LambdaExpression)methodCall.Arguments[1].Unwrap();
                var update   = methodCall.Arguments[2].Unwrap();

                if (!(sequence.Statement is SqlInsertStatement insertStatement))
                {
                    insertStatement    = new SqlInsertStatement(sequence.SelectQuery);
                    sequence.Statement = insertStatement;
                }

                if (insertStatement.Insert.Into == null)
                {
                    insertStatement.Insert.Into = (SqlTable)sequence.SelectQuery.From.Tables[0].Source;
                    insertStatement.SelectQuery.From.Tables.Clear();
                }

                if (update.NodeType == ExpressionType.Lambda)
                {
                    var fieldsContext = new TableBuilder.TableContext(builder, new SelectQuery(), insertStatement.Insert.Into);
                    UpdateBuilder.ParseSet(
                        builder,
                        buildInfo,
                        extract,
                        (LambdaExpression)update,
                        fieldsContext,
                        sequence,
                        insertStatement.Insert.Into,
                        insertStatement.Insert.Items);
                }
                else
                {
                    UpdateBuilder.ParseSet(
                        builder,
                        extract,
                        methodCall,
                        2,
                        sequence,
                        insertStatement.Insert.Items);
                }

                insertStatement.Insert.Items.RemoveDuplicatesFromTail((s1, s2) => s1.Column.Equals(s2.Column));

                return(sequence);
            }
Ejemplo n.º 4
0
        private static SelectQuery RemoveContextFromQuery(TableBuilder.TableContext tableContext, SelectQuery query)
        {
            var clonedTableSource = tableContext.SelectQuery.From.Tables[0];

            while (clonedTableSource.Joins.Count > 0)
            {
                var join = clonedTableSource.Joins[0];
                tableContext.SelectQuery.From.Tables.Add(join.Table);
                clonedTableSource.Joins.RemoveAt(0);
            }

            tableContext.SelectQuery.From.Tables.RemoveAt(0);
            var queryVisitor = new QueryVisitor();

            queryVisitor.Visit(query, e =>
            {
                if (e is SelectQuery selectQuery && selectQuery.From.Tables.Count > 0)
                {
                    if (selectQuery.From.Tables[0].Source is SelectQuery subSelect)
                    {
                        if (subSelect.From.Tables.Count == 0)
                        {
                            if (!subSelect.Where.IsEmpty)
                            {
                                selectQuery.Where.ConcatSearchCondition(subSelect.Where.SearchCondition);
                            }

                            selectQuery.From.Tables.RemoveAt(0);

                            query.Walk(new WalkOptions(), qe =>
                            {
                                if (qe is SqlColumn column && column.Parent == subSelect)
                                {
                                    return(column.Expression);
                                }

                                return(qe);
                            });
Ejemplo n.º 5
0
        public static IBuildContext BuildAssociationSelectMany(ExpressionBuilder builder, BuildInfo buildInfo, TableBuilder.TableContext tableContext,
                                                               AccessorMember onMember, AssociationDescriptor descriptor, ref bool isOuter)
        {
            var elementType = descriptor.GetElementType(builder.MappingSchema);

            var queryMethod = CreateAssociationQueryLambda(
                builder, onMember, descriptor, tableContext.OriginalType, tableContext.ObjectType, elementType,
                false, isOuter, tableContext.LoadWith, out isOuter);

            var parentRef = new ContextRefExpression(queryMethod.Parameters[0].Type, tableContext);
            var body      = queryMethod.GetBody(parentRef);

            IBuildContext context;

            context = builder.BuildSequence(new BuildInfo(buildInfo, body));
            context.SelectQuery.From.Tables[0].Alias = descriptor.GenerateAlias();

            return(context);
        }
Ejemplo n.º 6
0
        public static IBuildContext BuildAssociationInline(ExpressionBuilder builder, BuildInfo buildInfo, TableBuilder.TableContext tableContext,
                                                           AccessorMember onMember, AssociationDescriptor descriptor, bool inline, ref bool isOuter)
        {
            var elementType     = descriptor.GetElementType(builder.MappingSchema);
            var parentExactType = descriptor.GetParentElementType();

            var queryMethod = CreateAssociationQueryLambda(
                builder, onMember, descriptor, tableContext.OriginalType, parentExactType, elementType,
                inline, isOuter, tableContext.LoadWith, out isOuter);

            var parentRef = new ContextRefExpression(queryMethod.Parameters[0].Type, tableContext);
            var body      = queryMethod.GetBody(parentRef);

            var context = builder.BuildSequence(new BuildInfo(tableContext, body, new SelectQuery()));

            var tableSource = tableContext.SelectQuery.From.Tables.First();
            var join        = new SqlFromClause.Join(isOuter ? JoinType.OuterApply : JoinType.CrossApply, context.SelectQuery,
                                                     descriptor.GenerateAlias(), true, null);

            tableSource.Joins.Add(join.JoinedTable);

            return(new AssociationContext(builder, descriptor, tableContext, context, join.JoinedTable));
        }
Ejemplo n.º 7
0
 public LoadWithContext(IBuildContext context, TableBuilder.TableContext tableContext) : base(context)
 {
     _tableContext = tableContext;
 }
Ejemplo n.º 8
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

            var isSubQuery = sequence.SelectQuery.Select.IsDistinct;

            if (isSubQuery)
            {
                sequence = new SubQueryContext(sequence);
            }

            if (!(sequence.Statement is SqlInsertStatement insertStatement))
            {
                insertStatement    = new SqlInsertStatement(sequence.SelectQuery);
                sequence.Statement = insertStatement;
            }

            var insertType = InsertContext.InsertType.Insert;

            switch (methodCall.Method.Name)
            {
            case "Insert": insertType = InsertContext.InsertType.Insert;             break;

            case "InsertWithIdentity": insertType = InsertContext.InsertType.InsertWithIdentity; break;

            case "InsertWithOutput": insertType = InsertContext.InsertType.InsertOutput;       break;

            case "InsertWithOutputInto": insertType = InsertContext.InsertType.InsertOutputInto;   break;
            }

            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 (methodCall.Arguments.Count > 0)
            {
                var argument = methodCall.Arguments[0];
                if (typeof(IValueInsertable <>).IsSameOrParentOf(argument.Type) ||
                    typeof(ISelectInsertable <,>).IsSameOrParentOf(argument.Type))
                {
                    // static int Insert<T>              (this IValueInsertable<T> source)
                    // static int Insert<TSource,TTarget>(this ISelectInsertable<TSource,TTarget> source)

                    sequence.SelectQuery.Select.Columns.Clear();
                    foreach (var item in insertStatement.Insert.Items)
                    {
                        sequence.SelectQuery.Select.ExprNew(item.Expression !);
                    }
                }
                else if (methodCall.Arguments.Count > 1 &&
                         typeof(IQueryable <>).IsSameOrParentOf(argument.Type) &&
                         typeof(ITable <>).IsSameOrParentOf(methodCall.Arguments[1].Type))
                {
                    // static int Insert<TSource,TTarget>(this IQueryable<TSource> source, Table<TTarget> target, Expression<Func<TSource,TTarget>> setter)

                    var into   = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery()));
                    var setter = (LambdaExpression)GetArgumentByName("setter").Unwrap();

                    UpdateBuilder.BuildSetter(
                        builder,
                        buildInfo,
                        setter,
                        into,
                        insertStatement.Insert.Items,
                        sequence);

                    sequence.SelectQuery.Select.Columns.Clear();

                    foreach (var item in insertStatement.Insert.Items)
                    {
                        sequence.SelectQuery.Select.Columns.Add(new SqlColumn(sequence.SelectQuery, item.Expression !));
                    }

                    insertStatement.Insert.Into = ((TableBuilder.TableContext)into).SqlTable;
                }
                else if (typeof(ITable <>).IsSameOrParentOf(argument.Type))
                {
                    // static int Insert<T>(this Table<T> target, Expression<Func<T>> setter)
                    // static TTarget InsertWithOutput<TTarget>(this ITable<TTarget> target, Expression<Func<TTarget>> setter)
                    // static TTarget InsertWithOutput<TTarget>(this ITable<TTarget> target, Expression<Func<TTarget>> setter, Expression<Func<TTarget,TOutput>> outputExpression)
                    var argIndex            = 1;
                    var arg                 = methodCall.Arguments[argIndex].Unwrap();
                    LambdaExpression?setter = null;
                    switch (arg)
                    {
                    case LambdaExpression lambda:
                    {
                        setter = lambda;

                        UpdateBuilder.BuildSetter(
                            builder,
                            buildInfo,
                            setter,
                            sequence,
                            insertStatement.Insert.Items,
                            sequence);

                        break;
                    }

                    default:
                    {
                        var objType = arg.Type;

                        var ed   = builder.MappingSchema.GetEntityDescriptor(objType);
                        var into = sequence;
                        var ctx  = new TableBuilder.TableContext(builder, buildInfo, objType);

                        var table = new SqlTable(objType);

                        foreach (ColumnDescriptor c in ed.Columns.Where(c => !c.SkipOnInsert))
                        {
                            if (!table.Fields.TryGetValue(c.ColumnName, out var field))
                            {
                                continue;
                            }

                            var pe = Expression.MakeMemberAccess(arg, c.MemberInfo);

                            var column    = into.ConvertToSql(pe, 1, ConvertFlags.Field);
                            var parameter = builder.BuildParameterFromArgumentProperty(methodCall, argIndex, field.ColumnDescriptor);

                            insertStatement.Insert.Items.Add(new SqlSetExpression(column[0].Sql, parameter.SqlParameter));
                        }

                        var insertedTable = SqlTable.Inserted(methodCall.Method.GetGenericArguments()[0]);

                        break;
                    }
                    }

                    insertStatement.Insert.Into = ((TableBuilder.TableContext)sequence).SqlTable;
                    sequence.SelectQuery.From.Tables.Clear();
                }

                if (insertType == InsertContext.InsertType.InsertOutput || insertType == InsertContext.InsertType.InsertOutputInto)
                {
                    outputExpression = GetOutputExpression(methodCall.Method.GetGenericArguments().Last());

                    insertStatement.Output = new SqlOutputClause();

                    var insertedTable = SqlTable.Inserted(outputExpression.Parameters[0].Type);

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

                    insertStatement.Output.InsertedTable = insertedTable;

                    if (insertType == InsertContext.InsertType.InsertOutputInto)
                    {
                        var outputTable = GetArgumentByName("outputTable");
                        var destination = builder.BuildSequence(new BuildInfo(buildInfo, outputTable, new SelectQuery()));

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

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

            var insert = insertStatement.Insert;

            var q = insert.Into !.Fields.Values
                    .Except(insert.Items.Select(e => e.Column))
                    .OfType <SqlField>()
                    .Where(f => f.IsIdentity);

            foreach (var field in q)
            {
                var expr = builder.DataContext.CreateSqlProvider().GetIdentityExpression(insert.Into);

                if (expr != null)
                {
                    insert.Items.Insert(0, new SqlSetExpression(field, expr));

                    if (methodCall.Arguments.Count == 3)
                    {
                        sequence.SelectQuery.Select.Columns.Insert(0, new SqlColumn(sequence.SelectQuery, insert.Items[0].Expression !));
                    }
                }
            }

            insertStatement.Insert.WithIdentity = insertType == InsertContext.InsertType.InsertWithIdentity;
            sequence.Statement = insertStatement;

            if (insertType == InsertContext.InsertType.InsertOutput)
            {
                return(new InsertWithOutputContext(buildInfo.Parent, sequence, outputContext !, outputExpression !));
            }

            return(new InsertContext(buildInfo.Parent, sequence, insertType, outputExpression));
        }
Ejemplo n.º 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));
        }
Ejemplo n.º 10
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var mergeContext = (MergeContext)builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]));

            var kind = MergeKind.Merge;

            if (methodCall.IsSameGenericMethod(MergeWithOutputInto))
            {
                kind = MergeKind.MergeWithOutputInto;
            }
            else if (methodCall.IsSameGenericMethod(MergeWithOutput))
            {
                kind = MergeKind.MergeWithOutput;
            }

            if (kind != MergeKind.Merge)
            {
                var objectType = methodCall.Method.GetGenericArguments()[0];

                var actionField   = SqlField.FakeField(new DbDataType(typeof(string)), "$action", false);
                var insertedTable = SqlTable.Inserted(objectType);
                var deletedTable  = SqlTable.Deleted(objectType);

                mergeContext.Merge.Output = new SqlOutputClause()
                {
                    InsertedTable = insertedTable,
                    DeletedTable  = deletedTable,
                };

                var selectQuery = new SelectQuery();

                var actionFieldContext  = new SingleExpressionContext(null, builder, actionField, selectQuery);
                var deletedTableContext = new TableBuilder.TableContext(builder, selectQuery, deletedTable);
                var insertedTableConext = new TableBuilder.TableContext(builder, selectQuery, insertedTable);

                if (kind == MergeKind.MergeWithOutput)
                {
                    var outputExpression = (LambdaExpression)methodCall.Arguments[1].Unwrap();

                    var outputContext = new MergeOutputContext(
                        buildInfo.Parent,
                        outputExpression,
                        mergeContext,
                        actionFieldContext,
                        deletedTableContext,
                        insertedTableConext
                        );

                    return(outputContext);
                }
                else
                {
                    var outputExpression = (LambdaExpression)methodCall.Arguments[2].Unwrap();

                    var outputTable = methodCall.Arguments[1];
                    var destination = builder.BuildSequence(new BuildInfo(buildInfo, outputTable, new SelectQuery()));

                    UpdateBuilder.BuildSetterWithContext(
                        builder,
                        buildInfo,
                        outputExpression,
                        destination,
                        mergeContext.Merge.Output.OutputItems,
                        actionFieldContext,
                        deletedTableContext,
                        insertedTableConext
                        );

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

            return(mergeContext);
        }
Ejemplo n.º 11
0
            public override Expression BuildExpression(Expression expression, int level, bool enforceServerSide)
            {
                if (_isObject)
                {
                    if (expression == null)
                    {
                        var type  = _methodCall.Method.GetGenericArguments()[0];
                        var nctor = (NewExpression)Expression.Find(e => e is NewExpression ne && e.Type == type && ne.Arguments?.Count > 0);

                        Expression expr;

                        if (nctor != null)
                        {
                            var members = nctor.Members
                                          .Select(m => m is MethodInfo info ? info.GetPropertyInfo() : m)
                                          .ToList();

                            expr = Expression.New(
                                nctor.Constructor,
                                members.Select(m => Expression.PropertyOrField(_unionParameter, m.Name)),
                                members);

                            var ex = Builder.BuildExpression(this, expr, enforceServerSide);
                            return(ex);
                        }

                        var isNew = Expression.Find(e => e is NewExpression && e.Type == type) != null;
                        if (isNew)
                        {
                            var ta = TypeAccessor.GetAccessor(type);

                            expr = Expression.MemberInit(
                                Expression.New(ta.Type),
                                _members.Select(m =>
                                                Expression.Bind(m.Value.MemberExpression.Member, m.Value.MemberExpression)));
                            var ex = Builder.BuildExpression(this, expr, enforceServerSide);
                            return(ex);
                        }
                        else
                        {
                            var tableContext = new TableBuilder.TableContext(Builder,
                                                                             new BuildInfo((IBuildContext)null, Expression, new SelectQuery()), type);
                            var ex = tableContext.BuildExpression(null, 0, enforceServerSide);
                            return(ex);
                        }
                    }

                    if (level == 0 || level == 1)
                    {
                        var levelExpression = expression.GetLevelExpression(Builder.MappingSchema, 1);

                        if (ReferenceEquals(expression, levelExpression) && !IsExpression(expression, 1, RequestFor.Object).Result)
                        {
                            var idx = ConvertToIndex(expression, level, ConvertFlags.Field);
                            var n   = idx[0].Index;

                            if (Parent != null)
                            {
                                n = Parent.ConvertToParentIndex(n, this);
                            }

                            return(Builder.BuildSql(expression.Type, n));
                        }
                    }
                }

                var ret = _sequence1.BuildExpression(expression, level, enforceServerSide);

                //if (level == 1)
                //	_sequence2.BuildExpression(expression, level);

                return(ret);
            }