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

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

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

            return(sequence);
        }
示例#2
0
        internal static void BuildSetter(
            ExpressionBuilder builder,
            BuildInfo buildInfo,
            LambdaExpression setter,
            IBuildContext into,
            List <SelectQuery.SetExpression> items,
            IBuildContext sequence)
        {
            var path = Expression.Parameter(setter.Body.Type, "p");
            var ctx  = new ExpressionContext(buildInfo.Parent, sequence, setter);

            if (setter.Body.NodeType == ExpressionType.MemberInit)
            {
                var ex = (MemberInitExpression)setter.Body;
                var p  = sequence.Parent;

                BuildSetter(builder, into, items, ctx, ex, path);

                builder.ReplaceParent(ctx, p);
            }
            else
            {
                var sqlInfo = ctx.ConvertToSql(setter.Body, 0, ConvertFlags.All);

                foreach (var info in sqlInfo)
                {
                    if (info.Members.Count == 0)
                    {
                        throw new LinqException("Object initializer expected for insert statement.");
                    }

                    if (info.Members.Count != 1)
                    {
                        throw new InvalidOperationException();
                    }

                    var member = info.Members[0];
                    var pe     = Expression.MakeMemberAccess(path, member);
                    var column = into.ConvertToSql(pe, 1, ConvertFlags.Field);
                    var expr   = info.Sql;

                    items.Add(new SelectQuery.SetExpression(column[0].Sql, expr));
                }
            }
        }
示例#3
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.SelectQuery.WeakLeftJoin() : innerContext.SelectQuery.InnerJoin();
            var sql  = context.SelectQuery;

            sql.From.Tables[0].Joins.Add(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.JoinedTable.Condition, 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 '{outerKeySelector.Type}'.");
                    }

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

                    BuildJoin(builder, join.JoinedTable.Condition, outerKeyContext, arg1, innerKeyContext, arg2);
                }
            }
            else
            {
                BuildJoin(builder, join.JoinedTable.Condition, 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
                   );
        }
示例#4
0
        IBuildContext GetSubQueryContext(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo,
                                         SelectQuery 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).SelectQuery;

            // 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 '{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);
        }
示例#5
0
        protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo)
        {
            var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])
            {
                CreateSubQuery = true
            });

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

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

            var context = new AggregationContext(buildInfo.Parent, sequence, methodCall);
            var attr    = GetAggregateDefinition(methodCall, builder.MappingSchema);

            ISqlExpression sqlExpression = null;

            if (attr != null)
            {
                sqlExpression = attr.GetExpression(builder.MappingSchema, sequence.SelectQuery, methodCall, e =>
                {
                    var ex = e.Unwrap();

                    var l = ex as LambdaExpression;
                    if (l != null)
                    {
                        var p   = sequence.Parent;
                        var ctx = new ExpressionContext(buildInfo.Parent, sequence, l);

                        var res = builder.ConvertToSql(ctx, l.Body, true);

                        builder.ReplaceParent(ctx, p);
                        return(res);
                    }
                    return(builder.ConvertToSql(context, ex, true));
                });
            }

            if (sqlExpression == null)
            {
                var sql = sequence.ConvertToSql(null, 0, ConvertFlags.Field).Select(_ => _.Sql).ToArray();

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

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

                if (attr != null)
                {
                    sqlExpression = attr.GetExpression(methodCall.Method, sql);
                }
                else
                {
                    sqlExpression = new SqlFunction(methodCall.Type, methodCall.Method.Name, true, sql);
                }
            }

            if (sqlExpression == null)
            {
                throw new LinqToDBException("Invalid Aggregate function implementation");
            }

            context.Sql        = context.SelectQuery;
            context.FieldIndex = context.SelectQuery.Select.Add(sqlExpression, methodCall.Method.Name);

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

            var wrapped = false;

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

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

            SqlInfo[] sql;

            while (true)
            {
                var sparent = sequence.Parent;
                var order   = new ExpressionContext(buildInfo.Parent, sequence, lambda);
                var body    = lambda.Body.Unwrap();
                sql = builder.ConvertExpressions(order, body, ConvertFlags.Key, null);

                builder.ReplaceParent(order, sparent);

                if (wrapped)
                {
                    break;
                }

                // handle situation when order by uses complex field

                var isComplex = false;

                foreach (var sqlInfo in sql)
                {
                    // immutable expressions will be removed later
                    //
                    var isImmutable = QueryHelper.IsConstant(sqlInfo.Sql);
                    if (isImmutable)
                    {
                        continue;
                    }

                    // possible we have to extend this list
                    //
                    isComplex = null != new QueryVisitor().Find(sqlInfo.Sql,
                                                                e => e.ElementType == QueryElementType.SqlQuery);
                    if (isComplex)
                    {
                        break;
                    }
                }

                if (!isComplex)
                {
                    break;
                }

                sequence = new SubQueryContext(sequence);
                wrapped  = true;
            }


            if (!methodCall.Method.Name.StartsWith("Then") && !Configuration.Linq.DoNotClearOrderBys)
            {
                sequence.SelectQuery.OrderBy.Items.Clear();
            }

            foreach (var expr in sql)
            {
                // we do not need sorting by immutable values, like "Some", Func("Some"), "Some1" + "Some2". It does nothing for ordering
                //
                if (QueryHelper.IsConstant(expr.Sql))
                {
                    continue;
                }

                var e = builder.ConvertSearchCondition(expr.Sql);
                sequence.SelectQuery.OrderBy.Expr(e, methodCall.Method.Name.EndsWith("Descending"));
            }

            return(sequence);
        }
