Ejemplo n.º 1
0
        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;
            }
        }