public override Expression Visit(Expression expression)
        {
            if (expression == null)
            {
                return(null);
            }

            if (!(expression is NewExpression ||
                  expression is MemberInitExpression ||
                  expression is EntityShaperExpression))
            {
                // This skips the group parameter from GroupJoin
                if (expression is ParameterExpression parameter &&
                    parameter.Type.IsGenericType &&
                    parameter.Type.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                {
                    return(parameter);
                }

                if (_clientEval)
                {
                    if (expression is ConstantExpression)
                    {
                        return(expression);
                    }

                    if (expression is ParameterExpression parameterExpression)
                    {
                        return(Expression.Call(
                                   _getParameterValueMethodInfo.MakeGenericMethod(parameterExpression.Type),
                                   QueryCompilationContext2.QueryContextParameter,
                                   Expression.Constant(parameterExpression.Name)));
                    }

                    var translation = _sqlTranslator.Translate(expression);
                    if (translation == null)
                    {
                        return(base.Visit(expression));
                    }
                    else
                    {
                        return(_selectExpression.AddToProjection(translation, expression.Type));
                    }
                }
                else
                {
                    var translation = _sqlTranslator.Translate(expression);
                    if (translation == null)
                    {
                        return(null);
                    }

                    _projectionMapping[_projectionMembers.Peek()] = translation;

                    return(new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), expression.Type));
                }
            }

            return(base.Visit(expression));
        }
コード例 #2
0
        private static void LiftOrderBy(
            SelectExpression innerJoinSelectExpression,
            SelectExpression targetSelectExpression,
            TableExpressionBase innerJoinExpression)
        {
            var needOrderingChanges
                = innerJoinSelectExpression.OrderBy
                  .Any(x => x.Expression is SelectExpression ||
                       x.Expression.IsAliasWithColumnExpression() ||
                       x.Expression.IsAliasWithSelectExpression());

            var orderings = innerJoinSelectExpression.OrderBy.ToList();

            if (needOrderingChanges)
            {
                innerJoinSelectExpression.ClearOrderBy();
            }

            foreach (var ordering in orderings)
            {
                var orderingExpression = ordering.Expression;

                var aliasExpression = ordering.Expression as AliasExpression;

                if (aliasExpression?.Alias != null)
                {
                    var columnExpression = aliasExpression.TryGetColumnExpression();
                    if (columnExpression != null)
                    {
                        orderingExpression
                            = new ColumnExpression(
                                  aliasExpression.Alias,
                                  columnExpression.Property,
                                  columnExpression.Table);
                    }
                }

                var index = orderingExpression is SelectExpression
                    ? innerJoinSelectExpression.AddAliasToProjection(innerJoinSelectExpression.Alias + "_" + innerJoinSelectExpression.Projection.Count, orderingExpression)
                    : innerJoinSelectExpression.AddToProjection(orderingExpression);

                var expression = innerJoinSelectExpression.Projection[index];

                if (needOrderingChanges)
                {
                    innerJoinSelectExpression.AddToOrderBy(new Ordering(expression.TryGetColumnExpression() ?? expression, ordering.OrderingDirection));
                }

                var newExpression
                    = targetSelectExpression.UpdateColumnExpression(expression, innerJoinExpression);

                targetSelectExpression.AddToOrderBy(new Ordering(newExpression, ordering.OrderingDirection));
            }

            if ((innerJoinSelectExpression.Limit == null) &&
                (innerJoinSelectExpression.Offset == null))
            {
                innerJoinSelectExpression.ClearOrderBy();
            }
        }
