示例#1
0
        protected override Expression VisitMemberAccess(MemberExpression m)
        {
            Expression         source = this.Visit(m.Expression);
            DbEntityExpression ex     = source as DbEntityExpression;

            if (ex != null && this.mapping.IsAssociation(ex.Entity, m.Member))
            {
                DbProjectionExpression projection = (DbProjectionExpression)this.Visit(this.mapping.CreateMemberExpression(source, ex.Entity, m.Member));
                if (this.currentFrom != null && this.mapping.IsSingletonAssociation(ex.Entity, m.Member))
                {
                    // convert singleton associations directly to OUTER APPLY
                    projection = projection.AddOuterJoinTest();
                    Expression newFrom = new DbJoinExpression(DbJoinType.OuterApply, this.currentFrom, projection.Select, null);
                    this.currentFrom = newFrom;
                    return(projection.Projector);
                }
                return(projection);
            }
            else
            {
                Expression       result = QueryBinder.BindMember(source, m.Member);
                MemberExpression mex    = result as MemberExpression;
                if (mex != null && mex.Member == m.Member && mex.Expression == m.Expression)
                {
                    return(m);
                }
                return(result);
            }
        }
示例#2
0
        protected virtual Expression VisitProjection(DbProjectionExpression proj)
        {
            DbSelectExpression select    = (DbSelectExpression)Visit(proj.Select);
            Expression         projector = Visit(proj.Projector);

            return(UpdateProjection(proj, select, projector, proj.Aggregator));
        }
示例#3
0
        private Expression BindContains(Expression source, Expression match, bool isRoot)
        {
            ConstantExpression constSource = source as ConstantExpression;

            if (constSource != null && !IsQuery(constSource))
            {
                System.Diagnostics.Debug.Assert(!isRoot);
                List <Expression> values = new List <Expression>();
                foreach (object value in (IEnumerable)constSource.Value)
                {
                    values.Add(Expression.Constant(Convert.ChangeType(value, match.Type), match.Type));
                }
                match = this.Visit(match);
                return(new DbInExpression(match, values));
            }
            else if (isRoot && !this.mapping.Language.AllowSubqueryInSelectWithoutFrom)
            {
                var p         = Expression.Parameter(source.Type.GetSequenceElementType(), "x");
                var predicate = Expression.Lambda(p.Equal(match), p);
                var exp       = Expression.Call(typeof(Queryable), "Any", new Type[] { p.Type }, source, predicate);
                this.root = exp;
                return(this.Visit(exp));
            }
            else
            {
                DbProjectionExpression projection = this.VisitSequence(source);
                match = this.Visit(match);
                Expression result = new DbInExpression(match, projection.Select);
                if (isRoot)
                {
                    return(this.GetSingletonSequence(result, "SingleOrDefault"));
                }
                return(result);
            }
        }
示例#4
0
        private Expression BindFirst(Expression source, LambdaExpression predicate, string kind, bool isRoot)
        {
            DbProjectionExpression projection = this.VisitSequence(source);

            Expression where = null;
            if (predicate != null)
            {
                this.map[predicate.Parameters[0]] = projection.Projector;
                where = this.Visit(predicate.Body);
            }
            Expression take = kind.StartsWith("First") ? Expression.Constant(1) : null;

            if (take != null || where != null)
            {
                var alias           = this.GetNextAlias();
                ProjectedColumns pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias);
                projection = new DbProjectionExpression(
                    new DbSelectExpression(alias, pc.Columns, projection.Select, where, null, null, false, null, take),
                    pc.Projector
                    );
            }
            if (isRoot)
            {
                Type elementType          = projection.Projector.Type;
                ParameterExpression p     = Expression.Parameter(typeof(IEnumerable <>).MakeGenericType(elementType), "p");
                LambdaExpression    gator = Expression.Lambda(Expression.Call(typeof(Enumerable), kind, new Type[] { elementType }, p), p);
                return(new DbProjectionExpression(projection.Select, projection.Projector, gator));
            }
            return(projection);
        }
示例#5
0
        protected override Expression VisitProjection(DbProjectionExpression proj)
        {
            // don't parameterize the projector or aggregator!
            DbSelectExpression select = (DbSelectExpression)this.Visit(proj.Select);

            return(this.UpdateProjection(proj, select, proj.Projector, proj.Aggregator));
        }
 protected override Expression VisitProjection(DbProjectionExpression proj)
 {
     if (proj.Select.Skip != null)
     {
         Expression newTake = (proj.Select.Take != null) ? Expression.Add(proj.Select.Skip, proj.Select.Take) : null;
         if (newTake != null)
         {
             newTake = PartialEvaluator.Eval(newTake);
         }
         var newSelect   = proj.Select.SetSkip(null).SetTake(newTake);
         var elementType = proj.Type.GetSequenceElementType();
         var agg         = proj.Aggregator;
         var p           = agg != null ? agg.Parameters[0] : Expression.Parameter(elementType, "p");
         var skip        = Expression.Call(typeof(Enumerable), "Skip", new Type[] { elementType }, p, proj.Select.Skip);
         if (agg != null)
         {
             agg = (LambdaExpression)DbExpressionReplacer.Replace(agg, p, skip);
         }
         else
         {
             agg = Expression.Lambda(skip, p);
         }
         return(new DbProjectionExpression(newSelect, proj.Projector, agg));
     }
     return(proj);
 }
