예제 #1
0
        internal static ProjectedColumns ProjectColumns(Func <Expression, bool> fnCanBeColumn, Expression expression, IEnumerable <ColumnDeclaration> existingColumns, TableAlias newAlias, IEnumerable <TableAlias> existingAliases)
        {
            var projector = new ColumnProjector(fnCanBeColumn, expression, existingColumns, newAlias, existingAliases);
            var expr      = projector.Visit(expression);

            return(new ProjectedColumns(expr, projector._columns.AsReadOnly()));
        }
예제 #2
0
        internal static Expression GetMemberExpression(Expression root, IProperty property)
        {
            var relationProprety = property as RelationProperty;

            if (relationProprety != null)
            {
                //所关联的实体类型
                var relMetadata = EntityMetadataUnity.GetEntityMetadata(relationProprety.RelationType);
                var projection  = GetTableQuery(relMetadata);

                Expression parentExp = null, childExp = null;
                var        ship = RelationshipUnity.GetRelationship(relationProprety);
                if (ship.ThisType != relationProprety.EntityType)
                {
                    parentExp = projection.Projector;
                    childExp  = root;
                }
                else
                {
                    parentExp = root;
                    childExp  = projection.Projector;
                }

                Expression where = null;
                for (int i = 0, n = ship.Keys.Count; i < n; i++)
                {
                    var equal = GetMemberExpression(parentExp, ship.Keys[i].ThisProperty)
                                .Equal(GetMemberExpression(childExp, ship.Keys[i].OtherProperty));
                    where = (where != null) ? Expression.And(where, equal) : equal;
                }

                var newAlias = new TableAlias();
                var pc       = ColumnProjector.ProjectColumns(CanBeColumnExpression, projection.Projector, null, newAlias, projection.Select.Alias);

                var aggregator = GetAggregator(property.Type, typeof(IEnumerable <>).MakeGenericType(pc.Projector.Type));
                var result     = new ProjectionExpression(
                    new SelectExpression(newAlias, pc.Columns, projection.Select, where),
                    pc.Projector, aggregator
                    );

                return(ApplyPolicy(result, property.Info.ReflectionInfo));
            }

            var table = root as TableExpression;

            if (table != null)
            {
                var sqProperty = property as SubqueryProperty;
                if (sqProperty != null)
                {
                    return(new SubqueryColumnExpression(property.Type, table.Alias, property.Info.FieldName, sqProperty.Subquery));
                }
                else if (property is ISavedProperty)
                {
                    return(new ColumnExpression(property.Type, table.Alias, property.Name, property.Info));
                }
            }
            return(QueryBinder.BindMember(root, property.Info.ReflectionInfo));
        }
예제 #3
0
        protected override Expression VisitProjection(ProjectionExpression proj)
        {
            var saved = currentSelect;

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

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

                        var newAlias     = new TableAlias();
                        var pc           = ColumnProjector.ProjectColumns(QueryUtility.CanBeColumnExpression, newProjector, newOuterSelect.Columns, newAlias, newOuterSelect.Alias, newInnerSelect.Alias);
                        var join         = new JoinExpression(JoinType.OuterApply, newOuterSelect, newInnerSelect, null);
                        var joinedSelect = new SelectExpression(newAlias, pc.Columns, join, null, null, null, proj.IsSingleton, null, null, null, false);

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

                        // compute keys (this only works if join condition was a single column comparison)
                        var outerKeys = new List <Expression>();
                        var innerKeys = new List <Expression>();

                        if (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, saved.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));
                            var newProjection = new ProjectionExpression(joinedSelect, newProjector, proj.Aggregator);
                            return(new ClientJoinExpression(newProjection, outerKey, innerKey));
                        }
                    }
                }
                else
                {
                    isTopLevel = false;
                }

                return(base.VisitProjection(proj));
            }
            finally
            {
                currentSelect = saved;
            }
        }