コード例 #3
0
        internal static SelectExpression WhereAndSelectDatabaseExpressions(AdventureWorks adventureWorks)
        {
            QueryCompilationContext compilationContext = adventureWorks.GetService <IQueryCompilationContextFactory>()
                                                         .Create(async: false);
            SelectExpression databaseExpression = new SelectExpression(
                dependencies: new SelectExpressionDependencies(adventureWorks.GetService <IQuerySqlGeneratorFactory>(), adventureWorks.GetService <IRelationalTypeMappingSource>()),
                queryCompilationContext: (RelationalQueryCompilationContext)compilationContext);
            MainFromClause querySource = new MainFromClause(
                itemName: "product",
                itemType: typeof(Product),
                fromExpression: Expression.Constant(adventureWorks.ProductCategories));
            TableExpression tableExpression = new TableExpression(
                table: nameof(Product),
                schema: AdventureWorks.Production,
                alias: querySource.ItemName,
                querySource: querySource);

            databaseExpression.AddTable(tableExpression);
            IEntityType      productEntityType = adventureWorks.Model.FindEntityType(typeof(Product));
            IProperty        nameProperty      = productEntityType.FindProperty(nameof(Product.Name));
            ColumnExpression nameColumn        = new ColumnExpression(
                name: nameof(Product.Name), property: nameProperty, tableExpression: tableExpression);

            databaseExpression.AddToProjection(nameColumn);
            databaseExpression.AddToPredicate(Expression.GreaterThan(
                                                  left: new ExplicitCastExpression(
                                                      operand: new SqlFunctionExpression(
                                                          functionName: "LEN",
                                                          returnType: typeof(int),
                                                          arguments: new Expression[] { nameColumn }),
                                                      type: typeof(int)),
                                                  right: Expression.Constant(10)));
            return(databaseExpression.WriteLine());
        }
コード例 #4
0
        internal static SelectExpression SelectAndFirstDatabaseExpressions(AdventureWorks adventureWorks)
        {
            QueryCompilationContext compilationContext = adventureWorks.GetService <IQueryCompilationContextFactory>()
                                                         .Create(async: false);
            SelectExpression selectExpression = new SelectExpression(
                dependencies: new SelectExpressionDependencies(adventureWorks.GetService <IQuerySqlGeneratorFactory>(), adventureWorks.GetService <IRelationalTypeMappingSource>()),
                queryCompilationContext: (RelationalQueryCompilationContext)compilationContext);
            MainFromClause querySource = new MainFromClause(
                itemName: "product",
                itemType: typeof(Product),
                fromExpression: Expression.Constant(adventureWorks.ProductCategories));
            TableExpression tableExpression = new TableExpression(
                table: nameof(Product),
                schema: AdventureWorks.Production,
                alias: querySource.ItemName,
                querySource: querySource);

            selectExpression.AddTable(tableExpression);
            IEntityType productEntityType = adventureWorks.Model.FindEntityType(typeof(Product));
            IProperty   nameProperty      = productEntityType.FindProperty(nameof(Product.Name));

            selectExpression.AddToProjection(new ColumnExpression(
                                                 name: nameof(Product.Name), property: nameProperty, tableExpression: tableExpression));
            selectExpression.Limit = Expression.Constant(1);
            return(selectExpression.WriteLine());
        }
コード例 #5
0
            protected override Expression VisitEntityQueryable(Type elementType)
            {
                var relationalQueryCompilationContext = ((RelationalQueryCompilationContext)QueryCompilationContext);
                var queryMethodInfo = relationalQueryCompilationContext.EnumerableMethodProvider.QueryValues;
                var entityType      = QueryCompilationContext.Model.GetEntityType(elementType);

                var selectExpression
                    = new SelectExpression(elementType)
                    {
                    TableSource = entityType.StorageName
                    };

                _queryModelVisitor._queriesBySource.Add(_querySource, selectExpression);

                if (_queryModelVisitor.QuerySourceRequiresMaterialization(_querySource))
                {
                    foreach (var property in entityType.Properties)
                    {
                        selectExpression.AddToProjection(property);
                    }

                    queryMethodInfo
                        = relationalQueryCompilationContext.EnumerableMethodProvider.QueryEntities
                          .MakeGenericMethod(elementType);
                }

                return(Expression.Call(
                           queryMethodInfo,
                           QueryContextParameter,
                           Expression.Constant(new CommandBuilder(selectExpression, relationalQueryCompilationContext))));
            }
