protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression)
        {
            if (methodCallExpression.TryGetEFPropertyArguments(out var source, out var propertyName))
            {
                return(BindProperty(source, propertyName));
            }

            var subqueryTranslation = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression);

            if (subqueryTranslation != null)
            {
                if (subqueryTranslation.ResultType == ResultType.Enumerable)
                {
                    return(null);
                }

                var subquery = (SelectExpression)subqueryTranslation.QueryExpression;
                subquery.ApplyProjection();

                if (subquery.Projection.Count != 1)
                {
                    return(null);
                }

                if ((methodCallExpression.Method.Name == nameof(Queryable.Any) ||
                     methodCallExpression.Method.Name == nameof(Queryable.All) ||
                     methodCallExpression.Method.Name == nameof(Queryable.Contains)) &&
                    subquery.Tables.Count == 0)
                {
                    return(subquery.Projection[0].Expression);
                }

                return(new SubSelectExpression(subquery));
            }

            var @object = Visit(methodCallExpression.Object);

            if (TranslationFailed(methodCallExpression.Object, @object))
            {
                return(null);
            }

            var arguments = new SqlExpression[methodCallExpression.Arguments.Count];

            for (var i = 0; i < arguments.Length; i++)
            {
                var argument = Visit(methodCallExpression.Arguments[i]);
                if (TranslationFailed(methodCallExpression.Arguments[i], argument))
                {
                    return(null);
                }
                arguments[i] = (SqlExpression)argument;
            }

            return(_methodCallTranslatorProvider.Translate(_model, (SqlExpression)@object, methodCallExpression.Method, arguments));
        }
コード例 #2
0
        protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression)
        {
            // EF.Property case
            if (methodCallExpression.TryGetEFPropertyArguments(out var source, out var propertyName))
            {
                if (TryBindMember(source, MemberIdentity.Create(propertyName), out var result))
                {
                    return(result);
                }

#pragma warning disable CA1303 // Do not pass literals as localized parameters
                throw new InvalidOperationException("EF.Property called with wrong property name.");
#pragma warning restore CA1303 // Do not pass literals as localized parameters
            }

            // GroupBy Aggregate case
            if (methodCallExpression.Object == null &&
                methodCallExpression.Method.DeclaringType == typeof(Enumerable) &&
                methodCallExpression.Arguments.Count > 0 &&
                methodCallExpression.Arguments[0] is GroupByShaperExpression groupByShaperExpression)
            {
                var translatedAggregate = methodCallExpression.Method.Name switch
                {
                    nameof(Enumerable.Average) => TranslateAverage(GetSelector(methodCallExpression, groupByShaperExpression)),
                    nameof(Enumerable.Count) => TranslateCount(GetPredicate(methodCallExpression, groupByShaperExpression)),
                    nameof(Enumerable.LongCount) => TranslateLongCount(GetPredicate(methodCallExpression, groupByShaperExpression)),
                    nameof(Enumerable.Max) => TranslateMax(GetSelector(methodCallExpression, groupByShaperExpression)),
                    nameof(Enumerable.Min) => TranslateMin(GetSelector(methodCallExpression, groupByShaperExpression)),
                    nameof(Enumerable.Sum) => TranslateSum(GetSelector(methodCallExpression, groupByShaperExpression)),
                    _ => null
                };

                if (translatedAggregate == null)
                {
                    throw new InvalidOperationException(CoreStrings.TranslationFailed(methodCallExpression.Print()));
                }

                return(translatedAggregate);
            }

            // Subquery case
            var subqueryTranslation = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression);
            if (subqueryTranslation != null)
            {
        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 MaterializeCollectionNavigationExpression materializeCollectionNavigationExpression:
                        //return _selectExpression.AddCollectionProjection(
                        //    _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(
                        //    materializeCollectionNavigationExpression.Subquery),
                        //    materializeCollectionNavigationExpression.Navigation, null);
                        throw new NotImplementedException();

                    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]);

                            //return _selectExpression.AddCollectionProjection(result, null, elementType);
                            throw new NotImplementedException();
                        }

                        var subquery = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression);

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

                        break;
                    }
                    }


                    var translation = _expressionTranslatingExpressionVisitor.Translate(expression);
                    return(translation == null
                        ? base.Visit(expression)
                        : new ProjectionBindingExpression(_queryExpression, _queryExpression.AddToProjection(translation), expression.Type));
                }
                else
                {
                    var translation = _expressionTranslatingExpressionVisitor.Translate(expression);
                    if (translation == null)
                    {
                        return(null);
                    }

                    _projectionMapping[_projectionMembers.Peek()] = translation;

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

            return(base.Visit(expression));
        }
コード例 #4
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));
        }
コード例 #5
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));
        }
