예제 #1
0
        protected override Expression VisitMethodCall(MethodCallExpression methodCall)
        {
            // TODO: Handle List<>

            {
                // Pattern match for .Where(e => new[] { "a", "b", "c" }.Any(p => EF.Functions.Like(e.SomeText, p))),
                // which we translate to WHERE s.""SomeText"" LIKE ANY (ARRAY['a','b','c']) (see test Any_like)
                // Note: NavigationExpander normalized Any(x) to Where(x).Any()
                if (methodCall.Method.IsClosedFormOf(EnumerableAnyWithPredicate) &&
                    methodCall.Arguments[0].Type.IsArray &&
                    methodCall.Arguments[1] is LambdaExpression wherePredicate &&
                    wherePredicate.Body is MethodCallExpression wherePredicateMethodCall && (
                        wherePredicateMethodCall.Method == Like2MethodInfo ||
                        wherePredicateMethodCall.Method == ILike2MethodInfo))
                {
                    var array = (SqlExpression)Visit(methodCall.Arguments[0]);
                    var match = (SqlExpression)Visit(wherePredicateMethodCall.Arguments[1]);

                    return(_sqlExpressionFactory.ArrayAnyAll(match, array, ArrayComparisonType.Any,
                                                             wherePredicateMethodCall.Method == Like2MethodInfo ? "LIKE" : "ILIKE"));
                }
            }

            // Same for All (but without the normalization
            {
                if (methodCall.Method.IsClosedFormOf(EnumerableAll) &&
                    methodCall.Arguments[0].Type.IsArray &&
                    methodCall.Arguments[1] is LambdaExpression wherePredicate &&
                    wherePredicate.Body is MethodCallExpression wherePredicateMethodCall && (
                        wherePredicateMethodCall.Method == Like2MethodInfo ||
                        wherePredicateMethodCall.Method == ILike2MethodInfo))
                {
                    var array = (SqlExpression)Visit(methodCall.Arguments[0]);
                    var match = (SqlExpression)Visit(wherePredicateMethodCall.Arguments[1]);

                    return(_sqlExpressionFactory.ArrayAnyAll(match, array, ArrayComparisonType.All,
                                                             wherePredicateMethodCall.Method == Like2MethodInfo ? "LIKE" : "ILIKE"));
                }
            }

            // Note: we also handle the above with equality instead of Like, see NpgsqlArrayMethodTranslator
            return(base.VisitMethodCall(methodCall));
        }
예제 #2
0
        /// <summary>
        /// Identifies complex array-related constructs which cannot be translated in regular method translators, since
        /// they require accessing lambdas.
        /// </summary>
        protected virtual Expression VisitArrayMethodCall(MethodInfo method, ReadOnlyCollection <Expression> arguments)
        {
            {
                // Pattern match for .Where(e => new[] { "a", "b", "c" }.Any(p => EF.Functions.Like(e.SomeText, p))),
                // which we translate to WHERE s.""SomeText"" LIKE ANY (ARRAY['a','b','c']) (see test Any_like)
                // Note: NavigationExpander normalized Any(x) to Where(x).Any()
                if (method.IsClosedFormOf(EnumerableAnyWithPredicate) &&
                    arguments[1] is LambdaExpression wherePredicate &&
                    wherePredicate.Body is MethodCallExpression wherePredicateMethodCall && (
                        wherePredicateMethodCall.Method == Like2MethodInfo ||
                        wherePredicateMethodCall.Method == ILike2MethodInfo))
                {
                    var array = (SqlExpression)Visit(arguments[0]);
                    var match = (SqlExpression)Visit(wherePredicateMethodCall.Arguments[1]);

                    return(_sqlExpressionFactory.ArrayAnyAll(match, array, ArrayComparisonType.Any,
                                                             wherePredicateMethodCall.Method == Like2MethodInfo ? "LIKE" : "ILIKE"));
                }

                // Note: we also handle the above with equality instead of Like, see NpgsqlArrayMethodTranslator
            }

            {
                // Same for All (but without the normalization)
                if (method.IsClosedFormOf(EnumerableAll) &&
                    arguments[1] is LambdaExpression wherePredicate &&
                    wherePredicate.Body is MethodCallExpression wherePredicateMethodCall && (
                        wherePredicateMethodCall.Method == Like2MethodInfo ||
                        wherePredicateMethodCall.Method == ILike2MethodInfo))
                {
                    var array = (SqlExpression)Visit(arguments[0]);
                    var match = (SqlExpression)Visit(wherePredicateMethodCall.Arguments[1]);

                    return(_sqlExpressionFactory.ArrayAnyAll(match, array, ArrayComparisonType.All,
                                                             wherePredicateMethodCall.Method == Like2MethodInfo ? "LIKE" : "ILIKE"));
                }
            }

            {
                // Translate e => new[] { 4, 5 }.Any(p => e.SomeArray.Contains(p)),
                // using array overlap (&&)
                if (method.IsClosedFormOf(EnumerableAnyWithPredicate) &&
                    arguments[1] is LambdaExpression wherePredicate &&
                    wherePredicate.Body is MethodCallExpression wherePredicateMethodCall &&
                    wherePredicateMethodCall.Method.IsClosedFormOf(Contains) &&
                    wherePredicateMethodCall.Arguments[0].Type.IsArray &&
                    wherePredicateMethodCall.Arguments[1] is ParameterExpression parameterExpression &&
                    parameterExpression == wherePredicate.Parameters[0])
                {
                    var array1          = (SqlExpression)Visit(arguments[0]);
                    var array2          = (SqlExpression)Visit(wherePredicateMethodCall.Arguments[0]);
                    var inferredMapping = ExpressionExtensions.InferTypeMapping(array1, array2);

                    return(new SqlCustomBinaryExpression(
                               _sqlExpressionFactory.ApplyTypeMapping(array1, inferredMapping),
                               _sqlExpressionFactory.ApplyTypeMapping(array2, inferredMapping),
                               "&&",
                               typeof(bool),
                               _boolMapping));
                }
            }

            {
                // Translate e => new[] { 4, 5 }.All(p => e.SomeArray.Contains(p)),
                // using array containment (<@)
                if (method.IsClosedFormOf(EnumerableAll) &&
                    arguments[1] is LambdaExpression wherePredicate &&
                    wherePredicate.Body is MethodCallExpression wherePredicateMethodCall &&
                    wherePredicateMethodCall.Method.IsClosedFormOf(Contains) &&
                    wherePredicateMethodCall.Arguments[0].Type.IsArray &&
                    wherePredicateMethodCall.Arguments[1] is ParameterExpression parameterExpression &&
                    parameterExpression == wherePredicate.Parameters[0])
                {
                    var array1          = (SqlExpression)Visit(arguments[0]);
                    var array2          = (SqlExpression)Visit(wherePredicateMethodCall.Arguments[0]);
                    var inferredMapping = ExpressionExtensions.InferTypeMapping(array1, array2);

                    return(new SqlCustomBinaryExpression(
                               _sqlExpressionFactory.ApplyTypeMapping(array1, inferredMapping),
                               _sqlExpressionFactory.ApplyTypeMapping(array2, inferredMapping),
                               "<@",
                               typeof(bool),
                               _boolMapping));
                }
            }

            return(null);
        }