コード例 #6
0
        protected override Expression VisitEntityQueryable(Type elementType)
        {
            Check.NotNull(elementType, "elementType");

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

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

            selectExpression
            .AddTable(
                new TableExpression(
                    tableName,
                    QueryModelVisitor.QueryCompilationContext.GetSchema(entityType),
                    _querySource.ItemName.StartsWith("<generated>_")
                            ? tableName.First().ToString().ToLower()
                            : _querySource.ItemName,
                    _querySource));

            QueryModelVisitor.AddQuery(_querySource, selectExpression);

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

            if (QueryModelVisitor.QuerySourceRequiresMaterialization(_querySource))
            {
                foreach (var property in entityType.Properties)
                {
                    selectExpression.AddToProjection(
                        QueryModelVisitor.QueryCompilationContext
                        .GetColumnName(property),
                        property,
                        _querySource);
                }

                queryMethodInfo = RelationalQueryModelVisitor.CreateEntityMethodInfo.MakeGenericMethod(elementType);

                queryMethodArguments.Add(Expression.Constant(0));
                queryMethodArguments.Add(Expression.Constant(entityType));
                queryMethodArguments.Add(Expression.Constant(QueryModelVisitor.QuerySourceRequiresTracking(_querySource)));
            }

            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)));
        }
コード例 #7
0
        Expression VisitSelectExpression(SelectExpression selectExpression)
        {
            base.Visit(selectExpression);
            if (!RequiresRowNumberPaging(selectExpression))
            {
                return(selectExpression);
            }
            var subQuery = selectExpression.PushDownSubquery();

            foreach (var projection in subQuery.Projection)
            {
                selectExpression.AddToProjection(projection.LiftExpressionFromSubquery(subQuery));
            }
            if (subQuery.OrderBy.Count == 0)
            {
                subQuery.AddToOrderBy(
                    new Ordering(new SqlFunctionExpression("@@RowCount", typeof(int)), OrderingDirection.Asc));
            }
            var innerRowNumberExpression = new AliasExpression(
                RowNumberColumnName + (_counter != 0 ? $"{_counter}" : ""),
                new RowNumberExpression_SqlServer(subQuery.OrderBy));

            _counter++;
            subQuery.ClearOrderBy();
            subQuery.AddToProjection(innerRowNumberExpression, false);
            var rowNumberReferenceExpression = new ColumnReferenceExpression(innerRowNumberExpression, subQuery);
            var offset = subQuery.Offset ?? Expression.Constant(0);

            if (subQuery.Offset != null)
            {
                selectExpression.AddToPredicate
                    (Expression.GreaterThan(rowNumberReferenceExpression, offset));
                subQuery.Offset = null;
            }
            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);
                selectExpression.AddToPredicate(
                    Expression.LessThanOrEqual(rowNumberReferenceExpression, limitExpression));
                subQuery.Limit = null;
            }
            return(selectExpression);
        }
コード例 #8
0
        private AliasExpression CreateAliasedColumnExpression(
            IProperty property, IQuerySource querySource, SelectExpression selectExpression)
        {
            if (_targetSelectExpression != null &&
                selectExpression != _targetSelectExpression)
            {
                selectExpression?.AddToProjection(
                    _relationalAnnotationProvider.For(property).ColumnName,
                    property,
                    querySource);

                return(null);
            }

            return(CreateAliasedColumnExpressionCore(property, querySource, selectExpression));
        }
コード例 #9
0
        private AliasExpression CreateAliasedColumnExpression(
            IProperty property, IQuerySource querySource, SelectExpression selectExpression)
        {
            if (_targetSelectExpression != null &&
                selectExpression != _targetSelectExpression)
            {
                selectExpression?.AddToProjection(
                    _queryModelVisitor.QueryCompilationContext.RelationalExtensions.For(property).ColumnName,
                    property,
                    querySource);

                return(null);
            }

            return(CreateAliasedColumnExpressionCore(property, querySource, selectExpression));
        }
