示例#1
0
        protected override Expression VisitJoin(SqlJoinExpression join)
        {
            join = (SqlJoinExpression)base.VisitJoin(join);

            if (join.JoinType == SqlJoinType.CrossApply || join.JoinType == SqlJoinType.OuterApply)
            {
                if (join.Right is SqlTableExpression)
                {
                    return(new SqlJoinExpression(join.Type, SqlJoinType.Cross, join.Left, join.Right, null));
                }
                else
                {
                    if (@join.Right is SqlSelectExpression @select && select.Take == null && select.Skip == null && !SqlAggregateChecker.HasAggregates(select) && (select.GroupBy == null || select.GroupBy.Count == 0))
                    {
                        var selectWithoutWhere = select.ChangeWhere(null);
                        var referencedAliases  = SqlReferencedAliasGatherer.Gather(selectWithoutWhere);
                        var declaredAliases    = SqlDeclaredAliasGatherer.Gather(join.Left);

                        referencedAliases.IntersectWith(declaredAliases);

                        if (referencedAliases.Count == 0)
                        {
                            var where = select.Where;

                            select = selectWithoutWhere;

                            var pc = ColumnProjector.ProjectColumns(new Nominator(Nominator.CanBeColumn), where, select.Columns, select.Alias, SqlDeclaredAliasGatherer.Gather(select.From));

                            select = select.ChangeColumns(pc.Columns);
                            where  = pc.Projector;

                            var joinType = (where == null) ? SqlJoinType.Cross : (join.JoinType == SqlJoinType.CrossApply ? SqlJoinType.Inner : SqlJoinType.Left);

                            return(new SqlJoinExpression(typeof(void), joinType, join.Left, select, where));
                        }
                    }
                }
            }

            return(join);
        }
示例#2
0
        public virtual ProjectionExpression GetQueryExpression(IEntityMapping mapping)
        {
            Expression           projector;
            TableAlias           selectAlias;
            ProjectedColumns     pc;
            ProjectionExpression proj;

            var tableAlias = new TableAlias();

            selectAlias = new TableAlias();
            var table = new TableExpression(tableAlias, mapping);

            projector = this.GetEntityExpression(table, mapping);
            pc        = ColumnProjector.ProjectColumns(projector, null, selectAlias, tableAlias);

            proj = new ProjectionExpression(
                new SelectExpression(selectAlias, pc.Columns, table, null),
                pc.Projector
                );

            return((ProjectionExpression)ApplyPolicy(proj, mapping.EntityType));
        }
示例#3
0
    protected internal override Expression VisitProjection(ProjectionExpression proj)
    {
        Expression       projector;
        SelectExpression select = proj.Select;

        using (binder.SetCurrentSource(proj.Select))
            projector = this.Visit(proj.Projector);

        Alias            alias = binder.aliasGenerator.NextSelectAlias();
        ProjectedColumns pc    = ColumnProjector.ProjectColumns(projector, alias);

        projector = pc.Projector;

        select = new SelectExpression(alias, false, null, pc.Columns, select, null, null, null, 0);

        if (projector != proj.Projector)
        {
            return(new ProjectionExpression(select, projector, proj.UniqueFunction, proj.Type));
        }

        return(proj);
    }
示例#4
0
        public virtual Expression GetInsertResult(IEntityMapping mapping, Expression instance, LambdaExpression selector, Dictionary <MemberInfo, Expression> map)
        {
            var tableAlias = new TableAlias();
            var tex        = new TableExpression(tableAlias, mapping);
            var aggregator = Aggregator.GetAggregator(selector.Body.Type, typeof(IEnumerable <>).MakeGenericType(selector.Body.Type));

            Expression where = null;
            DeclarationCommand genIdCommand = null;
            var generatedIds = mapping.PrimaryKeys.Where(m => m.IsPrimaryKey && m.IsGenerated).ToList();

            if (generatedIds.Count > 0)
            {
                if (map == null || !generatedIds.Any(m => map.ContainsKey(m.Member)))
                {
                    var localMap = new Dictionary <MemberInfo, Expression>();
                    genIdCommand = this.GetGeneratedIdCommand(mapping, generatedIds, localMap);
                    map          = localMap;
                }

                // is this just a retrieval of one generated id member?
                var mex = selector.Body as MemberExpression;
                if (mex != null)
                {
                    var id = mapping.Get(mex.Member);
                    if (id != null && id.IsPrimaryKey && id.IsGenerated)
                    {
                        if (genIdCommand != null)
                        {
                            // just use the select from the genIdCommand
                            return(new ProjectionExpression(
                                       genIdCommand.Source,
                                       new ColumnExpression(mex.Type, genIdCommand.Variables[0].SqlType, genIdCommand.Source.Alias, genIdCommand.Source.Columns[0].Name),
                                       aggregator
                                       ));
                        }
                        else
                        {
                            TableAlias alias   = new TableAlias();
                            var        colType = id.SqlType;
                            return(new ProjectionExpression(
                                       new SelectExpression(alias, new[] { new ColumnDeclaration("", map[mex.Member], colType) }, null, null),
                                       new ColumnExpression(mex.Member.GetMemberType(), colType, alias, ""),
                                       aggregator
                                       ));
                        }
                    }

                    where = generatedIds.Select((m, i) =>
                                                this.GetMemberExpression(tex, mapping, m.Member).Equal(map[m.Member])
                                                ).Aggregate((x, y) => x.And(y));
                }
            }
            else
            {
                where = this.GetIdentityCheck(tex, mapping, instance);
            }

            Expression typeProjector = this.GetEntityExpression(tex, mapping);
            Expression selection     = DbExpressionReplacer.Replace(selector.Body, selector.Parameters[0], typeProjector);
            TableAlias newAlias      = new TableAlias();
            var        pc            = ColumnProjector.ProjectColumns(selection, null, newAlias, tableAlias);
            var        pe            = new ProjectionExpression(
                new SelectExpression(newAlias, pc.Columns, tex, where),
                pc.Projector,
                aggregator
                );

            if (genIdCommand != null)
            {
                return(new BlockCommand(genIdCommand, pe));
            }
            return(pe);
        }
