private ColumnProjector(Expression expression, IEnumerable <ColumnDeclaration> existingColumns, TableAlias newAlias, IEnumerable <TableAlias> existingAliases) { this.newAlias = newAlias; this.existingAliases = new HashSet <TableAlias>(existingAliases, TableAlias.Comparer); this.map = new Dictionary <ColumnExpression, ColumnExpression>(); if (existingColumns != null) { this.columns = new List <ColumnDeclaration>(existingColumns); this.columnNames = new HashSet <string>(existingColumns.Select(c => c.Name), StringComparer.Ordinal); } else { this.columns = new List <ColumnDeclaration>(); this.columnNames = new HashSet <string>(StringComparer.Ordinal); } this.candidates = Nominator.Nominate(expression); }
private bool GetEquiJoinKeyExpressions(Expression predicate, TableAlias outerAlias, List <Expression> outerExpressions, List <Expression> innerExpressions) { if (predicate.NodeType == ExpressionType.Equal) { var b = (BinaryExpression)predicate; ColumnExpression leftCol = this.GetColumnExpression(b.Left); ColumnExpression rightCol = this.GetColumnExpression(b.Right); if (leftCol != null && rightCol != null) { if (leftCol.Alias == outerAlias) { outerExpressions.Add(b.Left); innerExpressions.Add(b.Right); return(true); } else if (rightCol.Alias == outerAlias) { innerExpressions.Add(b.Left); outerExpressions.Add(b.Right); return(true); } } } bool hadKey = false; var parts = predicate.Split(ExpressionType.And, ExpressionType.AndAlso); if (parts.Length > 1) { foreach (var part in parts) { bool hasOuterAliasReference = ReferencedAliasGatherer.Gather(part).Contains(outerAlias); if (hasOuterAliasReference) { if (!GetEquiJoinKeyExpressions(part, outerAlias, outerExpressions, innerExpressions)) { return(false); } hadKey = true; } } } return(hadKey); }
protected override Expression VisitProjection(ProjectionExpression 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 ProjectionExpression(this.currentSelect, projector, proj.Aggregator)); } return(proj); } if (proj.IsSingleton && this.CanJoinOnServer(this.currentSelect)) { TableAlias newAlias = new TableAlias(); this.currentSelect = this.currentSelect.AddRedundantSelect(newAlias); // remap any references to the outer select to the new alias; SelectExpression source = (SelectExpression)ColumnMapper.Map(proj.Select, newAlias, this.currentSelect.Alias); // add outer-join test ProjectionExpression pex = this.dialect.AddOuterJoinTest(new ProjectionExpression(source, proj.Projector)); var pc = ColumnProjector.ProjectColumns(pex.Projector, this.currentSelect.Columns, this.currentSelect.Alias, newAlias, proj.Select.Alias); JoinExpression join = new JoinExpression(JoinType.OuterApply, this.currentSelect.From, pex.Select, null); this.currentSelect = new SelectExpression(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); }
private Expression MakeSubquery(Expression expression) { var newAlias = new TableAlias(); var aliases = TableAliasGatherer.Gather(expression); var decls = new List <ColumnDeclaration>(); foreach (var ta in aliases) { foreach (var col in this.columns[ta]) { string name = decls.GetAvailableColumnName(col.Name); var decl = new ColumnDeclaration(name, col, col.SqlType); decls.Add(decl); var newCol = new ColumnExpression(col.Type, col.SqlType, newAlias, name); this.map.Add(col, newCol); } } return(new SelectExpression(newAlias, decls, expression, null)); }
public SelectExpression( TableAlias alias, IEnumerable <ColumnDeclaration> columns, Expression from, Expression where, IEnumerable <OrderExpression> orderBy, IEnumerable <Expression> groupBy, bool isDistinct, Expression skip, Expression take, bool reverse ) : base(DbExpressionType.Select, typeof(void), alias) { this.columns = columns.ToReadOnly(); this.isDistinct = isDistinct; this.from = from; this.where = where; this.orderBy = orderBy.ToReadOnly(); this.groupBy = groupBy.ToReadOnly(); this.take = take; this.skip = skip; this.reverse = reverse; }
public static ProjectedColumns ProjectColumns(Expression expression, IEnumerable <ColumnDeclaration> existingColumns, TableAlias newAlias, params TableAlias[] existingAliases) { return(ProjectColumns(expression, existingColumns, newAlias, (IEnumerable <TableAlias>)existingAliases)); }
public static ProjectedColumns ProjectColumns(Expression expression, IEnumerable <ColumnDeclaration> existingColumns, TableAlias newAlias, IEnumerable <TableAlias> existingAliases) { ColumnProjector projector = new ColumnProjector(expression, existingColumns, newAlias, existingAliases); Expression expr = projector.Visit(expression); return(new ProjectedColumns(expr, projector.columns.AsReadOnly())); }
/// <summary> /// Rebind order expressions to reference a new alias and add to column declarations if necessary /// </summary> protected virtual BindResult RebindOrderings(IEnumerable <OrderExpression> orderings, TableAlias alias, HashSet <TableAlias> existingAliases, IEnumerable <ColumnDeclaration> existingColumns) { List <ColumnDeclaration> newColumns = null; List <OrderExpression> newOrderings = new List <OrderExpression>(); foreach (OrderExpression ordering in orderings) { Expression expr = ordering.Expression; ColumnExpression column = expr as ColumnExpression; if (column == null || (existingAliases != null && existingAliases.Contains(column.Alias))) { // check to see if a declared column already contains a similar expression int iOrdinal = 0; foreach (ColumnDeclaration decl in existingColumns) { ColumnExpression declColumn = decl.Expression as ColumnExpression; if (decl.Expression == ordering.Expression || (column != null && declColumn != null && column.Alias == declColumn.Alias && column.Name == declColumn.Name)) { // found it, so make a reference to this column expr = new ColumnExpression(column.Type, column.SqlType, alias, decl.Name); break; } iOrdinal++; } // if not already projected, add a new column declaration for it if (expr == ordering.Expression) { if (newColumns == null) { newColumns = new List <ColumnDeclaration>(existingColumns); existingColumns = newColumns; } string colName = column != null ? column.Name : "c" + iOrdinal; colName = newColumns.GetAvailableColumnName(colName); var colType = SqlType.Get(expr.Type); newColumns.Add(new ColumnDeclaration(colName, ordering.Expression, colType)); expr = new ColumnExpression(expr.Type, colType, alias, colName); } newOrderings.Add(new OrderExpression(ordering.OrderType, expr)); } } return(new BindResult(existingColumns, newOrderings)); }
protected AliasedExpression(DbExpressionType nodeType, Type type, TableAlias alias) : base(nodeType, type) { this.alias = alias; }
public bool Equals(TableAlias other) { return(other.hashCode == hashCode); }
public TableExpression(TableAlias alias, IEntityMapping entity) : base(DbExpressionType.Table, typeof(void), alias) { this.entity = entity; }
public static Expression Map(Expression expression, TableAlias newAlias, params TableAlias[] oldAliases) { return(Map(expression, newAlias, (IEnumerable <TableAlias>)oldAliases)); }
public static Expression Map(Expression expression, TableAlias newAlias, IEnumerable <TableAlias> oldAliases) { return(new ColumnMapper(oldAliases, newAlias).Visit(expression)); }
private ColumnMapper(IEnumerable <TableAlias> oldAliases, TableAlias newAlias) { this.oldAliases = new HashSet <TableAlias>(oldAliases, TableAlias.Comparer); this.newAlias = newAlias; }
private void ClearColumnsUsed(TableAlias alias) { this.allColumnsUsed[alias] = new HashSet <string>(); }
protected override Expression VisitProjection(ProjectionExpression proj) { SelectExpression 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 SelectExpression newOuterSelect = (SelectExpression)QueryDuplicator.Duplicate(save); // remap any references to the outer select to the new alias; SelectExpression newInnerSelect = (SelectExpression)ColumnMapper.Map(proj.Select, newOuterSelect.Alias, save.Alias); // add outer-join test ProjectionExpression newInnerProjection = this.dbExpressionBuilder.AddOuterJoinTest(new ProjectionExpression(newInnerSelect, proj.Projector)); newInnerSelect = newInnerProjection.Select; Expression newProjector = newInnerProjection.Projector; TableAlias newAlias = new TableAlias(); var pc = ColumnProjector.ProjectColumns(newProjector, null, newAlias, newOuterSelect.Alias, newInnerSelect.Alias); JoinExpression join = new JoinExpression(JoinType.OuterApply, newOuterSelect, newInnerSelect, null); SelectExpression joinedSelect = new SelectExpression(newAlias, pc.Columns, join, null, null, null, proj.IsSingleton, null, null, false); // 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, ((ColumnExpression)k).Alias)); ProjectionExpression newProjection = new ProjectionExpression(joinedSelect, newProjector, proj.Aggregator); return(new ClientJoinExpression(newProjection, outerKey, innerKey)); } } else { bool saveJoin = this.canJoinOnClient; this.canJoinOnClient = false; var result = base.VisitProjection(proj); this.canJoinOnClient = saveJoin; return(result); } } else { this.isTopLevel = false; } return(base.VisitProjection(proj)); } finally { this.currentSelect = save; } }