コード例 #10
0
            protected override Expression VisitEntityQueryable(Type elementType)
            {
                var relationalQueryCompilationContext = ((RelationalQueryCompilationContext)QueryCompilationContext);
                var queryMethodInfo = CreateValueReaderMethodInfo;
                var entityType      = QueryCompilationContext.Model.GetEntityType(elementType);

                var selectExpression = new SelectExpression();

                selectExpression
                .AddTable(
                    new TableExpression(
                        entityType.TableName(),
                        entityType.Schema(),
                        _querySource.ItemName.Replace("<generated>_", "t"),
                        _querySource));

                _queryModelVisitor._queriesBySource.Add(_querySource, selectExpression);

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

                if (_queryModelVisitor.QuerySourceRequiresMaterialization(_querySource))
                {
                    foreach (var property in entityType.Properties)
                    {
                        selectExpression.AddToProjection(property, _querySource);
                    }

                    queryMethodInfo = CreateEntityMethodInfo.MakeGenericMethod(elementType);
                    queryMethodArguments.Add(Expression.Constant(0));
                }

                return(Expression.Call(
                           relationalQueryCompilationContext.QueryMethodProvider.QueryMethod
                           .MakeGenericMethod(queryMethodInfo.ReturnType),
                           QueryContextParameter,
                           Expression.Constant(new CommandBuilder(selectExpression, relationalQueryCompilationContext)),
                           Expression.Lambda(
                               Expression.Call(queryMethodInfo, queryMethodArguments),
                               _readerParameter)));
            }
コード例 #11
0
            public override Expression?Visit(Expression?expression)
            {
                switch (expression)
                {
                case SqlExpression sqlExpression
                    when _mappings.TryGetValue(sqlExpression, out var outer):
                    return(outer);

                case ColumnExpression columnExpression
                    when _subquery.ContainsTableReference(columnExpression):
                    var index = _subquery.AddToProjection(columnExpression);

                    var projectionExpression = _subquery._projection[index];
                    return(new ColumnExpression(projectionExpression, _tableReferenceExpression));

                default:
                    return(base.Visit(expression));
                }
            }
コード例 #12
0
        private static void LiftOrderBy(
            SelectExpression innerJoinSelectExpression,
            SelectExpression targetSelectExpression,
            TableExpressionBase innerJoinExpression)
        {
            foreach (var ordering in innerJoinSelectExpression.OrderBy)
            {
                var orderingExpression = ordering.Expression;

                var aliasExpression = ordering.Expression as AliasExpression;

                if (aliasExpression?.Alias != null)
                {
                    var columnExpression = aliasExpression.TryGetColumnExpression();

                    if (columnExpression != null)
                    {
                        orderingExpression
                            = new ColumnExpression(
                                  aliasExpression.Alias,
                                  columnExpression.Property,
                                  columnExpression.Table);
                    }
                }

                var index = innerJoinSelectExpression.AddToProjection(orderingExpression);

                var expression = innerJoinSelectExpression.Projection[index];

                var newExpression
                    = targetSelectExpression.UpdateColumnExpression(expression, innerJoinExpression);

                targetSelectExpression.AddToOrderBy(new Ordering(newExpression, ordering.OrderingDirection));
            }

            if (innerJoinSelectExpression.Limit == null &&
                innerJoinSelectExpression.Offset == null)
            {
                innerJoinSelectExpression.ClearOrderBy();
            }
        }
コード例 #13
0
            private Expression BindSqlToValueBuffer(Expression sqlExpression, Type expressionType)
            {
                var targetExpression
                    = _queryModelVisitor.QueryCompilationContext.QuerySourceMapping
                      .GetExpression(_groupQuerySource);

                if (targetExpression.Type == typeof(ValueBuffer))
                {
                    var index = _selectExpression.AddToProjection(sqlExpression);

                    var readValueExpression
                        = _entityMaterializerSource
                          .CreateReadValueExpression(
                              targetExpression,
                              expressionType,
                              index,
                              sqlExpression.FindProperty(expressionType));

                    return(Expression.Convert(readValueExpression, expressionType));
                }

                return(null);
            }
