diff --git a/src/EFCore.Relational/Query/Pipeline/InExpressionValuesExpandingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/InExpressionValuesExpandingExpressionVisitor.cs index c06cadaf33e..1191f992ad2 100644 --- a/src/EFCore.Relational/Query/Pipeline/InExpressionValuesExpandingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/InExpressionValuesExpandingExpressionVisitor.cs @@ -77,17 +77,21 @@ public override Expression Visit(Expression expression) : null; var nullCheckExpression = hasNullValue - ? _sqlExpressionFactory.IsNull(inExpression.Item) + ? inExpression.Negated + ? _sqlExpressionFactory.IsNotNull(inExpression.Item) + : _sqlExpressionFactory.IsNull(inExpression.Item) : null; if (updatedInExpression != null && nullCheckExpression != null) { - return _sqlExpressionFactory.OrElse(updatedInExpression, nullCheckExpression); + return inExpression.Negated + ? _sqlExpressionFactory.AndAlso(updatedInExpression, nullCheckExpression) + : _sqlExpressionFactory.OrElse(updatedInExpression, nullCheckExpression); } if (updatedInExpression == null && nullCheckExpression == null) { - return _sqlExpressionFactory.Equal(_sqlExpressionFactory.Constant(true), _sqlExpressionFactory.Constant(false)); + return _sqlExpressionFactory.Equal(_sqlExpressionFactory.Constant(true), _sqlExpressionFactory.Constant(inExpression.Negated)); } return (SqlExpression)updatedInExpression ?? nullCheckExpression; diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryOptimizingExpressionVisitors.cs b/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryOptimizingExpressionVisitors.cs index e67158fa637..5347bc748e3 100644 --- a/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryOptimizingExpressionVisitors.cs +++ b/src/EFCore.Relational/Query/Pipeline/RelationalShapedQueryOptimizingExpressionVisitors.cs @@ -10,17 +10,16 @@ namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline { public class RelationalShapedQueryOptimizer : ShapedQueryOptimizer { - private readonly QueryCompilationContext _queryCompilationContext; - public RelationalShapedQueryOptimizer( QueryCompilationContext queryCompilationContext, ISqlExpressionFactory sqlExpressionFactory) { - _queryCompilationContext = queryCompilationContext; + UseRelationalNulls = RelationalOptionsExtension.Extract(queryCompilationContext.ContextOptions).UseRelationalNulls; SqlExpressionFactory = sqlExpressionFactory; } - protected ISqlExpressionFactory SqlExpressionFactory { get; private set; } + protected ISqlExpressionFactory SqlExpressionFactory { get; } + protected bool UseRelationalNulls { get; } public override Expression Visit(Expression query) { @@ -29,12 +28,12 @@ public override Expression Visit(Expression query) query = new CollectionJoinApplyingExpressionVisitor().Visit(query); query = new SelectExpressionTableAliasUniquifyingExpressionVisitor().Visit(query); - if (!RelationalOptionsExtension.Extract(_queryCompilationContext.ContextOptions).UseRelationalNulls) + if (!UseRelationalNulls) { query = new NullSemanticsRewritingVisitor(SqlExpressionFactory).Visit(query); } - query = new SqlExpressionOptimizingVisitor(SqlExpressionFactory).Visit(query); + query = new SqlExpressionOptimizingVisitor(SqlExpressionFactory, UseRelationalNulls).Visit(query); query = new NullComparisonTransformingExpressionVisitor().Visit(query); if (query is ShapedQueryExpression shapedQueryExpression) diff --git a/src/EFCore.Relational/Query/Pipeline/SqlExpressionOptimizingVisitor.cs b/src/EFCore.Relational/Query/Pipeline/SqlExpressionOptimizingVisitor.cs index 9d62c9befb0..c0e4f7d7f07 100644 --- a/src/EFCore.Relational/Query/Pipeline/SqlExpressionOptimizingVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/SqlExpressionOptimizingVisitor.cs @@ -10,6 +10,7 @@ namespace Microsoft.EntityFrameworkCore.Query.Pipeline public class SqlExpressionOptimizingVisitor : ExpressionVisitor { private readonly ISqlExpressionFactory _sqlExpressionFactory; + private readonly bool _useRelationalNulls; private static bool TryNegate(ExpressionType expressionType, out ExpressionType result) { @@ -29,9 +30,10 @@ private static bool TryNegate(ExpressionType expressionType, out ExpressionType return negated.HasValue; } - public SqlExpressionOptimizingVisitor(ISqlExpressionFactory sqlExpressionFactory) + public SqlExpressionOptimizingVisitor(ISqlExpressionFactory sqlExpressionFactory, bool useRelationalNulls) { _sqlExpressionFactory = sqlExpressionFactory; + _useRelationalNulls = useRelationalNulls; } protected override Expression VisitExtension(Expression extensionExpression) @@ -51,15 +53,9 @@ protected override Expression VisitExtension(Expression extensionExpression) private Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression) { - // !(true) -> false - // !(false) -> true - if (sqlUnaryExpression.OperatorType == ExpressionType.Not - && sqlUnaryExpression.Operand is SqlConstantExpression innerConstantBool - && innerConstantBool.Value is bool value) + if (sqlUnaryExpression.OperatorType == ExpressionType.Not) { - return value - ? _sqlExpressionFactory.Constant(false, sqlUnaryExpression.TypeMapping) - : _sqlExpressionFactory.Constant(true, sqlUnaryExpression.TypeMapping); + return VisitNot(sqlUnaryExpression); } // NULL IS NULL -> true @@ -80,27 +76,6 @@ private Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression 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) @@ -116,6 +91,47 @@ private Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression } } + var newOperand = (SqlExpression)Visit(sqlUnaryExpression.Operand); + + return sqlUnaryExpression.Update(newOperand); + } + + private Expression VisitNot(SqlUnaryExpression sqlUnaryExpression) + { + // !(true) -> false + // !(false) -> true + if (sqlUnaryExpression.Operand is SqlConstantExpression innerConstantBool + && innerConstantBool.Value is bool value) + { + return _sqlExpressionFactory.Constant(!value, sqlUnaryExpression.TypeMapping); + } + + if (sqlUnaryExpression.Operand is InExpression inExpression) + { + return Visit(inExpression.Negate()); + } + + if (sqlUnaryExpression.Operand is SqlUnaryExpression innerUnary) + { + // !(!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)); + } + } + if (sqlUnaryExpression.Operand is SqlBinaryExpression innerBinary) { // De Morgan's @@ -130,11 +146,11 @@ private Expression VisitSqlUnaryExpression(SqlUnaryExpression sqlUnaryExpression : _sqlExpressionFactory.AndAlso(newLeft, newRight); } - // note that those optimizations are only valid in 2-value logic + // 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)) + if (!_useRelationalNulls && TryNegate(innerBinary.OperatorType, out var negated)) { return Visit( _sqlExpressionFactory.MakeBinary( @@ -158,7 +174,6 @@ private Expression VisitSqlBinaryExpression(SqlBinaryExpression sqlBinaryExpress if (sqlBinaryExpression.OperatorType == ExpressionType.AndAlso || sqlBinaryExpression.OperatorType == ExpressionType.OrElse) { - var newLeftConstant = newLeft as SqlConstantExpression; var newRightConstant = newRight as SqlConstantExpression; @@ -194,6 +209,31 @@ private Expression VisitSqlBinaryExpression(SqlBinaryExpression sqlBinaryExpress return sqlBinaryExpression.Update(newLeft, newRight); } + // 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 (!_useRelationalNulls + && (sqlBinaryExpression.OperatorType == ExpressionType.Equal || sqlBinaryExpression.OperatorType == ExpressionType.NotEqual)) + { + // op(a, b) == true -> op(a, b) + // op(a, b) != false -> op(a, b) + // op(a, b) == false -> !op(a, b) + // op(a, b) != true -> !op(a, b) + var constant = sqlBinaryExpression.Left as SqlConstantExpression ?? sqlBinaryExpression.Right as SqlConstantExpression; + var binary = sqlBinaryExpression.Left as SqlBinaryExpression ?? sqlBinaryExpression.Right as SqlBinaryExpression; + if (constant != null && binary != null && TryNegate(binary.OperatorType, out var negated)) + { + return (bool)constant.Value == (sqlBinaryExpression.OperatorType == ExpressionType.Equal) + ? binary + : _sqlExpressionFactory.MakeBinary( + negated, + sqlBinaryExpression.Left, + sqlBinaryExpression.Right, + sqlBinaryExpression.TypeMapping); + } + } + return sqlBinaryExpression.Update(newLeft, newRight); } } diff --git a/src/EFCore.SqlServer/Query/Pipeline/SqlServerShapedQueryOptimizingExpressionVisitors.cs b/src/EFCore.SqlServer/Query/Pipeline/SqlServerShapedQueryOptimizingExpressionVisitors.cs index 5934c9553d3..909719ce6b9 100644 --- a/src/EFCore.SqlServer/Query/Pipeline/SqlServerShapedQueryOptimizingExpressionVisitors.cs +++ b/src/EFCore.SqlServer/Query/Pipeline/SqlServerShapedQueryOptimizingExpressionVisitors.cs @@ -20,6 +20,7 @@ public override Expression Visit(Expression query) { query = base.Visit(query); query = new SearchConditionConvertingExpressionVisitor(SqlExpressionFactory).Visit(query); + query = new SqlExpressionOptimizingVisitor(SqlExpressionFactory, UseRelationalNulls).Visit(query); return query; } diff --git a/src/EFCore.SqlServer/Query/Pipeline/SqlServerStringMethodTranslator.cs b/src/EFCore.SqlServer/Query/Pipeline/SqlServerStringMethodTranslator.cs index f5e7c0a066c..2c6a5347a46 100644 --- a/src/EFCore.SqlServer/Query/Pipeline/SqlServerStringMethodTranslator.cs +++ b/src/EFCore.SqlServer/Query/Pipeline/SqlServerStringMethodTranslator.cs @@ -216,10 +216,28 @@ public SqlExpression Translate(SqlExpression instance, MethodInfo method, IList< { var pattern = arguments[0]; var stringTypeMapping = ExpressionExtensions.InferTypeMapping(instance, pattern); - instance = _sqlExpressionFactory.ApplyTypeMapping(instance, stringTypeMapping); pattern = _sqlExpressionFactory.ApplyTypeMapping(pattern, stringTypeMapping); + if (pattern is SqlConstantExpression constantPattern) + { + if ((string)constantPattern.Value == string.Empty) + { + return _sqlExpressionFactory.Constant(true); + } + + return _sqlExpressionFactory.GreaterThan( + _sqlExpressionFactory.Function( + "CHARINDEX", + new[] + { + pattern, + instance + }, + typeof(int)), + _sqlExpressionFactory.Constant(0)); + } + return _sqlExpressionFactory.OrElse( _sqlExpressionFactory.Equal( pattern, diff --git a/src/EFCore/Query/Pipeline/EntityEqualityRewritingExpressionVisitor.cs b/src/EFCore/Query/Pipeline/EntityEqualityRewritingExpressionVisitor.cs index 2246b640731..8e3ce5e8767 100644 --- a/src/EFCore/Query/Pipeline/EntityEqualityRewritingExpressionVisitor.cs +++ b/src/EFCore/Query/Pipeline/EntityEqualityRewritingExpressionVisitor.cs @@ -315,7 +315,7 @@ protected virtual Expression VisitOrderingMethodCall(MethodCallExpression method } var genericMethodDefinition = methodCallExpression.Method.GetGenericMethodDefinition(); - var isFirstOrdering = + var firstOrdering = genericMethodDefinition == LinqMethodHelpers.QueryableOrderByMethodInfo || genericMethodDefinition == LinqMethodHelpers.QueryableOrderByDescendingMethodInfo; var isAscending = @@ -336,7 +336,7 @@ protected virtual Expression VisitOrderingMethodCall(MethodCallExpression method body.CreateEFPropertyExpression(keyProperty, makeNullable: false)), param); - var orderingMethodInfo = GetOrderingMethodInfo(isFirstOrdering, isAscending); + var orderingMethodInfo = GetOrderingMethodInfo(firstOrdering, isAscending); expression = Expression.Call( orderingMethodInfo.MakeGenericMethod(entityType.ClrType, keyProperty.ClrType), @@ -344,20 +344,20 @@ protected virtual Expression VisitOrderingMethodCall(MethodCallExpression method rewrittenKeySelector ); - isFirstOrdering = false; + firstOrdering = false; } return expression; - static MethodInfo GetOrderingMethodInfo(bool isFirstOrdering, bool isAscending) + static MethodInfo GetOrderingMethodInfo(bool firstOrdering, bool ascending) { - if (isFirstOrdering) + if (firstOrdering) { - return isAscending + return ascending ? LinqMethodHelpers.QueryableOrderByMethodInfo : LinqMethodHelpers.QueryableOrderByDescendingMethodInfo; } - return isAscending + return ascending ? LinqMethodHelpers.QueryableThenByMethodInfo : LinqMethodHelpers.QueryableThenByDescendingMethodInfo; } diff --git a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs index ab998b630a4..9327ca27c7e 100644 --- a/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs +++ b/test/EFCore.Specification.Tests/Query/GearsOfWarQueryTestBase.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Runtime.CompilerServices; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Internal; @@ -3154,48 +3155,6 @@ public virtual void Unnecessary_include_doesnt_get_added_complex_when_projecting } } - [ConditionalFact] - public virtual void Order_by_is_properly_lifted_from_subquery_created_by_include() - { - using (var ctx = CreateContext()) - { - var query = ctx.Gears - .OrderBy(g => g.Rank) - .Include(g => g.Tag) - .OrderBy(g => g.FullName) - .Where(g => !g.HasSoulPatch) - .Select(g => g.FullName); - - var result = query.ToList(); - - Assert.Equal(3, result.Count); - Assert.Equal("Augustus Cole", result[0]); - Assert.Equal("Dominic Santiago", result[1]); - Assert.Equal("Garron Paduk", result[2]); - } - } - - [ConditionalFact] - public virtual void Order_by_then_by_is_properly_lifted_from_subquery_created_by_include() - { - using (var ctx = CreateContext()) - { - var query = ctx.Gears - .OrderBy(g => g.Rank).ThenByDescending(g => g.Nickname) - .Include(g => g.Tag) - .OrderBy(g => g.FullName) - .Where(g => !g.HasSoulPatch) - .Select(g => g.FullName); - - var result = query.ToList(); - - Assert.Equal(3, result.Count); - Assert.Equal("Augustus Cole", result[0]); - Assert.Equal("Dominic Santiago", result[1]); - Assert.Equal("Garron Paduk", result[2]); - } - } - [ConditionalFact] public virtual void Multiple_order_bys_are_properly_lifted_from_subquery_created_by_include() { @@ -3262,23 +3221,6 @@ public virtual void Where_is_properly_lifted_from_subquery_created_by_include() } } - [ConditionalTheory] - [MemberData(nameof(IsAsyncData))] - public virtual Task Where_and_order_by_are_properly_lifted_from_subquery_created_by_tracking(bool isAsync) - { - return AssertQuery( - isAsync, - gs => gs - .Where(g => g.FullName != "Augustus Cole") - .AsNoTracking() - .OrderBy(g => g.Rank) - .AsTracking() - .OrderBy(g => g.FullName) - .Where(g => !g.HasSoulPatch) - .Select(g => g.FullName), - assertOrder: true); - } - [ConditionalFact] public virtual void Subquery_is_lifted_from_main_from_clause_of_SelectMany() { @@ -3800,7 +3742,7 @@ orderby f.Name } } - [ConditionalFact] + [ConditionalFact(Skip = "issue #16089")] public virtual void Navigation_access_via_EFProperty_on_derived_entity_using_cast() { using (var ctx = CreateContext()) @@ -3824,7 +3766,7 @@ orderby f.Name } } - [ConditionalFact] + [ConditionalFact(Skip = "issue #16089")] public virtual void Navigation_access_fk_on_derived_entity_using_cast() { using (var ctx = CreateContext()) @@ -4111,7 +4053,7 @@ public virtual void Optional_navigation_with_collection_composite_key() } } - [ConditionalFact] + [ConditionalFact(Skip = "issue #16089")] public virtual void Select_null_conditional_with_inheritance() { using (var context = CreateContext()) @@ -5896,7 +5838,7 @@ public virtual Task Include_on_derived_type_with_order_by_and_paging(bool isAsyn elementSorter: e => e.Name); } - [ConditionalTheory] + [ConditionalTheory(Skip = "issue #16089")] [MemberData(nameof(IsAsyncData))] public virtual Task Select_required_navigation_on_derived_type(bool isAsync) { @@ -5916,7 +5858,7 @@ public virtual Task Select_required_navigation_on_the_same_type_with_cast(bool i gs => gs.Select(g => g.CityOfBirth.Name)); } - [ConditionalTheory] + [ConditionalTheory(Skip = "issue #16089")] [MemberData(nameof(IsAsyncData))] public virtual Task Where_required_navigation_on_derived_type(bool isAsync) { diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs index c8c1670c73a..7fef0212c73 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/ComplexNavigationsQuerySqlServerTest.cs @@ -377,12 +377,11 @@ public override async Task Method_call_on_optional_navigation_translates_to_null { await base.Method_call_on_optional_navigation_translates_to_null_conditional_properly_for_arguments(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [e1].[Id], [e1].[Date], [e1].[Name], [e1].[OneToMany_Optional_Self_Inverse1Id], [e1].[OneToMany_Required_Self_Inverse1Id], [e1].[OneToOne_Optional_Self1Id] -//FROM [LevelOne] AS [e1] -//LEFT JOIN [LevelTwo] AS [e1.OneToOne_Optional_FK1] ON [e1].[Id] = [e1.OneToOne_Optional_FK1].[Level1_Optional_Id] -//WHERE ([e1.OneToOne_Optional_FK1].[Name] LIKE [e1.OneToOne_Optional_FK1].[Name] + N'%' AND (LEFT([e1.OneToOne_Optional_FK1].[Name], LEN([e1.OneToOne_Optional_FK1].[Name])) = [e1.OneToOne_Optional_FK1].[Name])) OR ([e1.OneToOne_Optional_FK1].[Name] = N'')"); + AssertSql( + @"SELECT [l].[Id], [l].[Date], [l].[Name], [l].[OneToMany_Optional_Self_Inverse1Id], [l].[OneToMany_Required_Self_Inverse1Id], [l].[OneToOne_Optional_Self1Id] +FROM [LevelOne] AS [l] +LEFT JOIN [LevelTwo] AS [l0] ON [l].[Id] = [l0].[Level1_Optional_Id] +WHERE (([l0].[Name] = N'') AND [l0].[Name] IS NOT NULL) OR ([l0].[Name] IS NOT NULL AND ([l0].[Name] IS NOT NULL AND (([l0].[Name] LIKE [l0].[Name] + N'%') AND (((LEFT([l0].[Name], LEN([l0].[Name])) = [l0].[Name]) AND (LEFT([l0].[Name], LEN([l0].[Name])) IS NOT NULL AND [l0].[Name] IS NOT NULL)) OR (LEFT([l0].[Name], LEN([l0].[Name])) IS NULL AND [l0].[Name] IS NULL)))))"); } public override async Task Optional_navigation_inside_method_call_translated_to_join_keeps_original_nullability(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs index a32a8af8597..9d92d70fa78 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/FromSqlQuerySqlServerTest.cs @@ -46,31 +46,29 @@ public override void FromSqlRaw_queryable_composed() { base.FromSqlRaw_queryable_composed(); - // issue #15994 -// AssertSql( -// @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] -//FROM ( -// SELECT * FROM ""Customers"" -//) AS [c] -//WHERE CHARINDEX(N'z', [c].[ContactName]) > 0"); + AssertSql( + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM ( + SELECT * FROM ""Customers"" +) AS [c] +WHERE CHARINDEX(N'z', [c].[ContactName]) > 0"); } public override void FromSqlRaw_queryable_composed_after_removing_whitespaces() { base.FromSqlRaw_queryable_composed_after_removing_whitespaces(); - // issue #15994 -// AssertSql( -// @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] -//FROM ( - + AssertSql( + @"SELECT [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName], [c].[ContactName], [c].[ContactTitle], [c].[Country], [c].[Fax], [c].[Phone], [c].[PostalCode], [c].[Region] +FROM ( + -// SELECT -// * FROM ""Customers"" -//) AS [c] -//WHERE CHARINDEX(N'z', [c].[ContactName]) > 0"); + SELECT + * FROM ""Customers"" +) AS [c] +WHERE CHARINDEX(N'z', [c].[ContactName]) > 0"); } public override void FromSqlRaw_queryable_composed_compiled() @@ -342,7 +340,7 @@ public override void FromSqlRaw_queryable_simple_projection_composed() { base.FromSqlRaw_queryable_simple_projection_composed(); - // issue #15994 + // issue #16079 // AssertSql( // @"SELECT [p].[ProductName] //FROM ( diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs index 3b772ce0cbd..cf20c879b3c 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/GearsOfWarQuerySqlServerTest.cs @@ -748,70 +748,124 @@ public override async Task Where_enum_has_flag_subquery(bool isAsync) { await base.Where_enum_has_flag_subquery(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] -//FROM [Gears] AS [g] -//WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND (([g].[Rank] & COALESCE(( -// SELECT TOP(1) [x].[Rank] -// FROM [Gears] AS [x] -// WHERE [x].[Discriminator] IN (N'Officer', N'Gear') -// ORDER BY [x].[Nickname], [x].[SquadId] -//), 0)) = COALESCE(( -// SELECT TOP(1) [x].[Rank] -// FROM [Gears] AS [x] -// WHERE [x].[Discriminator] IN (N'Officer', N'Gear') -// ORDER BY [x].[Nickname], [x].[SquadId] -//), 0))", -// // -// @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] -//FROM [Gears] AS [g] -//WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND ((1 & COALESCE(( -// SELECT TOP(1) [x].[Rank] -// FROM [Gears] AS [x] -// WHERE [x].[Discriminator] IN (N'Officer', N'Gear') -// ORDER BY [x].[Nickname], [x].[SquadId] -//), 0)) = COALESCE(( -// SELECT TOP(1) [x].[Rank] -// FROM [Gears] AS [x] -// WHERE [x].[Discriminator] IN (N'Officer', N'Gear') -// ORDER BY [x].[Nickname], [x].[SquadId] -//), 0))"); + AssertSql( + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (((([g].[Rank] & ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId])) = ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId])) AND ([g].[Rank] & ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL AND ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL)) OR ([g].[Rank] & ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL AND ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL))", + // + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ((((1 & ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId])) = ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId])) AND (1 & ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL AND ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL)) OR (1 & ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL AND ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL))"); } public override async Task Where_enum_has_flag_subquery_with_pushdown(bool isAsync) { await base.Where_enum_has_flag_subquery_with_pushdown(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] -//FROM [Gears] AS [g] -//WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND (([g].[Rank] & ( -// SELECT TOP(1) [x].[Rank] -// FROM [Gears] AS [x] -// WHERE [x].[Discriminator] IN (N'Officer', N'Gear') -// ORDER BY [x].[Nickname], [x].[SquadId] -//)) = ( -// SELECT TOP(1) [x].[Rank] -// FROM [Gears] AS [x] -// WHERE [x].[Discriminator] IN (N'Officer', N'Gear') -// ORDER BY [x].[Nickname], [x].[SquadId] -//))", -// // -// @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] -//FROM [Gears] AS [g] -//WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND ((1 & ( -// SELECT TOP(1) [x].[Rank] -// FROM [Gears] AS [x] -// WHERE [x].[Discriminator] IN (N'Officer', N'Gear') -// ORDER BY [x].[Nickname], [x].[SquadId] -//)) = ( -// SELECT TOP(1) [x].[Rank] -// FROM [Gears] AS [x] -// WHERE [x].[Discriminator] IN (N'Officer', N'Gear') -// ORDER BY [x].[Nickname], [x].[SquadId] -//))"); + AssertSql( + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (((([g].[Rank] & ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId])) = ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId])) AND ([g].[Rank] & ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL AND ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL)) OR ([g].[Rank] & ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL AND ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL))", + // + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ((((1 & ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId])) = ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId])) AND (1 & ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL AND ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NOT NULL)) OR (1 & ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL AND ( + SELECT TOP(1) [g0].[Rank] + FROM [Gears] AS [g0] + WHERE [g0].[Discriminator] IN (N'Gear', N'Officer') + ORDER BY [g0].[Nickname], [g0].[SquadId]) IS NULL))"); } public override async Task Where_enum_has_flag_subquery_client_eval(bool isAsync) @@ -865,13 +919,12 @@ public override async Task Where_has_flag_with_nullable_parameter(bool isAsync) { await base.Where_has_flag_with_nullable_parameter(isAsync); - // issue #15994 -// AssertSql( -// @"@__parameter_0='1' (Nullable = true) + AssertSql( + @"@__parameter_0='1' (Nullable = true) -//SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] -//FROM [Gears] AS [g] -//WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND (([g].[Rank] & @__parameter_0) = @__parameter_0)"); +SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (((([g].[Rank] & @__parameter_0) = @__parameter_0) AND ([g].[Rank] & @__parameter_0 IS NOT NULL AND @__parameter_0 IS NOT NULL)) OR ([g].[Rank] & @__parameter_0 IS NULL AND @__parameter_0 IS NULL))"); } public override async Task Select_enum_has_flag(bool isAsync) @@ -923,14 +976,13 @@ public override async Task Select_inverted_boolean(bool isAsync) { await base.Select_inverted_boolean(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [w].[Id], CASE -// WHEN [w].[IsAutomatic] = CAST(0 AS bit) -// THEN CAST(1 AS bit) ELSE CAST(0 AS bit) -//END AS [Manual] -//FROM [Weapons] AS [w] -//WHERE [w].[IsAutomatic] = CAST(1 AS bit)"); + AssertSql( + @"SELECT [w].[Id], CASE + WHEN [w].[IsAutomatic] <> CAST(1 AS bit) THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) +END AS [Manual] +FROM [Weapons] AS [w] +WHERE [w].[IsAutomatic] = CAST(1 AS bit)"); } public override async Task Select_comparison_with_null(bool isAsync) @@ -975,7 +1027,7 @@ public override async Task Select_ternary_operation_with_inverted_boolean(bool i AssertSql( @"SELECT [w].[Id], CASE - WHEN NOT ([w].[IsAutomatic] = CAST(1 AS bit)) THEN 1 + WHEN [w].[IsAutomatic] <> CAST(1 AS bit) THEN 1 ELSE 0 END AS [Num] FROM [Weapons] AS [w]"); @@ -1012,7 +1064,7 @@ public override async Task Select_ternary_operation_multiple_conditions_2(bool i AssertSql( @"SELECT [w].[Id], CASE - WHEN NOT ([w].[IsAutomatic] = CAST(1 AS bit)) AND (([w].[SynergyWithId] = 1) AND [w].[SynergyWithId] IS NOT NULL) THEN N'Yes' + WHEN ([w].[IsAutomatic] <> CAST(1 AS bit)) AND (([w].[SynergyWithId] = 1) AND [w].[SynergyWithId] IS NOT NULL) THEN N'Yes' ELSE N'No' END AS [IsCartidge] FROM [Weapons] AS [w]"); @@ -1024,7 +1076,7 @@ public override async Task Select_multiple_conditions(bool isAsync) AssertSql( @"SELECT [w].[Id], CASE - WHEN NOT ([w].[IsAutomatic] = CAST(1 AS bit)) AND (([w].[SynergyWithId] = 1) AND [w].[SynergyWithId] IS NOT NULL) THEN CAST(1 AS bit) + WHEN ([w].[IsAutomatic] <> CAST(1 AS bit)) AND (([w].[SynergyWithId] = 1) AND [w].[SynergyWithId] IS NOT NULL) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [IsCartidge] FROM [Weapons] AS [w]"); @@ -1036,7 +1088,7 @@ public override async Task Select_nested_ternary_operations(bool isAsync) AssertSql( @"SELECT [w].[Id], CASE - WHEN NOT ([w].[IsAutomatic] = CAST(1 AS bit)) THEN CASE + WHEN [w].[IsAutomatic] <> CAST(1 AS bit) THEN CASE WHEN ([w].[AmmunitionType] = 1) AND [w].[AmmunitionType] IS NOT NULL THEN N'ManualCartridge' ELSE N'Manual' END @@ -1049,18 +1101,17 @@ public override async Task Null_propagation_optimization1(bool isAsync) { await base.Null_propagation_optimization1(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] -//FROM [Gears] AS [g] -//WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND ([g].[LeaderNickname] = N'Marcus')"); + AssertSql( + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([g].[LeaderNickname] = N'Marcus') AND [g].[LeaderNickname] IS NOT NULL)"); } public override async Task Null_propagation_optimization2(bool isAsync) { await base.Null_propagation_optimization2(isAsync); - // issue #15994 + // issue #16050 // AssertSql( // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] //FROM [Gears] AS [g] @@ -1071,7 +1122,7 @@ public override async Task Null_propagation_optimization3(bool isAsync) { await base.Null_propagation_optimization3(isAsync); - // issue #15994 + // issue #16050 // AssertSql( // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] //FROM [Gears] AS [g] @@ -1082,8 +1133,7 @@ public override async Task Null_propagation_optimization4(bool isAsync) { await base.Null_propagation_optimization4(isAsync); - - // issue #15994 + // issue #16050 // AssertSql( // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] //FROM [Gears] AS [g] @@ -1094,7 +1144,7 @@ public override async Task Null_propagation_optimization5(bool isAsync) { await base.Null_propagation_optimization5(isAsync); - // issue #15994 + // issue #16050 // AssertSql( // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] //FROM [Gears] AS [g] @@ -1105,7 +1155,7 @@ public override async Task Null_propagation_optimization6(bool isAsync) { await base.Null_propagation_optimization6(isAsync); - // issue #15994 + // issue #16050 // AssertSql( // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] //FROM [Gears] AS [g] @@ -1116,7 +1166,7 @@ public override async Task Select_null_propagation_optimization7(bool isAsync) { await base.Select_null_propagation_optimization7(isAsync); - // issue #15994 + // issue #16050 // AssertSql( // @"SELECT [g].[LeaderNickname] + [g].[LeaderNickname] //FROM [Gears] AS [g] @@ -1163,7 +1213,7 @@ public override async Task Select_null_propagation_negative2(bool isAsync) { await base.Select_null_propagation_negative2(isAsync); - // issue #15994 + // issue #16081 // AssertSql( // @"SELECT CASE // WHEN [g1].[LeaderNickname] IS NOT NULL @@ -2119,7 +2169,7 @@ public override async Task Join_with_order_by_without_skip_or_take(bool isAsync) { await base.Join_with_order_by_without_skip_or_take(isAsync); - // issue #15994 + // issue #16086 // AssertSql( // @"SELECT [t].[Name], [g].[FullName] //FROM [Gears] AS [g] @@ -2202,15 +2252,16 @@ public override async Task Non_unicode_string_literals_is_used_for_non_unicode_c { await base.Non_unicode_string_literals_is_used_for_non_unicode_column_with_subquery(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [c].[Name], [c].[Location], [c].[Nation] -//FROM [Cities] AS [c] -//WHERE ([c].[Location] = 'Unknown') AND (( -// SELECT COUNT(*) -// FROM [Gears] AS [g] -// WHERE ([g].[Discriminator] IN (N'Officer', N'Gear') AND ([c].[Name] = [g].[CityOrBirthName])) AND ([g].[Nickname] = N'Paduk') -//) = 1)"); + AssertSql( + @"SELECT [c].[Name], [c].[Location], [c].[Nation] +FROM [Cities] AS [c] +WHERE (([c].[Location] = 'Unknown') AND [c].[Location] IS NOT NULL) AND ((( + SELECT COUNT(*) + FROM [Gears] AS [g] + WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([c].[Name] = [g].[CityOrBirthName])) AND ([g].[Nickname] = N'Paduk')) = 1) AND ( + SELECT COUNT(*) + FROM [Gears] AS [g] + WHERE ([g].[Discriminator] IN (N'Gear', N'Officer') AND ([c].[Name] = [g].[CityOrBirthName])) AND ([g].[Nickname] = N'Paduk')) IS NOT NULL)"); } public override async Task Non_unicode_string_literals_is_used_for_non_unicode_column_in_subquery(bool isAsync) @@ -2228,11 +2279,10 @@ public override async Task Non_unicode_string_literals_is_used_for_non_unicode_c { await base.Non_unicode_string_literals_is_used_for_non_unicode_column_with_contains(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [c].[Name], [c].[Location], [c].[Nation] -//FROM [Cities] AS [c] -//WHERE CHARINDEX(N'Jacinto', [c].[Location]) > 0"); + AssertSql( + @"SELECT [c].[Name], [c].[Location], [c].[Nation] +FROM [Cities] AS [c] +WHERE CHARINDEX('Jacinto', [c].[Location]) > 0"); } public override void Non_unicode_string_literals_is_used_for_non_unicode_column_with_concat() @@ -2591,16 +2641,16 @@ public override async Task Optional_navigation_type_compensation_works_with_pred { await base.Optional_navigation_type_compensation_works_with_predicate_negated(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[Note] -//FROM [Tags] AS [t] -//LEFT JOIN ( -// SELECT [t.Gear].* -// FROM [Gears] AS [t.Gear] -// WHERE [t.Gear].[Discriminator] IN (N'Officer', N'Gear') -//) AS [t0] ON ([t].[GearNickName] = [t0].[Nickname]) AND ([t].[GearSquadId] = [t0].[SquadId]) -//WHERE [t0].[HasSoulPatch] = CAST(0 AS bit)"); + + AssertSql( + @"SELECT [t].[Id], [t].[GearNickName], [t].[GearSquadId], [t].[Note] +FROM [Tags] AS [t] +LEFT JOIN ( + SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] + FROM [Gears] AS [g] + WHERE [g].[Discriminator] IN (N'Gear', N'Officer') +) AS [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) +WHERE CAST([t0].[HasSoulPatch] AS bit) <> CAST(1 AS bit)"); } public override async Task Optional_navigation_type_compensation_works_with_predicate_negated_complex1(bool isAsync) @@ -2649,7 +2699,7 @@ LEFT JOIN ( FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ) AS [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) -WHERE ([t0].[HasSoulPatch] = CAST(1 AS bit)) OR ((N'Cole' = N'') OR (CHARINDEX(N'Cole', [t].[Note]) > 0))"); +WHERE ([t0].[HasSoulPatch] = CAST(1 AS bit)) OR (CHARINDEX(N'Cole', [t].[Note]) > 0)"); } public override async Task Optional_navigation_type_compensation_works_with_binary_and_expression(bool isAsync) @@ -2658,7 +2708,7 @@ public override async Task Optional_navigation_type_compensation_works_with_bina AssertSql( @"SELECT CASE - WHEN ([t].[HasSoulPatch] = CAST(1 AS bit)) AND ((N'Cole' = N'') OR (CHARINDEX(N'Cole', [t0].[Note]) > 0)) THEN CAST(1 AS bit) + WHEN ([t].[HasSoulPatch] = CAST(1 AS bit)) AND (CHARINDEX(N'Cole', [t0].[Note]) > 0) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END FROM [Tags] AS [t0] @@ -2791,7 +2841,7 @@ LEFT JOIN ( FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ) AS [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) - WHERE (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND NOT (CAST([t0].[HasSoulPatch] AS bit) = CAST(1 AS bit))) THEN CAST(1 AS bit) + WHERE (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND (CAST([t0].[HasSoulPatch] AS bit) <> CAST(1 AS bit))) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END"); } @@ -2808,7 +2858,7 @@ LEFT JOIN ( FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ) AS [t0] ON (([t].[GearNickName] = [t0].[Nickname]) AND [t].[GearNickName] IS NOT NULL) AND (([t].[GearSquadId] = [t0].[SquadId]) AND [t].[GearSquadId] IS NOT NULL) -WHERE (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND NOT (CAST([t0].[HasSoulPatch] AS bit) = CAST(1 AS bit))"); +WHERE (([t].[Note] <> N'K.I.A.') OR [t].[Note] IS NULL) AND (CAST([t0].[HasSoulPatch] AS bit) <> CAST(1 AS bit))"); } public override async Task Optional_navigation_type_compensation_works_with_contains(bool isAsync) @@ -3027,12 +3077,13 @@ public override async Task Join_predicate_value_equals_condition(bool isAsync) { await base.Join_predicate_value_equals_condition(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] -//FROM [Gears] AS [g] -//INNER JOIN [Weapons] AS [w] ON [w].[SynergyWithId] IS NOT NULL -//WHERE [g].[Discriminator] IN (N'Officer', N'Gear')"); + AssertSql( + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] +FROM [Gears] AS [g] +INNER JOIN [Weapons] AS [w] ON [w].[SynergyWithId] IS NOT NULL +WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); + + } public override async Task Join_predicate_value(bool isAsync) @@ -3064,12 +3115,11 @@ public override async Task Left_join_predicate_value_equals_condition(bool isAsy { await base.Left_join_predicate_value_equals_condition(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] -//FROM [Gears] AS [g] -//LEFT JOIN [Weapons] AS [w] ON [w].[SynergyWithId] IS NOT NULL -//WHERE [g].[Discriminator] IN (N'Officer', N'Gear')"); + AssertSql( + @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] +FROM [Gears] AS [g] +LEFT JOIN [Weapons] AS [w] ON [w].[SynergyWithId] IS NOT NULL +WHERE [g].[Discriminator] IN (N'Gear', N'Officer')"); } public override async Task Left_join_predicate_value(bool isAsync) @@ -3306,7 +3356,7 @@ LEFT JOIN ( FROM [Gears] AS [g] WHERE [g].[Discriminator] IN (N'Gear', N'Officer') ) AS [t] ON [w].[OwnerFullName] = [t].[FullName] -WHERE ([w].[Id] <> 50) AND NOT (CAST([t].[HasSoulPatch] AS bit) = CAST(1 AS bit))"); +WHERE ([w].[Id] <> 50) AND (CAST([t].[HasSoulPatch] AS bit) <> CAST(1 AS bit))"); } public override async Task Distinct_with_optional_navigation_is_translated_to_sql(bool isAsync) @@ -3457,30 +3507,6 @@ WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] = CAS ORDER BY [g].[Rank]"); } - public override void Order_by_is_properly_lifted_from_subquery_created_by_include() - { - base.Order_by_is_properly_lifted_from_subquery_created_by_include(); - - // issue #15994 -// AssertSql( -// @"SELECT [g].[FullName] -//FROM [Gears] AS [g] -//WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND ([g].[HasSoulPatch] = CAST(0 AS bit)) -//ORDER BY [g].[FullName], [g].[Rank]"); - } - - public override void Order_by_then_by_is_properly_lifted_from_subquery_created_by_include() - { - base.Order_by_then_by_is_properly_lifted_from_subquery_created_by_include(); - - // issue #15994 -// AssertSql( -// @"SELECT [g].[FullName] -//FROM [Gears] AS [g] -//WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND ([g].[HasSoulPatch] = CAST(0 AS bit)) -//ORDER BY [g].[FullName], [g].[Rank], [g].[Nickname] DESC"); - } - public override void Multiple_order_bys_are_properly_lifted_from_subquery_created_by_include() { base.Multiple_order_bys_are_properly_lifted_from_subquery_created_by_include(); @@ -3488,7 +3514,7 @@ public override void Multiple_order_bys_are_properly_lifted_from_subquery_create AssertSql( @"SELECT [g].[FullName] FROM [Gears] AS [g] -WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND NOT ([g].[HasSoulPatch] = CAST(1 AS bit)) +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] <> CAST(1 AS bit)) ORDER BY [g].[FullName]"); } @@ -3496,12 +3522,11 @@ public override void Order_by_is_properly_lifted_from_subquery_with_same_order_b { base.Order_by_is_properly_lifted_from_subquery_with_same_order_by_in_the_outer_query(); - // issue #15994 -// AssertSql( -// @"SELECT [g].[FullName] -//FROM [Gears] AS [g] -//WHERE [g].[Discriminator] IN (N'Officer', N'Gear') AND ([g].[HasSoulPatch] = CAST(0 AS bit)) -//ORDER BY [g].[FullName]"); + AssertSql( + @"SELECT [g].[FullName] +FROM [Gears] AS [g] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] <> CAST(1 AS bit)) +ORDER BY [g].[FullName]"); } public override void Where_is_properly_lifted_from_subquery_created_by_include() @@ -3516,23 +3541,11 @@ LEFT JOIN [Tags] AS [g.Tag] ON ([g].[Nickname] = [g.Tag].[GearNickName]) AND ([g ORDER BY [g].[FullName]"); } - public override async Task Where_and_order_by_are_properly_lifted_from_subquery_created_by_tracking(bool isAsync) - { - await base.Where_and_order_by_are_properly_lifted_from_subquery_created_by_tracking(isAsync); - - // issue #15994 -// AssertSql( -// @"SELECT [g].[FullName] -//FROM [Gears] AS [g] -//WHERE ([g].[Discriminator] IN (N'Officer', N'Gear') AND ([g].[FullName] <> N'Augustus Cole')) AND ([g].[HasSoulPatch] = CAST(0 AS bit)) -//ORDER BY [g].[FullName], [g].[Rank]"); - } - public override void Subquery_is_lifted_from_main_from_clause_of_SelectMany() { base.Subquery_is_lifted_from_main_from_clause_of_SelectMany(); - // issue #15994 + // issue #16081 // AssertSql( // @"SELECT [g].[FullName] AS [Name1], [g2].[FullName] AS [Name2] //FROM [Gears] AS [g] @@ -3545,7 +3558,7 @@ public override async Task Subquery_containing_SelectMany_projecting_main_from_c { await base.Subquery_containing_SelectMany_projecting_main_from_clause_gets_lifted(isAsync); - // issue #15994 + // issue #16081 // AssertSql( // @"SELECT [gear].[FullName] //FROM [Gears] AS [gear] @@ -3558,40 +3571,37 @@ public override async Task Subquery_containing_join_projecting_main_from_clause_ { await base.Subquery_containing_join_projecting_main_from_clause_gets_lifted(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [gear].[Nickname] -//FROM [Gears] AS [gear] -//INNER JOIN [Tags] AS [tag] ON [gear].[Nickname] = [tag].[GearNickName] -//WHERE [gear].[Discriminator] IN (N'Officer', N'Gear') -//ORDER BY [gear].[Nickname], [tag].[Note]"); + AssertSql( + @"SELECT [g].[Nickname] +FROM [Gears] AS [g] +INNER JOIN [Tags] AS [t] ON [g].[Nickname] = [t].[GearNickName] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') +ORDER BY [g].[Nickname]"); } public override async Task Subquery_containing_left_join_projecting_main_from_clause_gets_lifted(bool isAsync) { await base.Subquery_containing_left_join_projecting_main_from_clause_gets_lifted(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [gear].[Nickname] -//FROM [Gears] AS [gear] -//LEFT JOIN [Tags] AS [tag] ON [gear].[Nickname] = [tag].[GearNickName] -//WHERE [gear].[Discriminator] IN (N'Officer', N'Gear') -//ORDER BY [gear].[Nickname], [gear].[Rank]"); + AssertSql( + @"SELECT [g].[Nickname] +FROM [Gears] AS [g] +LEFT JOIN [Tags] AS [t] ON [g].[Nickname] = [t].[GearNickName] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') +ORDER BY [g].[Nickname]"); } public override async Task Subquery_containing_join_gets_lifted_clashing_names(bool isAsync) { await base.Subquery_containing_join_gets_lifted_clashing_names(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [gear].[Nickname] -//FROM [Gears] AS [gear] -//INNER JOIN [Tags] AS [tag] ON [gear].[Nickname] = [tag].[GearNickName] -//INNER JOIN [Tags] AS [tag0] ON [gear].[Nickname] = [tag0].[GearNickName] -//WHERE [gear].[Discriminator] IN (N'Officer', N'Gear') AND (([tag].[GearNickName] <> N'Cole Train') OR [tag].[GearNickName] IS NULL) -//ORDER BY [gear].[Nickname], [tag0].[Id], [tag].[Note]"); + AssertSql( + @"SELECT [g].[Nickname] +FROM [Gears] AS [g] +INNER JOIN [Tags] AS [t] ON [g].[Nickname] = [t].[GearNickName] +INNER JOIN [Tags] AS [t0] ON [g].[Nickname] = [t0].[GearNickName] +WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND (([t].[GearNickName] <> N'Cole Train') OR [t].[GearNickName] IS NULL) +ORDER BY [g].[Nickname], [t0].[Id]"); } public override void Subquery_created_by_include_gets_lifted_nested() @@ -3613,7 +3623,7 @@ public override async Task Subquery_is_lifted_from_additional_from_clause(bool i { await base.Subquery_is_lifted_from_additional_from_clause(isAsync); - // issue #15994 + // issue #16081 // AssertSql( // @"SELECT [g1].[FullName] AS [Name1], [t].[FullName] AS [Name2] //FROM [Gears] AS [g1] @@ -3639,7 +3649,7 @@ SELECT [t].[FullName] FROM ( SELECT TOP(@__p_0) [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] - WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND NOT ([g].[HasSoulPatch] = CAST(1 AS bit)) + WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] <> CAST(1 AS bit)) ORDER BY [g].[FullName] ) AS [t] ORDER BY [t].[Rank]"); @@ -3656,7 +3666,7 @@ SELECT [t].[FullName] FROM ( SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] - WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND NOT ([g].[HasSoulPatch] = CAST(1 AS bit)) + WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] <> CAST(1 AS bit)) ORDER BY [g].[FullName] OFFSET @__p_0 ROWS ) AS [t] @@ -3674,7 +3684,7 @@ SELECT [t].[FullName] FROM ( SELECT TOP(@__p_0) [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] - WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND NOT ([g].[HasSoulPatch] = CAST(1 AS bit)) + WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] <> CAST(1 AS bit)) ) AS [t] ORDER BY [t].[Rank]"); } @@ -3690,7 +3700,7 @@ SELECT [t].[FullName] FROM ( SELECT TOP(@__p_0) [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] - WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND NOT ([g].[HasSoulPatch] = CAST(1 AS bit)) + WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] <> CAST(1 AS bit)) ) AS [t] ORDER BY [t].[Rank]"); } @@ -3706,7 +3716,7 @@ SELECT [t].[FullName] FROM ( SELECT TOP(@__p_0) [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] FROM [Gears] AS [g] - WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND NOT ([g].[HasSoulPatch] = CAST(1 AS bit)) + WHERE [g].[Discriminator] IN (N'Gear', N'Officer') AND ([g].[HasSoulPatch] <> CAST(1 AS bit)) ) AS [t] ORDER BY [t].[FullName], [t].[Rank]"); } @@ -4030,24 +4040,22 @@ public override void Navigation_access_via_EFProperty_on_derived_entity_using_ca { base.Navigation_access_via_EFProperty_on_derived_entity_using_cast(); - // issue #15994 -// AssertSql( -// @"SELECT [f].[Name], [t].[ThreatLevel] AS [Threat] -//FROM [ConditionalFactions] AS [f] -//LEFT JOIN ( -// SELECT [f.Commander].* -// FROM [LocustLeaders] AS [f.Commander] -// WHERE [f.Commander].[Discriminator] = N'LocustCommander' -//) AS [t] ON ([f].[Discriminator] = N'LocustHorde') AND ([f].[CommanderName] = [t].[Name]) -//WHERE ([f].[Discriminator] = N'LocustHorde') AND ([f].[Discriminator] = N'LocustHorde') -//ORDER BY [f].[Name]"); + AssertSql( + @"SELECT [f].[Name], [t].[ThreatLevel] AS [Threat] +FROM [ConditionalFactions] AS [f] +LEFT JOIN ( + SELECT [f.Commander].* + FROM [LocustLeaders] AS [f.Commander] + WHERE [f.Commander].[Discriminator] = N'LocustCommander' +) AS [t] ON ([f].[Discriminator] = N'LocustHorde') AND ([f].[CommanderName] = [t].[Name]) +WHERE ([f].[Discriminator] = N'LocustHorde') AND ([f].[Discriminator] = N'LocustHorde') +ORDER BY [f].[Name]"); } public override void Navigation_access_fk_on_derived_entity_using_cast() { base.Navigation_access_fk_on_derived_entity_using_cast(); - // issue #15994 // AssertSql( // @"SELECT [f].[Name] AS [Name0], [t].[Name] AS [CommanderName] //FROM [ConditionalFactions] AS [f] @@ -4321,7 +4329,6 @@ public override void Select_null_conditional_with_inheritance() { base.Select_null_conditional_with_inheritance(); - // issue #15994 // AssertSql( // @"SELECT [f].[CommanderName] //FROM [ConditionalFactions] AS [f] @@ -6595,7 +6602,6 @@ public override async Task Select_required_navigation_on_derived_type(bool isAsy { await base.Select_required_navigation_on_derived_type(isAsync); - // issue #15994 // AssertSql( // @"SELECT [ll.HighCommand].[Name] //FROM [LocustLeaders] AS [ll] @@ -6618,7 +6624,6 @@ public override async Task Where_required_navigation_on_derived_type(bool isAsyn { await base.Where_required_navigation_on_derived_type(isAsync); - // issue #15994 // AssertSql( // @"SELECT [ll].[Name], [ll].[Discriminator], [ll].[LocustHordeId], [ll].[ThreatLevel], [ll].[DefeatedByNickname], [ll].[DefeatedBySquadId], [ll].[HighCommandId] //FROM [LocustLeaders] AS [ll] @@ -6769,10 +6774,10 @@ public override async Task Negated_bool_ternary_inside_anonymous_type_in_project AssertSql( @"SELECT CASE - WHEN NOT (CASE + WHEN CASE WHEN CAST([t].[HasSoulPatch] AS bit) = CAST(1 AS bit) THEN CAST(1 AS bit) ELSE COALESCE([t].[HasSoulPatch], CAST(1 AS bit)) - END = CAST(1 AS bit)) THEN CAST(1 AS bit) + END <> CAST(1 AS bit) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS [c] FROM [Tags] AS [t0] @@ -6859,7 +6864,7 @@ public override async Task Join_on_entity_qsre_keys_composite_key(bool isAsync) { await base.Join_on_entity_qsre_keys_composite_key(isAsync); - // issue #15994 + // issue #16081 // AssertSql( // @"SELECT [g1].[FullName] AS [GearName1], [g2].[FullName] AS [GearName2] //FROM [Gears] AS [g1] @@ -6871,7 +6876,7 @@ public override async Task Join_on_entity_qsre_keys_inheritance(bool isAsync) { await base.Join_on_entity_qsre_keys_inheritance(isAsync); - // issue #15994 + // issue #16081 // AssertSql( // @"SELECT [g].[FullName] AS [GearName], [o].[FullName] AS [OfficerName] //FROM [Gears] AS [g] @@ -6940,20 +6945,20 @@ public override async Task Join_on_entity_qsre_keys_inner_key_is_nested_navigati { await base.Join_on_entity_qsre_keys_inner_key_is_nested_navigation(isAsync); - // issue #15994 -// AssertSql( -// @"SELECT [s].[Name] AS [SquadName], [t].[Name] AS [WeaponName] -//FROM [Squads] AS [s] -//INNER JOIN ( -// SELECT [ww].* -// FROM [Weapons] AS [ww] -// WHERE [ww].[IsAutomatic] = CAST(1 AS bit) -//) AS [t] ON [s].[Id] = ( -// SELECT TOP(1) [subQuery.Squad0].[Id] -// FROM [Gears] AS [subQuery0] -// INNER JOIN [Squads] AS [subQuery.Squad0] ON [subQuery0].[SquadId] = [subQuery.Squad0].[Id] -// WHERE [subQuery0].[Discriminator] IN (N'Officer', N'Gear') AND ([subQuery0].[FullName] = [t].[OwnerFullName]) -//)"); + AssertSql( + @"SELECT [s].[Name] AS [SquadName], [t0].[Name] AS [WeaponName] +FROM [Squads] AS [s] +INNER JOIN ( + SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId], [t].[Nickname], [t].[SquadId], [t].[AssignedCityName], [t].[CityOrBirthName], [t].[Discriminator], [t].[FullName], [t].[HasSoulPatch], [t].[LeaderNickname], [t].[LeaderSquadId], [t].[Rank], [s0].[Id] AS [Id0], [s0].[InternalNumber], [s0].[Name] AS [Name0] + FROM [Weapons] AS [w] + LEFT JOIN ( + SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] + FROM [Gears] AS [g] + WHERE [g].[Discriminator] IN (N'Gear', N'Officer') + ) AS [t] ON [w].[OwnerFullName] = [t].[FullName] + LEFT JOIN [Squads] AS [s0] ON [t].[SquadId] = [s0].[Id] + WHERE [w].[IsAutomatic] = CAST(1 AS bit) +) AS [t0] ON [s].[Id] = [t0].[Id0]"); } public override async Task GroupJoin_on_entity_qsre_keys_inner_key_is_nested_navigation(bool isAsync) @@ -7129,7 +7134,7 @@ public override async Task Project_one_value_type_from_empty_collection(bool isA { await base.Project_one_value_type_from_empty_collection(isAsync); - // issue #15994 + // issue #15864 // AssertSql( // @"SELECT [s].[Name], COALESCE(( // SELECT TOP(1) [g].[SquadId] @@ -7158,7 +7163,7 @@ public override async Task Select_subquery_projecting_single_constant_int(bool i { await base.Select_subquery_projecting_single_constant_int(isAsync); - // issue #15994 + // issue #15864 // AssertSql( // @"SELECT [s].[Name], COALESCE(( // SELECT TOP(1) 42 @@ -7184,7 +7189,7 @@ public override async Task Select_subquery_projecting_single_constant_bool(bool { await base.Select_subquery_projecting_single_constant_bool(isAsync); - // issue #15994 + // issue #15864 // AssertSql( // @"SELECT [s].[Name], COALESCE(( // SELECT TOP(1) CAST(1 AS bit) @@ -7598,7 +7603,7 @@ public override async Task Select_subquery_boolean(bool isAsync) { await base.Select_subquery_boolean(isAsync); - // issue #15994 + // issue #15864 // AssertSql( // @"SELECT COALESCE(( // SELECT TOP(1) [w].[IsAutomatic] @@ -7688,7 +7693,7 @@ public override async Task Select_subquery_boolean_empty(bool isAsync) { await base.Select_subquery_boolean_empty(isAsync); - // issue #15994 + // issue #15864 // AssertSql( // @"SELECT COALESCE(( // SELECT TOP(1) [w].[IsAutomatic] @@ -7975,7 +7980,7 @@ public override async Task Double_order_by_on_string_compare(bool isAsync) { await base.Double_order_by_on_string_compare(isAsync); - // issue #15994 + // issue #16092 // AssertSql( // @"SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId] //FROM [Weapons] AS [w] @@ -7999,7 +8004,7 @@ public override async Task String_compare_with_null_conditional_argument(bool is { await base.String_compare_with_null_conditional_argument(isAsync); - // issue #15994 + // issue #16092 // AssertSql( // @"SELECT [w.SynergyWith].[Id], [w.SynergyWith].[AmmunitionType], [w.SynergyWith].[IsAutomatic], [w.SynergyWith].[Name], [w.SynergyWith].[OwnerFullName], [w.SynergyWith].[SynergyWithId] //FROM [Weapons] AS [w] @@ -8014,7 +8019,7 @@ public override async Task String_compare_with_null_conditional_argument2(bool i { await base.String_compare_with_null_conditional_argument2(isAsync); - // issue #15994 + // issue #16092 // AssertSql( // @"SELECT [w.SynergyWith].[Id], [w.SynergyWith].[AmmunitionType], [w.SynergyWith].[IsAutomatic], [w.SynergyWith].[Name], [w.SynergyWith].[OwnerFullName], [w.SynergyWith].[SynergyWithId] //FROM [Weapons] AS [w] @@ -8418,7 +8423,7 @@ public override void OfTypeNav1() { base.OfTypeNav1(); - // issue #15994 + // issue #16094 // AssertSql( // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] //FROM [Gears] AS [g] @@ -8431,7 +8436,7 @@ public override void OfTypeNav2() { base.OfTypeNav2(); - // issue #15994 + // issue #16094 // AssertSql( // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] //FROM [Gears] AS [g] @@ -8444,7 +8449,7 @@ public override void OfTypeNav3() { base.OfTypeNav3(); - // issue #15994 + // issue #16094 // AssertSql( // @"SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOrBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] //FROM [Gears] AS [g] diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs index 49850a1d6a1..47990eed061 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/NullSemanticsQuerySqlServerTest.cs @@ -724,7 +724,7 @@ public override void Contains_with_local_array_closure_false_with_null() AssertSql( @"SELECT [e].[Id] FROM [Entities1] AS [e] -WHERE NOT ([e].[NullableStringA] IN (N'Foo') OR [e].[NullableStringA] IS NULL)"); +WHERE [e].[NullableStringA] NOT IN (N'Foo') AND [e].[NullableStringA] IS NOT NULL"); } public override void Contains_with_local_array_closure_with_multiple_nulls() diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Functions.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Functions.cs index 4a7c4caf0ae..f2a8452a15c 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Functions.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Functions.cs @@ -137,7 +137,7 @@ await AssertQuery( AssertSql( @"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 (N'M' = N'') OR (CHARINDEX(N'M', [c].[ContactName]) > 0)"); +WHERE CHARINDEX(N'M', [c].[ContactName]) > 0"); } public override async Task String_Compare_simple_zero(bool isAsync) @@ -1134,7 +1134,8 @@ FROM [Orders] AS [o] // @"SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] FROM [Orders] AS [o] -WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND (((N'1997' = N'') OR (CHARINDEX(N'1997', CONVERT(nvarchar(max), [o].[OrderDate])) > 0)) OR ((N'1998' = N'') OR (CHARINDEX(N'1998', CONVERT(nvarchar(max), [o].[OrderDate])) > 0)))"); +WHERE (([o].[CustomerID] = N'ALFKI') AND [o].[CustomerID] IS NOT NULL) AND ((CHARINDEX(N'1997', CONVERT(nvarchar(max), [o].[OrderDate])) > 0) OR (CHARINDEX(N'1998', CONVERT(nvarchar(max), [o].[OrderDate])) > 0))"); + } public override async Task Indexof_with_emptystring(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.JoinGroupJoin.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.JoinGroupJoin.cs index cbcf94ddb20..347c084196b 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.JoinGroupJoin.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.JoinGroupJoin.cs @@ -388,17 +388,17 @@ public override async Task GroupJoin_DefaultIfEmpty3(bool isAsync) { await base.GroupJoin_DefaultIfEmpty3(isAsync); - // issue #15994 -// AssertSql( -// @"@__p_0='1' - -//SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] -//FROM ( -// SELECT TOP(@__p_0) [c].* -// FROM [Customers] AS [c] -// ORDER BY [c].[CustomerID] -//) AS [t] -//LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID]"); + AssertSql( + @"@__p_0='1' + +SELECT [o].[OrderID], [o].[CustomerID], [o].[EmployeeID], [o].[OrderDate] +FROM ( + SELECT TOP(@__p_0) [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] + ORDER BY [c].[CustomerID] +) AS [t] +LEFT JOIN [Orders] AS [o] ON [t].[CustomerID] = [o].[CustomerID] +ORDER BY [t].[CustomerID]"); } public override async Task GroupJoin_Where(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.ResultOperators.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.ResultOperators.cs index fa30432a749..5a7a1879510 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.ResultOperators.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.ResultOperators.cs @@ -1056,10 +1056,10 @@ public override async Task Contains_with_local_collection_empty_inline(bool isAs { await base.Contains_with_local_collection_empty_inline(isAsync); - // issue #16037 -// AssertSql( -// @"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]"); + AssertSql( + @"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 CAST(1 AS bit) = CAST(1 AS bit)"); } public override async Task Contains_top_level(bool isAsync) @@ -1300,11 +1300,10 @@ public override async Task Where_subquery_all_not_equals_operator(bool isAsync) { await base.Where_subquery_all_not_equals_operator(isAsync); - // issue #16037 -// AssertSql( -// @"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] NOT IN (N'ABCDE', N'ALFKI', N'ANATR')"); + AssertSql( + @"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] NOT IN (N'ABCDE', N'ALFKI', N'ANATR')"); } public override async Task Where_subquery_all_not_equals(bool isAsync) @@ -1314,29 +1313,31 @@ public override async Task Where_subquery_all_not_equals(bool isAsync) AssertSql( @"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 NOT ([c].[CustomerID] IN (N'ABCDE', N'ALFKI', N'ANATR'))"); +WHERE [c].[CustomerID] NOT IN (N'ABCDE', N'ALFKI', N'ANATR')"); } public override async Task Where_subquery_all_not_equals_static(bool isAsync) { await base.Where_subquery_all_not_equals_static(isAsync); - // issue #16037 -// AssertSql( -// @"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] NOT IN (N'ABCDE', N'ALFKI', N'ANATR')"); + AssertSql( + @"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] NOT IN (N'ABCDE', N'ALFKI', N'ANATR')"); } public override async Task Where_subquery_where_all(bool isAsync) { await base.Where_subquery_where_all(isAsync); - // issue #15994 -// AssertSql( -// @"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].[City] = N'México D.F.') AND [c].[CustomerID] NOT IN (N'ABCDE', N'ALFKI', N'ANATR')"); + AssertSql( + @"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].[City] = N'México D.F.') AND [c].[City] IS NOT NULL) AND [c].[CustomerID] NOT IN (N'ABCDE', N'ALFKI', N'ANATR')", + // + @"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].[City] = N'México D.F.') AND [c].[City] IS NOT NULL) AND [c].[CustomerID] NOT IN (N'ABCDE', N'ALFKI', N'ANATR')"); } public override async Task Cast_to_same_Type_Count_works(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Where.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Where.cs index 18e4174afd1..b3c7947e042 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Where.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.Where.cs @@ -1154,7 +1154,7 @@ public override async Task Where_bool_member_false_shadow(bool isAsync) AssertSql( @"SELECT [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock] FROM [Products] AS [p] -WHERE NOT ([p].[Discontinued] = CAST(1 AS bit))"); +WHERE [p].[Discontinued] <> CAST(1 AS bit)"); } public override async Task Where_bool_member_equals_constant(bool isAsync) @@ -1281,18 +1281,17 @@ public override async Task Where_de_morgan_or_optimizated(bool isAsync) AssertSql( @"SELECT [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock] FROM [Products] AS [p] -WHERE NOT ([p].[Discontinued] = CAST(1 AS bit)) AND ([p].[ProductID] >= 20)"); +WHERE ([p].[Discontinued] <> CAST(1 AS bit)) AND ([p].[ProductID] >= 20)"); } public override async Task Where_de_morgan_and_optimizated(bool isAsync) { await base.Where_de_morgan_and_optimizated(isAsync); - // issue #16037 -// AssertSql( -// @"SELECT [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock] -//FROM [Products] AS [p] -//WHERE ([p].[Discontinued] = CAST(0 AS bit)) OR ([p].[ProductID] >= 20)"); + AssertSql( + @"SELECT [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock] +FROM [Products] AS [p] +WHERE ([p].[Discontinued] <> CAST(1 AS bit)) OR ([p].[ProductID] >= 20)"); } public override async Task Where_complex_negated_expression_optimized(bool isAsync) @@ -1302,7 +1301,7 @@ public override async Task Where_complex_negated_expression_optimized(bool isAsy AssertSql( @"SELECT [p].[ProductID], [p].[Discontinued], [p].[ProductName], [p].[SupplierID], [p].[UnitPrice], [p].[UnitsInStock] FROM [Products] AS [p] -WHERE (NOT ([p].[Discontinued] = CAST(1 AS bit)) AND ([p].[ProductID] < 60)) AND ([p].[ProductID] > 30)"); +WHERE (([p].[Discontinued] <> CAST(1 AS bit)) AND ([p].[ProductID] < 60)) AND ([p].[ProductID] > 30)"); } public override async Task Where_short_member_comparison(bool isAsync) @@ -1319,11 +1318,10 @@ public override async Task Where_comparison_to_nullable_bool(bool isAsync) { await base.Where_comparison_to_nullable_bool(isAsync); - // issue #15994 -// AssertSql( -// @"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'%KI'"); + AssertSql( + @"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'%KI'"); } public override async Task Where_true(bool isAsync) diff --git a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.cs b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.cs index cd91c904109..3788deb8c0e 100644 --- a/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.cs +++ b/test/EFCore.SqlServer.FunctionalTests/Query/SimpleQuerySqlServerTest.cs @@ -2044,7 +2044,7 @@ FROM [Customers] AS [c] ORDER BY [c].[CustomerID] OFFSET @__p_0 ROWS FETCH NEXT @__p_1 ROWS ONLY ) AS [t] - WHERE ([t].[CustomerID] IS NULL AND (CAST(0 AS bit) = CAST(1 AS bit))) OR ((N'B' IS NULL AND (CAST(0 AS bit) = CAST(1 AS bit))) OR NOT ([t].[CustomerID] LIKE N'B%'))) THEN CAST(1 AS bit) + WHERE ([t].[CustomerID] IS NULL AND (CAST(0 AS bit) = CAST(1 AS bit))) OR NOT ([t].[CustomerID] LIKE N'B%')) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END"); } @@ -2065,7 +2065,7 @@ SELECT TOP(@__p_0) [c].[CustomerID], [c].[Address], [c].[City], [c].[CompanyName FROM [Customers] AS [c] ORDER BY [c].[CustomerID] ) AS [t] - WHERE ([t].[CustomerID] IS NULL AND (CAST(0 AS bit) = CAST(1 AS bit))) OR ((N'A' IS NULL AND (CAST(0 AS bit) = CAST(1 AS bit))) OR NOT ([t].[CustomerID] LIKE N'A%'))) THEN CAST(1 AS bit) + WHERE ([t].[CustomerID] IS NULL AND (CAST(0 AS bit) = CAST(1 AS bit))) OR NOT ([t].[CustomerID] LIKE N'A%')) THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END"); } @@ -3243,7 +3243,7 @@ public override async Task Query_expression_with_to_string_and_contains(bool isA AssertSql( @"SELECT [o].[CustomerID] FROM [Orders] AS [o] -WHERE [o].[OrderDate] IS NOT NULL AND ((N'10' = N'') OR (CHARINDEX(N'10', CONVERT(VARCHAR(10), [o].[EmployeeID])) > 0))"); +WHERE [o].[OrderDate] IS NOT NULL AND (CHARINDEX(N'10', CONVERT(VARCHAR(10), [o].[EmployeeID])) > 0)"); } public override async Task Select_expression_long_to_string(bool isAsync)