示例#5
0
        /// <summary>
        /// Get an expression for a mapped property relative to a root expression.
        /// The root is either a TableExpression or an expression defining an entity instance.
        /// </summary>
        /// <param name="root"></param>
        /// <param name="member"></param>
        /// <returns></returns>
        public virtual Expression GetMemberExpression(Expression root, MemberInfo member)
        {
            if (IsRelationship(member))
            {
                Type rowType = GetRelatedType(member);
                ProjectionExpression projection = GetTableQuery(rowType);

                // make where clause for joining back to 'root'
                List <MemberInfo> declaredTypeMembers;
                List <MemberInfo> associatedMembers;
                GetAssociationKeys(member, out declaredTypeMembers, out associatedMembers);

                Expression where = null;
                for (int i = 0, n = associatedMembers.Count; i < n; i++)
                {
                    Expression equal = Expression.Equal(
                        GetMemberExpression(projection.Projector, associatedMembers[i]),
                        GetMemberExpression(root, declaredTypeMembers[i])
                        );
                    where = (where != null) ? Expression.And(where, equal) : equal;
                }

                TableAlias newAlias = new TableAlias();
                var        pc       = ColumnProjector.ProjectColumns(this.Language.CanBeColumn,
                                                                     projection.Projector,
                                                                     null,
                                                                     newAlias,
                                                                     projection.Source.Alias);

                LambdaExpression aggregator = GetAggregator(TypeHelper.GetMemberType(member),
                                                            typeof(IEnumerable <>).MakeGenericType(
                                                                pc.Projector.Type));
                return(new ProjectionExpression(
                           new SelectExpression(newAlias, pc.Columns, projection.Source, where),
                           pc.Projector,
                           aggregator
                           ));
            }
            var tableExpression = root as TableExpression;

            if (tableExpression != null)
            {
                if (IsColumn(member))
                {
                    IColumn column = null;
                    if (tableExpression.Table != null)
                    {
                        column = tableExpression.Table.GetColumnByPropertyName(member.Name);
                    }
                    var columnName = column != null?GetColumnName(column) : GetColumnName(member);

                    return(!string.IsNullOrEmpty(columnName)
                               ? new ColumnExpression(column,
                                                      TypeHelper.GetMemberType(member),
                                                      tableExpression.Alias,
                                                      columnName)
                               : root);
                }
                return(this.GetTypeProjection(root, TypeHelper.GetMemberType(member)));
            }
            return(QueryBinder.BindMember(root, member));
        }
示例#6
0
        protected override Expression VisitProjection(ProjectionExpression proj)
        {
            SelectExpression save = this.currentSelect;

            this.currentSelect = proj.Select;
            try
            {
                if (!this.isTopLevel)
                {
                    if (this.CanJoinOnClient(this.currentSelect))
                    {
                        // make a query that combines all the constraints from the outer queries into a single select
                        SelectExpression newOuterSelect = (SelectExpression)QueryDuplicator.Duplicate(save);

                        // remap any references to the outer select to the new alias;
                        SelectExpression newInnerSelect = (SelectExpression)ColumnMapper.Map(proj.Select, newOuterSelect.Alias, save.Alias);
                        // add outer-join test
                        ProjectionExpression newInnerProjection = this.language.AddOuterJoinTest(new ProjectionExpression(newInnerSelect, proj.Projector));
                        newInnerSelect = newInnerProjection.Select;
                        Expression newProjector = newInnerProjection.Projector;

                        TableAlias newAlias = new TableAlias();
                        var        pc       = ColumnProjector.ProjectColumns(this.language, newProjector, null, newAlias, newOuterSelect.Alias, newInnerSelect.Alias);

                        JoinExpression   join         = new JoinExpression(JoinType.OuterApply, newOuterSelect, newInnerSelect, null);
                        SelectExpression joinedSelect = new SelectExpression(newAlias, pc.Columns, join, null, null, null, proj.IsSingleton, null, null, false);

                        // apply client-join treatment recursively
                        this.currentSelect = joinedSelect;
                        newProjector       = this.Visit(pc.Projector);

                        // compute keys (this only works if join condition was a single column comparison)
                        List <Expression> outerKeys = new List <Expression>();
                        List <Expression> innerKeys = new List <Expression>();
                        if (this.GetEquiJoinKeyExpressions(newInnerSelect.Where, newOuterSelect.Alias, outerKeys, innerKeys))
                        {
                            // outerKey needs to refer to the outer-scope's alias
                            var outerKey = outerKeys.Select(k => ColumnMapper.Map(k, save.Alias, newOuterSelect.Alias));
                            // innerKey needs to refer to the new alias for the select with the new join
                            var innerKey = innerKeys.Select(k => ColumnMapper.Map(k, joinedSelect.Alias, ((ColumnExpression)k).Alias));
                            ProjectionExpression newProjection = new ProjectionExpression(joinedSelect, newProjector, proj.Aggregator);
                            return(new ClientJoinExpression(newProjection, outerKey, innerKey));
                        }
                    }
                    else
                    {
                        bool 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;
            }
        }