Esempio n. 1
0
            protected override Expression VisitMember(MemberExpression node)
            {
                if (!_translateToSql)
                {
                    var sqlExpression = _selectExpression.GetProjectionForMemberInfo(node.Member);
                    if (sqlExpression != null)
                    {
                        return(BindSqlToValueBuffer(sqlExpression, node.Type));
                    }

                    if (node.Member.Name == KeyName &&
                        node.Expression.TryGetReferencedQuerySource() == _groupQuerySource)
                    {
                        var querySourceFinder = new QuerySourceFindingExpressionVisitor();
                        querySourceFinder.Visit(_keySelector);

                        var currentParameter = _queryModelVisitor.CurrentParameter;

                        foreach (var querySource in querySourceFinder.QuerySources)
                        {
                            _queryModelVisitor.QueryCompilationContext.AddOrUpdateMapping(
                                querySource,
                                currentParameter);
                        }

                        return(_projectionExpressionVisitor.Visit(_keySelector));
                    }
                }

                return(base.VisitMember(node));
            }
            protected override Expression VisitMember(MemberExpression memberExpression)
            {
                if (!_translateToSql)
                {
                    // For composite Key case, projection member info will be already populated
                    var sqlExpression = _selectExpression.GetProjectionForMemberInfo(memberExpression.Member);
                    if (sqlExpression != null)
                    {
                        return(BindSqlToValueBuffer(sqlExpression, memberExpression.Type));
                    }

                    if (memberExpression.Member.Name == KeyName &&
                        memberExpression.Expression.TryGetReferencedQuerySource() == _groupQuerySource)
                    {
                        var querySourceFinder = new QuerySourceFindingExpressionVisitor();
                        querySourceFinder.Visit(_keySelector);

                        var currentParameter = _queryModelVisitor.CurrentParameter;

                        foreach (var querySource in querySourceFinder.QuerySources)
                        {
                            _queryModelVisitor.QueryCompilationContext.AddOrUpdateMapping(
                                querySource,
                                currentParameter);
                        }

                        sqlExpression = _projectionExpressionVisitor.Visit(_keySelector);
                        _sqlMapping[memberExpression] = sqlExpression;
                        return(sqlExpression);
                    }
                }

                return(base.VisitMember(memberExpression));
            }
        /// <summary>
        ///     Visits the given node.
        /// </summary>
        /// <param name="expression"> The expression to visit. </param>
        /// <returns>
        ///     An Expression to the translated input expression.
        /// </returns>
        public override Expression Visit(Expression expression)
        {
            if (expression == null || _targetSelectExpression == null)
            {
                return(expression);
            }

            switch (expression)
            {
            // To save mappings so that we can compose afterwards
            case NewExpression newExpression:
                return(VisitNew(newExpression));

            case MemberInitExpression memberInitExpression:
                return(VisitMemberInit(memberInitExpression));

            case QuerySourceReferenceExpression qsre:
                if (_targetSelectExpression.HandlesQuerySource(qsre.ReferencedQuerySource))
                {
                    _targetSelectExpression.ProjectStarTable
                        = _targetSelectExpression.GetTableForQuerySource(qsre.ReferencedQuerySource);
                }

                return(qsre);

            // Skip over Include and Correlated Collection methods
            case MethodCallExpression methodCallExpression
                when IncludeCompiler.IsIncludeMethod(methodCallExpression) ||
                CorrelatedCollectionOptimizingVisitor.IsCorrelatedCollectionMethod(methodCallExpression):
                return(methodCallExpression);

            // Group By key translation to cover composite key cases
            case MemberExpression memberExpression
                when memberExpression.Expression.TryGetReferencedQuerySource() == _querySource &&
                _querySource.ItemType.IsGrouping() &&
                memberExpression.Member.Name == nameof(IGrouping <int, int> .Key):

                var groupResultOperator
                    = (GroupResultOperator)((SubQueryExpression)((FromClauseBase)_querySource).FromExpression)
                      .QueryModel.ResultOperators.Last();

                var sqlTranslation
                    = _sqlTranslatingExpressionVisitorFactory
                      .Create(
                          QueryModelVisitor,
                          _isGroupAggregate ? _groupAggregateTargetSelectExpression : _targetSelectExpression,
                          inProjection: true)
                      .Visit(expression);

                if (sqlTranslation == null)
                {
                    // If the key is composite then we need to visit actual keySelector to construct the type.
                    // Since we are mapping translating actual KeySelector now, we need to re-map QuerySources
                    var querySourceFinder = new QuerySourceFindingExpressionVisitor();
                    querySourceFinder.Visit(groupResultOperator.KeySelector);

                    foreach (var querySource in querySourceFinder.QuerySources)
                    {
                        QueryModelVisitor.QueryCompilationContext.AddOrUpdateMapping(
                            querySource,
                            QueryModelVisitor.CurrentParameter);
                    }

                    _isGroupAggregate = false;
                    var translatedKey = Visit(groupResultOperator.KeySelector);
                    _isGroupAggregate = true;

                    return(translatedKey);
                }
                break;
            }

            // Fallback
            var sqlExpression
                = _sqlTranslatingExpressionVisitorFactory
                  .Create(
                      QueryModelVisitor,
                      _isGroupAggregate ? _groupAggregateTargetSelectExpression : _targetSelectExpression,
                      inProjection: true)
                  .Visit(expression);

            if (sqlExpression == null)
            {
                QueryModelVisitor.RequiresClientProjection = true;

                return(base.Visit(expression));
            }
            else if (sqlExpression is ConstantExpression &&
                     QueryModelVisitor.ParentQueryModelVisitor == null)
            {
                return(base.Visit(expression));
            }
            else
            {
                sqlExpression = sqlExpression.UnwrapNullableExpression();

                // We bind with ValueBuffer in GroupByAggregate case straight away
                // Since the expression can be some translation from [g].[Key] which won't bind with MemberAccessBindingEV
                if (!_isGroupAggregate &&
                    sqlExpression is ColumnExpression)
                {
                    var index = _targetSelectExpression.AddToProjection(sqlExpression);

                    _sourceExpressionProjectionMapping[expression] = _targetSelectExpression.Projection[index];

                    return(expression);
                }

                var targetExpression
                    = QueryModelVisitor.QueryCompilationContext.QuerySourceMapping
                      .GetExpression(_querySource);

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

                    _sourceExpressionProjectionMapping[expression] = _targetSelectExpression.Projection[index];

                    var readValueExpression
                        = _entityMaterializerSource
                          .CreateReadValueExpression(
                              targetExpression,
                              expression.Type.MakeNullable(),
                              index,
                              sqlExpression.FindProperty(expression.Type));

                    var outputDataInfo
                        = (expression as SubQueryExpression)?.QueryModel
                          .GetOutputDataInfo();

                    if (outputDataInfo is StreamedScalarValueInfo)
                    {
                        // Compensate for possible nulls
                        readValueExpression
                            = Expression.Coalesce(
                                  readValueExpression,
                                  Expression.Default(expression.Type));
                    }

                    return(Expression.Convert(readValueExpression, expression.Type));
                }

                return(expression);
            }
        }