示例#7
0
        private Expression ExecuteProjection(DbProjectionExpression projection, bool okayToDefer, QueryCommand command, Expression[] values)
        {
            okayToDefer &= (this.receivingMember != null && this.policy.IsDeferLoaded(this.receivingMember));

            var saveScope = this.scope;
            ParameterExpression reader = Expression.Parameter(typeof(IDataReader), "r" + nReaders++);

            this.scope = new Scope(this.scope, reader, projection.Select.Alias, projection.Select.Columns);
            LambdaExpression projector = Expression.Lambda(this.Visit(projection.Projector), reader);

            this.scope = saveScope;

            string methExecute = okayToDefer
                ? "ExecuteDeferred"
                : "Execute";

            // call low-level execute directly on supplied DbQueryProvider
            Expression result = Expression.Call(this.provider, methExecute, new Type[] { projector.Body.Type },
                                                Expression.Constant(command),
                                                projector,
                                                Expression.NewArrayInit(typeof(object), values)
                                                );

            if (projection.Aggregator != null)
            {
                // apply aggregator
                result = DbExpressionReplacer.Replace(projection.Aggregator.Body, projection.Aggregator.Parameters[0], result);
            }
            return(result);
        }
示例#8
0
        protected virtual Expression BuildExecuteCommand(DbStatementExpression command)
        {
            // parameterize query
            var expression = this.Parameterize(command);

            string commandText = this.mapping.Language.Format(expression);
            ReadOnlyCollection <DbNamedValueExpression> namedValues = NamedValueGatherer.Gather(expression);
            QueryCommand qc = new QueryCommand(commandText, namedValues.Select(v => new QueryParameter(v.Name, v.Type, v.DbType)), null);

            Expression[] values = namedValues.Select(v => Expression.Convert(this.Visit(v.Value), typeof(object))).ToArray();

            DbProjectionExpression projection = ProjectionFinder.FindProjection(expression);

            if (projection != null)
            {
                return(this.ExecuteProjection(projection, false, qc, values));
            }

            Expression plan = Expression.Call(this.provider, "ExecuteCommand", null,
                                              Expression.Constant(qc),
                                              Expression.NewArrayInit(typeof(object), values)
                                              );

            return(plan);
        }
示例#9
0
        protected virtual Expression BindOrderBy(Type resultType, Expression source, LambdaExpression orderSelector, DbOrderType orderType)
        {
            List <DbOrderExpression> myThenBys = this.thenBys;

            this.thenBys = null;
            DbProjectionExpression projection = this.VisitSequence(source);

            this.map[orderSelector.Parameters[0]] = projection.Projector;
            List <DbOrderExpression> orderings = new List <DbOrderExpression>();

            orderings.Add(new DbOrderExpression(orderType, this.Visit(orderSelector.Body)));

            if (myThenBys != null)
            {
                for (int i = myThenBys.Count - 1; i >= 0; i--)
                {
                    DbOrderExpression tb     = myThenBys[i];
                    LambdaExpression  lambda = (LambdaExpression)tb.Expression;
                    this.map[lambda.Parameters[0]] = projection.Projector;
                    orderings.Add(new DbOrderExpression(tb.OrderType, this.Visit(lambda.Body)));
                }
            }

            var alias           = this.GetNextAlias();
            ProjectedColumns pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias);

            return(new DbProjectionExpression(
                       new DbSelectExpression(alias, pc.Columns, projection.Select, null, orderings.AsReadOnly(), null),
                       pc.Projector
                       ));
        }
 public DbClientJoinExpression(DbProjectionExpression projection, 
     IEnumerable<Expression> outerKey, IEnumerable<Expression> innerKey)
     : base(DbExpressionType.ClientJoin, projection.Type)
 {
     _outerKey = outerKey.AsReadOnly();
     _innerKey = innerKey.AsReadOnly();
     _projection = projection;
 }
 public DbClientJoinExpression(DbProjectionExpression projection,
                               IEnumerable <Expression> outerKey, IEnumerable <Expression> innerKey)
     : base(DbExpressionType.ClientJoin, projection.Type)
 {
     _outerKey   = outerKey.AsReadOnly();
     _innerKey   = innerKey.AsReadOnly();
     _projection = projection;
 }
示例#12
0
        protected override Expression VisitProjection(DbProjectionExpression projection)
        {
            // visit mapping in reverse order
            Expression         projector = this.Visit(projection.Projector);
            DbSelectExpression select    = (DbSelectExpression)this.Visit(projection.Select);

            return(this.UpdateProjection(projection, select, projector, projection.Aggregator));
        }
