/// <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 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); }
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)))); }