예제 #4
0
        internal static Expression GetMemberExpression(TranslateContext transContext, Expression root, IProperty property)
        {
            if (property is RelationProperty relationProprety)
            {
                //所关联的实体类型
                var relMetadata = EntityMetadataUnity.GetEntityMetadata(relationProprety.RelationalType);
                var projection  = GetTableQuery(transContext, relMetadata, false, false);

                Expression parentExp = null, childExp = null;
                var        ship = RelationshipUnity.GetRelationship(relationProprety);

                if (ship.ThisType != relationProprety.EntityType)
                {
                    parentExp = projection.Projector;
                    childExp  = root;
                }
                else
                {
                    parentExp = root;
                    childExp  = projection.Projector;
                }

                var where = ship.Keys.Select(r =>
                                             GetMemberExpression(transContext, parentExp, r.ThisProperty).Equal(GetMemberExpression(transContext, childExp, r.OtherProperty)))
                            .Aggregate(Expression.And);

                var newAlias = new TableAlias();
                var pc       = ColumnProjector.ProjectColumns(CanBeColumnExpression, projection.Projector, null, newAlias, projection.Select.Alias);

                var aggregator = GetAggregator(property.Type, typeof(IEnumerable <>).MakeGenericType(pc.Projector.Type));
                var result     = new ProjectionExpression(
                    new SelectExpression(newAlias, pc.Columns, projection.Select, where),
                    pc.Projector, aggregator, projection.IsAsync, projection.IsNoTracking
                    );

                return(transContext.QueryPolicy.ApplyPolicy(result, property.Info.ReflectionInfo, ex => QueryBinder.Bind(transContext, ex)));
            }

            if (root is TableExpression table)
            {
                if (property is SubqueryProperty sqProperty)
                {
                    return(new SubqueryColumnExpression(property.Type, table.Alias, property.Info.FieldName, sqProperty.Subquery));
                }
                else if (property is ISavedProperty)
                {
                    return(new ColumnExpression(property.Type, table.Alias, property.Name, property.Info));
                }
            }

            return(QueryBinder.BindMember(root, property.Info.ReflectionInfo));
        }
        protected override Expression VisitProjection(ProjectionExpression proj)
        {
            if (isTopLevel)
            {
                isTopLevel    = false;
                currentSelect = proj.Select;
                var projector = Visit(proj.Projector);

                if (projector != proj.Projector || currentSelect != proj.Select)
                {
                    return(new ProjectionExpression(currentSelect, projector, proj.Aggregator, proj.IsAsync));
                }

                return(proj);
            }

            if (proj.IsSingleton && CanJoinOnServer(currentSelect))
            {
                var newAlias = new TableAlias();
                currentSelect = currentSelect.AddRedundantSelect(newAlias);
                var source = (SelectExpression)ColumnMapper.Map(proj.Select, newAlias, currentSelect.Alias);
                var pex    = new ProjectionExpression(source, proj.Projector, proj.IsAsync).AddOuterJoinTest();
                var pc     = ColumnProjector.ProjectColumns(QueryUtility.CanBeColumnExpression, pex.Projector, currentSelect.Columns, currentSelect.Alias, newAlias, proj.Select.Alias);

                // **fix** 解决返回关联对象后使用Distinct的问题
                var join = CreateJoinExpression(currentSelect.From, pex.Select, out bool isDistinct);
                currentSelect = new SelectExpression(currentSelect.Alias, pc.Columns, join, null);
                if (isDistinct)
                {
                    var newPc = ColumnProjector.ProjectColumns(QueryUtility.CanBeColumnExpression, proj.Projector, null, currentSelect.Alias, proj.Select.Alias);
                    currentSelect = new SelectExpression(currentSelect.Alias, newPc.Columns, currentSelect, null, null, null, isDistinct, null, null, null, null, false);
                    return(Visit(newPc.Projector));
                }

                return(Visit(pc.Projector));
            }

            var saveTop    = isTopLevel;
            var saveSelect = currentSelect;

            isTopLevel    = true;
            currentSelect = null;

            var result = base.VisitProjection(proj);

            isTopLevel    = saveTop;
            currentSelect = saveSelect;

            return(result);
        }
예제 #6
0
        internal static ProjectionExpression GetTableQuery(EntityMetadata entity, bool isNoTracking)
        {
            var tableAlias  = new TableAlias();
            var selectAlias = new TableAlias();
            var entityType  = entity.EntityType;
            var table       = new TableExpression(tableAlias, entity.TableName, entityType);

            var projector = GetTypeProjection(table, entity, isNoTracking);
            var pc        = ColumnProjector.ProjectColumns(CanBeColumnExpression, projector, null, selectAlias, tableAlias);

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

            return((ProjectionExpression)ApplyPolicy(proj, entityType));
        }
예제 #7
0
        internal static ProjectionExpression GetTableQuery(TranslateContext transContext, EntityMetadata entity, bool isNoTracking, bool isAsync)
        {
            var tableAlias  = new TableAlias();
            var selectAlias = new TableAlias();
            var entityType  = entity.EntityType;
            var table       = new TableExpression(tableAlias, entity.TableName, entityType);

            var projector = GetTypeProjection(transContext, table, entity);
            var pc        = ColumnProjector.ProjectColumns(CanBeColumnExpression, projector, null, selectAlias, tableAlias);

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

            return((ProjectionExpression)transContext.QueryPolicy.ApplyPolicy(proj, entityType, ex => QueryBinder.Bind(transContext, ex)));
        }
예제 #8
0
        /// <summary>
        /// 访问 <see cref="JoinExpression"/>。
        /// </summary>
        /// <param name="join">要访问的表达式。</param>
        /// <returns></returns>
        protected override Expression VisitJoin(JoinExpression join)
        {
            join = (JoinExpression)base.VisitJoin(join);

            if (join.JoinType == JoinType.CrossApply || join.JoinType == JoinType.OuterApply)
            {
                if (join.Right is TableExpression)
                {
                    return(new JoinExpression(JoinType.CrossJoin, join.Left, join.Right, null));
                }
                else
                {
                    var select = join.Right as SelectExpression;
                    // Only consider rewriting cross apply if
                    //   1) right side is a select
                    //   2) other than in the where clause in the right-side select, no left-side declared aliases are referenced
                    //   3) and has no behavior that would change semantics if the where clause is removed (like groups, aggregates, take, skip, etc).
                    // Note: it is best to attempt this after redundant subqueries have been removed.
                    if (select != null &&
                        select.Take == null &&
                        select.Skip == null &&
                        !AggregateChecker.HasAggregates(select) &&
                        (select.GroupBy == null || select.GroupBy.Count == 0))
                    {
                        var selectWithoutWhere = select.SetWhere(null);
                        var referencedAliases  = ReferencedAliasGatherer.Gather(selectWithoutWhere);
                        var declaredAliases    = DeclaredAliasGatherer.Gather(join.Left);
                        referencedAliases.IntersectWith(declaredAliases);
                        if (referencedAliases.Count == 0)
                        {
                            var where = select.Where;
                            select    = selectWithoutWhere;
                            var pc = ColumnProjector.ProjectColumns(this.CanBeColumn, where, select.Columns, select.Alias, DeclaredAliasGatherer.Gather(select.From));
                            select = select.SetColumns(pc.Columns);
                            where  = pc.Projector;
                            var jt = (where == null) ? JoinType.CrossJoin : (join.JoinType == JoinType.CrossApply ? JoinType.InnerJoin : JoinType.LeftOuter);
                            return(new JoinExpression(jt, join.Left, select, where));
                        }
                    }
                }
            }

            return(join);
        }