示例#13
0
        protected virtual Expression VisitClientJoin(DbClientJoinExpression join)
        {
            DbProjectionExpression          projection = (DbProjectionExpression)Visit(join.Projection);
            ReadOnlyCollection <Expression> outerKey   = VisitExpressionList(join.OuterKey);
            ReadOnlyCollection <Expression> innerKey   = VisitExpressionList(join.InnerKey);

            return(UpdateClientJoin(join, projection, outerKey, innerKey));
        }
        protected override Expression VisitProjection(DbProjectionExpression proj)
        {
            DbSelectExpression 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
                        DbSelectExpression newOuterSelect = (DbSelectExpression)QueryDuplicator.Duplicate(save);

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

                        DbTableAlias newAlias = new DbTableAlias();
                        var          pc       = ColumnProjector.ProjectColumns(this.language.CanBeColumn, newProjector, newOuterSelect.Columns, newAlias, newOuterSelect.Alias, newInnerSelect.Alias);

                        DbJoinExpression   join         = new DbJoinExpression(DbJoinType.OuterApply, newOuterSelect, newInnerSelect, null);
                        DbSelectExpression joinedSelect = new DbSelectExpression(newAlias, pc.Columns, join, null, null, null, proj.IsSingleton, null, null);

                        // 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, ((DbColumnExpression)k).Alias));
                            DbProjectionExpression newProjection = new DbProjectionExpression(joinedSelect, newProjector, proj.Aggregator);
                            return(new DbClientJoinExpression(newProjection, outerKey, innerKey));
                        }
                    }
                }
                else
                {
                    this.isTopLevel = false;
                }

                return(base.VisitProjection(proj));
            }
            finally
            {
                this.currentSelect = save;
            }
        }
        protected override Expression VisitProjection(DbProjectionExpression proj)
        {
            DbSelectExpression 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
                        DbSelectExpression newOuterSelect = (DbSelectExpression)QueryDuplicator.Duplicate(save);

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

                        DbTableAlias newAlias = new DbTableAlias();
                        var pc = ColumnProjector.ProjectColumns(this.language.CanBeColumn, newProjector, newOuterSelect.Columns, newAlias, newOuterSelect.Alias, newInnerSelect.Alias);

                        DbJoinExpression join = new DbJoinExpression(DbJoinType.OuterApply, newOuterSelect, newInnerSelect, null);
                        DbSelectExpression joinedSelect = new DbSelectExpression(newAlias, pc.Columns, join, null, null, null, proj.IsSingleton, null, null);

                        // 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, ((DbColumnExpression)k).Alias));
                            DbProjectionExpression newProjection = new DbProjectionExpression(joinedSelect, newProjector, proj.Aggregator);
                            return new DbClientJoinExpression(newProjection, outerKey, innerKey);
                        }
                    }
                }
                else
                {
                    this.isTopLevel = false;
                }

                return base.VisitProjection(proj);
            }
            finally 
            {
                this.currentSelect = save;
            }
        }
示例#16
0
        protected DbProjectionExpression UpdateProjection(DbProjectionExpression proj,
                                                          DbSelectExpression select, Expression projector, LambdaExpression aggregator)
        {
            if (select != proj.Select || projector != proj.Projector || aggregator != proj.Aggregator)
            {
                return(new DbProjectionExpression(select, projector, aggregator));
            }

            return(proj);
        }
示例#17
0
        protected DbClientJoinExpression UpdateClientJoin(DbClientJoinExpression join,
                                                          DbProjectionExpression projection, IEnumerable <Expression> outerKey,
                                                          IEnumerable <Expression> innerKey)
        {
            if (projection != join.Projection || outerKey != join.OuterKey || innerKey != join.InnerKey)
            {
                return(new DbClientJoinExpression(projection, outerKey, innerKey));
            }

            return(join);
        }
示例#18
0
        protected override Expression VisitClientJoin(DbClientJoinExpression join)
        {
            var innerKey = this.VisitExpressionList(join.InnerKey);
            var outerKey = this.VisitExpressionList(join.OuterKey);
            DbProjectionExpression projection = (DbProjectionExpression)this.Visit(join.Projection);

            if (projection != join.Projection || innerKey != join.InnerKey || outerKey != join.OuterKey)
            {
                return(new DbClientJoinExpression(projection, outerKey, innerKey));
            }
            return(join);
        }
示例#19
0
 protected override Expression VisitProjection(DbProjectionExpression projection)
 {
     if (this.isTop)
     {
         this.isTop = false;
         return(this.ExecuteProjection(projection, this.scope != null));
     }
     else
     {
         return(this.BuildInner(projection));
     }
 }
        public static DbProjectionExpression AddOuterJoinTest(this DbProjectionExpression proj)
        {
            string             colName      = proj.Select.Columns.GetAvailableColumnName("Test");
            DbSelectExpression newSource    = proj.Select.AddColumn(new DbColumnDeclaration(colName, Expression.Constant(1, typeof(int?))));
            Expression         newProjector =
                new DbOuterJoinedExpression(
                    new DbColumnExpression(typeof(int?), null, newSource.Alias, colName),
                    proj.Projector
                    );

            return(new DbProjectionExpression(newSource, newProjector, proj.Aggregator));
        }
示例#21
0
        private Expression BindDistinct(Expression source)
        {
            DbProjectionExpression projection = this.VisitSequence(source);
            DbSelectExpression     select     = projection.Select;
            var alias           = this.GetNextAlias();
            ProjectedColumns pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias);

            return(new DbProjectionExpression(
                       new DbSelectExpression(alias, pc.Columns, projection.Select, null, null, null, true, null, null),
                       pc.Projector
                       ));
        }
 protected override Expression VisitProjection(DbProjectionExpression proj)
 {
     proj = (DbProjectionExpression)base.VisitProjection(proj);
     if (proj.Select.From is DbSelectExpression) 
     {
         List<DbSelectExpression> redundant = RedundantSubqueryGatherer.Gather(proj.Select);
         if (redundant != null) 
         {
             proj = SubqueryRemover.Remove(proj, redundant);
         }
     }
     return proj;
 }
