protected override Expression VisitProjection(DbProjectionExpression proj) { if (isTopLevel) { isTopLevel = false; this.currentSelect = proj.Select; var projector = this.Visit(proj.Projector); if (projector != proj.Projector || this.currentSelect != proj.Select) { return(new DbProjectionExpression(this.currentSelect, projector, proj.Aggregator)); } return(proj); } if (proj.IsSingleton && this.CanJoinOnServer(this.currentSelect)) { var newAlias = new TableAlias(); this.currentSelect = this.currentSelect.AddRedundantSelect(this.language, newAlias); var source = DbColumnMapper.Map(proj.Select, newAlias, this.currentSelect.Alias) as DbSelectExpression; var pex = this.language.AddOuterJoinTest(new DbProjectionExpression(source, proj.Projector)); var pc = DbColumnProjector.ProjectColumns(this.language, pex.Projector, this.currentSelect.Columns, this.currentSelect.Alias, newAlias, proj.Select.Alias); var join = new DbJoinExpression(JoinType.OuterApply, this.currentSelect.From, pex.Select, null); this.currentSelect = new DbSelectExpression(this.currentSelect.Alias, pc.Columns, join, null); return(this.Visit(pc.Projector)); } var saveTop = this.isTopLevel; var saveSelect = this.currentSelect; this.isTopLevel = true; this.currentSelect = null; var result = base.VisitProjection(proj); this.isTopLevel = saveTop; this.currentSelect = saveSelect; return(result); }
protected override Expression VisitProjection(DbProjectionExpression proj) { var save = this.currentSelect; this.currentSelect = proj.Select; try { if (this.isTopLevel == false) { if (this.CanJoinOnClient(this.currentSelect)) { var newOuterSelect = DbQueryDuplicator.Duplicate(save) as DbSelectExpression; var newInnerSelect = DbColumnMapper.Map(proj.Select, newOuterSelect.Alias, save.Alias) as DbSelectExpression; var newInnerProjection = this.language.AddOuterJoinTest(new DbProjectionExpression(newInnerSelect, proj.Projector)); if (newInnerProjection != null) { newInnerSelect = newInnerProjection.Select; } var newProjector = newInnerProjection.Projector; var newAlias = new TableAlias(); var pc = DbColumnProjector.ProjectColumns(this.language, newProjector, null, newAlias, newOuterSelect.Alias, newInnerSelect.Alias); var join = new DbJoinExpression(JoinType.OuterApply, newOuterSelect, newInnerSelect, null); var joinedSelect = new DbSelectExpression(newAlias, pc.Columns, join, null, null, null, proj.IsSingleton, null, null, false); this.currentSelect = joinedSelect; if (pc != null) { newProjector = this.Visit(pc.Projector); } var outerKeys = new List <Expression>(); var innerKeys = new List <Expression>(); if (this.GetEquiJoinKeyExpressions(newInnerSelect.Where, newOuterSelect.Alias, outerKeys, innerKeys)) { var outerKey = outerKeys.Select(k => DbColumnMapper.Map(k, save.Alias, newOuterSelect.Alias)); var innerKey = innerKeys.Select(k => DbColumnMapper.Map(k, joinedSelect.Alias, ((DbColumnExpression)k).Alias)); var newProjection = new DbProjectionExpression(joinedSelect, newProjector, proj.Aggregator); return(new DbClientJoinExpression(newProjection, outerKey, innerKey)); } } else { var saveJoin = this.canJoinOnClient; this.canJoinOnClient = false; var result = base.VisitProjection(proj); this.canJoinOnClient = saveJoin; return(result); } } else { this.isTopLevel = false; } return(base.VisitProjection(proj)); } finally { this.currentSelect = save; } }