protected abstract IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo);
protected abstract SequenceConvertInfo Convert(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param);
public bool IsSequence(ExpressionBuilder builder, BuildInfo buildInfo) { return (builder.IsSequence(new BuildInfo(buildInfo, ((MethodCallExpression)buildInfo.Expression).Arguments[0]))); }
protected abstract bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo);
public IBuildContext BuildSequence(ExpressionBuilder builder, BuildInfo buildInfo) { return(BuildMethodCall(builder, (MethodCallExpression)buildInfo.Expression, buildInfo)); }
public SequenceConvertInfo Convert(ExpressionBuilder builder, BuildInfo buildInfo, ParameterExpression param) { return(Convert(builder, (MethodCallExpression)buildInfo.Expression, buildInfo, param)); }
public SequenceConvertInfo Convert(ExpressionBuilder builder, BuildInfo buildInfo, ParameterExpression param) { return(null); }
private IBuildContext GetSubQueryContext(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ISelectQuery sql, LambdaExpression innerKeyLambda, Expression outerKeySelector, Expression innerKeySelector, IBuildContext outerKeyContext) { var subQueryContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery())); subQueryContext = new SubQueryContext(subQueryContext); var subQueryParent = subQueryContext.Parent; var subQueryKeyContext = new ExpressionContext(buildInfo.Parent, subQueryContext, innerKeyLambda); // Process SubQuery. // var subQuerySql = ((SubQueryContext)subQueryContext).Select; // Make join and where for the counter. // if (outerKeySelector.NodeType == ExpressionType.New) { var new1 = (NewExpression)outerKeySelector; var new2 = (NewExpression)innerKeySelector; for (var i = 0; i < new1.Arguments.Count; i++) { var arg1 = new1.Arguments[i]; var arg2 = new2.Arguments[i]; BuildSubQueryJoin(builder, outerKeyContext, arg1, arg2, subQueryKeyContext, subQuerySql); } } else if (outerKeySelector.NodeType == ExpressionType.MemberInit) { var mi1 = (MemberInitExpression)outerKeySelector; var mi2 = (MemberInitExpression)innerKeySelector; for (var i = 0; i < mi1.Bindings.Count; i++) { if (mi1.Bindings[i].Member != mi2.Bindings[i].Member) { throw new LinqException( "List of member inits does not match for entity type '{0}'.".Args(outerKeySelector.Type)); } var arg1 = ((MemberAssignment)mi1.Bindings[i]).Expression; var arg2 = ((MemberAssignment)mi2.Bindings[i]).Expression; BuildSubQueryJoin(builder, outerKeyContext, arg1, arg2, subQueryKeyContext, subQuerySql); } } else { BuildSubQueryJoin(builder, outerKeyContext, outerKeySelector, innerKeySelector, subQueryKeyContext, subQuerySql); } builder.ReplaceParent(subQueryKeyContext, subQueryParent); subQuerySql.ParentSelect = sql; subQuerySql.Select.Columns.Clear(); return(subQueryContext); }
protected override SequenceConvertInfo Convert( ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo, ParameterExpression param) { return(null); }
public bool CanBuild(ExpressionBuilder builder, BuildInfo buildInfo) { return(buildInfo.Expression is ChangeTypeExpression); }
protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { return(methodCall.Arguments.Count == 2 && methodCall.IsQueryable("Concat", "Union")); }
protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { return(builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]))); }
protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var isGroup = methodCall.Method.Name == "GroupJoin"; var outerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0], buildInfo.SelectQuery)); var innerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery())); var context = new SubQueryContext(outerContext); innerContext = isGroup ? new GroupJoinSubQueryContext(innerContext) : new SubQueryContext(innerContext); var join = isGroup ? innerContext.Select.WeakLeftJoin() : innerContext.Select.InnerJoin(); var sql = context.Select; sql.From.Tables.First.Value.Joins.AddLast(join.JoinedTable); var selector = (LambdaExpression)methodCall.Arguments[4].Unwrap(); context.SetAlias(selector.Parameters[0].Name); innerContext.SetAlias(selector.Parameters[1].Name); var outerKeyLambda = (LambdaExpression)methodCall.Arguments[2].Unwrap(); var innerKeyLambda = (LambdaExpression)methodCall.Arguments[3].Unwrap(); var outerKeySelector = outerKeyLambda.Body.Unwrap(); var innerKeySelector = innerKeyLambda.Body.Unwrap(); var outerParent = context.Parent; var innerParent = innerContext.Parent; var outerKeyContext = new ExpressionContext(buildInfo.Parent, context, outerKeyLambda); var innerKeyContext = new InnerKeyContext(buildInfo.Parent, innerContext, innerKeyLambda); // Make join and where for the counter. // if (outerKeySelector.NodeType == ExpressionType.New) { var new1 = (NewExpression)outerKeySelector; var new2 = (NewExpression)innerKeySelector; for (var i = 0; i < new1.Arguments.Count; i++) { var arg1 = new1.Arguments[i]; var arg2 = new2.Arguments[i]; BuildJoin(builder, join, outerKeyContext, arg1, innerKeyContext, arg2); } } else if (outerKeySelector.NodeType == ExpressionType.MemberInit) { var mi1 = (MemberInitExpression)outerKeySelector; var mi2 = (MemberInitExpression)innerKeySelector; for (var i = 0; i < mi1.Bindings.Count; i++) { if (mi1.Bindings[i].Member != mi2.Bindings[i].Member) { throw new LinqException( "List of member inits does not match for entity type '{0}'.".Args(outerKeySelector.Type)); } var arg1 = ((MemberAssignment)mi1.Bindings[i]).Expression; var arg2 = ((MemberAssignment)mi2.Bindings[i]).Expression; BuildJoin(builder, join, outerKeyContext, arg1, innerKeyContext, arg2); } } else { BuildJoin(builder, join, outerKeyContext, outerKeySelector, innerKeyContext, innerKeySelector); } builder.ReplaceParent(outerKeyContext, outerParent); builder.ReplaceParent(innerKeyContext, innerParent); if (isGroup) { var inner = (GroupJoinSubQueryContext)innerContext; inner.Join = join.JoinedTable; inner.GetSubQueryContext = () => GetSubQueryContext(builder, methodCall, buildInfo, sql, innerKeyLambda, outerKeySelector, innerKeySelector, outerKeyContext); return(new GroupJoinContext( buildInfo.Parent, selector, context, inner, methodCall.Arguments[1], outerKeyLambda, innerKeyLambda)); } return(new JoinContext(buildInfo.Parent, selector, context, innerContext) #if DEBUG { MethodCall = methodCall } #endif ); }
protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { return(methodCall.IsQueryable("Skip", "Take")); }
private ISequenceBuilder GetBuilder(ExpressionBuilder builder, BuildInfo buildInfo) { return(_builder ?? (_builder = builder.GetBuilder(buildInfo))); }
protected override SequenceConvertInfo Convert( ExpressionBuilder builder, MethodCallExpression originalMethodCall, BuildInfo buildInfo, ParameterExpression param) { var methodCall = originalMethodCall; var selector = (LambdaExpression)methodCall.Arguments[1].Unwrap(); var info = builder.ConvertSequence(new BuildInfo(buildInfo, methodCall.Arguments[0]), selector.Parameters[0]); if (info != null) { methodCall = (MethodCallExpression)methodCall.Transform( ex => ConvertMethod(methodCall, 0, info, selector.Parameters[0], ex)); selector = (LambdaExpression)methodCall.Arguments[1].Unwrap(); } if (param != null && !ReferenceEquals(param, builder.SequenceParameter)) { var list = GetExpressions(selector.Parameters[0], param, 0, selector.Body.Unwrap()) .OrderByDescending(path => path.Level) .ToList(); if (list.Count > 0) { var plist = list.Where(e => ReferenceEquals(e.Expr, selector.Parameters[0])).ToList(); if (plist.Count > 1) { list = list.Except(plist.Skip(1)).ToList(); } var p = plist.FirstOrDefault(); if (p == null) { var types = methodCall.Method.GetGenericArguments(); var mgen = methodCall.Method.GetGenericMethodDefinition(); var btype = typeof(ExpressionHoder <,>).MakeGenericType(types[0], selector.Body.Type); var fields = btype.GetFieldsEx(); var pold = selector.Parameters[0]; var psel = Expression.Parameter(types[0], pold.Name); methodCall = Expression.Call( methodCall.Object, mgen.MakeGenericMethod(types[0], btype), methodCall.Arguments[0], Expression.Lambda( Expression.MemberInit( Expression.New(btype), Expression.Bind(fields[0], psel), Expression.Bind(fields[1], selector.Body.Transform(e => e == pold ? psel : e))), psel)); selector = (LambdaExpression)methodCall.Arguments[1].Unwrap(); param = Expression.Parameter(selector.Body.Type, param.Name); list.Add(new SequenceConvertPath { Path = param, Expr = Expression.MakeMemberAccess(param, fields[1]), Level = 1 }); var expr = Expression.MakeMemberAccess(param, fields[0]); foreach (var t in list) { t.Expr = t.Expr.Transform(ex => ReferenceEquals(ex, pold) ? expr : ex); } return(new SequenceConvertInfo { Parameter = param, Expression = methodCall, ExpressionsToReplace = list }); } if (info?.ExpressionsToReplace != null) { foreach (var path in info.ExpressionsToReplace) { path.Path = path.Path.Transform(e => ReferenceEquals(e, info.Parameter) ? p.Path : e); path.Expr = path.Expr.Transform(e => ReferenceEquals(e, info.Parameter) ? p.Path : e); path.Level += p.Level; list.Add(path); } list = list.OrderByDescending(path => path.Level).ToList(); } if (list.Count > 1) { return(new SequenceConvertInfo { Parameter = param, Expression = methodCall, ExpressionsToReplace = list .Where(e => !ReferenceEquals(e, p)) .Select(ei => { ei.Expr = ei.Expr.Transform(e => ReferenceEquals(e, p.Expr) ? p.Path : e); return ei; }) .ToList() }); } } } if (!ReferenceEquals(methodCall, originalMethodCall)) { return new SequenceConvertInfo { Parameter = param, Expression = methodCall } } ; return(null); }
protected override bool CanBuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { return(methodCall.IsQueryable("Where", "Having")); }