示例#23
0
 protected override Expression VisitProjection(DbProjectionExpression proj)
 {
     proj = (DbProjectionExpression)base.VisitProjection(proj);
     if (proj.Select.From is DbSelectExpression)
     {
         List <DbSelectExpression> redundant = RedundantSubqueryGatherer.Gather(proj.Select);
         if (redundant != null)
         {
             proj = SubqueryRemover.Remove(proj, redundant);
         }
     }
     return(proj);
 }
示例#24
0
        protected virtual Expression BuildExecuteBatch(BatchExpression batch)
        {
            // parameterize query
            Expression operation = this.Parameterize(batch.Operation.Body);

            string       commandText = this.mapping.Language.Format(operation);
            var          namedValues = NamedValueGatherer.Gather(operation);
            QueryCommand command     = new QueryCommand(commandText, namedValues.Select(v => new QueryParameter(v.Name, v.Type, v.DbType)), null);

            Expression[] values = namedValues.Select(v => Expression.Convert(this.Visit(v.Value), typeof(object))).ToArray();

            Expression paramSets = Expression.Call(typeof(Enumerable), "Select", new Type[] { batch.Operation.Parameters[1].Type, typeof(object[]) },
                                                   batch.Input,
                                                   Expression.Lambda(Expression.NewArrayInit(typeof(object), values), new[] { batch.Operation.Parameters[1] })
                                                   );

            Expression plan = null;

            DbProjectionExpression projection = ProjectionFinder.FindProjection(operation);

            if (projection != null)
            {
                var saveScope = this.scope;
                ParameterExpression reader = Expression.Parameter(typeof(IDataReader), "r" + nReaders++);
                this.scope = new Scope(this.scope, reader, projection.Select.Alias, projection.Select.Columns);
                LambdaExpression projector = Expression.Lambda(this.Visit(projection.Projector), reader);
                this.scope = saveScope;

                var columns = ColumnGatherer.Gather(projection.Projector);
                command = new QueryCommand(command.CommandText, command.Parameters, columns);

                plan = Expression.Call(this.provider, "ExecuteBatch", new Type[] { projector.Body.Type },
                                       Expression.Constant(command),
                                       paramSets,
                                       projector,
                                       batch.Size,
                                       batch.Stream
                                       );
            }
            else
            {
                plan = Expression.Call(this.provider, "ExecuteBatch", null,
                                       Expression.Constant(command),
                                       paramSets,
                                       batch.Size,
                                       batch.Stream
                                       );
            }

            return(plan);
        }
示例#25
0
        private Expression BindWhere(Type resultType, Expression source, LambdaExpression predicate)
        {
            DbProjectionExpression projection = this.VisitSequence(source);

            this.map[predicate.Parameters[0]] = projection.Projector;
            Expression where = this.Visit(predicate.Body);
            var alias           = this.GetNextAlias();
            ProjectedColumns pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias);

            return(new DbProjectionExpression(
                       new DbSelectExpression(alias, pc.Columns, projection.Select, where),
                       pc.Projector
                       ));
        }
示例#26
0
        private Expression BindSkip(Expression source, Expression skip)
        {
            DbProjectionExpression projection = this.VisitSequence(source);

            skip = this.Visit(skip);
            DbSelectExpression select = projection.Select;
            var alias           = this.GetNextAlias();
            ProjectedColumns pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias);

            return(new DbProjectionExpression(
                       new DbSelectExpression(alias, pc.Columns, projection.Select, null, null, null, false, skip, null),
                       pc.Projector
                       ));
        }
示例#27
0
        private Expression BindSelect(Type resultType, Expression source, LambdaExpression selector)
        {
            DbProjectionExpression projection = this.VisitSequence(source);

            this.map[selector.Parameters[0]] = projection.Projector;
            Expression       expression = this.Visit(selector.Body);
            var              alias      = this.GetNextAlias();
            ProjectedColumns pc         = this.ProjectColumns(expression, alias, projection.Select.Alias);

            return(new DbProjectionExpression(
                       new DbSelectExpression(alias, pc.Columns, projection.Select, null),
                       pc.Projector
                       ));
        }
