protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); var collectionSelector = (LambdaExpression)methodCall.Arguments[1].Unwrap(); var resultSelector = (LambdaExpression)methodCall.Arguments[2].Unwrap(); var expr = collectionSelector.Body.Unwrap(); DefaultIfEmptyBuilder.DefaultIfEmptyContext?defaultIfEmpty = null; if (expr is MethodCallExpression mc && AllJoinsBuilder.IsMatchingMethod(mc, true)) { defaultIfEmpty = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, sequence, null); sequence = new SubQueryContext(defaultIfEmpty); defaultIfEmpty.Disabled = true; }
protected override IBuildContext BuildMethodCall(ExpressionBuilder builder, MethodCallExpression methodCall, BuildInfo buildInfo) { var sequence = builder.BuildSequence(new BuildInfo(buildInfo, methodCall.Arguments[0])); var collectionSelector = (LambdaExpression)methodCall.Arguments[1].Unwrap(); var resultSelector = (LambdaExpression)methodCall.Arguments[2].Unwrap(); if (sequence.SelectQuery.HasUnion || !sequence.SelectQuery.IsSimple) { sequence = new SubQueryContext(sequence); } var expr = collectionSelector.Body.Unwrap(); DefaultIfEmptyBuilder.DefaultIfEmptyContext defaultIfEmpty = null; if (expr is MethodCallExpression mc && AllJoinsBuilder.IsMatchingMethod(mc, true)) { defaultIfEmpty = new DefaultIfEmptyBuilder.DefaultIfEmptyContext(buildInfo.Parent, sequence, null); defaultIfEmpty.Disabled = true; sequence = new SubQueryContext(defaultIfEmpty); } var context = new SelectManyContext(buildInfo.Parent, collectionSelector, sequence); context.SetAlias(collectionSelector.Parameters[0].Name); var collectionInfo = new BuildInfo(context, expr, new SelectQuery()); var collection = builder.BuildSequence(collectionInfo); if (resultSelector.Parameters.Count > 1) { collection.SetAlias(resultSelector.Parameters[1].Name); } if (defaultIfEmpty != null && (collectionInfo.JoinType == JoinType.Right || collectionInfo.JoinType == JoinType.Full)) { defaultIfEmpty.Disabled = false; } var leftJoin = collection is DefaultIfEmptyBuilder.DefaultIfEmptyContext || collectionInfo.JoinType == JoinType.Left; var sql = collection.SelectQuery; var sequenceTables = new HashSet <ISqlTableSource>(sequence.SelectQuery.From.Tables[0].GetTables()); var newQuery = null != QueryVisitor.Find(sql, e => e == collectionInfo.SelectQuery); var crossApply = null != QueryVisitor.Find(sql, e => e.ElementType == QueryElementType.TableSource && sequenceTables.Contains((ISqlTableSource)e) || e.ElementType == QueryElementType.SqlField && sequenceTables.Contains(((SqlField)e).Table) || e.ElementType == QueryElementType.Column && sequenceTables.Contains(((SqlColumn)e).Parent)); if (collection is JoinBuilder.GroupJoinSubQueryContext queryContext) { var groupJoin = queryContext.GroupJoin; groupJoin.SelectQuery.From.Tables[0].Joins[0].JoinType = JoinType.Inner; groupJoin.SelectQuery.From.Tables[0].Joins[0].IsWeak = false; } if (!newQuery) { if (collection.SelectQuery.Select.HasModifier) { if (crossApply) { var foundJoin = context.SelectQuery.FindJoin(j => j.Table.Source == collection.SelectQuery); if (foundJoin != null) { foundJoin.JoinType = leftJoin ? JoinType.OuterApply : JoinType.CrossApply; collection.SelectQuery.Where.ConcatSearchCondition(foundJoin.Condition); ((ISqlExpressionWalkable)collection.SelectQuery.Where).Walk(new WalkOptions(), e => { if (e is SqlColumn column) { if (column.Parent == collection.SelectQuery) { return(column.UnderlyingColumn); } } return(e); }); foundJoin.Condition.Conditions.Clear(); } } } context.Collection = new SubQueryContext(collection, sequence.SelectQuery, false); return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context)); } if (!crossApply) { if (!leftJoin) { context.Collection = new SubQueryContext(collection, sequence.SelectQuery, true); return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context)); } else { var join = sql.OuterApply(); sequence.SelectQuery.From.Tables[0].Joins.Add(join.JoinedTable); context.Collection = new SubQueryContext(collection, sequence.SelectQuery, false); return(new SelectContext(buildInfo.Parent, resultSelector, sequence, context)); } } void MoveSearchConditionsToJoin(SqlFromClause.Join join) { var tableSources = new HashSet <ISqlTableSource>(); ((ISqlExpressionWalkable)sql.Where.SearchCondition).Walk(new WalkOptions(), e => { if (e is ISqlTableSource ts && !tableSources.Contains(ts)) { tableSources.Add(ts); } return(e); }); bool ContainsTable(ISqlTableSource tbl, IQueryElement qe) { return(null != QueryVisitor.Find(qe, e => e == tbl || e.ElementType == QueryElementType.SqlField && tbl == ((SqlField)e).Table || e.ElementType == QueryElementType.Column && tbl == ((SqlColumn)e).Parent)); } var conditions = sql.Where.SearchCondition.Conditions; if (conditions.Count > 0) { for (var i = conditions.Count - 1; i >= 0; i--) { var condition = conditions[i]; if (!tableSources.Any(ts => ContainsTable(ts, condition))) { join.JoinedTable.Condition.Conditions.Insert(0, condition); conditions.RemoveAt(i); } } } }