diff --git a/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionTranslators/Internal/StartsWithTranslator.cs b/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionTranslators/Internal/StartsWithTranslator.cs
index 243c48abc10..f25e20e58ed 100644
--- a/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionTranslators/Internal/StartsWithTranslator.cs
+++ b/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionTranslators/Internal/StartsWithTranslator.cs
@@ -30,6 +30,7 @@ public virtual Expression Translate(MethodCallExpression methodCallExpression)
return ReferenceEquals(methodCallExpression.Method, _methodInfo)
? new LikeExpression(
+ // ReSharper disable once AssignNullToNotNullAttribute
methodCallExpression.Object,
Expression.Add(methodCallExpression.Arguments[0], Expression.Constant("%", typeof(string)), _concat))
: null;
diff --git a/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionTranslators/RelationalCompositeMethodCallTranslator.cs b/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionTranslators/RelationalCompositeMethodCallTranslator.cs
index ec1af67b8d8..956da5a9f7b 100644
--- a/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionTranslators/RelationalCompositeMethodCallTranslator.cs
+++ b/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionTranslators/RelationalCompositeMethodCallTranslator.cs
@@ -55,6 +55,6 @@ public virtual Expression Translate(MethodCallExpression methodCallExpression)
///
/// The translators.
protected virtual void AddTranslators([NotNull] IEnumerable translators)
- => _methodCallTranslators.AddRange(translators);
+ => _methodCallTranslators.InsertRange(0, translators);
}
}
diff --git a/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionVisitors/Internal/PredicateNegationExpressionOptimizer.cs b/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionVisitors/Internal/PredicateNegationExpressionOptimizer.cs
index 08a24632c45..57ef24e8f65 100644
--- a/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionVisitors/Internal/PredicateNegationExpressionOptimizer.cs
+++ b/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionVisitors/Internal/PredicateNegationExpressionOptimizer.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq.Expressions;
+using Microsoft.EntityFrameworkCore.Query.Expressions;
using Remotion.Linq.Parsing;
namespace Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal
@@ -98,9 +99,11 @@ protected override Expression VisitUnary(UnaryExpression node)
return Visit(innerUnary.Operand);
}
- var innerBinary = node.Operand as BinaryExpression;
+ var notNullableExpression = node.Operand as NotNullableExpression;
+ var innerBinary = (notNullableExpression?.Operand ?? node.Operand) as BinaryExpression;
if (innerBinary != null)
{
+ Expression result = null;
if ((innerBinary.NodeType == ExpressionType.Equal)
|| (innerBinary.NodeType == ExpressionType.NotEqual))
{
@@ -108,7 +111,7 @@ protected override Expression VisitUnary(UnaryExpression node)
// if user opts-out of the null semantics, we should not apply this rule
// !(a == b) -> a != b
// !(a != b) -> a == b
- return innerBinary.NodeType == ExpressionType.Equal
+ result = innerBinary.NodeType == ExpressionType.Equal
? Visit(Expression.NotEqual(innerBinary.Left, innerBinary.Right))
: Visit(Expression.Equal(innerBinary.Left, innerBinary.Right));
}
@@ -116,7 +119,7 @@ protected override Expression VisitUnary(UnaryExpression node)
if (innerBinary.NodeType == ExpressionType.AndAlso)
{
// !(a && b) -> !a || !b
- return Visit(
+ result = Visit(
Expression.MakeBinary(
ExpressionType.OrElse,
Expression.Not(innerBinary.Left),
@@ -126,7 +129,7 @@ protected override Expression VisitUnary(UnaryExpression node)
if (innerBinary.NodeType == ExpressionType.OrElse)
{
// !(a || b) -> !a && !b
- return Visit(
+ result = Visit(
Expression.MakeBinary(
ExpressionType.AndAlso,
Expression.Not(innerBinary.Left),
@@ -136,12 +139,19 @@ protected override Expression VisitUnary(UnaryExpression node)
if (_nodeTypeMapping.ContainsKey(innerBinary.NodeType))
{
// e.g. !(a > b) -> a <= b
- return Visit(
+ result = Visit(
Expression.MakeBinary(
_nodeTypeMapping[innerBinary.NodeType],
innerBinary.Left,
innerBinary.Right));
}
+
+ if (result != null)
+ {
+ return notNullableExpression != null
+ ? new NotNullableExpression(result)
+ : result;
+ }
}
}
diff --git a/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionVisitors/Internal/RelationalNullsExpandingVisitor.cs b/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionVisitors/Internal/RelationalNullsExpandingVisitor.cs
index 1c214fa66df..9fe589bab04 100644
--- a/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionVisitors/Internal/RelationalNullsExpandingVisitor.cs
+++ b/src/Microsoft.EntityFrameworkCore.Relational/Query/ExpressionVisitors/Internal/RelationalNullsExpandingVisitor.cs
@@ -114,13 +114,9 @@ var rightOperand
/// directly from your code. This API may change or be removed in future releases.
///
protected override Expression VisitExtension(Expression node)
- {
- var notNullableExpression = node as NotNullableExpression;
-
- return notNullableExpression != null
+ => node is NotNullableExpression
? node
: base.VisitExtension(node);
- }
private static Expression UnwrapConvertExpression(Expression expression, out Type conversionResultType)
{
diff --git a/src/Microsoft.EntityFrameworkCore.Relational/Query/Sql/DefaultQuerySqlGenerator.cs b/src/Microsoft.EntityFrameworkCore.Relational/Query/Sql/DefaultQuerySqlGenerator.cs
index 45661c85725..1f2609e54c2 100644
--- a/src/Microsoft.EntityFrameworkCore.Relational/Query/Sql/DefaultQuerySqlGenerator.cs
+++ b/src/Microsoft.EntityFrameworkCore.Relational/Query/Sql/DefaultQuerySqlGenerator.cs
@@ -1632,21 +1632,27 @@ protected override Expression VisitBinary(BinaryExpression expression)
}
else
{
+ Expression newLeft;
+ Expression newRight;
if (expression.IsLogicalOperation())
{
var parentIsSearchCondition = _isSearchCondition;
_isSearchCondition = true;
- var left = Visit(expression.Left);
- var right = Visit(expression.Right);
+ newLeft = Visit(expression.Left);
+ newRight = Visit(expression.Right);
_isSearchCondition = parentIsSearchCondition;
-
- return Expression.MakeBinary(expression.NodeType, left, right);
+ }
+ else
+ {
+ newLeft = Visit(expression.Left);
+ newRight = Visit(expression.Right);
}
- if (IsSearchCondition(expression))
+ var newExpression = expression.Update(newLeft, expression.Conversion, newRight);
+ if (IsSearchCondition(newExpression))
{
return Expression.Condition(
- expression,
+ newExpression,
Expression.Constant(true, typeof(bool)),
Expression.Constant(false, typeof(bool)));
}
diff --git a/src/Microsoft.EntityFrameworkCore.Specification.Tests/QueryTestBase.cs b/src/Microsoft.EntityFrameworkCore.Specification.Tests/QueryTestBase.cs
index 8987a8ee66e..4b68667dabb 100644
--- a/src/Microsoft.EntityFrameworkCore.Specification.Tests/QueryTestBase.cs
+++ b/src/Microsoft.EntityFrameworkCore.Specification.Tests/QueryTestBase.cs
@@ -426,6 +426,13 @@ public virtual void All_top_level()
cs => cs.All(c => c.ContactName.StartsWith("A")));
}
+ [ConditionalFact]
+ public virtual void All_top_level_column()
+ {
+ AssertQuery(
+ cs => cs.All(c => c.ContactName.StartsWith(c.ContactName)));
+ }
+
[ConditionalFact]
public virtual void All_top_level_subquery()
{
diff --git a/src/Microsoft.EntityFrameworkCore.SqlServer/Microsoft.EntityFrameworkCore.SqlServer.csproj b/src/Microsoft.EntityFrameworkCore.SqlServer/Microsoft.EntityFrameworkCore.SqlServer.csproj
index e6e49a7d90f..6cec87b11a9 100644
--- a/src/Microsoft.EntityFrameworkCore.SqlServer/Microsoft.EntityFrameworkCore.SqlServer.csproj
+++ b/src/Microsoft.EntityFrameworkCore.SqlServer/Microsoft.EntityFrameworkCore.SqlServer.csproj
@@ -106,9 +106,11 @@
+
+
@@ -116,6 +118,7 @@
+
@@ -192,4 +195,4 @@
-->
-
+
\ No newline at end of file
diff --git a/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerCompositeMethodCallTranslator.cs b/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerCompositeMethodCallTranslator.cs
index 486c2696078..0003848d259 100644
--- a/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerCompositeMethodCallTranslator.cs
+++ b/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerCompositeMethodCallTranslator.cs
@@ -29,7 +29,10 @@ public class SqlServerCompositeMethodCallTranslator : RelationalCompositeMethodC
new SqlServerStringTrimEndTranslator(),
new SqlServerStringTrimStartTranslator(),
new SqlServerStringTrimTranslator(),
- new SqlServerConvertTranslator()
+ new SqlServerConvertTranslator(),
+ new SqlServerContainsCharIndexTranslator(),
+ new SqlServerEndsWithCharIndexTranslator(),
+ new SqlServerStartsWithCharIndexTranslator(),
};
// ReSharper disable once SuggestBaseTypeForParameter
diff --git a/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerContainsCharIndexTranslator.cs b/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerContainsCharIndexTranslator.cs
new file mode 100644
index 00000000000..4e7aaa1012c
--- /dev/null
+++ b/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerContainsCharIndexTranslator.cs
@@ -0,0 +1,43 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Linq.Expressions;
+using System.Reflection;
+using Microsoft.EntityFrameworkCore.Query.Expressions;
+
+namespace Microsoft.EntityFrameworkCore.Query.ExpressionTranslators.Internal
+{
+ ///
+ /// This API supports the Entity Framework Core infrastructure and is not intended to be used
+ /// directly from your code. This API may change or be removed in future releases.
+ ///
+ public class SqlServerContainsCharIndexTranslator : IMethodCallTranslator
+ {
+ private static readonly MethodInfo _methodInfo
+ = typeof(string).GetRuntimeMethod(nameof(string.Contains), new[] { typeof(string) });
+
+ public virtual Expression Translate(MethodCallExpression methodCallExpression)
+ {
+ if (ReferenceEquals(methodCallExpression.Method, _methodInfo))
+ {
+ var patternExpression = methodCallExpression.Arguments[0];
+ var patternConstantExpression = patternExpression as ConstantExpression;
+
+ var charIndexExpression = Expression.GreaterThan(
+ new SqlFunctionExpression("CHARINDEX", typeof(int), new[] { patternExpression, methodCallExpression.Object }),
+ Expression.Constant(0));
+
+ return
+ patternConstantExpression != null
+ ? (string)patternConstantExpression.Value == string.Empty
+ ? (Expression)Expression.Constant(true)
+ : charIndexExpression
+ : Expression.OrElse(
+ charIndexExpression,
+ Expression.Equal(patternExpression, Expression.Constant(string.Empty)));
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerEndsWithCharIndexTranslator.cs b/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerEndsWithCharIndexTranslator.cs
new file mode 100644
index 00000000000..df9d0de5daf
--- /dev/null
+++ b/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerEndsWithCharIndexTranslator.cs
@@ -0,0 +1,51 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Linq.Expressions;
+using System.Reflection;
+using Microsoft.EntityFrameworkCore.Query.Expressions;
+
+namespace Microsoft.EntityFrameworkCore.Query.ExpressionTranslators.Internal
+{
+ ///
+ /// This API supports the Entity Framework Core infrastructure and is not intended to be used
+ /// directly from your code. This API may change or be removed in future releases.
+ ///
+ public class SqlServerEndsWithCharIndexTranslator : IMethodCallTranslator
+ {
+ private static readonly MethodInfo _methodInfo
+ = typeof(string).GetRuntimeMethod(nameof(string.EndsWith), new[] { typeof(string) });
+
+ public virtual Expression Translate(MethodCallExpression methodCallExpression)
+ {
+ if (ReferenceEquals(methodCallExpression.Method, _methodInfo))
+ {
+ var patternExpression = methodCallExpression.Arguments[0];
+ var patternConstantExpression = patternExpression as ConstantExpression;
+
+ var endsWithExpression = Expression.Equal(
+ new SqlFunctionExpression(
+ "RIGHT",
+ // ReSharper disable once PossibleNullReferenceException
+ methodCallExpression.Object.Type,
+ new[]
+ {
+ methodCallExpression.Object,
+ new SqlFunctionExpression("LEN", typeof(int), new[] { patternExpression })
+ }),
+ patternExpression);
+
+ return new NotNullableExpression(
+ patternConstantExpression != null
+ ? (string)patternConstantExpression.Value == string.Empty
+ ? (Expression)Expression.Constant(true)
+ : endsWithExpression
+ : Expression.OrElse(
+ endsWithExpression,
+ Expression.Equal(patternExpression, Expression.Constant(string.Empty))));
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerStartsWithCharIndexTranslator.cs b/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerStartsWithCharIndexTranslator.cs
new file mode 100644
index 00000000000..7d635c9349c
--- /dev/null
+++ b/src/Microsoft.EntityFrameworkCore.SqlServer/Query/ExpressionTranslators/Internal/SqlServerStartsWithCharIndexTranslator.cs
@@ -0,0 +1,50 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Linq.Expressions;
+using System.Reflection;
+using Microsoft.EntityFrameworkCore.Query.Expressions;
+
+namespace Microsoft.EntityFrameworkCore.Query.ExpressionTranslators.Internal
+{
+ ///
+ /// This API supports the Entity Framework Core infrastructure and is not intended to be used
+ /// directly from your code. This API may change or be removed in future releases.
+ ///
+ public class SqlServerStartsWithCharIndexTranslator : IMethodCallTranslator
+ {
+ private static readonly MethodInfo _methodInfo
+ = typeof(string).GetRuntimeMethod(nameof(string.StartsWith), new[] { typeof(string) });
+
+ private static readonly MethodInfo _concat
+ = typeof(string).GetRuntimeMethod(nameof(string.Concat), new[] { typeof(string), typeof(string) });
+
+ public virtual Expression Translate(MethodCallExpression methodCallExpression)
+ {
+ if (ReferenceEquals(methodCallExpression.Method, _methodInfo))
+ {
+ var patternExpression = methodCallExpression.Arguments[0];
+ var patternConstantExpression = patternExpression as ConstantExpression;
+
+ var startsWithExpression = Expression.AndAlso(
+ new LikeExpression(
+ // ReSharper disable once AssignNullToNotNullAttribute
+ methodCallExpression.Object,
+ Expression.Add(methodCallExpression.Arguments[0], Expression.Constant("%", typeof(string)), _concat)),
+ Expression.Equal(
+ new SqlFunctionExpression("CHARINDEX", typeof(int), new[] { patternExpression, methodCallExpression.Object }),
+ Expression.Constant(1)));
+
+ return patternConstantExpression != null
+ ? (string)patternConstantExpression.Value == string.Empty
+ ? (Expression)Expression.Constant(true)
+ : startsWithExpression
+ : Expression.OrElse(
+ startsWithExpression,
+ Expression.Equal(patternExpression, Expression.Constant(string.Empty)));
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/ComplexNavigationsQuerySqlServerTest.cs b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/ComplexNavigationsQuerySqlServerTest.cs
index beacf61f434..7748becaf80 100644
--- a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/ComplexNavigationsQuerySqlServerTest.cs
+++ b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/ComplexNavigationsQuerySqlServerTest.cs
@@ -288,7 +288,8 @@ public override void Navigation_inside_method_call_translated_to_join()
@"SELECT [e1].[Id], [e1].[Name], [e1].[OneToMany_Optional_Self_InverseId], [e1].[OneToMany_Required_Self_InverseId], [e1].[OneToOne_Optional_SelfId]
FROM [Level1] AS [e1]
INNER JOIN [Level2] AS [e1.OneToOne_Required_FK] ON [e1].[Id] = [e1.OneToOne_Required_FK].[Level1_Required_Id]
-WHERE [e1.OneToOne_Required_FK].[Name] LIKE N'L' + N'%'", Sql);
+WHERE [e1.OneToOne_Required_FK].[Name] LIKE N'L' + N'%' AND (CHARINDEX(N'L', [e1.OneToOne_Required_FK].[Name]) = 1)",
+ Sql);
}
public override void Join_navigation_in_outer_selector_translated_to_extra_join()
diff --git a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/FromSqlQuerySqlServerTest.cs b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/FromSqlQuerySqlServerTest.cs
index f3dcf3525a0..b30e8ddd888 100644
--- a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/FromSqlQuerySqlServerTest.cs
+++ b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/FromSqlQuerySqlServerTest.cs
@@ -48,7 +48,7 @@ public override void From_sql_queryable_composed()
FROM (
SELECT * FROM ""Customers""
) AS [c]
-WHERE [c].[ContactName] LIKE (N'%' + N'z') + N'%'",
+WHERE CHARINDEX(N'z', [c].[ContactName]) > 0",
Sql);
}
diff --git a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/GearsOfWarQuerySqlServerTest.cs b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/GearsOfWarQuerySqlServerTest.cs
index 6a69125817e..e8272fd5230 100644
--- a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/GearsOfWarQuerySqlServerTest.cs
+++ b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/GearsOfWarQuerySqlServerTest.cs
@@ -882,7 +882,7 @@ public override void Null_propagation_optimization2()
Assert.Equal(
@"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
FROM [Gear] AS [g]
-WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND [g].[LeaderNickname] LIKE N'%' + N'us'",
+WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND RIGHT([g].[LeaderNickname], LEN(N'us')) = N'us'",
Sql);
}
@@ -894,7 +894,7 @@ public override void Null_propagation_optimization3()
Assert.Equal(
@"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank]
FROM [Gear] AS [g]
-WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND [g].[LeaderNickname] LIKE N'%' + N'us'",
+WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND RIGHT([g].[LeaderNickname], LEN(N'us')) = N'us'",
Sql);
}
@@ -1248,7 +1248,7 @@ public override void Non_unicode_string_literals_is_used_for_non_unicode_column_
Assert.Equal(
@"SELECT [c].[Name], [c].[Location]
FROM [City] AS [c]
-WHERE [c].[Location] LIKE ('%' + 'Jacinto') + '%'",
+WHERE CHARINDEX(N'Jacinto', [c].[Location]) > 0",
Sql);
}
diff --git a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/IncludeSqlServerTest.cs b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/IncludeSqlServerTest.cs
index 98ce31247c9..bdfbee0157e 100644
--- a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/IncludeSqlServerTest.cs
+++ b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/IncludeSqlServerTest.cs
@@ -274,7 +274,7 @@ public override void Include_collection_order_by_collection_column()
Assert.Equal(
@"SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[CustomerID] LIKE N'W' + N'%'
+WHERE [c].[CustomerID] LIKE N'W' + N'%' AND (CHARINDEX(N'W', [c].[CustomerID]) = 1)
ORDER BY (
SELECT TOP(1) [oo].[OrderDate]
FROM [Orders] AS [oo]
@@ -292,7 +292,7 @@ FROM [Orders] AS [oo]
ORDER BY [oo].[OrderDate] DESC
) AS [c0_0], [c].[CustomerID]
FROM [Customers] AS [c]
- WHERE [c].[CustomerID] LIKE N'W' + N'%'
+ WHERE [c].[CustomerID] LIKE N'W' + N'%' AND (CHARINDEX(N'W', [c].[CustomerID]) = 1)
ORDER BY [c0_0] DESC, [c].[CustomerID]
) AS [c0] ON [o].[CustomerID] = [c0].[CustomerID]
ORDER BY [c0].[c0_0] DESC, [c0].[CustomerID]",
@@ -1252,9 +1252,9 @@ public override void Then_include_collection_order_by_collection_column()
base.Then_include_collection_order_by_collection_column();
Assert.Equal(
- @"SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
+ @"SELECT TOP(1) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[CustomerID] LIKE N'W' + N'%'
+WHERE [c].[CustomerID] LIKE N'W' + N'%' AND (CHARINDEX(N'W', [c].[CustomerID]) = 1)
ORDER BY (
SELECT TOP(1) [oo].[OrderDate]
FROM [Orders] AS [oo]
@@ -1272,7 +1272,7 @@ FROM [Orders] AS [oo]
ORDER BY [oo].[OrderDate] DESC
) AS [c0_0], [c].[CustomerID]
FROM [Customers] AS [c]
- WHERE [c].[CustomerID] LIKE N'W' + N'%'
+ WHERE [c].[CustomerID] LIKE N'W' + N'%' AND (CHARINDEX(N'W', [c].[CustomerID]) = 1)
ORDER BY [c0_0] DESC, [c].[CustomerID]
) AS [c0] ON [o].[CustomerID] = [c0].[CustomerID]
ORDER BY [c0].[c0_0] DESC, [c0].[CustomerID], [o].[OrderID]
@@ -1290,12 +1290,12 @@ FROM [Orders] AS [oo]
ORDER BY [oo].[OrderDate] DESC
) AS [c0_0], [c].[CustomerID]
FROM [Customers] AS [c]
- WHERE [c].[CustomerID] LIKE N'W' + N'%'
+ WHERE [c].[CustomerID] LIKE N'W' + N'%' AND (CHARINDEX(N'W', [c].[CustomerID]) = 1)
ORDER BY [c0_0] DESC, [c].[CustomerID]
) AS [c0] ON [o].[CustomerID] = [c0].[CustomerID]
) AS [o1] ON [o0].[OrderID] = [o1].[OrderID]
ORDER BY [o1].[c0_0] DESC, [o1].[CustomerID], [o1].[OrderID]",
- Sql);
+ Sql);
}
private const string FileLineEnding = @"
diff --git a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/InheritanceSqlServerTest.cs b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/InheritanceSqlServerTest.cs
index ed1021b66f5..2c1ee04c44c 100644
--- a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/InheritanceSqlServerTest.cs
+++ b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/InheritanceSqlServerTest.cs
@@ -362,7 +362,7 @@ INSERT INTO [Animal] ([Species], [CountryId], [Discriminator], [Name], [EagleId]
SELECT TOP(2) [k].[Species], [k].[CountryId], [k].[Discriminator], [k].[Name], [k].[EagleId], [k].[IsFlightless], [k].[FoundOn]
FROM [Animal] AS [k]
-WHERE ([k].[Discriminator] = N'Kiwi') AND [k].[Species] LIKE N'%' + N'owenii'
+WHERE ([k].[Discriminator] = N'Kiwi') AND (RIGHT([k].[Species], LEN(N'owenii')) = N'owenii')
@p1: Apteryx owenii (Nullable = false) (Size = 100)
@p0: Aquila chrysaetos canadensis (Size = 100)
@@ -374,7 +374,7 @@ FROM [Animal] AS [k]
SELECT TOP(2) [k].[Species], [k].[CountryId], [k].[Discriminator], [k].[Name], [k].[EagleId], [k].[IsFlightless], [k].[FoundOn]
FROM [Animal] AS [k]
-WHERE ([k].[Discriminator] = N'Kiwi') AND [k].[Species] LIKE N'%' + N'owenii'
+WHERE ([k].[Discriminator] = N'Kiwi') AND (RIGHT([k].[Species], LEN(N'owenii')) = N'owenii')
@p0: Apteryx owenii (Nullable = false) (Size = 100)
@@ -385,7 +385,7 @@ DELETE FROM [Animal]
SELECT COUNT(*)
FROM [Animal] AS [k]
-WHERE ([k].[Discriminator] = N'Kiwi') AND [k].[Species] LIKE N'%' + N'owenii'",
+WHERE ([k].[Discriminator] = N'Kiwi') AND (RIGHT([k].[Species], LEN(N'owenii')) = N'owenii')",
Sql);
}
diff --git a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/NullSemanticsQuerySqlServerTest.cs b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/NullSemanticsQuerySqlServerTest.cs
index 8d71123eed6..23f4bea7dfd 100644
--- a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/NullSemanticsQuerySqlServerTest.cs
+++ b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/NullSemanticsQuerySqlServerTest.cs
@@ -913,7 +913,7 @@ public override void Where_equal_with_and_and_contains()
Assert.Equal(
@"SELECT [e].[Id]
FROM [NullSemanticsEntity1] AS [e]
-WHERE [e].[NullableStringA] LIKE (N'%' + [e].[NullableStringB]) + N'%' AND ([e].[BoolA] = 1)",
+WHERE ((CHARINDEX([e].[NullableStringB], [e].[NullableStringA]) > 0) OR ([e].[NullableStringB] = N'')) AND ([e].[BoolA] = 1)",
Sql);
}
@@ -941,7 +941,7 @@ FROM [NullSemanticsEntity1] AS [e]
WHERE CASE
WHEN @__prm_0 = 0
THEN CAST(1 AS BIT) ELSE CASE
- WHEN [e].[StringA] LIKE N'A' + N'%'
+ WHEN [e].[StringA] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [e].[StringA]) = 1)
THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END
END = 1",
@@ -965,7 +965,7 @@ THEN CASE
THEN CASE
WHEN [e].[BoolA] = 1
THEN CASE
- WHEN [e].[StringA] LIKE N'A' + N'%'
+ WHEN [e].[StringA] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [e].[StringA]) = 1)
THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END ELSE CAST(0 AS BIT)
END ELSE CAST(1 AS BIT)
diff --git a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/QueryBugsTest.cs b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/QueryBugsTest.cs
index f5710396a54..4515a98fe14 100644
--- a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/QueryBugsTest.cs
+++ b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/QueryBugsTest.cs
@@ -1321,6 +1321,668 @@ public class Comment5456
public Post5456 Blog { get; set; }
}
+ [Fact]
+ public virtual void Repro474_string_contains_on_argument_with_wildcard_constant()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result1 = ctx.Customers.Where(c => c.FirstName.Contains("%B")).Select(c => c.FirstName).ToList();
+ var expected1 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.Contains("%B"));
+ Assert.True(expected1.Count() == result1.Count);
+
+ var result2 = ctx.Customers.Where(c => c.FirstName.Contains("a_")).Select(c => c.FirstName).ToList();
+ var expected2 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.Contains("a_"));
+ Assert.True(expected2.Count() == result2.Count);
+
+ var result3 = ctx.Customers.Where(c => c.FirstName.Contains(null)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result3.Count);
+
+ var result4 = ctx.Customers.Where(c => c.FirstName.Contains("")).Select(c => c.FirstName).ToList();
+ Assert.True(ctx.Customers.Count() == result4.Count);
+
+ var result5 = ctx.Customers.Where(c => c.FirstName.Contains("_Ba_")).Select(c => c.FirstName).ToList();
+ var expected5 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.Contains("_Ba_"));
+ Assert.True(expected5.Count() == result5.Count);
+
+ var result6 = ctx.Customers.Where(c => !c.FirstName.Contains("%B%a%r")).Select(c => c.FirstName).ToList();
+ var expected6 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && !c.Contains("%B%a%r"));
+ Assert.True(expected6.Count() == result6.Count);
+
+ var result7 = ctx.Customers.Where(c => !c.FirstName.Contains("")).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result7.Count);
+
+ var result8 = ctx.Customers.Where(c => !c.FirstName.Contains(null)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result8.Count);
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_contains_on_argument_with_wildcard_parameter()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var prm1 = "%B";
+ var result1 = ctx.Customers.Where(c => c.FirstName.Contains(prm1)).Select(c => c.FirstName).ToList();
+ var expected1 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.Contains(prm1));
+ Assert.True(expected1.Count() == result1.Count);
+
+ var prm2 = "a_";
+ var result2 = ctx.Customers.Where(c => c.FirstName.Contains(prm2)).Select(c => c.FirstName).ToList();
+ var expected2 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.Contains(prm2));
+ Assert.True(expected2.Count() == result2.Count);
+
+ var prm3 = (string)null;
+ var result3 = ctx.Customers.Where(c => c.FirstName.Contains(prm3)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result3.Count);
+
+ var prm4 = "";
+ var result4 = ctx.Customers.Where(c => c.FirstName.Contains(prm4)).Select(c => c.FirstName).ToList();
+ Assert.True(ctx.Customers.Count() == result4.Count);
+
+ var prm5 = "_Ba_";
+ var result5 = ctx.Customers.Where(c => c.FirstName.Contains(prm5)).Select(c => c.FirstName).ToList();
+ var expected5 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.Contains(prm5));
+ Assert.True(expected5.Count() == result5.Count);
+
+ var prm6 = "%B%a%r";
+ var result6 = ctx.Customers.Where(c => !c.FirstName.Contains(prm6)).Select(c => c.FirstName).ToList();
+ var expected6 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && !c.Contains(prm6));
+ Assert.True(expected6.Count() == result6.Count);
+
+ var prm7 = "";
+ var result7 = ctx.Customers.Where(c => !c.FirstName.Contains(prm7)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result7.Count);
+
+ var prm8 = (string)null;
+ var result8 = ctx.Customers.Where(c => !c.FirstName.Contains(prm8)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result8.Count);
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_contains_on_argument_with_wildcard_column()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result = ctx.Customers.Select(c => c.FirstName)
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName), (fn, ln) => new { fn, ln })
+ .Where(r => r.fn.Contains(r.ln))
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ var expected = ctx.Customers.Select(c => c.FirstName).ToList()
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName).ToList(), (fn, ln) => new { fn, ln })
+ .Where(r => r.ln == "" || (r.fn != null && r.ln != null && r.fn.Contains(r.ln)))
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ Assert.Equal(result.Count, expected.Count);
+ for (int i = 0; i < result.Count; i++)
+ {
+ Assert.True(expected[i].fn == result[i].fn);
+ Assert.True(expected[i].ln == result[i].ln);
+ }
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_contains_on_argument_with_wildcard_column_negated()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result = ctx.Customers.Select(c => c.FirstName)
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName), (fn, ln) => new { fn, ln })
+ .Where(r => !r.fn.Contains(r.ln))
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ var expected = ctx.Customers.Select(c => c.FirstName).ToList()
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName).ToList(), (fn, ln) => new { fn, ln })
+ .Where(r => r.ln != "" && r.fn != null && r.ln != null && !r.fn.Contains(r.ln))
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ Assert.Equal(result.Count, expected.Count);
+ for (int i = 0; i < result.Count; i++)
+ {
+ Assert.True(expected[i].fn == result[i].fn);
+ Assert.True(expected[i].ln == result[i].ln);
+ }
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_starts_with_on_argument_with_wildcard_constant()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result1 = ctx.Customers.Where(c => c.FirstName.StartsWith("%B")).Select(c => c.FirstName).ToList();
+ var expected1 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.StartsWith("%B"));
+ Assert.True(expected1.Count() == result1.Count);
+
+ var result2 = ctx.Customers.Where(c => c.FirstName.StartsWith("a_")).Select(c => c.FirstName).ToList();
+ var expected2 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.StartsWith("a_"));
+ Assert.True(expected2.Count() == result2.Count);
+
+ var result3 = ctx.Customers.Where(c => c.FirstName.StartsWith(null)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result3.Count);
+
+ var result4 = ctx.Customers.Where(c => c.FirstName.StartsWith("")).Select(c => c.FirstName).ToList();
+ Assert.True(ctx.Customers.Count() == result4.Count);
+
+ var result5 = ctx.Customers.Where(c => c.FirstName.StartsWith("_Ba_")).Select(c => c.FirstName).ToList();
+ var expected5 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.StartsWith("_Ba_"));
+ Assert.True(expected5.Count() == result5.Count);
+
+ var result6 = ctx.Customers.Where(c => !c.FirstName.StartsWith("%B%a%r")).Select(c => c.FirstName).ToList();
+ var expected6 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && !c.StartsWith("%B%a%r"));
+ Assert.True(expected6.Count() == result6.Count);
+
+ var result7 = ctx.Customers.Where(c => !c.FirstName.StartsWith("")).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result7.Count);
+
+ var result8 = ctx.Customers.Where(c => !c.FirstName.StartsWith(null)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result8.Count);
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_starts_with_on_argument_with_wildcard_parameter()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var prm1 = "%B";
+ var result1 = ctx.Customers.Where(c => c.FirstName.StartsWith(prm1)).Select(c => c.FirstName).ToList();
+ var expected1 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.StartsWith(prm1));
+ Assert.True(expected1.Count() == result1.Count);
+
+ var prm2 = "a_";
+ var result2 = ctx.Customers.Where(c => c.FirstName.StartsWith(prm2)).Select(c => c.FirstName).ToList();
+ var expected2 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.StartsWith(prm2));
+ Assert.True(expected2.Count() == result2.Count);
+
+ var prm3 = (string)null;
+ var result3 = ctx.Customers.Where(c => c.FirstName.StartsWith(prm3)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result3.Count);
+
+ var prm4 = "";
+ var result4 = ctx.Customers.Where(c => c.FirstName.StartsWith(prm4)).Select(c => c.FirstName).ToList();
+ Assert.True(ctx.Customers.Count() == result4.Count);
+
+ var prm5 = "_Ba_";
+ var result5 = ctx.Customers.Where(c => c.FirstName.StartsWith(prm5)).Select(c => c.FirstName).ToList();
+ var expected5 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.StartsWith(prm5));
+ Assert.True(expected5.Count() == result5.Count);
+
+ var prm6 = "%B%a%r";
+ var result6 = ctx.Customers.Where(c => !c.FirstName.StartsWith(prm6)).Select(c => c.FirstName).ToList();
+ var expected6 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && !c.StartsWith(prm6));
+ Assert.True(expected6.Count() == result6.Count);
+
+ var prm7 = "";
+ var result7 = ctx.Customers.Where(c => !c.FirstName.StartsWith(prm7)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result7.Count);
+
+ var prm8 = (string)null;
+ var result8 = ctx.Customers.Where(c => !c.FirstName.StartsWith(prm8)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result8.Count);
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_starts_with_on_argument_with_wildcard_column()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result = ctx.Customers.Select(c => c.FirstName)
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName), (fn, ln) => new { fn, ln })
+ .Where(r => r.fn.StartsWith(r.ln))
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ var expected = ctx.Customers.Select(c => c.FirstName).ToList()
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName).ToList(), (fn, ln) => new { fn, ln })
+ .Where(r => r.ln == "" || (r.fn != null && r.ln != null && r.fn.StartsWith(r.ln)))
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ Assert.Equal(result.Count, expected.Count);
+ for (int i = 0; i < result.Count; i++)
+ {
+ Assert.True(expected[i].fn == result[i].fn);
+ Assert.True(expected[i].ln == result[i].ln);
+ }
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_starts_with_on_argument_with_wildcard_column_negated()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result = ctx.Customers.Select(c => c.FirstName)
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName), (fn, ln) => new { fn, ln })
+ .Where(r => !r.fn.StartsWith(r.ln))
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ var expected = ctx.Customers.Select(c => c.FirstName).ToList()
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName).ToList(), (fn, ln) => new { fn, ln })
+ .Where(r => r.ln != "" && r.fn != null && r.ln != null && !r.fn.StartsWith(r.ln))
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ Assert.Equal(result.Count, expected.Count);
+ for (int i = 0; i < result.Count; i++)
+ {
+ Assert.True(expected[i].fn == result[i].fn);
+ Assert.True(expected[i].ln == result[i].ln);
+ }
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_ends_with_on_argument_with_wildcard_constant()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result1 = ctx.Customers.Where(c => c.FirstName.StartsWith("%B")).Select(c => c.FirstName).ToList();
+ var expected1 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.StartsWith("%B"));
+ Assert.True(expected1.Count() == result1.Count);
+
+ var result2 = ctx.Customers.Where(c => c.FirstName.StartsWith("_r")).Select(c => c.FirstName).ToList();
+ var expected2 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.StartsWith("_r"));
+ Assert.True(expected2.Count() == result2.Count);
+
+ var result3 = ctx.Customers.Where(c => c.FirstName.StartsWith(null)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result3.Count);
+
+ var result4 = ctx.Customers.Where(c => c.FirstName.StartsWith("")).Select(c => c.FirstName).ToList();
+ Assert.True(ctx.Customers.Count() == result4.Count);
+
+ var result5 = ctx.Customers.Where(c => c.FirstName.StartsWith("a__r_")).Select(c => c.FirstName).ToList();
+ var expected5 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.StartsWith("a__r_"));
+ Assert.True(expected5.Count() == result5.Count);
+
+ var result6 = ctx.Customers.Where(c => !c.FirstName.StartsWith("%B%a%r")).Select(c => c.FirstName).ToList();
+ var expected6 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && !c.StartsWith("%B%a%r"));
+ Assert.True(expected6.Count() == result6.Count);
+
+ var result7 = ctx.Customers.Where(c => !c.FirstName.StartsWith("")).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result7.Count);
+
+ var result8 = ctx.Customers.Where(c => !c.FirstName.StartsWith(null)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result8.Count);
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_ends_with_on_argument_with_wildcard_parameter()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var prm1 = "%B";
+ var result1 = ctx.Customers.Where(c => c.FirstName.StartsWith(prm1)).Select(c => c.FirstName).ToList();
+ var expected1 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.StartsWith(prm1));
+ Assert.True(expected1.Count() == result1.Count);
+
+ var prm2 = "_r";
+ var result2 = ctx.Customers.Where(c => c.FirstName.StartsWith(prm2)).Select(c => c.FirstName).ToList();
+ var expected2 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.StartsWith(prm2));
+ Assert.True(expected2.Count() == result2.Count);
+
+ var prm3 = (string)null;
+ var result3 = ctx.Customers.Where(c => c.FirstName.StartsWith(prm3)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result3.Count);
+
+ var prm4 = "";
+ var result4 = ctx.Customers.Where(c => c.FirstName.StartsWith(prm4)).Select(c => c.FirstName).ToList();
+ Assert.True(ctx.Customers.Count() == result4.Count);
+
+ var prm5 = "a__r_";
+ var result5 = ctx.Customers.Where(c => c.FirstName.StartsWith(prm5)).Select(c => c.FirstName).ToList();
+ var expected5 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && c.StartsWith(prm5));
+ Assert.True(expected5.Count() == result5.Count);
+
+ var prm6 = "%B%a%r";
+ var result6 = ctx.Customers.Where(c => !c.FirstName.StartsWith(prm6)).Select(c => c.FirstName).ToList();
+ var expected6 = ctx.Customers.Select(c => c.FirstName).ToList().Where(c => c != null && !c.StartsWith(prm6));
+ Assert.True(expected6.Count() == result6.Count);
+
+ var prm7 = "";
+ var result7 = ctx.Customers.Where(c => !c.FirstName.StartsWith(prm7)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result7.Count);
+
+ var prm8 = (string)null;
+ var result8 = ctx.Customers.Where(c => !c.FirstName.StartsWith(prm8)).Select(c => c.FirstName).ToList();
+ Assert.True(0 == result8.Count);
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_ends_with_on_argument_with_wildcard_column()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result = ctx.Customers.Select(c => c.FirstName)
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName), (fn, ln) => new { fn, ln })
+ .Where(r => r.fn.EndsWith(r.ln))
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ var expected = ctx.Customers.Select(c => c.FirstName).ToList()
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName).ToList(), (fn, ln) => new { fn, ln })
+ .Where(r => r.ln == "" || (r.fn != null && r.ln != null && r.fn.EndsWith(r.ln)))
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ Assert.Equal(result.Count, expected.Count);
+ for (int i = 0; i < result.Count; i++)
+ {
+ Assert.True(expected[i].fn == result[i].fn);
+ Assert.True(expected[i].ln == result[i].ln);
+ }
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_ends_with_on_argument_with_wildcard_column_negated()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result = ctx.Customers.Select(c => c.FirstName)
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName), (fn, ln) => new { fn, ln })
+ .Where(r => !r.fn.EndsWith(r.ln))
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ var expected = ctx.Customers.Select(c => c.FirstName).ToList()
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName).ToList(), (fn, ln) => new { fn, ln })
+ .Where(r => r.ln != "" && r.fn != null && r.ln != null && !r.fn.EndsWith(r.ln))
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ Assert.Equal(result.Count, expected.Count);
+ for (int i = 0; i < result.Count; i++)
+ {
+ Assert.True(expected[i].fn == result[i].fn);
+ Assert.True(expected[i].ln == result[i].ln);
+ }
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_ends_with_inside_conditional()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result = ctx.Customers.Select(c => c.FirstName)
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName), (fn, ln) => new { fn, ln })
+ .Where(r => r.fn.EndsWith(r.ln) ? true : false)
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ var expected = ctx.Customers.Select(c => c.FirstName).ToList()
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName).ToList(), (fn, ln) => new { fn, ln })
+ .Where(r => (r.ln == "" || (r.fn != null && r.ln != null && r.fn.EndsWith(r.ln))) ? true : false )
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ Assert.Equal(result.Count, expected.Count);
+ for (int i = 0; i < result.Count; i++)
+ {
+ Assert.True(expected[i].fn == result[i].fn);
+ Assert.True(expected[i].ln == result[i].ln);
+ }
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_ends_with_inside_conditional_negated()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result = ctx.Customers.Select(c => c.FirstName)
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName), (fn, ln) => new { fn, ln })
+ .Where(r => !r.fn.EndsWith(r.ln) ? true : false)
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ var expected = ctx.Customers.Select(c => c.FirstName).ToList()
+ .SelectMany(c => ctx.Customers.Select(c2 => c2.LastName).ToList(), (fn, ln) => new { fn, ln })
+ .Where(r => (r.ln != "" && r.fn != null && r.ln != null && !r.fn.EndsWith(r.ln)) ? true : false)
+ .ToList().OrderBy(r => r.fn).ThenBy(r => r.ln).ToList();
+
+ Assert.Equal(result.Count, expected.Count);
+ for (int i = 0; i < result.Count; i++)
+ {
+ Assert.True(expected[i].fn == result[i].fn);
+ Assert.True(expected[i].ln == result[i].ln);
+ }
+ }
+ }
+
+ [Fact]
+ public virtual void Repro474_string_ends_with_equals_nullable_column()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result = ctx.Customers
+ .SelectMany(c => ctx.Customers, (c1, c2) => new { c1, c2 })
+ .Where(r => r.c1.FirstName.EndsWith(r.c2.LastName) == r.c1.NullableBool.Value)
+ .ToList().Select(r => new { r.c1.FirstName, r.c2.LastName, r.c1.NullableBool }).OrderBy(r => r.FirstName).ThenBy(r => r.LastName).ToList();
+
+ var expected = ctx.Customers.ToList()
+ .SelectMany(c => ctx.Customers.ToList(), (c1, c2) => new { c1, c2 })
+ .Where(r => (r.c2.LastName != null && r.c1.FirstName != null && r.c1.NullableBool.HasValue && r.c1.FirstName.EndsWith(r.c2.LastName) == r.c1.NullableBool.Value) || (r.c2.LastName == null && r.c1.NullableBool == false))
+ .ToList().Select(r => new { r.c1.FirstName, r.c2.LastName, r.c1.NullableBool }).OrderBy(r => r.FirstName).ThenBy(r => r.LastName).ToList();
+
+ Assert.Equal(result.Count, expected.Count);
+ for (int i = 0; i < result.Count; i++)
+ {
+ Assert.True(expected[i].FirstName == result[i].FirstName);
+ Assert.True(expected[i].LastName == result[i].LastName);
+ }
+ }
+ }
+
+
+ [Fact]
+ public virtual void Repro474_string_ends_with_not_equals_nullable_column()
+ {
+ CreateDatabase474();
+
+ var loggingFactory = new TestSqlLoggerFactory();
+ var serviceProvider = new ServiceCollection()
+ .AddEntityFrameworkSqlServer()
+ .AddSingleton(loggingFactory)
+ .BuildServiceProvider();
+
+ using (var ctx = new MyContext474(serviceProvider))
+ {
+ var result = ctx.Customers
+ .SelectMany(c => ctx.Customers, (c1, c2) => new { c1, c2 })
+ .Where(r => r.c1.FirstName.EndsWith(r.c2.LastName) != r.c1.NullableBool.Value)
+ .ToList().Select(r => new { r.c1.FirstName, r.c2.LastName, r.c1.NullableBool }).OrderBy(r => r.FirstName).ThenBy(r => r.LastName).ToList();
+
+ var expected = ctx.Customers.ToList()
+ .SelectMany(c => ctx.Customers.ToList(), (c1, c2) => new { c1, c2 })
+ .Where(r =>
+ (r.c2.LastName != null && r.c1.FirstName != null && r.c1.NullableBool.HasValue && r.c1.FirstName.EndsWith(r.c2.LastName) != r.c1.NullableBool.Value)
+ || r.c1.NullableBool == null
+ || (r.c2.LastName == null && r.c1.NullableBool == true))
+ .ToList().Select(r => new { r.c1.FirstName, r.c2.LastName, r.c1.NullableBool }).OrderBy(r => r.FirstName).ThenBy(r => r.LastName).ToList();
+
+ Assert.Equal(result.Count, expected.Count);
+ for (int i = 0; i < result.Count; i++)
+ {
+ Assert.True(expected[i].FirstName == result[i].FirstName);
+ Assert.True(expected[i].LastName == result[i].LastName);
+ }
+ }
+ }
+
+ private void CreateDatabase474()
+ {
+ CreateTestStore(
+ "Repro474",
+ _fixture.ServiceProvider,
+ (sp, co) => new MyContext474(sp),
+ context =>
+ {
+ var c11 = new Customer474 { FirstName = "%Bar", LastName = "%B", NullableBool = true };
+ var c12 = new Customer474 { FirstName = "Ba%r", LastName = "a%", NullableBool = true };
+ var c13 = new Customer474 { FirstName = "Bar%", LastName = "%B%", NullableBool = true };
+ var c14 = new Customer474 { FirstName = "%Ba%r%", LastName = null, NullableBool = false };
+ var c15 = new Customer474 { FirstName = "B%a%%r%", LastName = "r%", NullableBool = false };
+ var c16 = new Customer474 { FirstName = null, LastName = "%B%a%r" };
+ var c17 = new Customer474 { FirstName = "%B%a%r", LastName = "" };
+ var c18 = new Customer474 { FirstName = "", LastName = "%%r%" };
+
+ var c21 = new Customer474 { FirstName = "_Bar", LastName = "_B", NullableBool = false };
+ var c22 = new Customer474 { FirstName = "Ba_r", LastName = "a_", NullableBool = false };
+ var c23 = new Customer474 { FirstName = "Bar_", LastName = "_B_", NullableBool = false };
+ var c24 = new Customer474 { FirstName = "_Ba_r_", LastName = null, NullableBool = true };
+ var c25 = new Customer474 { FirstName = "B_a__r_", LastName = "r_", NullableBool = true };
+ var c26 = new Customer474 { FirstName = null, LastName = "_B_a_r" };
+ var c27 = new Customer474 { FirstName = "_B_a_r", LastName = "" };
+ var c28 = new Customer474 { FirstName = "", LastName = "__r_" };
+
+ context.Customers.AddRange(c11, c12, c13, c14, c15, c16, c17, c18, c21, c22, c23, c24, c25, c26, c27, c28);
+
+ context.SaveChanges();
+ });
+ }
+
+ public class MyContext474 : DbContext
+ {
+ private readonly IServiceProvider _serviceProvider;
+
+ public MyContext474(IServiceProvider serviceProvider)
+ {
+ _serviceProvider = serviceProvider;
+ }
+
+ public DbSet Customers { get; set; }
+
+ protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
+ => optionsBuilder.UseSqlServer(SqlServerTestStore.CreateConnectionString("Repro474"));
+ }
+
+ public class Customer474
+ {
+ public int Id { get; set; }
+ public string FirstName { get; set; }
+ public string LastName { get; set; }
+
+ public bool? NullableBool { get; set; }
+ }
+
private static void CreateTestStore(
string databaseName,
IServiceProvider serviceProvider,
diff --git a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/QueryNavigationsSqlServerTest.cs b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/QueryNavigationsSqlServerTest.cs
index e4a1176923c..2662e3249f8 100644
--- a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/QueryNavigationsSqlServerTest.cs
+++ b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/QueryNavigationsSqlServerTest.cs
@@ -405,7 +405,7 @@ public override void Select_collection_navigation_simple()
Assert.Equal(
@"SELECT [c].[CustomerID]
FROM [Customers] AS [c]
-WHERE [c].[CustomerID] LIKE N'A' + N'%'
+WHERE [c].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [c].[CustomerID]) = 1)
ORDER BY [c].[CustomerID]
@_outer_CustomerID: ALFKI (Size = 450)
@@ -538,7 +538,7 @@ SELECT CASE
WHEN NOT EXISTS (
SELECT 1
FROM [Orders] AS [o0]
- WHERE (([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) AND NOT (([o0].[CustomerID] = N'ALFKI') AND [o0].[CustomerID] IS NOT NULL))
+ WHERE (([c].[CustomerID] = [o0].[CustomerID]) AND [o0].[CustomerID] IS NOT NULL) AND (([o0].[CustomerID] <> N'ALFKI') OR [o0].[CustomerID] IS NULL))
THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END
)
@@ -579,7 +579,7 @@ FROM [Customers] AS [c]
WHERE NOT EXISTS (
SELECT 1
FROM [Orders] AS [o]
- WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND NOT (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL))",
+ WHERE (([c].[CustomerID] = [o].[CustomerID]) AND [o].[CustomerID] IS NOT NULL) AND (([o].[CustomerID] <> N'ALFKI') OR [o].[CustomerID] IS NULL))",
Sql);
}
@@ -713,7 +713,7 @@ FROM [Order Details] AS [o3]
WHERE [o].[OrderID] = [o3].[OrderID]
)
FROM [Orders] AS [o]
-WHERE [o].[CustomerID] LIKE N'A' + N'%'",
+WHERE [o].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [o].[CustomerID]) = 1)",
Sql);
}
@@ -776,7 +776,7 @@ public override void Collection_select_nav_prop_first_or_default_then_nav_prop()
Assert.StartsWith(
@"SELECT [e].[CustomerID]
FROM [Customers] AS [e]
-WHERE [e].[CustomerID] LIKE N'A' + N'%'
+WHERE [e].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [e].[CustomerID]) = 1)
ORDER BY [e].[CustomerID]
@_outer_CustomerID: ALFKI (Size = 450)
@@ -804,7 +804,7 @@ public override void Collection_select_nav_prop_first_or_default_then_nav_prop_n
Assert.StartsWith(
@"SELECT 1
FROM [Customers] AS [e]
-WHERE [e].[CustomerID] LIKE N'A' + N'%'
+WHERE [e].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [e].[CustomerID]) = 1)
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o.Customer].[CustomerID], [o.Customer].[Address], [o.Customer].[City], [o.Customer].[CompanyName], [o.Customer].[ContactName], [o.Customer].[ContactTitle], [o.Customer].[Country], [o.Customer].[Fax], [o.Customer].[Phone], [o.Customer].[PostalCode], [o.Customer].[Region]
FROM [Orders] AS [o]
@@ -827,7 +827,7 @@ public override void Collection_select_nav_prop_single_or_default_then_nav_prop_
Assert.StartsWith(
@"SELECT 1
FROM [Customers] AS [e]
-WHERE [e].[CustomerID] LIKE N'A' + N'%'
+WHERE [e].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [e].[CustomerID]) = 1)
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o.Customer].[CustomerID], [o.Customer].[Address], [o.Customer].[City], [o.Customer].[CompanyName], [o.Customer].[ContactName], [o.Customer].[ContactTitle], [o.Customer].[Country], [o.Customer].[Fax], [o.Customer].[Phone], [o.Customer].[PostalCode], [o.Customer].[Region]
FROM [Orders] AS [o]
@@ -850,7 +850,7 @@ public override void Collection_select_nav_prop_first_or_default_then_nav_prop_n
Assert.StartsWith(
@"SELECT 1
FROM [Customers] AS [e]
-WHERE [e].[CustomerID] LIKE N'A' + N'%'
+WHERE [e].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [e].[CustomerID]) = 1)
SELECT [oo].[OrderID], [oo].[CustomerID], [oo].[EmployeeID], [oo].[OrderDate], [oo.Customer].[CustomerID], [oo.Customer].[Address], [oo.Customer].[City], [oo.Customer].[CompanyName], [oo.Customer].[ContactName], [oo.Customer].[ContactTitle], [oo.Customer].[Country], [oo.Customer].[Fax], [oo.Customer].[Phone], [oo.Customer].[PostalCode], [oo.Customer].[Region]
FROM [Orders] AS [oo]
@@ -873,7 +873,7 @@ public override void Collection_select_nav_prop_first_or_default_then_nav_prop_n
Assert.StartsWith(
@"SELECT 1
FROM [Customers] AS [e]
-WHERE [e].[CustomerID] LIKE N'A' + N'%'
+WHERE [e].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [e].[CustomerID]) = 1)
SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate], [o.Customer].[CustomerID], [o.Customer].[Address], [o.Customer].[City], [o.Customer].[CompanyName], [o.Customer].[ContactName], [o.Customer].[ContactTitle], [o.Customer].[Country], [o.Customer].[Fax], [o.Customer].[Phone], [o.Customer].[PostalCode], [o.Customer].[Region]
FROM [Orders] AS [o]
@@ -1094,7 +1094,7 @@ public override void Project_single_entity_value_subquery_works()
Assert.Equal(
@"SELECT [c].[CustomerID]
FROM [Customers] AS [c]
-WHERE [c].[CustomerID] LIKE N'A' + N'%'
+WHERE [c].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [c].[CustomerID]) = 1)
ORDER BY [c].[CustomerID]
@_outer_CustomerID: ALFKI (Size = 450)
diff --git a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/QuerySqlServerTest.cs b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/QuerySqlServerTest.cs
index 729d6afe478..b9686a79f89 100644
--- a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/QuerySqlServerTest.cs
+++ b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/QuerySqlServerTest.cs
@@ -1619,7 +1619,7 @@ public override void Any_predicate()
WHEN EXISTS (
SELECT 1
FROM [Customers] AS [c]
- WHERE [c].[ContactName] LIKE N'A' + N'%')
+ WHERE [c].[ContactName] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [c].[ContactName]) = 1))
THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END",
Sql);
@@ -1635,7 +1635,7 @@ FROM [Customers] AS [c]
WHERE NOT EXISTS (
SELECT 1
FROM [Orders] AS [o]
- WHERE [o].[CustomerID] LIKE N'A' + N'%')",
+ WHERE [o].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [o].[CustomerID]) = 1))",
Sql);
}
@@ -1649,7 +1649,7 @@ FROM [Customers] AS [c]
WHERE (([c].[City] <> N'London') OR [c].[City] IS NULL) AND NOT EXISTS (
SELECT 1
FROM [Orders] AS [o]
- WHERE [o].[CustomerID] LIKE N'A' + N'%')",
+ WHERE [o].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [o].[CustomerID]) = 1))",
Sql);
}
@@ -1663,7 +1663,7 @@ FROM [Customers] AS [c]
WHERE NOT EXISTS (
SELECT 1
FROM [Orders] AS [o]
- WHERE [o].[CustomerID] LIKE N'A' + N'%') AND (([c].[City] <> N'London') OR [c].[City] IS NULL)",
+ WHERE [o].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [o].[CustomerID]) = 1)) AND (([c].[City] <> N'London') OR [c].[City] IS NULL)",
Sql);
}
@@ -1677,7 +1677,7 @@ FROM [Customers] AS [c]
WHERE EXISTS (
SELECT 1
FROM [Orders] AS [o]
- WHERE [o].[CustomerID] LIKE N'A' + N'%')",
+ WHERE [o].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [o].[CustomerID]) = 1))",
Sql);
}
@@ -1691,7 +1691,7 @@ FROM [Customers] AS [c]
WHERE (([c].[City] <> N'London') OR [c].[City] IS NULL) AND EXISTS (
SELECT 1
FROM [Orders] AS [o]
- WHERE [o].[CustomerID] LIKE N'A' + N'%')",
+ WHERE [o].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [o].[CustomerID]) = 1))",
Sql);
}
@@ -1705,7 +1705,7 @@ FROM [Customers] AS [c]
WHERE EXISTS (
SELECT 1
FROM [Orders] AS [o]
- WHERE [o].[CustomerID] LIKE N'A' + N'%') AND (([c].[City] <> N'London') OR [c].[City] IS NULL)",
+ WHERE [o].[CustomerID] LIKE N'A' + N'%' AND (CHARINDEX(N'A', [o].[CustomerID]) = 1)) AND (([c].[City] <> N'London') OR [c].[City] IS NULL)",
Sql);
}
@@ -1732,7 +1732,22 @@ public override void All_top_level()
WHEN NOT EXISTS (
SELECT 1
FROM [Customers] AS [c]
- WHERE NOT ([c].[ContactName] LIKE N'A' + N'%'))
+ WHERE NOT ([c].[ContactName] LIKE N'A' + N'%') OR (CHARINDEX(N'A', [c].[ContactName]) <> 1))
+ THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
+END",
+ Sql);
+ }
+
+ public override void All_top_level_column()
+ {
+ base.All_top_level_column();
+
+ Assert.Equal(
+ @"SELECT CASE
+ WHEN NOT EXISTS (
+ SELECT 1
+ FROM [Customers] AS [c]
+ WHERE (NOT ([c].[ContactName] LIKE [c].[ContactName] + N'%') OR (CHARINDEX([c].[ContactName], [c].[ContactName]) <> 1)) AND (([c].[ContactName] <> N'') OR [c].[ContactName] IS NULL))
THEN CAST(1 AS BIT) ELSE CAST(0 AS BIT)
END",
Sql);
@@ -3955,7 +3970,7 @@ public override void Where_comparison_to_nullable_bool()
Assert.Equal(
@"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[CustomerID] LIKE N'%' + N'KI'",
+WHERE RIGHT([c].[CustomerID], LEN(N'KI')) = N'KI'",
Sql);
}
@@ -4090,7 +4105,7 @@ public override void String_StartsWith_Literal()
Assert.Equal(
@"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE N'M' + N'%'",
+WHERE [c].[ContactName] LIKE N'M' + N'%' AND (CHARINDEX(N'M', [c].[ContactName]) = 1)",
Sql);
}
@@ -4101,7 +4116,7 @@ public override void String_StartsWith_Identity()
Assert.Equal(
@"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE [c].[ContactName] + N'%'",
+WHERE ([c].[ContactName] LIKE [c].[ContactName] + N'%' AND (CHARINDEX([c].[ContactName], [c].[ContactName]) = 1)) OR ([c].[ContactName] = N'')",
Sql);
}
@@ -4112,7 +4127,7 @@ public override void String_StartsWith_Column()
Assert.Equal(
@"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE [c].[ContactName] + N'%'",
+WHERE ([c].[ContactName] LIKE [c].[ContactName] + N'%' AND (CHARINDEX([c].[ContactName], [c].[ContactName]) = 1)) OR ([c].[ContactName] = N'')",
Sql);
}
@@ -4125,7 +4140,7 @@ public override void String_StartsWith_MethodCall()
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE @__LocalMethod1_0 + N'%'",
+WHERE ([c].[ContactName] LIKE @__LocalMethod1_0 + N'%' AND (CHARINDEX(@__LocalMethod1_0, [c].[ContactName]) = 1)) OR (@__LocalMethod1_0 = N'')",
Sql);
}
@@ -4136,7 +4151,7 @@ public override void String_EndsWith_Literal()
Assert.Equal(
@"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE N'%' + N'b'",
+WHERE RIGHT([c].[ContactName], LEN(N'b')) = N'b'",
Sql);
}
@@ -4147,7 +4162,7 @@ public override void String_EndsWith_Identity()
Assert.Equal(
@"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE N'%' + [c].[ContactName]",
+WHERE (RIGHT([c].[ContactName], LEN([c].[ContactName])) = [c].[ContactName]) OR ([c].[ContactName] = N'')",
Sql);
}
@@ -4158,7 +4173,7 @@ public override void String_EndsWith_Column()
Assert.Equal(
@"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE N'%' + [c].[ContactName]",
+WHERE (RIGHT([c].[ContactName], LEN([c].[ContactName])) = [c].[ContactName]) OR ([c].[ContactName] = N'')",
Sql);
}
@@ -4171,7 +4186,7 @@ public override void String_EndsWith_MethodCall()
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE N'%' + @__LocalMethod2_0",
+WHERE (RIGHT([c].[ContactName], LEN(@__LocalMethod2_0)) = @__LocalMethod2_0) OR (@__LocalMethod2_0 = N'')",
Sql);
}
@@ -4185,7 +4200,7 @@ public override void String_Contains_Literal()
Assert.Equal(
@"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE (N'%' + N'M') + N'%'",
+WHERE CHARINDEX(N'M', [c].[ContactName]) > 0",
Sql);
}
@@ -4196,7 +4211,7 @@ public override void String_Contains_Identity()
Assert.Equal(
@"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE (N'%' + [c].[ContactName]) + N'%'",
+WHERE (CHARINDEX([c].[ContactName], [c].[ContactName]) > 0) OR ([c].[ContactName] = N'')",
Sql);
}
@@ -4207,7 +4222,7 @@ public override void String_Contains_Column()
Assert.Equal(
@"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE (N'%' + [c].[ContactName]) + N'%'",
+WHERE (CHARINDEX([c].[ContactName], [c].[ContactName]) > 0) OR ([c].[ContactName] = N'')",
Sql);
}
@@ -4223,7 +4238,7 @@ public override void String_Contains_MethodCall()
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE (N'%' + @__LocalMethod1_0) + N'%'",
+WHERE (CHARINDEX(@__LocalMethod1_0, [c].[ContactName]) > 0) OR (@__LocalMethod1_0 = N'')",
Sql);
}
@@ -5675,11 +5690,11 @@ public override void Environment_newline_is_funcletized()
Assert.Equal(
@"@__NewLine_0:
- (Size = 450)
+ (Size = 4000)
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[CustomerID] LIKE (N'%' + @__NewLine_0) + N'%'",
+WHERE (CHARINDEX(@__NewLine_0, [c].[CustomerID]) > 0) OR (@__NewLine_0 = N'')",
Sql);
}
diff --git a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/RowNumberPagingTest.cs b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/RowNumberPagingTest.cs
index d3cec4fab37..eb0b33f0a92 100644
--- a/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/RowNumberPagingTest.cs
+++ b/test/Microsoft.EntityFrameworkCore.SqlServer.FunctionalTests/RowNumberPagingTest.cs
@@ -208,7 +208,7 @@ public override void String_Contains_Literal()
Assert.Equal(
@"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE (N'%' + N'M') + N'%'",
+WHERE CHARINDEX(N'M', [c].[ContactName]) > 0",
Sql);
}
@@ -224,7 +224,7 @@ public override void String_Contains_MethodCall()
SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region]
FROM [Customers] AS [c]
-WHERE [c].[ContactName] LIKE (N'%' + @__LocalMethod1_0) + N'%'",
+WHERE (CHARINDEX(@__LocalMethod1_0, [c].[ContactName]) > 0) OR (@__LocalMethod1_0 = N'')",
Sql);
}