示例#28
0
        protected virtual Expression BindSelectMany(Type resultType, Expression source, LambdaExpression collectionSelector, LambdaExpression resultSelector)
        {
            DbProjectionExpression projection = this.VisitSequence(source);

            this.map[collectionSelector.Parameters[0]] = projection.Projector;

            Expression collection = collectionSelector.Body;

            // check for DefaultIfEmpty
            bool defaultIfEmpty      = false;
            MethodCallExpression mcs = collection as MethodCallExpression;

            if (mcs != null && mcs.Method.Name == "DefaultIfEmpty" && mcs.Arguments.Count == 1 &&
                (mcs.Method.DeclaringType == typeof(Queryable) || mcs.Method.DeclaringType == typeof(Enumerable)))
            {
                collection     = mcs.Arguments[0];
                defaultIfEmpty = true;
            }

            DbProjectionExpression collectionProjection = (DbProjectionExpression)this.VisitSequence(collection);
            bool       isTable  = collectionProjection.Select.From is DbTableExpression;
            DbJoinType joinType = isTable ? DbJoinType.CrossJoin : defaultIfEmpty ? DbJoinType.OuterApply : DbJoinType.CrossApply;

            if (joinType == DbJoinType.OuterApply)
            {
                collectionProjection = collectionProjection.AddOuterJoinTest();
            }
            DbJoinExpression join = new DbJoinExpression(joinType, projection.Select, collectionProjection.Select, null);

            var alias = this.GetNextAlias();
            ProjectedColumns pc;

            if (resultSelector == null)
            {
                pc = this.ProjectColumns(collectionProjection.Projector, alias, projection.Select.Alias, collectionProjection.Select.Alias);
            }
            else
            {
                this.map[resultSelector.Parameters[0]] = projection.Projector;
                this.map[resultSelector.Parameters[1]] = collectionProjection.Projector;
                Expression result = this.Visit(resultSelector.Body);
                pc = this.ProjectColumns(result, alias, projection.Select.Alias, collectionProjection.Select.Alias);
            }
            return(new DbProjectionExpression(
                       new DbSelectExpression(alias, pc.Columns, join, null),
                       pc.Projector
                       ));
        }
示例#29
0
        protected override Expression VisitClientJoin(DbClientJoinExpression join)
        {
            // convert client join into a up-front lookup table builder & replace client-join in tree with lookup accessor

            // 1) lookup = query.Select(e => new KVP(key: inner, value: e)).ToLookup(kvp => kvp.Key, kvp => kvp.Value)
            Expression innerKey = MakeJoinKey(join.InnerKey);
            Expression outerKey = MakeJoinKey(join.OuterKey);

            ConstructorInfo        kvpConstructor  = typeof(KeyValuePair <,>).MakeGenericType(innerKey.Type, join.Projection.Projector.Type).GetConstructor(new Type[] { innerKey.Type, join.Projection.Projector.Type });
            Expression             constructKVPair = Expression.New(kvpConstructor, innerKey, join.Projection.Projector);
            DbProjectionExpression newProjection   = new DbProjectionExpression(join.Projection.Select, constructKVPair);

            int        iLookup   = ++nLookup;
            Expression execution = this.ExecuteProjection(newProjection, false);

            ParameterExpression kvp = Expression.Parameter(constructKVPair.Type, "kvp");

            // filter out nulls
            if (join.Projection.Projector.NodeType == (ExpressionType)DbExpressionType.OuterJoined)
            {
                LambdaExpression pred = Expression.Lambda(
                    Expression.PropertyOrField(kvp, "Value").NotEqual(TypeHelper.GetNullConstant(join.Projection.Projector.Type)),
                    kvp
                    );
                execution = Expression.Call(typeof(Enumerable), "Where", new Type[] { kvp.Type }, execution, pred);
            }

            // make lookup
            LambdaExpression keySelector     = Expression.Lambda(Expression.PropertyOrField(kvp, "Key"), kvp);
            LambdaExpression elementSelector = Expression.Lambda(Expression.PropertyOrField(kvp, "Value"), kvp);
            Expression       toLookup        = Expression.Call(typeof(Enumerable), "ToLookup", new Type[] { kvp.Type, outerKey.Type, join.Projection.Projector.Type }, execution, keySelector, elementSelector);

            // 2) agg(lookup[outer])
            ParameterExpression lookup   = Expression.Parameter(toLookup.Type, "lookup" + iLookup);
            PropertyInfo        property = lookup.Type.GetProperty("Item");
            Expression          access   = Expression.Call(lookup, property.GetGetMethod(), this.Visit(outerKey));

            if (join.Projection.Aggregator != null)
            {
                // apply aggregator
                access = DbExpressionReplacer.Replace(join.Projection.Aggregator.Body, join.Projection.Aggregator.Parameters[0], access);
            }

            this.variables.Add(lookup);
            this.initializers.Add(toLookup);

            return(access);
        }
