/// <summary>
        ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to
        ///     the same compatibility standards as public APIs. It may be changed or removed without notice in
        ///     any release. You should only use it directly in your code with extreme caution and knowing that
        ///     doing so can result in application failures when updating to a new Entity Framework Core release.
        /// </summary>
        protected override Expression VisitUnary(UnaryExpression unaryExpression)
        {
            Check.NotNull(unaryExpression, nameof(unaryExpression));

            var operand = Visit(unaryExpression.Operand);

            if (TranslationFailed(unaryExpression.Operand, operand, out var sqlOperand))
            {
                return(null);
            }

            switch (unaryExpression.NodeType)
            {
            case ExpressionType.Not:
                return(_sqlExpressionFactory.Not(sqlOperand));

            case ExpressionType.Negate:
                return(_sqlExpressionFactory.Negate(sqlOperand));

            case ExpressionType.Convert:
                // Object convert needs to be converted to explicit cast when mismatching types
                if (operand.Type.IsInterface &&
                    unaryExpression.Type.GetInterfaces().Any(e => e == operand.Type) ||
                    unaryExpression.Type.UnwrapNullableType() == operand.Type ||
                    unaryExpression.Type.UnwrapNullableType() == typeof(Enum))
                {
                    return(sqlOperand);
                }

                break;
            }

            return(null);
        }
Beispiel #2
0
        protected override Expression VisitUnary(UnaryExpression unaryExpression)
        {
            var operand = Visit(unaryExpression.Operand);

            if (TranslationFailed(unaryExpression.Operand, operand))
            {
                return(null);
            }

            var sqlOperand = (SqlExpression)operand;

            switch (unaryExpression.NodeType)
            {
            case ExpressionType.Not:
                return(_sqlExpressionFactory.Not(sqlOperand));

            case ExpressionType.Negate:
                return(_sqlExpressionFactory.Negate(sqlOperand));

            case ExpressionType.Convert:
                // Object convert needs to be converted to explicit cast when mismatching types
                if (operand.Type.IsInterface &&
                    unaryExpression.Type.GetInterfaces().Any(e => e == operand.Type) ||
                    unaryExpression.Type.UnwrapNullableType() == operand.Type ||
                    unaryExpression.Type.UnwrapNullableType() == typeof(Enum))
                {
                    return(sqlOperand);
                }
                sqlOperand = _sqlExpressionFactory.ApplyDefaultTypeMapping(sqlOperand);

                return(_sqlExpressionFactory.Convert(sqlOperand, unaryExpression.Type));
            }

            return(null);
        }
Beispiel #3
0
        protected override Expression VisitUnary(UnaryExpression unaryExpression)
        {
            var operand = Visit(unaryExpression.Operand);

            if (operand is EntityProjectionExpression)
            {
                return(unaryExpression.Update(operand));
            }

            if (TranslationFailed(unaryExpression.Operand, operand))
            {
                return(null);
            }

            var sqlOperand = (SqlExpression)operand;

            switch (unaryExpression.NodeType)
            {
            case ExpressionType.Not:
                return(_sqlExpressionFactory.Not(sqlOperand));

            case ExpressionType.Negate:
                return(_sqlExpressionFactory.Negate(sqlOperand));

            case ExpressionType.Convert:
                // Object convert needs to be converted to explicit cast when mismatching types
                if (operand.Type.IsInterface &&
                    unaryExpression.Type.GetInterfaces().Any(e => e == operand.Type) ||
                    unaryExpression.Type.UnwrapNullableType() == operand.Type ||
                    unaryExpression.Type.UnwrapNullableType() == typeof(Enum))
                {
                    return(sqlOperand);
                }

                //// Introduce explicit cast only if the target type is mapped else we need to client eval
                //if (unaryExpression.Type == typeof(object)
                //    || _sqlExpressionFactory.FindMapping(unaryExpression.Type) != null)
                //{
                //    sqlOperand = _sqlExpressionFactory.ApplyDefaultTypeMapping(sqlOperand);

                //    return _sqlExpressionFactory.Convert(sqlOperand, unaryExpression.Type);
                //}

                break;
            }

            return(null);
        }
        private SqlExpression TranslateStartsEndsWith(SqlExpression instance, SqlExpression pattern, bool startsWith)
        {
            var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern);

            instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping);
            pattern  = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping);

            if (pattern is SqlConstantExpression constantExpression)
            {
                // The pattern is constant. Aside from null or empty, we escape all special characters (%, _, \)
                // in C# and send a simple LIKE
                if (!(constantExpression.Value is string constantString))
                {
                    return(_sqlExpressionFactory.Like(instance, _sqlExpressionFactory.Constant(null, stringTypeMapping)));
                }

                if (constantString.Length == 0)
                {
                    return(_sqlExpressionFactory.Constant(true));
                }

                return(constantString.Any(c => IsLikeWildChar(c))
                    ? _sqlExpressionFactory.Like(
                           instance,
                           _sqlExpressionFactory.Constant(
                               startsWith
                                ? EscapeLikePattern(constantString) + '%'
                                : '%' + EscapeLikePattern(constantString)),
                           _sqlExpressionFactory.Constant(
                               LikeEscapeChar.ToString())) // SQL Server has no char mapping, avoid value conversion warning)
                    : _sqlExpressionFactory.Like(
                           instance,
                           _sqlExpressionFactory.Constant(startsWith ? constantString + '%' : '%' + constantString)));
            }

            // The pattern is non-constant, we use LEFT or RIGHT to extract substring and compare.
            // For StartsWith we also first run a LIKE to quickly filter out most non-matching results (sargable, but imprecise
            // because of wildchars).
            if (startsWith)
            {
                return(_sqlExpressionFactory.OrElse(
                           _sqlExpressionFactory.AndAlso(
                               _sqlExpressionFactory.Like(
                                   instance,
                                   _sqlExpressionFactory.Add(
                                       pattern,
                                       _sqlExpressionFactory.Constant("%"))),
                               _sqlExpressionFactory.Equal(
                                   _sqlExpressionFactory.Function(
                                       "substr",
                                       new[]
                {
                    instance,
                    _sqlExpressionFactory.Constant(1),
                    _sqlExpressionFactory.Function(
                        "length",
                        new[] { pattern },
                        nullable: true,
                        argumentsPropagateNullability: new[] { true },
                        typeof(int))
                },
                                       nullable: true,
                                       argumentsPropagateNullability: new[] { true, false, true },
                                       typeof(string),
                                       stringTypeMapping),
                                   pattern)),
                           _sqlExpressionFactory.Equal(
                               pattern,
                               _sqlExpressionFactory.Constant(string.Empty))));
            }

            return(_sqlExpressionFactory.OrElse(
                       _sqlExpressionFactory.Equal(
                           _sqlExpressionFactory.Function(
                               "substr",
                               new[]
            {
                instance,
                _sqlExpressionFactory.Negate(
                    _sqlExpressionFactory.Function(
                        "length",
                        new[] { pattern },
                        nullable: true,
                        argumentsPropagateNullability: new[] { true },
                        typeof(int)))
            },
                               nullable: true,
                               argumentsPropagateNullability: new[] { true, true },
                               typeof(string),
                               stringTypeMapping),
                           pattern),
                       _sqlExpressionFactory.Equal(
                           pattern,
                           _sqlExpressionFactory.Constant(string.Empty))));
        }