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); } }
protected virtual Expression VisitProjection(DbProjectionExpression proj) { DbSelectExpression select = (DbSelectExpression)Visit(proj.Select); Expression projector = Visit(proj.Projector); return(UpdateProjection(proj, select, projector, proj.Aggregator)); }
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); } }
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 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); }
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 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); }
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; }
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 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; } }
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 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); }
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); }
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)); }
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; }
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); }
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); }
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 )); }
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 )); }
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 )); }
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 )); }
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); }
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); }
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)); }
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; }
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; }
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); }
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 ); }
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); }