protected override void GenerateLimitOffset(SelectExpression expression)
 {
     if (expression.Limit != null)
     {
         Sql.AppendLine()
             .Append("LIMIT ")
             .Append(expression.Limit);
     }
 }
示例#2
0
        public CommandBuilder(
            [NotNull] SelectExpression selectExpression,
            [NotNull] RelationalQueryCompilationContext relationalQueryCompilationContext)
        {
            Check.NotNull(selectExpression, "selectExpression");
            Check.NotNull(relationalQueryCompilationContext, "relationalQueryCompilationContext");

            _selectExpression = selectExpression;
            _relationalQueryCompilationContext = relationalQueryCompilationContext;
        }
        protected override void GenerateLimitOffset(SelectExpression selectExpression)
        {
            Check.NotNull(selectExpression, nameof(selectExpression));

            if (selectExpression.Limit != null || selectExpression.Offset != null)
            {
                Sql.AppendLine()
                    .Append("LIMIT ")
                    .Append(selectExpression.Limit ?? -1);

                if (selectExpression.Offset != null)
                {
                    Sql.Append(" OFFSET ")
                        .Append(selectExpression.Offset);
                }
            }
        }
        public virtual SelectExpression Clone([NotNull] string alias)
        {
            Check.NotEmpty(alias, nameof(alias));

            var selectExpression
                = new SelectExpression(alias)
                    {
                        _limit = _limit,
                        _offset = _offset,
                        _isDistinct = _isDistinct,
                        _subqueryDepth = _subqueryDepth,
                        _projectStar = _projectStar,
                        Predicate = Predicate
                    };

            selectExpression._projection.AddRange(_projection);

            selectExpression.AddTables(_tables);
            selectExpression.AddToOrderBy(_orderBy);

            return selectExpression;
        }
        private IEnumerable<Expression> CreateIncludeRelatedValuesStrategyFactories(
            IQuerySource querySource,
            IEnumerable<INavigation> navigationPath)
        {
            var selectExpression
                = _queryCompilationContext.FindSelectExpression(querySource);

            var targetTableExpression
                = selectExpression.FindTableForQuerySource(querySource);

            var readerIndex = 0;
            var canProduceInnerJoin = true;

            foreach (var navigation in navigationPath)
            {
                var targetEntityType = navigation.GetTargetType();
                var targetTableName = _queryCompilationContext.GetTableName(targetEntityType);
                var targetTableAlias = targetTableName[0].ToString().ToLower();

                if (!navigation.IsCollection())
                {
                    var joinedTableExpression
                        = new TableExpression(
                            targetTableName,
                            _queryCompilationContext.GetSchema(targetEntityType),
                            targetTableAlias,
                            querySource);

                    var valueBufferOffset = selectExpression.Projection.Count;

                    canProduceInnerJoin
                        = canProduceInnerJoin
                          && (navigation.ForeignKey.IsRequired
                              && navigation.PointsToPrincipal());

                    var joinExpression
                        = canProduceInnerJoin
                            ? selectExpression
                                .AddInnerJoin(joinedTableExpression)
                            : selectExpression
                                .AddOuterJoin(joinedTableExpression);

                    var materializer
                        = new MaterializerFactory(
                            _queryCompilationContext.EntityMaterializerSource)
                            .CreateMaterializer(
                                targetEntityType,
                                selectExpression,
                                projectionAdder:
                                    (p, se) => se.AddToProjection(
                                        new AliasExpression(
                                            new ColumnExpression(
                                                _queryCompilationContext.GetColumnName(p),
                                                p,
                                                joinedTableExpression))) - valueBufferOffset,
                                querySource: null);

                    joinExpression.Predicate
                        = BuildJoinEqualityExpression(
                            navigation,
                            (navigation.PointsToPrincipal()
                                ? targetEntityType
                                : navigation.EntityType)
                                .GetPrimaryKey().Properties,
                            navigation.PointsToPrincipal() ? targetTableExpression : joinExpression,
                            navigation.PointsToPrincipal() ? joinExpression : targetTableExpression);

                    targetTableExpression = joinedTableExpression;

                    yield return
                        Expression.Lambda(
                            Expression.Call(
                                _queryCompilationContext.QueryMethodProvider
                                    .CreateReferenceIncludeRelatedValuesStrategyMethod,
                                Expression.Convert(
                                    EntityQueryModelVisitor.QueryContextParameter,
                                    typeof(RelationalQueryContext)),
                                Expression.Constant(valueBufferOffset),
                                Expression.Constant(readerIndex),
                                materializer));
                }
                else
                {
                    var principalTable
                        = selectExpression.Tables.Last(t => t.QuerySource == querySource);

                    foreach (var property in navigation.EntityType.GetPrimaryKey().Properties)
                    {
                        selectExpression
                            .AddToOrderBy(
                                _queryCompilationContext.GetColumnName(property),
                                property,
                                principalTable,
                                OrderingDirection.Asc);
                    }

                    var targetSelectExpression = new SelectExpression();

                    targetTableExpression
                        = new TableExpression(
                            targetTableName,
                            _queryCompilationContext.GetSchema(targetEntityType),
                            targetTableAlias,
                            querySource);

                    targetSelectExpression.AddTable(targetTableExpression);

                    var materializer
                        = new MaterializerFactory(
                            _queryCompilationContext.EntityMaterializerSource)
                            .CreateMaterializer(
                                targetEntityType,
                                targetSelectExpression,
                                (p, se) => se.AddToProjection(
                                    _queryCompilationContext.GetColumnName(p),
                                    p,
                                    querySource),
                                querySource: null);

                    var innerJoinSelectExpression
                        = selectExpression.Clone(
                            selectExpression.OrderBy.Select(o => o.Expression).Last(o => o.IsAliasWithColumnExpression())
                                .TryGetColumnExpression().TableAlias);

                    innerJoinSelectExpression.IsDistinct = true;
                    innerJoinSelectExpression.ClearProjection();

                    foreach (var expression
                        in innerJoinSelectExpression.OrderBy
                            .Select(o => o.Expression))
                    {
                        innerJoinSelectExpression.AddToProjection(expression);
                    }

                    innerJoinSelectExpression.ClearOrderBy();

                    var primaryKeyProperties = navigation.EntityType.GetPrimaryKey().Properties;

                    var innerJoinExpression
                        = targetSelectExpression.AddInnerJoin(innerJoinSelectExpression);

                    targetSelectExpression.UpdateOrderByColumnBinding(selectExpression.OrderBy, innerJoinExpression);

                    innerJoinExpression.Predicate
                        = BuildJoinEqualityExpression(
                            navigation,
                            primaryKeyProperties,
                            targetTableExpression,
                            innerJoinExpression);

                    selectExpression = targetSelectExpression;
                    readerIndex++;

                    yield return
                        Expression.Lambda(
                            Expression.Call(
                                _queryCompilationContext.QueryMethodProvider
                                    .CreateCollectionIncludeRelatedValuesStrategyMethod,
                                Expression.Call(
                                    _queryCompilationContext.QueryMethodProvider.QueryMethod,
                                    EntityQueryModelVisitor.QueryContextParameter,
                                    Expression.Constant(
                                        new CommandBuilder(
                                            () => _queryCompilationContext.CreateSqlQueryGenerator(targetSelectExpression),
                                            _queryCompilationContext.ValueBufferFactoryFactory))),
                                materializer));
                }
            }
        }
        private SelectExpression PushDownSubquery()
        {
            _subqueryDepth
                = _subqueryDepth != null
                    ? _subqueryDepth + 1
                    : 0;

            var subquery
                = new SelectExpression("t" + _subqueryDepth);

            var columnAliasCounter = 0;

            foreach (var aliasExpression in _projection.OfType<AliasExpression>())
            {
                var columnExpression = ((Expression)aliasExpression).TryGetColumnExpression();
                if (columnExpression != null
                    && subquery._projection.OfType<AliasExpression>().Any(ae =>
                        ae.TryGetColumnExpression()?.Name == columnExpression.Name))
                {
                    aliasExpression.Alias = "c" + columnAliasCounter++;
                }

                subquery._projection.Add(aliasExpression);
            }

            subquery.AddTables(_tables);
            subquery.AddToOrderBy(_orderBy);

            subquery._limit = _limit;
            subquery._offset = _offset;
            subquery._isDistinct = _isDistinct;
            subquery._subqueryDepth = _subqueryDepth;
            subquery._projectStar = _projectStar;

            _limit = null;
            _offset = null;
            _isDistinct = false;

            ClearTables();
            ClearProjection();
            ClearOrderBy();

            _projectStar = true;

            AddTable(subquery);

            return subquery;
        }
        private void PushDownSubquery()
        {
            var subquery = new SelectExpression();

            var columnAliasCounter = 0;

            foreach (var columnExpression in _projection)
            {
                if (subquery._projection.FindIndex(ce => ce.Name == columnExpression.Name) != -1)
                {
                    columnExpression.Alias = "c" + columnAliasCounter++;
                }

                subquery._projection.Add(columnExpression);
            }
            
            subquery.AddTables(_tables);
            subquery.AddToOrderBy(_orderBy);

            subquery._limit = _limit;
            subquery._isDistinct = _isDistinct;
            subquery._subquery = _subquery;
            subquery._projectStar = _projectStar;

            _limit = null;
            _isDistinct = false;

            ClearTables();
            ClearProjection();
            ClearOrderBy();

            _projectStar = true;
            _subquery = subquery;
        }
 protected override void GenerateTop(SelectExpression selectExpression)
 {
     // Handled by GenerateLimitOffset
 }
        public override ISqlQueryGenerator CreateSqlQueryGenerator(SelectExpression selectExpression)
        {
            Check.NotNull(selectExpression, nameof(selectExpression));

            return new NpgsqlQueryGenerator(selectExpression);
        }
        private CommandBuilder setupCommandBuilder(DbContext context)
        {
            var source = new EntityMaterializerSource(new MemberMapper(new FieldMatcher()));

            var loggerFactory = new LoggerFactory();

            var selectExpression = new SelectExpression();
            var queryCompilationContext = new RelationalQueryCompilationContext(
                context.Model,
                loggerFactory.CreateLogger("new"),
                new LinqOperatorProvider(),
                new RelationalResultOperatorHandler(),
                source,
                new EntityKeyFactorySource(new BoxedValueReaderSource()),
                new AsyncQueryMethodProvider(),
                new CompositeMethodCallTranslator());

            return new CommandBuilder(selectExpression, queryCompilationContext);
        }
 protected override void GenerateTop(SelectExpression expression)
 {
     // not supported in SQLite
 }
 public override ISqlQueryGenerator CreateSqlQueryGenerator(SelectExpression selectExpression) =>
     new SqliteQuerySqlGenerator(selectExpression);
        protected override Expression VisitEntityQueryable([NotNull] Type elementType)
        {
            Check.NotNull(elementType, nameof(elementType));

            var queryMethodInfo = RelationalQueryModelVisitor.CreateValueReaderMethodInfo;
            var entityType = QueryModelVisitor.QueryCompilationContext.Model.GetEntityType(elementType);

            var selectExpression = new SelectExpression();
            var tableName = QueryModelVisitor.QueryCompilationContext.GetTableName(entityType);

            var alias = _querySource.ItemName.StartsWith("<generated>_")
                ? tableName.First().ToString().ToLower()
                : _querySource.ItemName;

            var fromSqlAnnotation = GetAnnotations<FromSqlAnnotation>(_querySource).SingleOrDefault();

            selectExpression.AddTable(
                (fromSqlAnnotation != null)
                    ? (TableExpressionBase)new RawSqlDerivedTableExpression(
                        fromSqlAnnotation.Sql,
                        fromSqlAnnotation.Parameters,
                        alias,
                        _querySource)
                    : new TableExpression(
                        tableName,
                        QueryModelVisitor.QueryCompilationContext.GetSchema(entityType),
                        alias,
                        _querySource));

            QueryModelVisitor.AddQuery(_querySource, selectExpression);

            var queryMethodArguments
                = new List<Expression>
                    {
                        Expression.Constant(_querySource),
                        EntityQueryModelVisitor.QueryContextParameter,
                        EntityQueryModelVisitor.QuerySourceScopeParameter,
                        _readerParameter
                    };

            if (QueryModelVisitor.QuerySourceRequiresMaterialization(_querySource))
            {
                var materializer
                    = new MaterializerFactory(
                        QueryModelVisitor
                            .QueryCompilationContext
                            .EntityMaterializerSource)
                        .CreateMaterializer(
                            entityType,
                            selectExpression,
                            (p, se) =>
                                se.AddToProjection(
                                    QueryModelVisitor.QueryCompilationContext.GetColumnName(p),
                                    p,
                                    _querySource),
                            _querySource);

                queryMethodInfo
                    = RelationalQueryModelVisitor.CreateEntityMethodInfo
                        .MakeGenericMethod(elementType);

                var keyProperties
                    = entityType.GetPrimaryKey().Properties;

                var keyFactory
                    = QueryModelVisitor.QueryCompilationContext.EntityKeyFactorySource
                        .GetKeyFactory(keyProperties);

                queryMethodArguments.AddRange(
                    new[]
                        {
                            Expression.Constant(0),
                            Expression.Constant(entityType),
                            Expression.Constant(QueryModelVisitor.QuerySourceRequiresTracking(_querySource)),
                            Expression.Constant(keyFactory),
                            Expression.Constant(keyProperties),
                            materializer
                        });
            }

            return Expression.Call(
                QueryModelVisitor.QueryCompilationContext.QueryMethodProvider.QueryMethod
                    .MakeGenericMethod(queryMethodInfo.ReturnType),
                EntityQueryModelVisitor.QueryContextParameter,
                Expression.Constant(new CommandBuilder(selectExpression, QueryModelVisitor.QueryCompilationContext)),
                Expression.Lambda(
                    Expression.Call(queryMethodInfo, queryMethodArguments),
                    _readerParameter));
        }
 public override ISqlQueryGenerator CreateSqlQueryGenerator(SelectExpression selectExpression) 
     => new SqlServerQuerySqlGenerator(Check.NotNull(selectExpression, nameof(selectExpression)));
        protected override Expression VisitEntityQueryable(Type elementType)
        {
            Check.NotNull(elementType, nameof(elementType));

            var queryMethodInfo = RelationalQueryModelVisitor.CreateValueBufferMethodInfo;
            var relationalQueryCompilationContext = QueryModelVisitor.QueryCompilationContext;
            var entityType = relationalQueryCompilationContext.Model.GetEntityType(elementType);
            var selectExpression = new SelectExpression();
            var tableName = relationalQueryCompilationContext.GetTableName(entityType);

            var tableAlias
                = _querySource.HasGeneratedItemName()
                    ? tableName[0].ToString().ToLower()
                    : _querySource.ItemName;

            var fromSqlAnnotation
                = relationalQueryCompilationContext.QueryAnnotations
                    .OfType<FromSqlQueryAnnotation>()
                    .SingleOrDefault(a => a.QuerySource == _querySource);

            selectExpression.AddTable(
                fromSqlAnnotation != null
                    ? (TableExpressionBase)
                        new RawSqlDerivedTableExpression(
                            fromSqlAnnotation.Sql,
                            fromSqlAnnotation.Parameters,
                            tableAlias,
                            _querySource)
                    : new TableExpression(
                        tableName,
                        relationalQueryCompilationContext.GetSchema(entityType),
                        tableAlias,
                        _querySource));

            var composable = true;

            if (fromSqlAnnotation != null)
            {
                var sqlStart = fromSqlAnnotation.Sql.Cast<char>().SkipWhile(char.IsWhiteSpace).Take(7).ToArray();

                if (sqlStart.Length != 7
                    || !char.IsWhiteSpace(sqlStart.Last())
                    || !new string(sqlStart).StartsWith("SELECT", StringComparison.OrdinalIgnoreCase))
                {
                    if (relationalQueryCompilationContext.QueryAnnotations
                        .OfType<IncludeQueryAnnotation>().Any())
                    {
                        throw new InvalidOperationException(Strings.StoredProcedureIncludeNotSupported);
                    }
                    QueryModelVisitor.RequiresClientEval = true;

                    composable = false;
                }

                if (!fromSqlAnnotation.QueryModel.BodyClauses.Any()
                    && !fromSqlAnnotation.QueryModel.ResultOperators.Any())
                {
                    composable = false;
                }
            }

            QueryModelVisitor.AddQuery(_querySource, selectExpression);

            var queryMethodArguments
                = new List<Expression>
                    {
                        Expression.Constant(_querySource),
                        EntityQueryModelVisitor.QueryContextParameter,
                        EntityQueryModelVisitor.QuerySourceScopeParameter,
                        _valueBufferParameter,
                        Expression.Constant(0)
                    };

            if (QueryModelVisitor.QuerySourceRequiresMaterialization(_querySource)
                || QueryModelVisitor.RequiresClientEval)
            {
                var materializer
                    = new MaterializerFactory(
                        relationalQueryCompilationContext
                            .EntityMaterializerSource)
                        .CreateMaterializer(
                            entityType,
                            selectExpression,
                            (p, se) =>
                                se.AddToProjection(
                                    relationalQueryCompilationContext.GetColumnName(p),
                                    p,
                                    _querySource),
                            _querySource);

                queryMethodInfo
                    = RelationalQueryModelVisitor.CreateEntityMethodInfo
                        .MakeGenericMethod(elementType);

                var keyProperties
                    = entityType.GetPrimaryKey().Properties;

                var keyFactory
                    = relationalQueryCompilationContext.EntityKeyFactorySource
                        .GetKeyFactory(keyProperties);

                queryMethodArguments.AddRange(
                    new[]
                        {
                            Expression.Constant(entityType),
                            Expression.Constant(QueryModelVisitor.QuerySourceRequiresTracking(_querySource)),
                            Expression.Constant(keyFactory),
                            Expression.Constant(keyProperties),
                            materializer
                        });
            }

            Func<ISqlQueryGenerator> sqlQueryGeneratorFactory;

            if (composable)
            {
                sqlQueryGeneratorFactory = () =>
                    relationalQueryCompilationContext.CreateSqlQueryGenerator(selectExpression);
            }
            else
            {
                sqlQueryGeneratorFactory = () =>
                    new RawSqlQueryGenerator(selectExpression, fromSqlAnnotation.Sql, fromSqlAnnotation.Parameters);
            }

            return Expression.Call(
                relationalQueryCompilationContext.QueryMethodProvider.ShapedQueryMethod
                    .MakeGenericMethod(queryMethodInfo.ReturnType),
                EntityQueryModelVisitor.QueryContextParameter,
                Expression.Constant(
                    new CommandBuilder(
                        sqlQueryGeneratorFactory,
                        relationalQueryCompilationContext.ValueBufferFactoryFactory)),
                Expression.Lambda(
                    Expression.Call(queryMethodInfo, queryMethodArguments),
                    _valueBufferParameter));
        }