コード例 #14
0
        Expression VisitSelectExpression(SelectExpression selectExpression)
        {
            base.Visit(selectExpression);
            if (!RequiresRowNumberPaging(selectExpression))
            {
                return(selectExpression);
            }
            SelectExpression selectExpression2 = selectExpression.PushDownSubquery();

            foreach (Expression item in selectExpression2.Projection)
            {
                selectExpression.AddToProjection(item.LiftExpressionFromSubquery(selectExpression2), true);
            }
            AliasExpression aliasExpression = new AliasExpression("row_number" + ((_counter != 0) ? $"{_counter}" : ""), new RowNumberExpression_DB2(selectExpression2.OrderBy));

            _counter++;
            selectExpression2.ClearOrderBy();
            selectExpression2.AddToProjection(aliasExpression, false);
            ColumnReferenceExpression left = new ColumnReferenceExpression(aliasExpression, selectExpression2);
            Expression expression          = selectExpression2.Offset ?? Expression.Constant(0);

            if (selectExpression2.Offset != null)
            {
                selectExpression.AddToPredicate(Expression.GreaterThan(left, expression));
                selectExpression2.Offset = null;
            }
            if (selectExpression2.Limit != null)
            {
                object     obj   = (selectExpression2.Limit as ConstantExpression)?.Value;
                object     obj2  = (expression as ConstantExpression)?.Value;
                Expression right = (obj != null && obj2 != null) ? ((Expression)Expression.Constant((int)obj2 + (int)obj)) : ((Expression)Expression.Add(expression, selectExpression2.Limit));
                selectExpression.AddToPredicate(Expression.LessThanOrEqual(left, right));
                selectExpression2.Limit = null;
            }
            return(selectExpression);
        }
コード例 #15
0
        private IEnumerable <Expression> CreateIncludeRelatedValuesStrategyFactories(
            IQuerySource querySource,
            IEnumerable <INavigation> navigationPath)
        {
            var selectExpression
                = _queryCompilationContext.FindSelectExpression(querySource);

            var targetTableExpression
                = selectExpression.FindTableForQuerySource(querySource);

            var readerIndex = 0;

            foreach (var navigation in navigationPath)
            {
                if (!navigation.IsCollection())
                {
                    var targetEntityType = navigation.GetTargetType();
                    var targetTableName  = _queryCompilationContext.GetTableName(targetEntityType);
                    var targetTableAlias = targetTableName.First().ToString().ToLower();

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

                    var readerOffset = selectExpression.Projection.Count;

                    var columnExpressions
                        = targetEntityType.Properties
                          .Select(p => new ColumnExpression(
                                      _queryCompilationContext.GetColumnName(p),
                                      p,
                                      joinedTableExpression));

                    var joinExpression
                        = navigation.ForeignKey.IsRequired &&
                          navigation.PointsToPrincipal
                            ? selectExpression
                          .AddInnerJoin(joinedTableExpression, columnExpressions)
                            : selectExpression
                          .AddOuterJoin(joinedTableExpression, columnExpressions);

                    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(readerIndex),
                                 Expression.Constant(readerOffset))));
                }
                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 targetEntityType = navigation.GetTargetType();
                    var targetTableName  = _queryCompilationContext.GetTableName(targetEntityType);
                    var targetTableAlias = targetTableName.First().ToString().ToLower();

                    var targetSelectExpression = new SelectExpression();

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

                    targetSelectExpression.AddTable(targetTableExpression);

                    foreach (var property in targetEntityType.Properties)
                    {
                        targetSelectExpression
                        .AddToProjection(
                            _queryCompilationContext.GetColumnName(property),
                            property,
                            querySource);
                    }

                    var innerJoinSelectExpression
                        = selectExpression.Clone(
                              ((ColumnExpression)selectExpression.OrderBy.Last().Expression).TableAlias);

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

                    foreach (var columnExpression
                             in innerJoinSelectExpression.OrderBy
                             .Select(o => o.Expression)
                             .Cast <ColumnExpression>())
                    {
                        innerJoinSelectExpression.AddToProjection(columnExpression);
                    }

                    innerJoinSelectExpression.ClearOrderBy();

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

                    var innerJoinExpression
                        = targetSelectExpression.AddInnerJoin(innerJoinSelectExpression);

                    foreach (var ordering in selectExpression.OrderBy)
                    {
                        var columnExpression = (ColumnExpression)ordering.Expression;

                        targetSelectExpression
                        .AddToOrderBy(
                            columnExpression.Name,
                            columnExpression.Property,
                            innerJoinExpression,
                            ordering.OrderingDirection);
                    }

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

                    var readerParameter = Expression.Parameter(typeof(DbDataReader));

                    selectExpression = targetSelectExpression;
                    readerIndex++;

                    yield return
                        (Expression.Lambda(
                             Expression.Call(
                                 _queryCompilationContext.QueryMethodProvider
                                 .CreateCollectionIncludeRelatedValuesStrategyMethod,
                                 Expression.Call(
                                     _queryCompilationContext.QueryMethodProvider.QueryMethod
                                     .MakeGenericMethod(typeof(IValueReader)),
                                     EntityQueryModelVisitor.QueryContextParameter,
                                     Expression.Constant(new CommandBuilder(targetSelectExpression, _queryCompilationContext)),
                                     Expression.Lambda(
                                         Expression.Call(
                                             _createValueReaderForIncludeMethodInfo,
                                             EntityQueryModelVisitor.QueryContextParameter,
                                             readerParameter,
                                             Expression.Constant(targetEntityType)),
                                         readerParameter)))));
                }
            }
        }
