protected ClientJoinExpression UpdateClientJoin(ClientJoinExpression join, ProjectionExpression projection, IEnumerable<Expression> outerKey, IEnumerable<Expression> innerKey) { if (projection != join.Projection || outerKey != join.OuterKey || innerKey != join.InnerKey) { return new ClientJoinExpression(projection, outerKey, innerKey); } return join; }
protected override Expression VisitClientJoin(ClientJoinExpression join) { var innerKey = this.VisitExpressionList(join.InnerKey); var outerKey = this.VisitExpressionList(join.OuterKey); ProjectionExpression projection = (ProjectionExpression)this.Visit(join.Projection); if (projection != join.Projection || innerKey != join.InnerKey || outerKey != join.OuterKey) { return new ClientJoinExpression(projection, outerKey, innerKey); } return join; }
protected override Expression VisitClientJoin(ClientJoinExpression join) { var innerKey = this.VisitExpressionList(join.InnerKey); var outerKey = this.VisitExpressionList(join.OuterKey); ProjectionExpression projection = (ProjectionExpression)this.Visit(join.Projection); if (projection != join.Projection || innerKey != join.InnerKey || outerKey != join.OuterKey) { return(new ClientJoinExpression(projection, outerKey, innerKey)); } return(join); }
protected override Expression VisitClientJoin(ClientJoinExpression join) { // treat client joins as new top level var saveTop = isTopLevel; var saveSelect = currentSelect; isTopLevel = true; currentSelect = null; Expression result = base.VisitClientJoin(join); isTopLevel = saveTop; currentSelect = saveSelect; return result; }
/// <summary> /// /// </summary> /// <param name="join"></param> /// <returns></returns> protected override Expression VisitClientJoin(ClientJoinExpression 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); ProjectionExpression newProjection = new ProjectionExpression(join.Projection.Source, 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.NotEqual( Expression.PropertyOrField(kvp, "Value"), Expression.Constant(null, 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); }
protected override Expression VisitClientJoin(ClientJoinExpression join) { // treat client joins as new top level var saveTop = isTopLevel; var saveSelect = currentSelect; isTopLevel = true; currentSelect = null; Expression result = base.VisitClientJoin(join); isTopLevel = saveTop; currentSelect = saveSelect; return(result); }
protected override Expression VisitClientJoin(ClientJoinExpression 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 System.Type[] { innerKey.Type, join.Projection.Projector.Type }); Expression constructKVPair = Expression.New(kvpConstructor, innerKey, join.Projection.Projector); ProjectionExpression newProjection = new ProjectionExpression(join.Projection.Source, constructKVPair); int iLookup = ++nLookup; Expression execution = 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.NotEqual( Expression.PropertyOrField(kvp, "Value"), Expression.Constant(null, join.Projection.Projector.Type) ), kvp ); execution = Expression.Call(typeof(Enumerable), "Where", new System.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 System.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(), Visit(outerKey)); if (join.Projection.Aggregator != null) { // apply aggregator access = DbExpressionReplacer.Replace(join.Projection.Aggregator.Body, join.Projection.Aggregator.Parameters[0], access); } variables.Add(lookup); initializers.Add(toLookup); return access; }
protected override Expression VisitClientJoin(ClientJoinExpression 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); var kvpConstructor = ReflectionCache.GetMember("KeyValueConstructor", new[] { innerKey.Type, join.Projection.Projector.Type }, pars => typeof(KeyValuePair <,>).MakeGenericType(pars).GetConstructor(pars)); Expression constructKVPair = Expression.New(kvpConstructor, innerKey, join.Projection.Projector); ProjectionExpression newProjection = new ProjectionExpression(join.Projection.Select, constructKVPair, _isAsync, join.Projection.IsNoTracking); int iLookup = ++_lookup; Expression execution = ExecuteProjection(newProjection, false); ParameterExpression kvp = Expression.Parameter(constructKVPair.Type, "kvp"); // filter out nulls if (join.Projection.Projector.NodeType == (ExpressionType)DbExpressionType.OuterJoined) { var nullType = ReflectionCache.GetMember("NullableType", join.Projection.Projector.Type, k => k.GetNullableType()); var pred = Expression.Lambda( Expression.PropertyOrField(kvp, "Value").NotEqual(Expression.Constant(null, nullType)), kvp ); execution = Expression.Call(typeof(Enumerable), nameof(Enumerable.Where), new Type[] { kvp.Type }, execution, pred); } // make lookup var keySelector = Expression.Lambda(Expression.PropertyOrField(kvp, "Key"), kvp); var elementSelector = Expression.Lambda(Expression.PropertyOrField(kvp, "Value"), kvp); var toLookup = Expression.Call(typeof(Enumerable), nameof(Enumerable.ToLookup), new Type[] { kvp.Type, outerKey.Type, join.Projection.Projector.Type }, execution, keySelector, elementSelector); // 2) agg(lookup[outer]) var lookup = Expression.Parameter(toLookup.Type, $"lookup{iLookup}"); var property = lookup.Type.GetProperty("Item"); Expression access = Expression.Call(lookup, property.GetGetMethod(), Visit(outerKey)); if (join.Projection.Aggregator != null) { // apply aggregator access = DbExpressionReplacer.Replace(join.Projection.Aggregator.Body, join.Projection.Aggregator.Parameters[0], access); } _variables.Add(lookup); _initializers.Add(toLookup); return(access); }
protected virtual Expression VisitClientJoin(ClientJoinExpression join) { this.AddAlias(join.Projection.Select.Alias); this.Write("ClientJoin("); this.WriteLine(Indentation.Inner); this.Write("OuterKey("); this.VisitExpressionList(join.OuterKey); this.Write("),"); this.WriteLine(Indentation.Same); this.Write("InnerKey("); this.VisitExpressionList(join.InnerKey); this.Write("),"); this.WriteLine(Indentation.Same); this.Visit(join.Projection); this.WriteLine(Indentation.Outer); this.Write(")"); return join; }
protected virtual Expression VisitClientJoin(ClientJoinExpression join) { var projection = (ProjectionExpression)this.Visit(join.Projection); var outerKey = this.VisitExpressionList(join.OuterKey); var innerKey = this.VisitExpressionList(join.InnerKey); return this.UpdateClientJoin(join, projection, outerKey, innerKey); }