Beispiel #1
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);
        }
 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);
 }
Beispiel #3
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);
        }