Esempio n. 1
0
 // ?a == ?b -> [(a == b) && (a != null && b != null)] || (a == null && b == null))
 //
 // a | b | F1 = a == b | F2 = (a != null && b != null) | F3 = F1 && F2 |
 //   |   |             |                               |               |
 // 0 | 0 | 1           | 1                             | 1             |
 // 0 | 1 | 0           | 1                             | 0             |
 // 0 | N | N           | 0                             | 0             |
 // 1 | 0 | 0           | 1                             | 0             |
 // 1 | 1 | 1           | 1                             | 1             |
 // 1 | N | N           | 0                             | 0             |
 // N | 0 | N           | 0                             | 0             |
 // N | 1 | N           | 0                             | 0             |
 // N | N | N           | 0                             | 0             |
 //
 // a | b | F4 = (a == null && b == null) | Final = F3 OR F4 |
 //   |   |                               |                  |
 // 0 | 0 | 0                             | 1 OR 0 = 1       |
 // 0 | 1 | 0                             | 0 OR 0 = 0       |
 // 0 | N | 0                             | 0 OR 0 = 0       |
 // 1 | 0 | 0                             | 0 OR 0 = 0       |
 // 1 | 1 | 0                             | 1 OR 0 = 1       |
 // 1 | N | 0                             | 0 OR 0 = 0       |
 // N | 0 | 0                             | 0 OR 0 = 0       |
 // N | 1 | 0                             | 0 OR 0 = 0       |
 // N | N | 1                             | 0 OR 1 = 1       |
 private SqlBinaryExpression ExpandNullableEqualNullable(
     SqlExpression left, SqlExpression right, SqlExpression leftIsNull, SqlExpression rightIsNull)
 => _sqlExpressionFactory.OrElse(
     _sqlExpressionFactory.AndAlso(
         _sqlExpressionFactory.Equal(left, right),
         _sqlExpressionFactory.AndAlso(
             _sqlExpressionFactory.Not(leftIsNull),
             _sqlExpressionFactory.Not(rightIsNull))),
     _sqlExpressionFactory.AndAlso(
         leftIsNull,
         rightIsNull));
        /// <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);
        }
        protected override ShapedQueryExpression TranslateAll(ShapedQueryExpression source, LambdaExpression predicate)
        {
            var selectExpression = (SelectExpression)source.QueryExpression;

            if (selectExpression.Limit != null ||
                selectExpression.Offset != null)
            {
                selectExpression.PushdownIntoSubQuery();
            }

            var translation = TranslateLambdaExpression(source, predicate);

            if (translation != null)
            {
                selectExpression.ApplyPredicate(_sqlExpressionFactory.Not(translation));
                selectExpression.ReplaceProjection(new Dictionary <ProjectionMember, Expression>());
                if (selectExpression.Limit == null &&
                    selectExpression.Offset == null)
                {
                    selectExpression.ClearOrdering();
                }

                translation             = _sqlExpressionFactory.Exists(selectExpression, true);
                source.QueryExpression  = _sqlExpressionFactory.Select(translation);
                source.ShaperExpression = new ProjectionBindingExpression(source.QueryExpression, new ProjectionMember(), typeof(bool));

                return(source);
            }

            throw new InvalidOperationException();
        }
Esempio n. 4
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);
        }
Esempio n. 5
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);
        }
        //protected override Expression VisitNew(NewExpression newExpression)
        //{
        //    if (newExpression.Members == null
        //        || newExpression.Arguments.Count == 0)
        //    {
        //        return null;
        //    }

        //    var bindings = new Expression[newExpression.Arguments.Count];

        //    for (var i = 0; i < bindings.Length; i++)
        //    {
        //        var translation = Visit(newExpression.Arguments[i]);

        //        if (translation == null)
        //        {
        //            return null;
        //        }

        //        bindings[i] = translation;
        //    }

        //    return Expression.Constant(bindings);
        //}

        protected override Expression VisitUnary(UnaryExpression unaryExpression)
        {
            var operand = Visit(unaryExpression.Operand);

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

            // In certain cases EF.Property would have convert node around the source.
            if (operand is EntityShaperExpression &&
                unaryExpression.Type == typeof(object) &&
                unaryExpression.NodeType == ExpressionType.Convert)
            {
                return(operand);
            }

            var sqlOperand = (SqlExpression)operand;

            if (unaryExpression.NodeType == 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));
            }

            if (unaryExpression.NodeType == ExpressionType.Not)
            {
                return(_sqlExpressionFactory.Not(sqlOperand));
            }

            return(null);
        }