示例#7
0
        internal static void ParseSet(
            ExpressionBuilder builder,
            BuildInfo buildInfo,
            LambdaExpression extract,
            LambdaExpression update,
            IBuildContext select,
            SqlTable table,
            List <SelectQuery.SetExpression> items)
        {
            var ext = extract.Body;

            while (ext.NodeType == ExpressionType.Convert || ext.NodeType == ExpressionType.ConvertChecked)
            {
                ext = ((UnaryExpression)ext).Operand;
            }

            if (ext.NodeType != ExpressionType.MemberAccess || ext.GetRootObject(builder.MappingSchema) != extract.Parameters[0])
            {
                throw new LinqException("Member expression expected for the 'Set' statement.");
            }

            var body   = (MemberExpression)ext;
            var member = body.Member;

            if (member is MethodInfo)
            {
                member = ((MethodInfo)member).GetPropertyInfo();
            }

            var members = body.GetMembers();
            var name    = members
                          .Skip(1)
                          .Select(ex =>
            {
                var me = ex as MemberExpression;

                if (me == null)
                {
                    return(null);
                }

                var m = me.Member;

                if (m is MethodInfo)
                {
                    m = ((MethodInfo)m).GetPropertyInfo();
                }

                return(m);
            })
                          .Where(m => m != null && !m.IsNullableValueMember())
                          .Select(m => m.Name)
                          .Aggregate((s1, s2) => s1 + "." + s2);

            if (table != null && !table.Fields.ContainsKey(name))
            {
                throw new LinqException("Member '{0}.{1}' is not a table column.", member.DeclaringType.Name, name);
            }

            var column = table != null ?
                         table.Fields[name] :
                         select.ConvertToSql(
                body, 1, ConvertFlags.Field)[0].Sql;
            //Expression.MakeMemberAccess(Expression.Parameter(member.DeclaringType, "p"), member), 1, ConvertFlags.Field)[0].Sql;
            var sp   = select.Parent;
            var ctx  = new ExpressionContext(buildInfo.Parent, select, update);
            var expr = builder.ConvertToSqlExpression(ctx, update.Body);

            builder.ReplaceParent(ctx, sp);

            items.Add(new SelectQuery.SetExpression(column, expr));
        }