Example #1
0
            protected override Expression VisitLeaf(Expression node)
            {
                if (translatabilityVisitor.Visit(node) is TranslatableExpression)
                {
                    var path = string.Join(".", GetNameParts());

                    if (!readValueExpressions.TryGetValue(path, out var readValueExpression))
                    {
                        var readValueExpressionFactory
                            = readValueExpressionFactories
                              .FirstOrDefault(f => f.CanReadExpression(node));

                        if (readValueExpressionFactory == null)
                        {
                            throw new NotSupportedException("Could not find an expression factory to read a value.");
                        }

                        readValueExpression
                            = readValueExpressionFactory
                              .CreateExpression(node, readerParameter, readerIndex++);

                        readValueExpressions[path] = readValueExpression;
                    }

                    return(readValueExpression);
                }

                return(node);
            }
Example #2
0
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            var @object   = Visit(node.Object);
            var arguments = Visit(node.Arguments);

            if (node.Method.IsGenericMethod &&
                node.Method.GetGenericMethodDefinition() == enumerableContainsMethodInfo &&
                arguments[0].Type.GetSequenceType().IsScalarType() &&
                translatabilityAnalyzingExpressionVisitor.Visit(arguments[1]) is TranslatableExpression)
            {
                var canUseValues = false;

                switch (arguments[0])
                {
                case ConstantExpression constantExpression:
                {
                    canUseValues = constantExpression.Value != null;
                    break;
                }

                case NewArrayExpression newArrayExpression:
                {
                    canUseValues = true;
                    break;
                }

                case ListInitExpression listInitExpression:
                {
                    canUseValues = listInitExpression.Initializers.All(i => i.Arguments.Count == 1);
                    break;
                }

                case Expression expression:
                {
                    canUseValues = true;
                    break;
                }
                }

                if (canUseValues)
                {
                    return(new SqlInExpression(arguments[1], arguments[0]));
                }
            }

            return(node.Update(@object, arguments));
        }
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            var @object   = Visit(node.Object);
            var arguments = Visit(node.Arguments);

            var method = node.Method;

            var collectionType = method.DeclaringType.FindGenericType(typeof(ICollection <>));

            if (collectionType != null &&
                @object.Type.GetSequenceType().IsScalarType() &&
                translatabilityAnalyzingExpressionVisitor.Visit(arguments[0]) is TranslatableExpression)
            {
                var canRewriteMethod = false;

                if (method.DeclaringType == collectionType)
                {
                    canRewriteMethod = true;
                }
                else
                {
                    var map = method.DeclaringType.GetTypeInfo().GetRuntimeInterfaceMap(collectionType);

                    var index = map.InterfaceMethods.ToList().FindIndex(m => m.Name == nameof(ICollection <int> .Contains));

                    canRewriteMethod = method == map.TargetMethods[index];
                }

                if (canRewriteMethod)
                {
                    var canUseValues = false;

                    switch (@object)
                    {
                    case ConstantExpression constantExpression:
                    {
                        canUseValues = constantExpression.Value != null;
                        break;
                    }

                    case NewArrayExpression newArrayExpression:
                    {
                        canUseValues = true;
                        break;
                    }

                    case ListInitExpression listInitExpression:
                    {
                        canUseValues = listInitExpression.Initializers.All(i => i.Arguments.Count == 1);
                        break;
                    }

                    case Expression expression:
                    {
                        canUseValues = true;
                        break;
                    }
                    }

                    if (canUseValues)
                    {
                        return(new SqlInExpression(arguments[0], @object));
                    }
                }
            }

            return(node.Update(@object, arguments));
        }
Example #4
0
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            var @object   = Visit(node.Object);
            var arguments = Visit(node.Arguments);

            if (node.Method.IsQueryableOrEnumerableMethod() &&
                !node.ContainsNonLambdaDelegates() &&
                arguments[0] is GroupByResultExpression relationalGrouping)
            {
                switch (node.Method.Name)
                {
                case nameof(Queryable.Average):
                case nameof(Queryable.Max) when node.Method.ReturnType.IsScalarType():
                case nameof(Queryable.Min) when node.Method.ReturnType.IsScalarType():
                case nameof(Queryable.Sum):
                {
                    var selector = relationalGrouping.ElementSelector;

                    if (node.Arguments.Count == 2)
                    {
                        selector = node.Arguments[1].UnwrapLambda().ExpandParameters(selector);
                    }

                    if (!(translatabilityAnalyzingExpressionVisitor.Visit(selector) is TranslatableExpression))
                    {
                        break;
                    }

                    if (node.Method.Name == nameof(Queryable.Average))
                    {
                        return(new SqlAggregateExpression(
                                   "AVG",
                                   new SqlCastExpression(selector, node.Method.ReturnType),
                                   node.Method.ReturnType,
                                   relationalGrouping.IsDistinct && node.Arguments.Count == 1));
                    }

                    return(new SqlAggregateExpression(
                               node.Method.Name.ToUpperInvariant(),
                               selector,
                               node.Method.ReturnType,
                               relationalGrouping.IsDistinct && node.Arguments.Count == 1));
                }

                case nameof(Queryable.Count):
                case nameof(Queryable.LongCount):
                {
                    var selector = relationalGrouping.ElementSelector;

                    if (node.Arguments.Count == 2)
                    {
                        var predicate = node.Arguments[1].UnwrapLambda().ExpandParameters(selector);

                        if (!(translatabilityAnalyzingExpressionVisitor.Visit(predicate) is TranslatableExpression))
                        {
                            break;
                        }

                        selector
                            = Expression.Condition(
                                  predicate,
                                  Expression.Constant(1, typeof(int?)),
                                  Expression.Constant(null, typeof(int?)));
                    }

                    return(new SqlAggregateExpression(
                               "COUNT",
                               selector.Type.IsScalarType() ? selector : new SqlFragmentExpression("*", selector.Type),
                               node.Method.ReturnType,
                               relationalGrouping.IsDistinct && node.Arguments.Count == 1));
                }

                case nameof(Queryable.Distinct):
                {
                    return(new GroupByResultExpression(
                               relationalGrouping.SelectExpression,
                               relationalGrouping.OuterKeySelector,
                               relationalGrouping.InnerKeySelector,
                               relationalGrouping.InnerKeyLambda,
                               relationalGrouping.ElementSelector,
                               true));
                }

                case nameof(Queryable.Select):
                {
                    var selectorLambda = node.Arguments[1].UnwrapLambda();

                    if (selectorLambda == null || selectorLambda.Parameters.Count == 2)
                    {
                        // index parameter not supported
                        break;
                    }

                    var selectorBody
                        = selectorLambda
                          .ExpandParameters(relationalGrouping.ElementSelector);

                    if (!(translatabilityAnalyzingExpressionVisitor.Visit(selectorBody) is TranslatableExpression))
                    {
                        break;
                    }

                    return(new GroupByResultExpression(
                               relationalGrouping.SelectExpression,
                               relationalGrouping.OuterKeySelector,
                               relationalGrouping.InnerKeySelector,
                               relationalGrouping.InnerKeyLambda,
                               selectorBody,
                               relationalGrouping.IsDistinct));
                }
                }
            }

            return(node.Update(@object, arguments));
        }