Esempio n. 7
0
        private Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression)
        {
            // !(true) -> false
            // !(false) -> true
            if (sqlUnaryExpression.OperatorType == ExpressionType.Not &&
                sqlUnaryExpression.Operand is SqlConstantExpression innerConstantBool &&
                innerConstantBool.Value is bool value)
            {
                return(value
                    ? _sqlExpressionFactory.Constant(false, sqlUnaryExpression.TypeMapping)
                    : _sqlExpressionFactory.Constant(true, sqlUnaryExpression.TypeMapping));
            }

            // NULL IS NULL -> true
            // non_nullablee_constant IS NULL -> false
            if (sqlUnaryExpression.OperatorType == ExpressionType.Equal &&
                sqlUnaryExpression.Operand is SqlConstantExpression innerConstantNull1)
            {
                return(_sqlExpressionFactory.Constant(innerConstantNull1.Value == null, sqlUnaryExpression.TypeMapping));
            }

            // NULL IS NOT NULL -> false
            // non_nullablee_constant IS NOT NULL -> true
            if (sqlUnaryExpression.OperatorType == ExpressionType.NotEqual &&
                sqlUnaryExpression.Operand is SqlConstantExpression innerConstantNull2)
            {
                return(_sqlExpressionFactory.Constant(innerConstantNull2.Value != null, sqlUnaryExpression.TypeMapping));
            }

            if (sqlUnaryExpression.Operand is SqlUnaryExpression innerUnary)
            {
                if (sqlUnaryExpression.OperatorType == ExpressionType.Not)
                {
                    // !(!a) -> a
                    if (innerUnary.OperatorType == ExpressionType.Not)
                    {
                        return(Visit(innerUnary.Operand));
                    }

                    if (innerUnary.OperatorType == ExpressionType.Equal)
                    {
                        //!(a IS NULL) -> a IS NOT NULL
                        return(Visit(_sqlExpressionFactory.IsNotNull(innerUnary.Operand)));
                    }

                    //!(a IS NOT NULL) -> a IS NULL
                    if (innerUnary.OperatorType == ExpressionType.NotEqual)
                    {
                        return(Visit(_sqlExpressionFactory.IsNull(innerUnary.Operand)));
                    }
                }

                // (!a) IS NULL <==> a IS NULL
                if (sqlUnaryExpression.OperatorType == ExpressionType.Equal &&
                    innerUnary.OperatorType == ExpressionType.Not)
                {
                    return(Visit(_sqlExpressionFactory.IsNull(innerUnary.Operand)));
                }

                // (!a) IS NOT NULL <==> a IS NOT NULL
                if (sqlUnaryExpression.OperatorType == ExpressionType.NotEqual &&
                    innerUnary.OperatorType == ExpressionType.Not)
                {
                    return(Visit(_sqlExpressionFactory.IsNotNull(innerUnary.Operand)));
                }
            }

            if (sqlUnaryExpression.Operand is SqlBinaryExpression innerBinary)
            {
                // De Morgan's
                if (innerBinary.OperatorType == ExpressionType.AndAlso ||
                    innerBinary.OperatorType == ExpressionType.OrElse)
                {
                    var newLeft  = (SqlExpression)Visit(_sqlExpressionFactory.Not(innerBinary.Left));
                    var newRight = (SqlExpression)Visit(_sqlExpressionFactory.Not(innerBinary.Right));

                    return(innerBinary.OperatorType == ExpressionType.AndAlso
                        ? _sqlExpressionFactory.OrElse(newLeft, newRight)
                        : _sqlExpressionFactory.AndAlso(newLeft, newRight));
                }

                // note that those optimizations are only valid in 2-value logic
                // they are safe to do here because null semantics removes possibility of nulls in the tree
                // however if we decide to do "partial" null semantics (that doesn't distinguish between NULL and FALSE, e.g. for predicates)
                // we need to be extra careful here
                if (TryNegate(innerBinary.OperatorType, out var negated))
                {
                    return(Visit(
                               _sqlExpressionFactory.MakeBinary(
                                   negated,
                                   innerBinary.Left,
                                   innerBinary.Right,
                                   innerBinary.TypeMapping)));
                }
            }

            var newOperand = (SqlExpression)Visit(sqlUnaryExpression.Operand);

            return(sqlUnaryExpression.Update(newOperand));
        }