コード例 #16
0
            private Expression VisitSelectExpression(SelectExpression selectExpression)
            {
                base.Visit(selectExpression);

                if (!RequiresRowNumberPaging(selectExpression))
                {
                    return(selectExpression);
                }

                var projections = new List <Expression>();

                projections.AddRange(selectExpression.Projection);

                var subQuery = selectExpression.PushDownSubquery();

                foreach (var projection in projections)
                {
                    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(column.Name, column.Property, subQuery);
                        alias  = new AliasExpression(alias.Alias, column);
                        selectExpression.AddToProjection(alias);
                    }
                    else
                    {
                        selectExpression.AddToProjection(projection);
                    }
                }

                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.ClearProjection();
                subQuery.AddToProjection(rowNumber);
                subQuery.IsProjectStar = true;

                Expression predicate = null;

                var offset = subQuery.Offset ?? 0;

                if (subQuery.Offset.HasValue)
                {
                    predicate = Expression.GreaterThan(columnExpression, Expression.Constant(offset));
                }

                if (subQuery.Limit.HasValue)
                {
                    var exp = Expression.LessThanOrEqual(columnExpression, Expression.Constant(offset + subQuery.Limit.Value));
                    if (predicate != null)
                    {
                        exp = Expression.AndAlso(predicate, exp);
                    }
                    predicate = exp;
                }

                selectExpression.Predicate = predicate;

                return(selectExpression);
            }
コード例 #17
0
        public override Expression Visit(Expression expression)
        {
            if (expression == null)
            {
                return(null);
            }

            if (!(expression is NewExpression ||
                  expression is MemberInitExpression ||
                  expression is EntityShaperExpression ||
                  expression is IncludeExpression))
            {
                // This skips the group parameter from GroupJoin
                if (expression is ParameterExpression parameter &&
                    parameter.Type.IsGenericType &&
                    parameter.Type.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                {
                    return(parameter);
                }

                if (_clientEval)
                {
                    if (expression is ConstantExpression)
                    {
                        return(expression);
                    }

                    if (expression is ParameterExpression parameterExpression)
                    {
                        return(Expression.Call(
                                   _getParameterValueMethodInfo.MakeGenericMethod(parameterExpression.Type),
                                   QueryCompilationContext.QueryContextParameter,
                                   Expression.Constant(parameterExpression.Name)));
                    }

                    if (expression is MaterializeCollectionNavigationExpression materializeCollectionNavigationExpression)
                    {
                        return(_selectExpression.AddCollectionProjection(
                                   _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(
                                       materializeCollectionNavigationExpression.Subquery),
                                   materializeCollectionNavigationExpression.Navigation, null));
                    }

                    if (expression is MethodCallExpression methodCallExpression)
                    {
                        if (methodCallExpression.Method.IsGenericMethod &&
                            methodCallExpression.Method.DeclaringType == typeof(Enumerable) &&
                            methodCallExpression.Method.Name == nameof(Enumerable.ToList))
                        {
                            var elementType = methodCallExpression.Method.GetGenericArguments()[0];

                            var result = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression.Arguments[0]);

                            return(_selectExpression.AddCollectionProjection(result, null, elementType));
                        }

                        var subquery = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression);

                        if (subquery != null)
                        {
                            if (subquery.ResultType == ResultType.Enumerable)
                            {
                                return(_selectExpression.AddCollectionProjection(subquery, null, subquery.ShaperExpression.Type));
                            }
                        }
                    }

                    var translation = _sqlTranslator.Translate(expression);
                    if (translation == null)
                    {
                        return(base.Visit(expression));
                    }
                    else
                    {
                        return(new ProjectionBindingExpression(_selectExpression, _selectExpression.AddToProjection(translation), expression.Type));
                    }
                }
                else
                {
                    var translation = _sqlTranslator.Translate(expression);
                    if (translation == null)
                    {
                        return(null);
                    }

                    _projectionMapping[_projectionMembers.Peek()] = translation;

                    return(new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), expression.Type));
                }
            }

            return(base.Visit(expression));
        }
