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)); }
static void BuildJoin( ExpressionBuilder builder, SqlFromClause.Join join, IBuildContext outerKeyContext, Expression outerKeySelector, IBuildContext innerKeyContext, Expression innerKeySelector) { var predicate = builder.ConvertObjectComparison( ExpressionType.Equal, outerKeyContext, outerKeySelector, innerKeyContext, innerKeySelector); if (predicate == null) { predicate = new SqlPredicate.ExprExpr( builder.ConvertToSql(outerKeyContext, outerKeySelector), SqlPredicate.Operator.Equal, builder.ConvertToSql(innerKeyContext, innerKeySelector)); predicate = builder.Convert(outerKeyContext, predicate); } join.JoinedTable.Condition.Conditions.Add(new SqlCondition(false, predicate)); }
protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var outerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0], buildInfo.SelectQuery)); var innerContext = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[1], new SelectQuery())); outerContext = new SubQueryContext(outerContext); 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); 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 (conditionIndex != -1) { var condition = (LambdaExpression)methodCall.Arguments[conditionIndex].Unwrap(); var conditionExpr = builder.ConvertExpression(condition.Body.Unwrap()); 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( new ExpressionContext(null, new[] { outerContext, innerContext }, condition), conditionExpr, join.JoinedTable.Condition.Conditions, false); } else { outerContext.SelectQuery.From.Table(innerContext.SelectQuery); } return(new SelectContext(buildInfo.Parent, selector, outerContext, innerContext) #if DEBUG { MethodCall = methodCall } #endif ); }
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; 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); builder.BuildSearchCondition( joinContext, conditionExpr, @join.JoinedTable.Condition.Conditions); } else { outerContext.SelectQuery.From.Table(innerContext.SelectQuery); } return(joinContext); }