/// <summary> /// Creates a subquery based on this SelectExpression and makes that table the single entry in /// <see cref="Tables" />. Clears all other top-level aspects of this SelectExpression. /// </summary> /// <returns> /// A SelectExpression. /// </returns> public virtual SelectExpression PushDownSubquery() { _subqueryDepth++; var subquery = new SelectExpression(_querySqlGeneratorFactory, _queryCompilationContext, SystemAliasPrefix); var columnAliasCounter = 0; foreach (var expression in _projection) { var aliasExpression = expression as AliasExpression; if (aliasExpression != null) { var columnExpression = aliasExpression.TryGetColumnExpression(); if (columnExpression != null && subquery._projection.OfType <AliasExpression>() .Any(ae => (ae.Alias ?? ae.TryGetColumnExpression()?.Name) == (aliasExpression.Alias ?? columnExpression.Name))) { aliasExpression.Alias = "c" + columnAliasCounter++; } } else { aliasExpression = new AliasExpression("c" + columnAliasCounter++, expression); } subquery._projection.Add(aliasExpression); } subquery.AddTables(_tables); subquery.AddToOrderBy(_orderBy); subquery.Predicate = Predicate; subquery._limit = _limit; subquery._offset = _offset; subquery._isDistinct = _isDistinct; subquery._subqueryDepth = _subqueryDepth; subquery.ProjectStarAlias = ProjectStarAlias; subquery.IsProjectStar = IsProjectStar || !subquery._projection.Any(); _limit = null; _offset = null; _isDistinct = false; ProjectStarAlias = null; Predicate = null; ClearTables(); ClearProjection(); ClearOrderBy(); AddTable(subquery, createUniqueAlias: false); ProjectStarAlias = subquery.Alias; return(subquery); }
/// <summary> /// Creates a new instance of a ColumnReferenceExpression. /// </summary> /// <param name="aliasExpression"> The referenced AliasExpression. </param> /// <param name="tableExpression"> The target table expression. </param> public ColumnReferenceExpression( [NotNull] AliasExpression aliasExpression, [NotNull] TableExpressionBase tableExpression) : this( Check.NotNull(aliasExpression, nameof(aliasExpression)).Alias, aliasExpression, Check.NotNull(tableExpression, nameof(tableExpression))) { }
public InExpression( [NotNull] AliasExpression operand, [NotNull] SelectExpression subQuery) { Check.NotNull(operand, nameof(operand)); Check.NotNull(subQuery, nameof(subQuery)); Operand = operand; SubQuery = subQuery; }
public InExpression( [NotNull] AliasExpression operand, [NotNull] IReadOnlyList <Expression> values) { Check.NotNull(operand, nameof(operand)); Check.NotNull(values, nameof(values)); Operand = operand; Values = values; }
// TODO: Make polymorphic public virtual Expression UpdateColumnExpression( [NotNull] Expression expression, [NotNull] TableExpressionBase tableExpression) { Check.NotNull(expression, nameof(expression)); Check.NotNull(tableExpression, nameof(tableExpression)); var columnExpression = expression as ColumnExpression; if (columnExpression != null) { return(new ColumnExpression(columnExpression.Name, columnExpression.Property, tableExpression)); } var aliasExpression = expression as AliasExpression; if (aliasExpression != null) { var newAliasExpression = new AliasExpression( aliasExpression.Alias, UpdateColumnExpression(aliasExpression.Expression, tableExpression)) { SourceMember = aliasExpression.SourceMember }; return(newAliasExpression); } switch (expression.NodeType) { case ExpressionType.Coalesce: { var binaryExpression = (BinaryExpression)expression; var left = UpdateColumnExpression(binaryExpression.Left, tableExpression); var right = UpdateColumnExpression(binaryExpression.Right, tableExpression); return(binaryExpression.Update(left, binaryExpression.Conversion, right)); } case ExpressionType.Conditional: { var conditionalExpression = (ConditionalExpression)expression; var test = UpdateColumnExpression(conditionalExpression.Test, tableExpression); var ifTrue = UpdateColumnExpression(conditionalExpression.IfTrue, tableExpression); var ifFalse = UpdateColumnExpression(conditionalExpression.IfFalse, tableExpression); return(conditionalExpression.Update(test, ifTrue, ifFalse)); } } return(expression); }
/// <summary> /// Adds a column to the ORDER BY of this SelectExpression. /// </summary> /// <param name="column"> The column name. </param> /// <param name="property"> The corresponding EF property. </param> /// <param name="table"> The target table. </param> /// <param name="orderingDirection"> The ordering direction. </param> /// <returns> /// An AliasExpression corresponding to the expression added to the ORDER BY. /// </returns> public virtual AliasExpression AddToOrderBy( [NotNull] string column, [NotNull] IProperty property, [NotNull] TableExpressionBase table, OrderingDirection orderingDirection) { Check.NotEmpty(column, nameof(column)); Check.NotNull(property, nameof(property)); Check.NotNull(table, nameof(table)); var columnExpression = new ColumnExpression(column, property, table); var aliasExpression = new AliasExpression(columnExpression); if (_orderBy.FindIndex(o => o.Expression.TryGetColumnExpression()?.Equals(columnExpression) ?? false) == -1) { _orderBy.Add(new Ordering(aliasExpression, orderingDirection)); } return(aliasExpression); }
/// <summary> /// Adds a ColumnExpression to the projection. /// </summary> /// <param name="columnExpression"> The column expression. </param> /// <returns> /// The corresponding index of the added expression in <see cref="Projection"/>. /// </returns> public virtual int AddToProjection([NotNull] ColumnExpression columnExpression) { Check.NotNull(columnExpression, nameof(columnExpression)); var projectionIndex = _projection .FindIndex(e => { var ce = e.TryGetColumnExpression(); return(ce != null && ce.Property == columnExpression.Property && ce.Name == columnExpression.Name && ce.TableAlias == columnExpression.TableAlias); }); if (projectionIndex == -1) { var aliasExpression = new AliasExpression(columnExpression); // Alias != null means SelectExpression in subquery which needs projections to have unique aliases if (Alias != null) { var currentAlias = columnExpression.Name; var uniqueAlias = CreateUniqueProjectionAlias(currentAlias); if (!string.Equals(currentAlias, uniqueAlias, StringComparison.OrdinalIgnoreCase)) { aliasExpression.Alias = uniqueAlias; } } projectionIndex = _projection.Count; _projection.Add(aliasExpression); IsProjectStar = false; } return(projectionIndex); }
/// <summary> /// Adds multiple expressions to the ORDER BY of this SelectExpression. /// </summary> /// <param name="orderings"> The orderings expressions. </param> public virtual void AddToOrderBy([NotNull] IEnumerable <Ordering> orderings) { Check.NotNull(orderings, nameof(orderings)); foreach (var ordering in orderings) { var aliasExpression = ordering.Expression as AliasExpression; var columnExpression = ordering.Expression as ColumnExpression; if (aliasExpression != null) { var newAlias = new AliasExpression(aliasExpression.Alias, aliasExpression.Expression); _orderBy.Add(new Ordering(newAlias, ordering.OrderingDirection)); } else if (columnExpression != null) { _orderBy.Add(new Ordering(new AliasExpression(columnExpression), ordering.OrderingDirection)); } else { _orderBy.Add(ordering); } } }
/// <summary> /// Adds an <see cref="AliasExpression" /> to the projection. /// </summary> /// <param name="aliasExpression"> The alias expression. </param> /// <returns> /// The corresponding index of the added expression in <see cref="Projection" />. /// </returns> public virtual int AddToProjection([NotNull] AliasExpression aliasExpression) { Check.NotNull(aliasExpression, nameof(aliasExpression)); var alias = aliasExpression.Alias; var expression = aliasExpression.Expression; var columnExpression = expression as ColumnExpression; var projectionIndex = _projection .FindIndex(e => { var ae = e as AliasExpression; var ce = e.TryGetColumnExpression(); return((ce != null && columnExpression != null && ce.Name == columnExpression.Name && ce.TableAlias == columnExpression.TableAlias) || ae?.Expression == expression); }); if (projectionIndex == -1) { // Alias != null means SelectExpression in subquery which needs projections to have unique aliases if (Alias != null) { var currentAlias = alias ?? columnExpression?.Name ?? expression.NodeType.ToString(); var uniqueAlias = CreateUniqueProjectionAlias(currentAlias); if (columnExpression == null || !string.Equals(currentAlias, uniqueAlias, StringComparison.OrdinalIgnoreCase)) { alias = uniqueAlias; } } projectionIndex = _projection.Count; if (alias != null) { foreach (var orderByAliasExpression in _orderBy.Select(o => o.Expression).OfType <AliasExpression>()) { if (orderByAliasExpression.TryGetColumnExpression() == null) { // TODO: This seems bad if (orderByAliasExpression.Expression.ToString() == expression.ToString()) { orderByAliasExpression.Alias = alias; orderByAliasExpression.IsProjected = true; } } } } _projection.Add(new AliasExpression(alias, expression)); IsProjectStar = false; } return(projectionIndex); }
// TODO: Make polymorphic public virtual Expression UpdateColumnExpression( [NotNull] Expression expression, [NotNull] TableExpressionBase tableExpression) { Check.NotNull(expression, nameof(expression)); Check.NotNull(tableExpression, nameof(tableExpression)); var columnExpression = expression as ColumnExpression; if (columnExpression != null) { return new ColumnExpression(columnExpression.Name, columnExpression.Property, tableExpression); } var aliasExpression = expression as AliasExpression; if (aliasExpression != null) { var newAliasExpression = new AliasExpression( aliasExpression.Alias, UpdateColumnExpression(aliasExpression.Expression, tableExpression)) { SourceMember = aliasExpression.SourceMember }; return newAliasExpression; } switch (expression.NodeType) { case ExpressionType.Coalesce: { var binaryExpression = (BinaryExpression)expression; var left = UpdateColumnExpression(binaryExpression.Left, tableExpression); var right = UpdateColumnExpression(binaryExpression.Right, tableExpression); return binaryExpression.Update(left, binaryExpression.Conversion, right); } case ExpressionType.Conditional: { var conditionalExpression = (ConditionalExpression)expression; var test = UpdateColumnExpression(conditionalExpression.Test, tableExpression); var ifTrue = UpdateColumnExpression(conditionalExpression.IfTrue, tableExpression); var ifFalse = UpdateColumnExpression(conditionalExpression.IfFalse, tableExpression); return conditionalExpression.Update(test, ifTrue, ifFalse); } } return expression; }
private bool Equals(AliasExpression other) => string.Equals(_alias, other._alias) && Equals(_expression, other._expression);
/// <summary> /// Adds an <see cref="AliasExpression"/> to the projection. /// </summary> /// <param name="aliasExpression"> The alias expression. </param> /// <returns> /// The corresponding index of the added expression in <see cref="Projection"/>. /// </returns> public virtual int AddToProjection([NotNull] AliasExpression aliasExpression) => AddAliasToProjection(aliasExpression.Alias, aliasExpression.Expression);
public virtual SelectExpression PushDownSubquery() { _subqueryDepth++; var subquery = new SelectExpression(_querySqlGeneratorFactory, _queryCompilationContext, SystemAliasPrefix); var columnAliasCounter = 0; foreach (var expression in _projection) { var aliasExpression = expression as AliasExpression; if (aliasExpression != null) { var columnExpression = aliasExpression.TryGetColumnExpression(); if (columnExpression != null && subquery._projection.OfType<AliasExpression>() .Any(ae => ae.TryGetColumnExpression()?.Name == columnExpression.Name)) { aliasExpression.Alias = "c" + columnAliasCounter++; } } else { aliasExpression = new AliasExpression("c" + columnAliasCounter++, expression); } subquery._projection.Add(aliasExpression); } subquery.AddTables(_tables); subquery.AddToOrderBy(_orderBy); subquery.Predicate = Predicate; subquery._limit = _limit; subquery._offset = _offset; subquery._isDistinct = _isDistinct; subquery._subqueryDepth = _subqueryDepth; subquery.IsProjectStar = IsProjectStar || !subquery._projection.Any(); _limit = null; _offset = null; _isDistinct = false; Predicate = null; ClearTables(); ClearProjection(); ClearOrderBy(); AddTable(subquery, createUniqueAlias: false); return subquery; }
private Expression VisitSelectExpression(SelectExpression selectExpression) { base.Visit(selectExpression); if (!RequiresRowNumberPaging(selectExpression)) { return selectExpression; } var subQuery = selectExpression.PushDownSubquery(); foreach (var projection in subQuery.Projection) { var alias = projection as AliasExpression; var column = projection as ColumnExpression; if (column != null) { column = new ColumnExpression(column.Name, column.Property, subQuery); selectExpression.AddToProjection(column); continue; } column = alias?.TryGetColumnExpression(); if (column != null) { column = new ColumnExpression(alias.Alias ?? column.Name, column.Property, subQuery); alias = new AliasExpression(alias.Alias, column); selectExpression.AddToProjection(alias); } else { column = new ColumnExpression(alias?.Alias, alias.Expression.Type, subQuery); selectExpression.AddToProjection(column); } } if (subQuery.OrderBy.Count == 0) { subQuery.AddToOrderBy( new Ordering(new SqlFunctionExpression("@@RowCount", typeof(int)), OrderingDirection.Asc)); } var columnExpression = new ColumnExpression(RowNumberColumnName, typeof(int), subQuery); var rowNumber = new RowNumberExpression(columnExpression, subQuery.OrderBy); subQuery.ClearOrderBy(); subQuery.AddToProjection(rowNumber, false); Expression predicate = null; var offset = subQuery.Offset ?? Expression.Constant(0); if (subQuery.Offset != null) { predicate = Expression.GreaterThan(columnExpression, offset); } if (subQuery.Limit != null) { var constantValue = (subQuery.Limit as ConstantExpression)?.Value; var offsetValue = (offset as ConstantExpression)?.Value; var limitExpression = constantValue != null && offsetValue != null ? (Expression)Expression.Constant((int)offsetValue + (int)constantValue) : Expression.Add(offset, subQuery.Limit); var expression = Expression.LessThanOrEqual(columnExpression, limitExpression); if (predicate != null) { expression = Expression.AndAlso(predicate, expression); } predicate = expression; } selectExpression.Predicate = predicate; return selectExpression; }
private bool Equals(AliasExpression other) => Equals(_expression, other._expression) && string.Equals(_alias, other._alias);
public virtual int AddToProjection([NotNull] ColumnExpression columnExpression) { Check.NotNull(columnExpression, nameof(columnExpression)); var projectionIndex = _projection .FindIndex(e => { var ce = e.TryGetColumnExpression(); return ce?.Property == columnExpression.Property && ce?.Type == columnExpression.Type && ce.TableAlias == columnExpression.TableAlias; }); if (projectionIndex == -1) { var aliasExpression = new AliasExpression(columnExpression); if (Alias != null) { var currentAlias = columnExpression.Name; var uniqueAlias = CreateUniqueProjectionAlias(currentAlias); if (!string.Equals(currentAlias, uniqueAlias, StringComparison.OrdinalIgnoreCase)) { aliasExpression.Alias = uniqueAlias; } } projectionIndex = _projection.Count; _projection.Add(aliasExpression); IsProjectStar = false; } return projectionIndex; }
public virtual AliasExpression AddToOrderBy( [NotNull] string column, [NotNull] IProperty property, [NotNull] TableExpressionBase table, OrderingDirection orderingDirection) { Check.NotEmpty(column, nameof(column)); Check.NotNull(property, nameof(property)); Check.NotNull(table, nameof(table)); var columnExpression = new ColumnExpression(column, property, table); var aliasExpression = new AliasExpression(columnExpression); if (_orderBy.FindIndex(o => o.Expression.TryGetColumnExpression()?.Equals(columnExpression) ?? false) == -1) { _orderBy.Add(new Ordering(aliasExpression, orderingDirection)); } return aliasExpression; }
/// <summary> /// Creates a subquery based on this SelectExpression and makes that table the single entry in /// <see cref="Tables" />. Clears all other top-level aspects of this SelectExpression. /// </summary> /// <returns> /// A SelectExpression. /// </returns> public virtual SelectExpression PushDownSubquery() { _subqueryDepth++; var subquery = new SelectExpression(Dependencies, _queryCompilationContext, SystemAliasPrefix); var columnAliasCounter = 0; foreach (var expression in _projection) { var aliasExpression = expression as AliasExpression; if (aliasExpression != null) { var columnExpression = aliasExpression.TryGetColumnExpression(); if ((columnExpression != null && subquery._projection.OfType <AliasExpression>() .Any(ae => (ae.Alias ?? ae.TryGetColumnExpression()?.Name) == (aliasExpression.Alias ?? columnExpression.Name))) || columnExpression == null) { aliasExpression.Alias = "c" + columnAliasCounter++; } } else { aliasExpression = new AliasExpression("c" + columnAliasCounter++, expression); } subquery._projection.Add(aliasExpression); } subquery.AddTables(_tables); subquery.AddToOrderBy(_orderBy); subquery.Predicate = Predicate; subquery._limit = _limit; subquery._offset = _offset; subquery._isDistinct = _isDistinct; subquery._subqueryDepth = _subqueryDepth; subquery.ProjectStarTable = ProjectStarTable; subquery.IsProjectStar = IsProjectStar || !subquery._projection.Any(); _limit = null; _offset = null; _isDistinct = false; ProjectStarTable = null; Predicate = null; ClearTables(); ClearProjection(); ClearOrderBy(); _tables.Add(subquery); ProjectStarTable = subquery; foreach (var ordering in subquery.OrderBy) { var expression = ordering.Expression; var aliasExpression = expression as AliasExpression; if (aliasExpression != null) { if (aliasExpression.Alias != null) { _orderBy.Add( new Ordering( new ColumnExpression(aliasExpression.Alias, aliasExpression.Type, subquery), ordering.OrderingDirection)); } else { var newExpression = UpdateColumnExpression(aliasExpression.Expression, subquery); _orderBy.Add( new Ordering( new AliasExpression(newExpression), ordering.OrderingDirection)); } } else { if (!subquery.IsProjectStar) { subquery.AddToProjection(expression); } var newExpression = UpdateColumnExpression(expression, subquery); _orderBy.Add( new Ordering( new AliasExpression(newExpression), ordering.OrderingDirection)); } } if (subquery.Limit == null && subquery.Offset == null) { subquery.ClearOrderBy(); } return(subquery); }
public virtual void AddToOrderBy([NotNull] IEnumerable<Ordering> orderings) { Check.NotNull(orderings, nameof(orderings)); foreach (var ordering in orderings) { var aliasExpression = ordering.Expression as AliasExpression; var columnExpression = ordering.Expression as ColumnExpression; if (aliasExpression != null) { var newAlias = new AliasExpression(aliasExpression.Alias, aliasExpression.Expression); _orderBy.Add(new Ordering(newAlias, ordering.OrderingDirection)); } else if (columnExpression != null) { _orderBy.Add(new Ordering(new AliasExpression(columnExpression), ordering.OrderingDirection)); } else { _orderBy.Add(ordering); } } }