public override IQuerySqlGenerator CreateDefault(SelectExpression selectExpression) => new MyCatQuerySqlGenerator( CommandBuilderFactory, SqlGenerationHelper, ParameterNameGeneratorFactory, RelationalTypeMapper, Check.NotNull(selectExpression, nameof(selectExpression)));
private void DiscriminateProjectionQuery( IEntityType entityType, Microsoft.EntityFrameworkCore.Query.Expressions.SelectExpression selectExpression, IQuerySource querySource) { Expression discriminatorPredicate; if (entityType.IsQueryType) { discriminatorPredicate = GenerateDiscriminatorExpression(entityType, selectExpression, querySource); } else { var sharedTypes = new HashSet <IEntityType>( _model.GetEntityTypes() .Where(e => !e.IsQueryType) .Where( et => et.Relational().TableName == entityType.Relational().TableName && et.Relational().Schema == entityType.Relational().Schema)); var currentPath = new Stack <IEntityType>(); currentPath.Push(entityType); var allPaths = new List <List <IEntityType> >(); FindPaths(entityType.RootType(), sharedTypes, currentPath, allPaths); discriminatorPredicate = allPaths .Select( p => p.Select( et => GenerateDiscriminatorExpression(et, selectExpression, querySource)) .Aggregate( (Expression)null, (result, current) => result != null ? current != null ? Expression.AndAlso(result, current) : result : current)) .Aggregate( (Expression)null, (result, current) => result != null ? current != null ? Expression.OrElse(result, current) : result : current); } if (discriminatorPredicate != null) { selectExpression.Predicate = new DiscriminatorPredicateExpression(discriminatorPredicate, querySource); } }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> protected override void GenerateLimitOffset(SelectExpression selectExpression) { if (selectExpression.Projection.OfType<RowNumberExpression>().Any()) { return; } if (selectExpression.Offset != null && !selectExpression.OrderBy.Any()) { Sql.AppendLine().Append("ORDER BY @@ROWCOUNT"); } base.GenerateLimitOffset(selectExpression); }
public virtual SqlTranslatingExpressionVisitor Create( RelationalQueryModelVisitor queryModelVisitor, SelectExpression targetSelectExpression = null, Expression topLevelPredicate = null, bool bindParentQueries = false, bool inProjection = false) => new SqlTranslatingExpressionVisitor( _relationalAnnotationProvider, _compositeExpressionFragmentTranslator, _methodCallTranslator, _memberTranslator, Check.NotNull(queryModelVisitor, nameof(queryModelVisitor)), targetSelectExpression, topLevelPredicate, bindParentQueries, inProjection);
private Shaper CreateShaper(Type elementType, IEntityType entityType, Microsoft.EntityFrameworkCore.Query.Expressions.SelectExpression selectExpression) { Shaper shaper; if (QueryModelVisitor.QueryCompilationContext .QuerySourceRequiresMaterialization(_querySource) || QueryModelVisitor.RequiresClientEval) { var materializerExpression = _materializerFactory .CreateMaterializer( entityType, selectExpression, (p, se) => se.AddToProjection( p, _querySource), out var typeIndexMap); var materializer = materializerExpression.Compile(); shaper = (Shaper)_createEntityShaperMethodInfo.MakeGenericMethod(elementType) .Invoke( obj: null, parameters: new object[] { _querySource, QueryModelVisitor.QueryCompilationContext.IsTrackingQuery && !entityType.IsQueryType, entityType.FindPrimaryKey(), materializer, materializerExpression, typeIndexMap, QueryModelVisitor.QueryCompilationContext.IsQueryBufferRequired && !entityType.IsQueryType }); } else { shaper = new ValueBufferShaper(_querySource); } return(shaper); }
private static Expression GenerateDiscriminatorExpression( IEntityType entityType, Microsoft.EntityFrameworkCore.Query.Expressions.SelectExpression selectExpression, IQuerySource querySource) { var concreteEntityTypes = entityType.GetConcreteTypesInHierarchy().ToList(); if (concreteEntityTypes.Count == 1 && concreteEntityTypes[0].RootType() == concreteEntityTypes[0]) { return(null); } var discriminatorColumn = selectExpression.BindProperty( concreteEntityTypes[0].Relational().DiscriminatorProperty, querySource); var firstDiscriminatorValue = Expression.Constant( concreteEntityTypes[0].Relational().DiscriminatorValue, discriminatorColumn.Type); var discriminatorPredicate = Expression.Equal(discriminatorColumn, firstDiscriminatorValue); if (concreteEntityTypes.Count > 1) { discriminatorPredicate = concreteEntityTypes .Skip(1) .Select( concreteEntityType => Expression.Constant( concreteEntityType.Relational().DiscriminatorValue, discriminatorColumn.Type)) .Aggregate( discriminatorPredicate, (current, discriminatorValue) => Expression.OrElse( Expression.Equal(discriminatorColumn, discriminatorValue), current)); } return(discriminatorPredicate); }
protected override void GenerateLimitOffset(SelectExpression selectExpression) { Check.NotNull(selectExpression, nameof(selectExpression)); if ((selectExpression.Limit != null) || (selectExpression.Offset != null)) { Sql.AppendLine() .Append("LIMIT "); Visit(selectExpression.Limit ?? Expression.Constant(-1)); if (selectExpression.Offset != null) { Sql.Append(" OFFSET "); Visit(selectExpression.Offset); } } }
public virtual SelectExpression Clone([NotNull] string alias) { Check.NotNull(alias, nameof(alias)); var selectExpression = new SelectExpression(_querySqlGeneratorFactory, _queryCompilationContext, alias) { _limit = _limit, _offset = _offset, _isDistinct = _isDistinct, _subqueryDepth = _subqueryDepth, IsProjectStar = IsProjectStar, Predicate = Predicate }; selectExpression._projection.AddRange(_projection); selectExpression.AddTables(_tables); selectExpression.AddToOrderBy(_orderBy); return selectExpression; }
/// <summary> /// Creates a new instance of a ExistsExpression.. /// </summary> /// <param name="subquery"> The subquery operand of the EXISTS expression. </param> public ExistsExpression([NotNull] SelectExpression subquery) { Check.NotNull(subquery, nameof(subquery)); Subquery = 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 static bool RequiresRowNumberPaging(SelectExpression selectExpression) => selectExpression.Offset != null && !selectExpression.Projection.Any(p => p is RowNumberExpression);
/// <summary> /// Creates a query SQL generator for a FromSql query. /// </summary> /// <param name="selectExpression"> The select expression. </param> /// <param name="sql"> The SQL. </param> /// <param name="arguments"> The arguments. </param> /// <returns> /// The query SQL generator. /// </returns> public virtual IQuerySqlGenerator CreateFromSql( SelectExpression selectExpression, string sql, Expression arguments) => new FromSqlNonComposedQuerySqlGenerator( CommandBuilderFactory, SqlGenerationHelper, ParameterNameGeneratorFactory, RelationalTypeMapper, Check.NotNull(selectExpression, nameof(selectExpression)), Check.NotEmpty(sql, nameof(sql)), Check.NotNull(arguments, nameof(arguments)));
/// <summary> /// Makes a copy of this SelectExpression. /// </summary> /// <param name="alias"> The alias. </param> /// <returns> /// A copy of this SelectExpression. /// </returns> public virtual SelectExpression Clone([CanBeNull] string alias = null) { var selectExpression = new SelectExpression(_querySqlGeneratorFactory, _queryCompilationContext) { _limit = _limit, _offset = _offset, _isDistinct = _isDistinct, _subqueryDepth = _subqueryDepth, IsProjectStar = IsProjectStar, Predicate = Predicate }; if (alias != null) { selectExpression.Alias = _queryCompilationContext.CreateUniqueTableAlias(alias); } selectExpression._projection.AddRange(_projection); selectExpression.AddTables(_tables); selectExpression.AddToOrderBy(_orderBy); return selectExpression; }
public override IQuerySqlGenerator CreateDefault(SelectExpression selectExpression) { throw new NotImplementedException(); }
/// <summary> /// Creates a default query SQL generator. /// </summary> /// <param name="selectExpression"> The select expression. </param> /// <returns> /// The new default query SQL generator. /// </returns> public abstract IQuerySqlGenerator CreateDefault(SelectExpression selectExpression);
protected override void GenerateTop(SelectExpression selectExpression) { // Handled by GenerateLimitOffset }
public virtual Expression<Func<ValueBuffer, object>> CreateMaterializer( IEntityType entityType, SelectExpression selectExpression, Func<IProperty, SelectExpression, int> projectionAdder, IQuerySource querySource) { Check.NotNull(entityType, nameof(entityType)); Check.NotNull(selectExpression, nameof(selectExpression)); Check.NotNull(projectionAdder, nameof(projectionAdder)); var valueBufferParameter = Expression.Parameter(typeof(ValueBuffer), "valueBuffer"); var concreteEntityTypes = entityType.GetConcreteTypesInHierarchy().ToArray(); var indexMap = new int[concreteEntityTypes[0].PropertyCount()]; var propertyIndex = 0; foreach (var property in concreteEntityTypes[0].GetProperties()) { indexMap[propertyIndex++] = projectionAdder(property, selectExpression); } var materializer = _entityMaterializerSource .CreateMaterializeExpression( concreteEntityTypes[0], valueBufferParameter, indexMap); if (concreteEntityTypes.Length == 1 && concreteEntityTypes[0].RootType() == concreteEntityTypes[0]) { return Expression.Lambda<Func<ValueBuffer, object>>(materializer, valueBufferParameter); } var discriminatorProperty = _relationalAnnotationProvider.For(concreteEntityTypes[0]).DiscriminatorProperty; var discriminatorColumn = selectExpression.Projection .OfType<AliasExpression>() .Last(c => c.TryGetColumnExpression()?.Property == discriminatorProperty); var firstDiscriminatorValue = Expression.Constant( _relationalAnnotationProvider.For(concreteEntityTypes[0]).DiscriminatorValue); var discriminatorPredicate = Expression.Equal(discriminatorColumn, firstDiscriminatorValue); if (concreteEntityTypes.Length == 1) { selectExpression.Predicate = new DiscriminatorPredicateExpression(discriminatorPredicate, querySource); return Expression.Lambda<Func<ValueBuffer, object>>(materializer, valueBufferParameter); } var discriminatorValueVariable = Expression.Variable(discriminatorProperty.ClrType); var returnLabelTarget = Expression.Label(typeof(object)); var blockExpressions = new Expression[] { Expression.Assign( discriminatorValueVariable, _entityMaterializerSource .CreateReadValueExpression( valueBufferParameter, discriminatorProperty.ClrType, discriminatorProperty.GetIndex())), Expression.IfThenElse( Expression.Equal(discriminatorValueVariable, firstDiscriminatorValue), Expression.Return(returnLabelTarget, materializer), Expression.Throw( Expression.Call( _createUnableToDiscriminateException, Expression.Constant(concreteEntityTypes[0])))), Expression.Label( returnLabelTarget, Expression.Default(returnLabelTarget.Type)) }; foreach (var concreteEntityType in concreteEntityTypes.Skip(1)) { indexMap = new int[concreteEntityType.PropertyCount()]; propertyIndex = 0; foreach (var property in concreteEntityType.GetProperties()) { indexMap[propertyIndex++] = projectionAdder(property, selectExpression); } var discriminatorValue = Expression.Constant( _relationalAnnotationProvider.For(concreteEntityType).DiscriminatorValue); materializer = _entityMaterializerSource .CreateMaterializeExpression(concreteEntityType, valueBufferParameter, indexMap); blockExpressions[1] = Expression.IfThenElse( Expression.Equal(discriminatorValueVariable, discriminatorValue), Expression.Return(returnLabelTarget, materializer), blockExpressions[1]); discriminatorPredicate = Expression.OrElse( Expression.Equal(discriminatorColumn, discriminatorValue), discriminatorPredicate); } selectExpression.Predicate = new DiscriminatorPredicateExpression(discriminatorPredicate, querySource); return Expression.Lambda<Func<ValueBuffer, object>>( Expression.Block(new[] { discriminatorValueVariable }, blockExpressions), valueBufferParameter); }
/// <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 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; }
public bool IsCorrelated(SelectExpression selectExpression) { _selectExpression = selectExpression; Visit(_selectExpression); return _correlated; }