コード例 #18
0
        public override Expression?Visit(Expression?expression)
        {
            if (expression == null)
            {
                return(null);
            }

            if (!(expression is NewExpression ||
                  expression is MemberInitExpression ||
                  expression is EntityShaperExpression ||
                  expression is IncludeExpression))
            {
                // This skips the group parameter from GroupJoin
                if (expression is ParameterExpression parameter &&
                    parameter.Type.IsGenericType &&
                    parameter.Type.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                {
                    return(parameter);
                }

                if (_clientEval)
                {
                    switch (expression)
                    {
                    case ConstantExpression _:
                        return(expression);

                    case ProjectionBindingExpression projectionBindingExpression:
                        if (projectionBindingExpression.Index is int index)
                        {
                            var newIndex = _selectExpression.AddToProjection(_existingProjections[index]);

                            return(new ProjectionBindingExpression(_selectExpression, newIndex, expression.Type));
                        }

                        if (projectionBindingExpression.ProjectionMember != null)
                        {
                            // This would be SqlExpression. EntityProjectionExpression would be wrapped inside EntityShaperExpression.
                            var mappedProjection = (SqlExpression)((SelectExpression)projectionBindingExpression.QueryExpression)
                                                   .GetMappedProjection(projectionBindingExpression.ProjectionMember);

                            return(new ProjectionBindingExpression(
                                       _selectExpression, _selectExpression.AddToProjection(mappedProjection), expression.Type));
                        }

                        throw new InvalidOperationException(CoreStrings.TranslationFailed(projectionBindingExpression.Print()));

                    case ParameterExpression parameterExpression:
                        if (parameterExpression.Name?.StartsWith(QueryCompilationContext.QueryParameterPrefix, StringComparison.Ordinal)
                            == true)
                        {
                            return(Expression.Call(
                                       _getParameterValueMethodInfo.MakeGenericMethod(parameterExpression.Type),
                                       QueryCompilationContext.QueryContextParameter,
                                       Expression.Constant(parameterExpression.Name)));
                        }

                        throw new InvalidOperationException(CoreStrings.TranslationFailed(parameterExpression.Print()));

                    case MaterializeCollectionNavigationExpression materializeCollectionNavigationExpression:
                        return(_selectExpression.AddCollectionProjection(
                                   _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(
                                       materializeCollectionNavigationExpression.Subquery) !,
                                   materializeCollectionNavigationExpression.Navigation,
                                   materializeCollectionNavigationExpression.Navigation.ClrType.TryGetSequenceType() !));

                    case MethodCallExpression methodCallExpression:
                    {
                        if (methodCallExpression.Method.IsGenericMethod &&
                            methodCallExpression.Method.DeclaringType == typeof(Enumerable) &&
                            methodCallExpression.Method.Name == nameof(Enumerable.ToList))
                        {
                            var elementType = methodCallExpression.Method.GetGenericArguments()[0];

                            var result = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(
                                methodCallExpression.Arguments[0]);

                            if (result != null)
                            {
                                return(_selectExpression.AddCollectionProjection(result, null, elementType));
                            }
                        }
                        else
                        {
                            var subquery = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression);
                            if (subquery != null)
                            {
                                if (subquery.ResultCardinality == ResultCardinality.Enumerable)
                                {
                                    return(_selectExpression.AddCollectionProjection(subquery, null, subquery.ShaperExpression.Type));
                                }
コード例 #19
0
            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(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);
            }
コード例 #20
0
        public override Expression Visit(Expression expression)
        {
            if (expression == null)
            {
                return(null);
            }

            if (!(expression is NewExpression ||
                  expression is MemberInitExpression ||
                  expression is EntityShaperExpression ||
                  expression is IncludeExpression))
            {
                // This skips the group parameter from GroupJoin
                if (expression is ParameterExpression parameter &&
                    parameter.Type.IsGenericType &&
                    parameter.Type.GetGenericTypeDefinition() == typeof(IEnumerable <>))
                {
                    return(parameter);
                }

                if (_clientEval)
                {
                    if (expression is ConstantExpression)
                    {
                        return(expression);
                    }

                    if (expression is ParameterExpression parameterExpression)
                    {
                        return(Expression.Call(
                                   _getParameterValueMethodInfo.MakeGenericMethod(parameterExpression.Type),
                                   QueryCompilationContext.QueryContextParameter,
                                   Expression.Constant(parameterExpression.Name)));
                    }

                    if (expression is MethodCallExpression methodCallExpression &&
                        methodCallExpression.Method.Name == "MaterializeCollectionNavigation")
                    {
                        var result     = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression.Arguments[0]);
                        var navigation = (INavigation)((ConstantExpression)methodCallExpression.Arguments[1]).Value;

                        return(_selectExpression.AddCollectionProjection(result, navigation));
                    }

                    var translation = _sqlTranslator.Translate(expression);
                    if (translation == null)
                    {
                        return(base.Visit(expression));
                    }
                    else
                    {
                        return(_selectExpression.AddToProjection(translation, expression.Type));
                    }
                }
                else
                {
                    var translation = _sqlTranslator.Translate(expression);
                    if (translation == null)
                    {
                        return(null);
                    }

                    _projectionMapping[_projectionMembers.Peek()] = translation;

                    return(new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), expression.Type));
                }
            }

            return(base.Visit(expression));
        }
コード例 #21
0
        private void IncludeCollection(IQuerySource querySource, Type resultType, Expression accessorLambda, INavigation navigation)
        {
            var selectExpression = QueryCompilationContext.FindSelectExpression(querySource);

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

            foreach (var property in primaryKeyProperties)
            {
                selectExpression
                .AddToOrderBy(
                    QueryCompilationContext.GetColumnName(property),
                    property,
                    querySource,
                    OrderingDirection.Asc);
            }

            var targetEntityType = navigation.GetTargetType();
            var targetTableName  = QueryCompilationContext.GetTableName(targetEntityType);

            var targetSelectExpression = new SelectExpression();

            var targetTableAlias
                = CreateUniqueAlias(selectExpression, targetTableName.First().ToString().ToLower());

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

            targetSelectExpression.AddTable(targetTableExpression);

            foreach (var property in targetEntityType.Properties)
            {
                targetSelectExpression
                .AddToProjection(
                    QueryCompilationContext.GetColumnName(property),
                    property,
                    querySource);
            }

            var innerJoinSelectExpression
                = selectExpression.Clone(
                      ((ColumnExpression)selectExpression.OrderBy.First().Expression).TableAlias);

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

            foreach (var columnExpression
                     in innerJoinSelectExpression.OrderBy
                     .Select(o => o.Expression)
                     .Cast <ColumnExpression>())
            {
                innerJoinSelectExpression.AddToProjection(columnExpression);
            }

            innerJoinSelectExpression.ClearOrderBy();

            var innerJoinExpression
                = targetSelectExpression.AddInnerJoin(innerJoinSelectExpression);

            targetSelectExpression.AddToOrderBy(selectExpression.OrderBy);

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

            var readerParameter = Expression.Parameter(typeof(DbDataReader));

            Expression
                = Expression.Call(
                      QueryCompilationContext.QueryMethodProvider.IncludeCollectionMethod
                      .MakeGenericMethod(resultType),
                      QueryContextParameter,
                      Expression,
                      Expression.Constant(navigation),
                      Expression.Call(
                          QueryCompilationContext.QueryMethodProvider.QueryMethod
                          .MakeGenericMethod(typeof(IValueReader)),
                          QueryContextParameter,
                          Expression.Constant(new CommandBuilder(targetSelectExpression, QueryCompilationContext)),
                          Expression.Lambda(
                              Expression.Call(
                                  _createValueReaderForIncludeMethodInfo,
                                  QueryContextParameter,
                                  readerParameter,
                                  Expression.Constant(targetEntityType)),
                              readerParameter)),
                      accessorLambda);
        }