コード例 #6
0
        protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression)
        {
            // EF.Property case
            if (methodCallExpression.TryGetEFPropertyArguments(out var source, out var propertyName))
            {
                return(BindProperty(Visit(source), propertyName, methodCallExpression.Type));
            }

            // Subquery case
            var subqueryTranslation = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression);

            if (subqueryTranslation != null)
            {
                var subquery = (InMemoryQueryExpression)subqueryTranslation.QueryExpression;
                if (subqueryTranslation.ResultType == ResultType.Enumerable)
                {
                    return(null);
                }

                subquery.ApplyServerProjection();
                if (subquery.Projection.Count != 1)
                {
                    return(null);
                }

                Expression result;

                // Unwrap ResultEnumerable
                var selectMethod     = (MethodCallExpression)subquery.ServerQueryExpression;
                var resultEnumerable = (NewExpression)selectMethod.Arguments[0];
                var resultFunc       = ((LambdaExpression)resultEnumerable.Arguments[0]).Body;
                // New ValueBuffer construct
                if (resultFunc is NewExpression newValueBufferExpression)
                {
                    var innerExpression = ((NewArrayExpression)newValueBufferExpression.Arguments[0]).Expressions[0];
                    if (innerExpression is UnaryExpression unaryExpression &&
                        innerExpression.NodeType == ExpressionType.Convert &&
                        innerExpression.Type == typeof(object))
                    {
                        result = unaryExpression.Operand;
                    }
                    else
                    {
                        result = innerExpression;
                    }

                    return(result.Type == methodCallExpression.Type
                        ? result
                        : Expression.Convert(result, methodCallExpression.Type));
                }
                else
                {
                    var selector            = (LambdaExpression)selectMethod.Arguments[1];
                    var readValueExpression = ((NewArrayExpression)((NewExpression)selector.Body).Arguments[0]).Expressions[0];
                    if (readValueExpression is UnaryExpression unaryExpression2 &&
                        unaryExpression2.NodeType == ExpressionType.Convert &&
                        unaryExpression2.Type == typeof(object))
                    {
                        readValueExpression = unaryExpression2.Operand;
                    }

                    var valueBufferVariable    = Expression.Variable(typeof(ValueBuffer));
                    var replacedReadExpression = ReplacingExpressionVisitor.Replace(
                        selector.Parameters[0],
                        valueBufferVariable,
                        readValueExpression);

                    replacedReadExpression = replacedReadExpression.Type == methodCallExpression.Type
                        ? replacedReadExpression
                        : Expression.Convert(replacedReadExpression, methodCallExpression.Type);

                    return(Expression.Block(
                               variables: new[] { valueBufferVariable },
                               Expression.Assign(valueBufferVariable, resultFunc),
                               Expression.Condition(
                                   Expression.MakeMemberAccess(valueBufferVariable, _valueBufferIsEmpty),
                                   Expression.Default(methodCallExpression.Type),
                                   replacedReadExpression)));
                }
            }
コード例 #7
0
        protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression)
        {
            if (methodCallExpression.TryGetEFPropertyArguments(out var source, out var propertyName))
            {
                Type convertedType = null;
                if (source is UnaryExpression unaryExpression &&
                    unaryExpression.NodeType == ExpressionType.Convert)
                {
                    source = unaryExpression.Operand;
                    if (unaryExpression.Type != typeof(object))
                    {
                        convertedType = unaryExpression.Type;
                    }
                }

                if (source is EntityShaperExpression entityShaper)
                {
                    var entityType = entityShaper.EntityType;
                    if (convertedType != null)
                    {
                        entityType = entityType.RootType().GetDerivedTypesInclusive()
                                     .FirstOrDefault(et => et.ClrType == convertedType);
                    }

                    if (entityType != null)
                    {
                        var property = entityType.FindProperty(propertyName);

                        return(BindProperty(entityShaper, property));
                    }
                }

                throw new InvalidOperationException();
            }

            if (methodCallExpression.Method.DeclaringType == typeof(Queryable))
            {
                var translation = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression);

                var subquery = (SelectExpression)translation.QueryExpression;
                subquery.ApplyProjection();

                if (methodCallExpression.Method.Name == nameof(Queryable.Any) ||
                    methodCallExpression.Method.Name == nameof(Queryable.All) ||
                    methodCallExpression.Method.Name == nameof(Queryable.Contains))
                {
                    if (subquery.Tables.Count == 0 &&
                        subquery.Projection.Count == 1)
                    {
                        return(subquery.Projection[0].Expression);
                    }
                    else
                    {
                        throw new InvalidOperationException();
                    }
                }
                else
                {
                    return(new SubSelectExpression(subquery));
                }
            }

            var @object = Visit(methodCallExpression.Object);

            if (TranslationFailed(methodCallExpression.Object, @object))
            {
                return(null);
            }

            var arguments = new SqlExpression[methodCallExpression.Arguments.Count];

            for (var i = 0; i < arguments.Length; i++)
            {
                var argument = Visit(methodCallExpression.Arguments[i]);
                if (TranslationFailed(methodCallExpression.Arguments[i], argument))
                {
                    return(null);
                }
                arguments[i] = (SqlExpression)argument;
            }

            return(_methodCallTranslatorProvider.Translate(_model, (SqlExpression)@object, methodCallExpression.Method, arguments));
        }