示例#30
0
        protected override Expression VisitProjection(DbProjectionExpression proj)
        {
            if (isTopLevel)
            {
                isTopLevel         = false;
                this.currentSelect = proj.Select;
                Expression 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))
            {
                DbTableAlias newAlias = new DbTableAlias();
                this.currentSelect = this.currentSelect.AddRedundantSelect(newAlias);

                // remap any references to the outer select to the new alias;
                DbSelectExpression source = (DbSelectExpression)ColumnMapper.Map(proj.Select, newAlias, this.currentSelect.Alias);

                // add outer-join test
                DbProjectionExpression pex = new DbProjectionExpression(source, proj.Projector).AddOuterJoinTest();

                var pc = ColumnProjector.ProjectColumns(this.language.CanBeColumn, pex.Projector, this.currentSelect.Columns,
                                                        this.currentSelect.Alias, newAlias, proj.Select.Alias);

                DbJoinExpression join = new DbJoinExpression(DbJoinType.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;
            Expression result = base.VisitProjection(proj);

            this.isTopLevel    = saveTop;
            this.currentSelect = saveSelect;
            return(result);
        }
示例#31
0
        protected override Expression VisitExists(DbExistsExpression exists)
        {
            // how did we get here? Translate exists into count query
            var newSelect = exists.Select.SetColumns(
                new[] { new DbColumnDeclaration("value", new DbAggregateExpression(typeof(int), DbAggregateType.Count, null, false)) }
                );

            var projection =
                new DbProjectionExpression(
                    newSelect,
                    new DbColumnExpression(typeof(int), null, newSelect.Alias, "value"),
                    Aggregator.Aggregate(typeof(int), typeof(IEnumerable <int>))
                    );

            var expression = projection.GreaterThan(Expression.Constant(0));

            return(this.Visit(expression));
        }
示例#32
0
        private Expression ExecuteProjection(DbProjectionExpression projection, bool okayToDefer)
        {
            // parameterize query
            projection = (DbProjectionExpression)this.Parameterize(projection);

            if (this.scope != null)
            {
                // also convert references to outer alias to named values!  these become SQL parameters too
                projection = (DbProjectionExpression)OuterParameterizer.Parameterize(this.scope.Alias, projection);
            }

            string commandText = this.mapping.Language.Format(projection.Select);
            ReadOnlyCollection <DbNamedValueExpression> namedValues = NamedValueGatherer.Gather(projection.Select);
            QueryCommand command = new QueryCommand(commandText, namedValues.Select(v => new QueryParameter(v.Name, v.Type, v.DbType)), null);

            Expression[] values = namedValues.Select(v => Expression.Convert(this.Visit(v.Value), typeof(object))).ToArray();

            return(this.ExecuteProjection(projection, okayToDefer, command, values));
        }
        protected override Expression VisitProjection(DbProjectionExpression proj)
        {
            if (isTopLevel)
            {
                isTopLevel = false;
                this.currentSelect = proj.Select;
                Expression 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))
            {
                DbTableAlias newAlias = new DbTableAlias();
                this.currentSelect = this.currentSelect.AddRedundantSelect(newAlias);

                // remap any references to the outer select to the new alias;
                DbSelectExpression source = (DbSelectExpression)ColumnMapper.Map(proj.Select, newAlias, this.currentSelect.Alias);

                // add outer-join test
                DbProjectionExpression pex = new DbProjectionExpression(source, proj.Projector).AddOuterJoinTest();

                var pc = ColumnProjector.ProjectColumns(this.language.CanBeColumn, pex.Projector, this.currentSelect.Columns, 
                    this.currentSelect.Alias, newAlias, proj.Select.Alias);

                DbJoinExpression join = new DbJoinExpression(DbJoinType.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;
            Expression result = base.VisitProjection(proj);
            this.isTopLevel = saveTop;
            this.currentSelect = saveSelect;
            return result;
        }
示例#34
0
        protected override Expression VisitDeclaration(DbDeclaration decl)
        {
            if (decl.Source != null)
            {
                // make query that returns all these declared values as an object[]
                var projection = new DbProjectionExpression(
                    decl.Source,
                    Expression.NewArrayInit(
                        typeof(object),
                        decl.Variables.Select(v => v.Expression.Type.IsValueType
                            ? Expression.Convert(v.Expression, typeof(object))
                            : v.Expression).ToArray()
                        ),
                    Aggregator.Aggregate(typeof(object[]), typeof(IEnumerable <object[]>))
                    );

                // create execution variable to hold the array of declared variables
                var vars = Expression.Parameter(typeof(object[]), "vars");
                this.variables.Add(vars);
                this.initializers.Add(Expression.Constant(null, typeof(object[])));

                // create subsitution for each variable (so it will find the variable value in the new vars array)
                for (int i = 0, n = decl.Variables.Count; i < n; i++)
                {
                    var v = decl.Variables[i];
                    DbNamedValueExpression nv = new DbNamedValueExpression(
                        v.Name, v.DbType,
                        Expression.Convert(Expression.ArrayIndex(vars, Expression.Constant(i)), v.Expression.Type)
                        );
                    this.variableMap.Add(v.Name, nv);
                }

                // make sure the execution of the select stuffs the results into the new vars array
                return(MakeAssign(vars, this.Visit(projection)));
            }

            // probably bad if we get here since we must not allow mulitple commands
            throw new InvalidOperationException("Declaration query not allowed for this langauge");
        }
        protected override Expression VisitProjection(DbProjectionExpression proj)
        {
            // select * from table order by x skip s take t 
            // =>
            // select * from (select top s * from (select top s + t from table order by x) order by -x) order by x

            if (proj.Select.Skip != null && proj.Select.Take != null && proj.Select.OrderBy.Count > 0)
            {
                var skip = proj.Select.Skip;
                var take = proj.Select.Take;
                var select = proj.Select;
                var skipPlusTake = PartialEvaluator.Eval(Expression.Add(skip, take));

                select = proj.Select.SetTake(skipPlusTake).SetSkip(null);
                select = select.AddRedundantSelect(new DbTableAlias());
                select = select.SetTake(take);

                // propogate order-bys to new layer
                select = (DbSelectExpression)OrderByRewriter.Rewrite(select);
                var inverted = select.OrderBy.Select(ob => new DbOrderExpression(
                    ob.OrderType == DbOrderType.Ascending ? DbOrderType.Descending : DbOrderType.Ascending,
                    ob.Expression
                    ));
                select = select.SetOrderBy(inverted);

                select = select.AddRedundantSelect(new DbTableAlias());
                select = select.SetTake(Expression.Constant(0)); // temporary
                select = (DbSelectExpression)OrderByRewriter.Rewrite(select);
                var reverted = select.OrderBy.Select(ob => new DbOrderExpression(
                    ob.OrderType == DbOrderType.Ascending ? DbOrderType.Descending : DbOrderType.Ascending,
                    ob.Expression
                    ));
                select = select.SetOrderBy(reverted);
                select = select.SetTake(null);

                return new DbProjectionExpression(select, proj.Projector, proj.Aggregator);
            }
            return proj;
        }
 protected override Expression VisitProjection(DbProjectionExpression proj)
 {
     if (proj.Select.Skip != null)
     {
         Expression newTake = (proj.Select.Take != null) ? Expression.Add(proj.Select.Skip, proj.Select.Take) : null;
         if (newTake != null)
         {
             newTake = PartialEvaluator.Eval(newTake);
         }
         var newSelect = proj.Select.SetSkip(null).SetTake(newTake);
         var elementType = proj.Type.GetSequenceElementType();
         var agg = proj.Aggregator;
         var p = agg != null ? agg.Parameters[0] : Expression.Parameter(elementType, "p");
         var skip = Expression.Call(typeof(Enumerable), "Skip", new Type[]{elementType}, p, proj.Select.Skip);
         if (agg != null) {
             agg = (LambdaExpression)DbExpressionReplacer.Replace(agg, p, skip);
         }
         else {
             agg = Expression.Lambda(skip, p);
         }
         return new DbProjectionExpression(newSelect, proj.Projector, agg);
     }
     return proj;
 }
 protected DbClientJoinExpression UpdateClientJoin(DbClientJoinExpression join, 
     DbProjectionExpression projection, IEnumerable<Expression> outerKey, 
     IEnumerable<Expression> innerKey)
 {
     if (projection != join.Projection || outerKey != join.OuterKey || innerKey != join.InnerKey)
         return new DbClientJoinExpression(projection, outerKey, innerKey);
     
     return join;
 }
示例#38
0
 private Expression BindFirst(Expression source, LambdaExpression predicate, string kind, bool isRoot)
 {
     DbProjectionExpression projection = this.VisitSequence(source);
     Expression where = null;
     if (predicate != null)
     {
         this.map[predicate.Parameters[0]] = projection.Projector;
         where = this.Visit(predicate.Body);
     }
     Expression take = kind.StartsWith("First") ? Expression.Constant(1) : null;
     if (take != null || where != null)
     {
         var alias = this.GetNextAlias();
         ProjectedColumns pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias);
         projection = new DbProjectionExpression(
             new DbSelectExpression(alias, pc.Columns, projection.Select, where, null, null, false, null, take),
             pc.Projector
             );
     }
     if (isRoot)
     {
         Type elementType = projection.Projector.Type;
         ParameterExpression p = Expression.Parameter(typeof(IEnumerable<>).MakeGenericType(elementType), "p");
         LambdaExpression gator = Expression.Lambda(Expression.Call(typeof(Enumerable), kind, new Type[] { elementType }, p), p);
         return new DbProjectionExpression(projection.Select, projection.Projector, gator);
     }
     return projection;
 }
        protected virtual Expression VisitProjection(DbProjectionExpression proj)
        {
            DbSelectExpression select = (DbSelectExpression)Visit(proj.Select);
            Expression projector = Visit(proj.Projector);

            return UpdateProjection(proj, select, projector, proj.Aggregator);
        }
 protected DbProjectionExpression UpdateProjection(DbProjectionExpression proj, 
     DbSelectExpression select, Expression projector, LambdaExpression aggregator)
 {
     if (select != proj.Select || projector != proj.Projector || aggregator != proj.Aggregator)
         return new DbProjectionExpression(select, projector, aggregator);
     
     return proj;
 }
 protected override Expression VisitProjection(DbProjectionExpression projection)
 {
     // visit mapping in reverse order
     Expression projector = this.Visit(projection.Projector);
     DbSelectExpression select = (DbSelectExpression)this.Visit(projection.Select);
     return this.UpdateProjection(projection, select, projector, projection.Aggregator);
 }
 protected override Expression VisitProjection(DbProjectionExpression proj)
 {
     Expression projector = this.Visit(proj.Projector);
     return this.UpdateProjection(proj, proj.Select, projector, proj.Aggregator);
 }
示例#43
0
        protected virtual Expression BindGroupBy(Expression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector)
        {
            DbProjectionExpression projection = this.VisitSequence(source);

            this.map[keySelector.Parameters[0]] = projection.Projector;
            Expression keyExpr = this.Visit(keySelector.Body);

            Expression elemExpr = projection.Projector;
            if (elementSelector != null)
            {
                this.map[elementSelector.Parameters[0]] = projection.Projector;
                elemExpr = this.Visit(elementSelector.Body);
            }

            // Use ProjectColumns to get group-by expressions from key expression
            ProjectedColumns keyProjection = this.ProjectColumns(keyExpr, projection.Select.Alias, projection.Select.Alias);
            IEnumerable<Expression> groupExprs = keyProjection.Columns.Select(c => c.Expression);

            // make duplicate of source query as basis of element subquery by visiting the source again
            DbProjectionExpression subqueryBasis = this.VisitSequence(source);

            // recompute key columns for group expressions relative to subquery (need these for doing the correlation predicate)
            this.map[keySelector.Parameters[0]] = subqueryBasis.Projector;
            Expression subqueryKey = this.Visit(keySelector.Body);

            // use same projection trick to get group-by expressions based on subquery
            ProjectedColumns subqueryKeyPC = this.ProjectColumns(subqueryKey, subqueryBasis.Select.Alias, subqueryBasis.Select.Alias);
            IEnumerable<Expression> subqueryGroupExprs = subqueryKeyPC.Columns.Select(c => c.Expression);
            Expression subqueryCorrelation = this.BuildPredicateWithNullsEqual(subqueryGroupExprs, groupExprs);

            // compute element based on duplicated subquery
            Expression subqueryElemExpr = subqueryBasis.Projector;
            if (elementSelector != null)
            {
                this.map[elementSelector.Parameters[0]] = subqueryBasis.Projector;
                subqueryElemExpr = this.Visit(elementSelector.Body);
            }

            // build subquery that projects the desired element
            var elementAlias = this.GetNextAlias();
            ProjectedColumns elementPC = this.ProjectColumns(subqueryElemExpr, elementAlias, subqueryBasis.Select.Alias);
            DbProjectionExpression elementSubquery =
                new DbProjectionExpression(
                    new DbSelectExpression(elementAlias, elementPC.Columns, subqueryBasis.Select, subqueryCorrelation),
                    elementPC.Projector
                    );

            var alias = this.GetNextAlias();

            // make it possible to tie aggregates back to this group-by
            GroupByInfo info = new GroupByInfo(alias, elemExpr);
            this.groupByMap.Add(elementSubquery, info);

            Expression resultExpr;
            if (resultSelector != null)
            {
                Expression saveGroupElement = this.currentGroupElement;
                this.currentGroupElement = elementSubquery;
                // compute result expression based on key & element-subquery
                this.map[resultSelector.Parameters[0]] = keyProjection.Projector;
                this.map[resultSelector.Parameters[1]] = elementSubquery;
                resultExpr = this.Visit(resultSelector.Body);
                this.currentGroupElement = saveGroupElement;
            }
            else
            {
                // result must be IGrouping<K,E>
                resultExpr = 
                    Expression.New(
                        typeof(Grouping<,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type).GetConstructors()[0],
                        new Expression[] { keyExpr, elementSubquery }
                        );

                resultExpr = Expression.Convert(resultExpr, typeof(IGrouping<,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type));
            }

            ProjectedColumns pc = this.ProjectColumns(resultExpr, alias, projection.Select.Alias);

            // make it possible to tie aggregates back to this group-by
            NewExpression newResult = this.GetNewExpression(pc.Projector);
            if (newResult != null && newResult.Type.IsGenericType && newResult.Type.GetGenericTypeDefinition() == typeof(Grouping<,>))
            {
                Expression projectedElementSubquery = newResult.Arguments[1];
                this.groupByMap.Add(projectedElementSubquery, info);
            }

            return new DbProjectionExpression(
                new DbSelectExpression(alias, pc.Columns, projection.Select, null, null, groupExprs),
                pc.Projector
                );
        }
示例#44
0
 protected override Expression VisitProjection(DbProjectionExpression proj)
 {
     // treat these like scalar subqueries
     if (proj.Projector is DbColumnExpression)
     {
         this.Write("(");
         this.WriteLine(Indentation.Inner);
         this.Visit(proj.Select);
         this.Write(")");
         this.Indent(Indentation.Outer);
     }
     else
     {
         throw new NotSupportedException("Non-scalar projections cannot be translated to SQL.");
     }
     return proj;
 }
        protected virtual bool CompareProjection(DbProjectionExpression a, 
            DbProjectionExpression b)
        {
            if (!Compare(a.Select, b.Select))
                return false;

            ScopedDictionary<DbTableAlias, DbTableAlias> save = _aliasScope;
            try
            {
                _aliasScope = new ScopedDictionary<DbTableAlias, DbTableAlias>(_aliasScope);
                _aliasScope.Add(a.Select.Alias, b.Select.Alias);

                return Compare(a.Projector, b.Projector)
                    && Compare(a.Aggregator, b.Aggregator)
                    && a.IsSingleton == b.IsSingleton;
            }
            finally
            {
                _aliasScope = save;
            }
        }
 public static DbProjectionExpression Remove(DbProjectionExpression projection, params DbSelectExpression[] selectsToRemove)
 {
     return Remove(projection, (IEnumerable<DbSelectExpression>)selectsToRemove);
 }
 public static DbProjectionExpression Remove(DbProjectionExpression projection, IEnumerable<DbSelectExpression> selectsToRemove)
 {
     return (DbProjectionExpression)new SubqueryRemover(selectsToRemove).Visit(projection);
 }